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.
164 lines
4.2 KiB
Go
164 lines
4.2 KiB
Go
package server
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/git-pkgs/proxy/internal/database"
|
|
"github.com/git-pkgs/proxy/internal/enrichment"
|
|
)
|
|
|
|
func TestHandlePackagesList(t *testing.T) {
|
|
// Create a real database for testing
|
|
dir := t.TempDir()
|
|
dbPath := filepath.Join(dir, "test.db")
|
|
db, err := database.Create(dbPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = db.Close() }()
|
|
|
|
// Create test data
|
|
pkg1 := &database.Package{
|
|
PURL: "pkg:npm/lodash",
|
|
Ecosystem: testEcosystemNPM,
|
|
Name: "lodash",
|
|
LatestVersion: sql.NullString{String: "4.17.21", Valid: true},
|
|
License: sql.NullString{String: "MIT", Valid: true},
|
|
}
|
|
pkg2 := &database.Package{
|
|
PURL: "pkg:cargo/serde",
|
|
Ecosystem: "cargo",
|
|
Name: "serde",
|
|
LatestVersion: sql.NullString{String: "1.0.0", Valid: true},
|
|
License: sql.NullString{String: "MIT OR Apache-2.0", Valid: true},
|
|
}
|
|
_ = db.UpsertPackage(pkg1)
|
|
_ = db.UpsertPackage(pkg2)
|
|
|
|
ver1 := &database.Version{
|
|
PURL: "pkg:npm/lodash@4.17.21",
|
|
PackagePURL: pkg1.PURL,
|
|
}
|
|
ver2 := &database.Version{
|
|
PURL: "pkg:cargo/serde@1.0.0",
|
|
PackagePURL: pkg2.PURL,
|
|
}
|
|
_ = db.UpsertVersion(ver1)
|
|
_ = db.UpsertVersion(ver2)
|
|
|
|
art1 := &database.Artifact{
|
|
VersionPURL: ver1.PURL,
|
|
Filename: "lodash.tgz",
|
|
UpstreamURL: "https://example.com/lodash.tgz",
|
|
StoragePath: sql.NullString{String: "/cache/lodash.tgz", Valid: true},
|
|
Size: sql.NullInt64{Int64: 1024, Valid: true},
|
|
HitCount: 100,
|
|
FetchedAt: sql.NullTime{Time: time.Now(), Valid: true},
|
|
}
|
|
art2 := &database.Artifact{
|
|
VersionPURL: ver2.PURL,
|
|
Filename: "serde.crate",
|
|
UpstreamURL: "https://example.com/serde.crate",
|
|
StoragePath: sql.NullString{String: "/cache/serde.crate", Valid: true},
|
|
Size: sql.NullInt64{Int64: 2048, Valid: true},
|
|
HitCount: 50,
|
|
FetchedAt: sql.NullTime{Time: time.Now(), Valid: true},
|
|
}
|
|
_ = db.UpsertArtifact(art1)
|
|
_ = db.UpsertArtifact(art2)
|
|
|
|
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
|
enrichSvc := enrichment.New(logger)
|
|
handler := NewAPIHandler(enrichSvc, db)
|
|
|
|
t.Run("list all packages", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/api/packages", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandlePackagesList(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
var resp PackagesListResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if resp.Count != 2 {
|
|
t.Errorf("expected count 2, got %d", resp.Count)
|
|
}
|
|
if resp.Total != 2 {
|
|
t.Errorf("expected total 2, got %d", resp.Total)
|
|
}
|
|
if len(resp.Results) != 2 {
|
|
t.Errorf("expected 2 results, got %d", len(resp.Results))
|
|
}
|
|
if resp.SortBy != defaultSortBy {
|
|
t.Errorf("expected default sort to be hits, got %s", resp.SortBy)
|
|
}
|
|
})
|
|
|
|
t.Run("with ecosystem filter", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/api/packages?ecosystem=npm", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandlePackagesList(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
var resp PackagesListResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if resp.Ecosystem != testEcosystemNPM {
|
|
t.Errorf("expected ecosystem npm, got %s", resp.Ecosystem)
|
|
}
|
|
if resp.Count != 1 {
|
|
t.Errorf("expected count 1, got %d", resp.Count)
|
|
}
|
|
})
|
|
|
|
t.Run("with sort parameter", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/api/packages?sort=name", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandlePackagesList(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", w.Code)
|
|
}
|
|
|
|
var resp PackagesListResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if resp.SortBy != "name" {
|
|
t.Errorf("expected sort by name, got %s", resp.SortBy)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid sort parameter", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/api/packages?sort=invalid", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandlePackagesList(w, req)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("expected status 400, got %d", w.Code)
|
|
}
|
|
})
|
|
}
|