forked from mirrors/pkg-proxy
* Fix all golangci-lint issues across the codebase Resolve 77 lint issues reported by golangci-lint with gocritic, gocognit, gocyclo, maintidx, dupl, mnd, unparam, ireturn, goconst, and errcheck enabled. Net reduction of ~175 lines through shared helpers and deduplication. * Suppress staticcheck SA1019 for intentional deprecated field usage The Storage.Path field is deprecated but still read for backwards compatibility with existing configs that haven't migrated to the URL field.
317 lines
7.6 KiB
Go
317 lines
7.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/git-pkgs/proxy/internal/cooldown"
|
|
)
|
|
|
|
const testVersion100 = "1.0.0"
|
|
|
|
func testProxy() *Proxy {
|
|
return &Proxy{
|
|
Logger: slog.Default(),
|
|
HTTPClient: http.DefaultClient,
|
|
}
|
|
}
|
|
|
|
func TestNPMExtractVersionFromFilename(t *testing.T) {
|
|
h := &NPMHandler{}
|
|
|
|
tests := []struct {
|
|
packageName string
|
|
filename string
|
|
want string
|
|
}{
|
|
{"lodash", "lodash-4.17.21.tgz", "4.17.21"},
|
|
{"@babel/core", "core-7.23.0.tgz", "7.23.0"},
|
|
{"@types/node", "node-20.10.0.tgz", "20.10.0"},
|
|
{"express", "express-4.18.2.tgz", "4.18.2"},
|
|
{"lodash", "lodash.tgz", ""}, // no version
|
|
{"lodash", "lodash-4.17.21.zip", ""}, // wrong extension
|
|
{"lodash", "other-4.17.21.tgz", ""}, // wrong package name
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := h.extractVersionFromFilename(tt.packageName, tt.filename)
|
|
if got != tt.want {
|
|
t.Errorf("extractVersionFromFilename(%q, %q) = %q, want %q",
|
|
tt.packageName, tt.filename, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNPMRewriteMetadata(t *testing.T) {
|
|
h := &NPMHandler{
|
|
proxy: testProxy(),
|
|
proxyURL: "http://localhost:8080",
|
|
}
|
|
|
|
input := `{
|
|
"name": "lodash",
|
|
"versions": {
|
|
"4.17.21": {
|
|
"name": "lodash",
|
|
"version": "4.17.21",
|
|
"dist": {
|
|
"tarball": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
|
"shasum": "abc123"
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
output, err := h.rewriteMetadata("lodash", []byte(input))
|
|
if err != nil {
|
|
t.Fatalf("rewriteMetadata failed: %v", err)
|
|
}
|
|
|
|
var result map[string]any
|
|
if err := json.Unmarshal(output, &result); err != nil {
|
|
t.Fatalf("failed to parse output: %v", err)
|
|
}
|
|
|
|
versions := result["versions"].(map[string]any)
|
|
v := versions["4.17.21"].(map[string]any)
|
|
dist := v["dist"].(map[string]any)
|
|
tarball := dist["tarball"].(string)
|
|
|
|
expected := "http://localhost:8080/npm/lodash/-/lodash-4.17.21.tgz"
|
|
if tarball != expected {
|
|
t.Errorf("tarball = %q, want %q", tarball, expected)
|
|
}
|
|
}
|
|
|
|
func TestNPMRewriteMetadataScopedPackage(t *testing.T) {
|
|
h := &NPMHandler{
|
|
proxy: testProxy(),
|
|
proxyURL: "http://localhost:8080",
|
|
}
|
|
|
|
input := `{
|
|
"name": "@babel/core",
|
|
"versions": {
|
|
"7.23.0": {
|
|
"name": "@babel/core",
|
|
"version": "7.23.0",
|
|
"dist": {
|
|
"tarball": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz"
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
output, err := h.rewriteMetadata("@babel/core", []byte(input))
|
|
if err != nil {
|
|
t.Fatalf("rewriteMetadata failed: %v", err)
|
|
}
|
|
|
|
var result map[string]any
|
|
if err := json.Unmarshal(output, &result); err != nil {
|
|
t.Fatalf("failed to parse output: %v", err)
|
|
}
|
|
|
|
versions := result["versions"].(map[string]any)
|
|
v := versions["7.23.0"].(map[string]any)
|
|
dist := v["dist"].(map[string]any)
|
|
tarball := dist["tarball"].(string)
|
|
|
|
expected := "http://localhost:8080/npm/@babel%2Fcore/-/core-7.23.0.tgz"
|
|
if tarball != expected {
|
|
t.Errorf("tarball = %q, want %q", tarball, expected)
|
|
}
|
|
}
|
|
|
|
func TestNPMHandlerMetadataProxy(t *testing.T) {
|
|
// Create a mock upstream server
|
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/testpkg" {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{
|
|
"name": "testpkg",
|
|
"versions": {
|
|
"1.0.0": {
|
|
"name": "testpkg",
|
|
"version": "1.0.0",
|
|
"dist": {
|
|
"tarball": "https://registry.npmjs.org/testpkg/-/testpkg-1.0.0.tgz"
|
|
}
|
|
}
|
|
}
|
|
}`))
|
|
}))
|
|
defer upstream.Close()
|
|
|
|
h := &NPMHandler{
|
|
proxy: testProxy(),
|
|
upstreamURL: upstream.URL,
|
|
proxyURL: "http://proxy.local",
|
|
}
|
|
|
|
// Test metadata request
|
|
req := httptest.NewRequest(http.MethodGet, "/testpkg", nil)
|
|
req.SetPathValue("name", "testpkg")
|
|
|
|
w := httptest.NewRecorder()
|
|
h.handlePackageMetadata(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("status = %d, want %d", w.Code, http.StatusOK)
|
|
}
|
|
|
|
var result map[string]any
|
|
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
|
|
// Check that tarball URL was rewritten
|
|
versions := result["versions"].(map[string]any)
|
|
v := versions[testVersion100].(map[string]any)
|
|
dist := v["dist"].(map[string]any)
|
|
tarball := dist["tarball"].(string)
|
|
|
|
if tarball != "http://proxy.local/npm/testpkg/-/testpkg-1.0.0.tgz" {
|
|
t.Errorf("tarball URL not rewritten correctly: %s", tarball)
|
|
}
|
|
}
|
|
|
|
func TestNPMRewriteMetadataCooldown(t *testing.T) {
|
|
now := time.Now()
|
|
old := now.Add(-10 * 24 * time.Hour).Format(time.RFC3339)
|
|
recent := now.Add(-1 * time.Hour).Format(time.RFC3339)
|
|
|
|
proxy := testProxy()
|
|
proxy.Cooldown = &cooldown.Config{Default: "3d"}
|
|
|
|
h := &NPMHandler{
|
|
proxy: proxy,
|
|
proxyURL: "http://localhost:8080",
|
|
}
|
|
|
|
input := `{
|
|
"name": "testpkg",
|
|
"dist-tags": {"latest": "2.0.0"},
|
|
"time": {
|
|
"1.0.0": "` + old + `",
|
|
"2.0.0": "` + recent + `"
|
|
},
|
|
"versions": {
|
|
"1.0.0": {
|
|
"name": "testpkg",
|
|
"version": "1.0.0",
|
|
"dist": {
|
|
"tarball": "https://registry.npmjs.org/testpkg/-/testpkg-1.0.0.tgz"
|
|
}
|
|
},
|
|
"2.0.0": {
|
|
"name": "testpkg",
|
|
"version": "2.0.0",
|
|
"dist": {
|
|
"tarball": "https://registry.npmjs.org/testpkg/-/testpkg-2.0.0.tgz"
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
output, err := h.rewriteMetadata("testpkg", []byte(input))
|
|
if err != nil {
|
|
t.Fatalf("rewriteMetadata failed: %v", err)
|
|
}
|
|
|
|
var result map[string]any
|
|
if err := json.Unmarshal(output, &result); err != nil {
|
|
t.Fatalf("failed to parse output: %v", err)
|
|
}
|
|
|
|
versions := result["versions"].(map[string]any)
|
|
|
|
// Old version should remain
|
|
if _, ok := versions[testVersion100]; !ok {
|
|
t.Error("version 1.0.0 should not be filtered")
|
|
}
|
|
|
|
// Recent version should be filtered
|
|
if _, ok := versions["2.0.0"]; ok {
|
|
t.Error("version 2.0.0 should be filtered by cooldown")
|
|
}
|
|
|
|
// dist-tags.latest should be updated to 1.0.0
|
|
distTags := result["dist-tags"].(map[string]any)
|
|
if distTags["latest"] != testVersion100 {
|
|
t.Errorf("dist-tags.latest = %q, want %q", distTags["latest"], testVersion100)
|
|
}
|
|
}
|
|
|
|
func TestNPMRewriteMetadataCooldownExemptPackage(t *testing.T) {
|
|
now := time.Now()
|
|
recent := now.Add(-1 * time.Hour).Format(time.RFC3339)
|
|
|
|
proxy := testProxy()
|
|
proxy.Cooldown = &cooldown.Config{
|
|
Default: "3d",
|
|
Packages: map[string]string{"pkg:npm/testpkg": "0"},
|
|
}
|
|
|
|
h := &NPMHandler{
|
|
proxy: proxy,
|
|
proxyURL: "http://localhost:8080",
|
|
}
|
|
|
|
input := `{
|
|
"name": "testpkg",
|
|
"time": {"1.0.0": "` + recent + `"},
|
|
"versions": {
|
|
"1.0.0": {
|
|
"name": "testpkg",
|
|
"version": "1.0.0",
|
|
"dist": {"tarball": "https://registry.npmjs.org/testpkg/-/testpkg-1.0.0.tgz"}
|
|
}
|
|
}
|
|
}`
|
|
|
|
output, err := h.rewriteMetadata("testpkg", []byte(input))
|
|
if err != nil {
|
|
t.Fatalf("rewriteMetadata failed: %v", err)
|
|
}
|
|
|
|
var result map[string]any
|
|
if err := json.Unmarshal(output, &result); err != nil {
|
|
t.Fatalf("failed to parse output: %v", err)
|
|
}
|
|
|
|
versions := result["versions"].(map[string]any)
|
|
if _, ok := versions[testVersion100]; !ok {
|
|
t.Error("exempt package version should not be filtered")
|
|
}
|
|
}
|
|
|
|
func TestNPMHandlerMetadataNotFound(t *testing.T) {
|
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}))
|
|
defer upstream.Close()
|
|
|
|
h := &NPMHandler{
|
|
proxy: testProxy(),
|
|
upstreamURL: upstream.URL,
|
|
proxyURL: "http://proxy.local",
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/nonexistent", nil)
|
|
req.SetPathValue("name", "nonexistent")
|
|
|
|
w := httptest.NewRecorder()
|
|
h.handlePackageMetadata(w, req)
|
|
|
|
if w.Code != http.StatusNotFound {
|
|
t.Errorf("status = %d, want %d", w.Code, http.StatusNotFound)
|
|
}
|
|
}
|