From 1009bc7c69d8910799e85e50c878ba6d713d5331 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Fri, 3 Jul 2026 13:55:30 +1000 Subject: [PATCH] test: database closed-db error paths + pure goproxy/generic/helm/repotype gaps --- internal/database/database_test.go | 59 ++++++++++++++++++- .../provider/generic/generic_extra_test.go | 13 ++++ .../provider/goproxy/goproxy_extra_test.go | 27 +++++++++ internal/provider/helm/helm_extra_test.go | 18 ++++++ pkg/models/repotype_test.go | 18 ++++++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 internal/provider/generic/generic_extra_test.go create mode 100644 internal/provider/goproxy/goproxy_extra_test.go create mode 100644 internal/provider/helm/helm_extra_test.go create mode 100644 pkg/models/repotype_test.go diff --git a/internal/database/database_test.go b/internal/database/database_test.go index b1e6aba..af3746e 100644 --- a/internal/database/database_test.go +++ b/internal/database/database_test.go @@ -11,7 +11,10 @@ import ( "git.unkin.net/unkin/artifactapi/pkg/models" ) -var testDB *DB +var ( + testDB *DB + testDSN string +) func TestMain(m *testing.M) { c := context.Background() @@ -20,6 +23,7 @@ func TestMain(m *testing.M) { // Docker unavailable: run anyway so tests self-skip via requireDB. os.Exit(m.Run()) } + testDSN = dsn db, err := New(dsn) if err != nil { terminate() @@ -254,6 +258,59 @@ func TestStats(t *testing.T) { } } +func TestDatabaseErrorPaths(t *testing.T) { + requireDB(t) + bad, err := New(testDSN) + if err != nil { + t.Fatal(err) + } + bad.Close() // every query now fails + ctx := context.Background() + + if _, err := bad.ListRemotes(ctx); err == nil { + t.Error("ListRemotes should error on closed db") + } + if _, err := bad.ListVirtuals(ctx); err == nil { + t.Error("ListVirtuals should error") + } + if _, err := bad.ListArtifacts(ctx, "r", 10, 0); err == nil { + t.Error("ListArtifacts should error") + } + if _, err := bad.ListLocalFiles(ctx, "r", 10, 0); err == nil { + t.Error("ListLocalFiles should error") + } + if _, err := bad.ListLocalFilesByPrefix(ctx, "r", "p"); err == nil { + t.Error("ListLocalFilesByPrefix should error") + } + if _, err := bad.ListLocalFilePackages(ctx, "r"); err == nil { + t.Error("ListLocalFilePackages should error") + } + if _, err := bad.ListFilesByPrefix(ctx, "r", "p"); err == nil { + t.Error("ListFilesByPrefix should error") + } + if _, err := bad.ListPackages(ctx, "r"); err == nil { + t.Error("ListPackages should error") + } + if _, err := bad.FindOrphanedBlobs(ctx, 0); err == nil { + t.Error("FindOrphanedBlobs should error") + } + if _, err := bad.GetOverviewStats(ctx); err == nil { + t.Error("GetOverviewStats should error") + } + if _, err := bad.GetTopRemotes(ctx, 5); err == nil { + t.Error("GetTopRemotes should error") + } + if _, err := bad.GetTopFilesByHits(ctx, 5); err == nil { + t.Error("GetTopFilesByHits should error") + } + if _, err := bad.GetTopFilesByBandwidth(ctx, 5); err == nil { + t.Error("GetTopFilesByBandwidth should error") + } + if _, err := bad.ListRPMMetadataEntries(ctx, "r"); err == nil { + t.Error("ListRPMMetadataEntries should error") + } +} + func TestRPMMetadata(t *testing.T) { requireDB(t) seedRemote(t, "r-rpm") diff --git a/internal/provider/generic/generic_extra_test.go b/internal/provider/generic/generic_extra_test.go new file mode 100644 index 0000000..601d0f6 --- /dev/null +++ b/internal/provider/generic/generic_extra_test.go @@ -0,0 +1,13 @@ +package generic + +import ( + "testing" + + "git.unkin.net/unkin/artifactapi/pkg/models" +) + +func TestGenericRewriteResponse(t *testing.T) { + if out, err := (&Provider{}).RewriteResponse([]byte("x"), models.Remote{}, "http://p"); out != nil || err != nil { + t.Error("generic never rewrites") + } +} diff --git a/internal/provider/goproxy/goproxy_extra_test.go b/internal/provider/goproxy/goproxy_extra_test.go new file mode 100644 index 0000000..eb2f3cf --- /dev/null +++ b/internal/provider/goproxy/goproxy_extra_test.go @@ -0,0 +1,27 @@ +package goproxy + +import ( + "context" + "testing" + + "git.unkin.net/unkin/artifactapi/pkg/models" +) + +func TestGoProxyURLAuthRewrite(t *testing.T) { + p := &Provider{} + if got := p.UpstreamURL(models.Remote{BaseURL: "https://proxy.golang.org/"}, "/mod/@v/list"); got != "https://proxy.golang.org/mod/@v/list" { + t.Errorf("upstream url %q", got) + } + if out, err := p.RewriteResponse([]byte("x"), models.Remote{}, "http://p"); out != nil || err != nil { + t.Error("goproxy never rewrites") + } + if h, _ := p.AuthHeaders(context.Background(), models.Remote{Username: "u", Password: "p"}); h.Get("Authorization") == "" { + t.Error("expected basic auth header") + } + if got := p.ContentType("mod/@v/v1.0.0.info"); got != "application/json" { + t.Errorf("info content type %q", got) + } + if got := p.ContentType("mod/@v/v1.0.0.mod"); got != "text/plain" { + t.Errorf("mod content type %q", got) + } +} diff --git a/internal/provider/helm/helm_extra_test.go b/internal/provider/helm/helm_extra_test.go new file mode 100644 index 0000000..2f93783 --- /dev/null +++ b/internal/provider/helm/helm_extra_test.go @@ -0,0 +1,18 @@ +package helm + +import "testing" + +func TestHelmContentTypeBranches(t *testing.T) { + p := &Provider{} + for path, want := range map[string]string{ + "charts/x-1.0.0.tgz": "application/gzip", + "x.tar.gz": "application/gzip", + "index.yaml": "text/yaml", + "x.yml": "text/yaml", + "other": "application/octet-stream", + } { + if got := p.ContentType(path); got != want { + t.Errorf("ContentType(%q)=%q want %q", path, got, want) + } + } +} diff --git a/pkg/models/repotype_test.go b/pkg/models/repotype_test.go new file mode 100644 index 0000000..bedcc52 --- /dev/null +++ b/pkg/models/repotype_test.go @@ -0,0 +1,18 @@ +package models + +import "testing" + +func TestRepoType(t *testing.T) { + if RepoTypeRemote.String() != "remote" || RepoTypeLocal.String() != "local" { + t.Error("RepoType.String") + } + if !RepoTypeRemote.Valid() || RepoType("bogus").Valid() { + t.Error("RepoType.Valid") + } + if rt, err := ParseRepoType("local"); err != nil || rt != RepoTypeLocal { + t.Errorf("ParseRepoType(local) = %v %v", rt, err) + } + if _, err := ParseRepoType("nope"); err == nil { + t.Error("ParseRepoType should reject unknown") + } +}