From 082d3f1ddb59b6dcd7548953bceeedea9190c816 Mon Sep 17 00:00:00 2001 From: Matthew Suozzo Date: Fri, 21 Feb 2025 17:18:18 -0500 Subject: [PATCH] Fix timewarp pypi support (#353) --- internal/timewarp/timewarp.go | 4 +- internal/timewarp/timewarp_test.go | 92 +++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/internal/timewarp/timewarp.go b/internal/timewarp/timewarp.go index bec138c0..86d05795 100644 --- a/internal/timewarp/timewarp.go +++ b/internal/timewarp/timewarp.go @@ -30,7 +30,7 @@ import ( var ( npmRegistry = urlx.MustParse("https://registry.npmjs.org/") - pypiRegistry = urlx.MustParse("https://pypi.org/simple") + pypiRegistry = urlx.MustParse("https://pypi.org/") lowTimeBound = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) ) @@ -295,7 +295,7 @@ func timeWarpPyPIProjectRequest(client httpx.BasicClient, obj map[string]any, at if t.Before(at.Add(time.Second)) { pastFiles = append(pastFiles, file) } - if t.Before(firstSeen) { + if t.Before(firstSeen) || firstSeen.IsZero() { firstSeen = t } } diff --git a/internal/timewarp/timewarp_test.go b/internal/timewarp/timewarp_test.go index a04a04c2..992babcf 100644 --- a/internal/timewarp/timewarp_test.go +++ b/internal/timewarp/timewarp_test.go @@ -60,6 +60,11 @@ func TestHandler_ServeHTTP(t *testing.T) { }, }, }, + URLValidator: func(expected, actual string) { + if diff := cmp.Diff(expected, actual); diff != "" { + t.Fatalf("URL mismatch (-want +got):\n%s", diff) + } + }, }, want: &http.Response{ StatusCode: http.StatusOK, @@ -89,13 +94,13 @@ func TestHandler_ServeHTTP(t *testing.T) { }, { name: "pypi project request - successful time warp", - url: "http://localhost:8081/some-package", + url: "http://localhost:8081/pypi/some-package/json", basicAuth: "pypi:2022-01-01T00:00:00Z", client: &httpxtest.MockClient{ Calls: []httpxtest.Call{ { Method: "GET", - URL: "https://pypi.org/simple/some-package", + URL: "https://pypi.org/pypi/some-package/json", Response: &http.Response{ StatusCode: http.StatusOK, Header: http.Header{ @@ -126,7 +131,7 @@ func TestHandler_ServeHTTP(t *testing.T) { }, { Method: "GET", - URL: "https://pypi.org/simple/pypi/some-package/1.0.0/json", + URL: "https://pypi.org/pypi/some-package/1.0.0/json", Response: &http.Response{ StatusCode: http.StatusOK, Header: http.Header{ @@ -142,6 +147,11 @@ func TestHandler_ServeHTTP(t *testing.T) { }, }, }, + URLValidator: func(expected, actual string) { + if diff := cmp.Diff(expected, actual); diff != "" { + t.Fatalf("URL mismatch (-want +got):\n%s", diff) + } + }, }, want: &http.Response{ StatusCode: http.StatusOK, @@ -165,6 +175,82 @@ func TestHandler_ServeHTTP(t *testing.T) { }`)), }, }, + { + name: "pypi project request - timewarp but no available packages", + url: "http://localhost:8081/pypi/some-package/json", + basicAuth: "pypi:2022-01-01T00:00:00Z", + client: &httpxtest.MockClient{ + Calls: []httpxtest.Call{ + { + Method: "GET", + URL: "https://pypi.org/pypi/some-package/json", + Response: &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: io.NopCloser(bytes.NewBufferString(`{ + "info": { + "name": "some-package", + "version": "2.0.0", + "requires_dist": ["req1", "req2", "req3"] + }, + "releases": { + "1.0.0": [ + { + "upload_time_iso_8601": "2023-06-01T00:00:00Z", + "filename": "some-package-1.0.0.tar.gz" + } + ], + "2.0.0": [ + { + "upload_time_iso_8601": "2024-06-01T00:00:00Z", + "filename": "some-package-2.0.0.tar.gz" + } + ] + } + }`)), + }, + }, + { + Method: "GET", + URL: "https://pypi.org/pypi/some-package/json", + Response: &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: io.NopCloser(bytes.NewBufferString(`{ + "info": { + "name": "some-package", + "version": "1.0.0", + "requires_dist": ["req1", "req2"] + } + }`)), + }, + }, + }, + URLValidator: func(expected, actual string) { + if diff := cmp.Diff(expected, actual); diff != "" { + t.Fatalf("URL mismatch (-want +got):\n%s", diff) + } + }, + }, + want: &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + Body: io.NopCloser(bytes.NewBufferString(`{ + "info": { + "name": "some-package", + "version": "1.0.0", + "requires_dist": ["req1", "req2"] + }, + "releases": {} + }`)), + }, + }, { name: "invalid platform", url: "http://localhost:8081/some-package",