diff --git a/internal/provider/rpm/rpm_meta_test.go b/internal/provider/rpm/rpm_meta_test.go
index 3e6d7b9..19d1a69 100644
--- a/internal/provider/rpm/rpm_meta_test.go
+++ b/internal/provider/rpm/rpm_meta_test.go
@@ -171,6 +171,28 @@ func TestRPMServeRepodata(t *testing.T) {
}
}
+type errRPMReader struct{}
+
+func (errRPMReader) ListRPMMetadataEntries(context.Context, string) ([]provider.RPMMetadata, error) {
+ return nil, io.ErrUnexpectedEOF
+}
+func (errRPMReader) ListFilesByPrefix(context.Context, string, string) ([]provider.FileEntry, error) {
+ return nil, nil
+}
+func (errRPMReader) ListPackages(context.Context, string) ([]string, error) { return nil, nil }
+
+func TestRPMServeMetadataError(t *testing.T) {
+ p := &Provider{}
+ for _, path := range []string{"repodata/repomd.xml", "repodata/h-primary.xml.gz", "repodata/h-filelists.xml.gz", "repodata/h-other.xml.gz"} {
+ w := httptest.NewRecorder()
+ r := httptest.NewRequest(http.MethodGet, "/"+path, nil)
+ p.ServeLocalIndex(w, r, errRPMReader{}, "repo", path)
+ if w.Code != 500 {
+ t.Errorf("%s with failing reader = %d, want 500", path, w.Code)
+ }
+ }
+}
+
func TestRPMFullMetadataXML(t *testing.T) {
// A fully-populated entry exercises every optional-field branch in the
// primary/filelists/other XML generators.
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index cf59063..3b04165 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -351,6 +351,10 @@ func TestServerValidationErrors(t *testing.T) {
if resp, _ := req(t, "POST", "/api/v2/remotes", `not json`); resp.StatusCode != 400 {
t.Errorf("invalid json: %d", resp.StatusCode)
}
+ // Invalid regex pattern -> 400 from ValidatePatterns.
+ if resp, _ := req(t, "POST", "/api/v2/remotes", `{"name":"badre","package_type":"generic","repo_type":"remote","base_url":"https://x","blocklist":["[unterminated"]}`); resp.StatusCode != 400 {
+ t.Errorf("invalid regex: %d", resp.StatusCode)
+ }
}
func TestServerDockerAndHead(t *testing.T) {
diff --git a/internal/storage/storage_test.go b/internal/storage/storage_test.go
index f927826..0379900 100644
--- a/internal/storage/storage_test.go
+++ b/internal/storage/storage_test.go
@@ -113,6 +113,12 @@ func TestS3DownloadMissing(t *testing.T) {
if _, _, err := testS3.Download(context.Background(), "does/not/exist"); err == nil {
t.Error("expected error downloading missing key")
}
+ if _, err := testS3.Stat(context.Background(), "does/not/exist"); err == nil {
+ t.Error("expected error stat-ing missing key")
+ }
+ if exists, err := testS3.Exists(context.Background(), "does/not/exist"); err != nil || exists {
+ t.Errorf("Exists(missing) = %v, %v; want false, nil", exists, err)
+ }
}
func TestCASStore(t *testing.T) {
diff --git a/internal/virtual/merger_test.go b/internal/virtual/merger_test.go
index 5b610fc..2e117fe 100644
--- a/internal/virtual/merger_test.go
+++ b/internal/virtual/merger_test.go
@@ -56,6 +56,23 @@ func TestPyPIMerge(t *testing.T) {
}
}
+func TestPyPIMergeNoProxyAndBadLinks(t *testing.T) {
+ m := &PyPIMerger{}
+ members := []MemberIndex{{
+ RemoteName: "a",
+ Body: []byte("foo.whl\nno href\nnot a link"),
+ }}
+ // No proxy base URL: hrefs are left as-is.
+ out, err := m.MergeIndexes(members, "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ s := string(out)
+ if !strings.Contains(s, ">foo.whl") {
+ t.Errorf("missing link: %s", s)
+ }
+}
+
func TestHelmMerge(t *testing.T) {
m := &HelmMerger{}
memberA := `apiVersion: v1