diff --git a/internal/provider/rpm/rpm_meta_test.go b/internal/provider/rpm/rpm_meta_test.go index 9a0c525..3e6d7b9 100644 --- a/internal/provider/rpm/rpm_meta_test.go +++ b/internal/provider/rpm/rpm_meta_test.go @@ -171,6 +171,31 @@ func TestRPMServeRepodata(t *testing.T) { } } +func TestRPMFullMetadataXML(t *testing.T) { + // A fully-populated entry exercises every optional-field branch in the + // primary/filelists/other XML generators. + metas := []provider.RPMMetadata{{ + Name: "full", Epoch: 1, Version: "2.0", Release: "3", Arch: "x86_64", + Summary: "s", Description: "d", License: "MIT", Vendor: "acme", + Group: "System", BuildHost: "build.example.com", SourceRPM: "full-2.0.src.rpm", + URL: "https://example.com", Packager: "pkgr", ContentHash: "sha256:abc", + RPMSize: 100, InstalledSize: 200, + Requires: []provider.RPMDep{{Name: "libc", Flags: "GE", Epoch: "0", Version: "2.0", Release: "1"}}, + Provides: []provider.RPMDep{{Name: "full", Flags: "EQ", Version: "2.0"}}, + Files: []provider.RPMFile{{Path: "/usr/bin/full", Type: "file"}, {Path: "/etc/full", Type: "dir"}}, + Changelogs: []provider.RPMChangelog{{Author: "a", Date: 100, Text: "changed"}}, + }} + for _, gen := range []func([]provider.RPMMetadata) []byte{generatePrimaryXMLGZ, generateFilelistsXMLGZ, generateOtherXMLGZ} { + zr, err := gzip.NewReader(bytes.NewReader(gen(metas))) + if err != nil { + t.Fatal(err) + } + if _, err := io.ReadAll(zr); err != nil { + t.Error(err) + } + } +} + func TestRPMPrimaryXMLContents(t *testing.T) { // Exercise xmlEscape and dependency entry writing through the gzip'd XML. metas := []provider.RPMMetadata{{ diff --git a/internal/proxy/engine_test.go b/internal/proxy/engine_test.go index 6e42fb7..de4f73e 100644 --- a/internal/proxy/engine_test.go +++ b/internal/proxy/engine_test.go @@ -413,6 +413,44 @@ func TestRevalidationUpstreamError(t *testing.T) { res.Reader.Close() } +func TestTTLFor(t *testing.T) { + e := &Engine{} + if got := e.ttlFor(models.Remote{ImmutableTTL: 100}, ClassImmutable); got != 100*time.Second { + t.Errorf("immutable ttl = %v", got) + } + if got := e.ttlFor(models.Remote{ImmutableTTL: 0}, ClassImmutable); got != 0 { + t.Errorf("immutable ttl=0 (forever) = %v", got) + } + if got := e.ttlFor(models.Remote{MutableTTL: 50}, ClassMutable); got != 50*time.Second { + t.Errorf("mutable ttl = %v", got) + } +} + +func TestHeadUpstreamStatusError(t *testing.T) { + requireStack(t) + r := seed(t, genericRemote("eng-head500")) + if _, err := testEngine.Head(context.Background(), r, "err500", prov(t, models.PackageGeneric)); err == nil { + t.Error("expected error for HEAD of 500 upstream") + } +} + +func TestHeadCachedIndex(t *testing.T) { + requireStack(t) + ctx := context.Background() + r := seed(t, models.Remote{Name: "eng-headidx", PackageType: models.PackageNPM, RepoType: models.RepoTypeRemote, BaseURL: upstream.URL, CheckMutable: true, MutableTTL: 3600}) + p := prov(t, models.PackageNPM) + // Cache the mutable index, then HEAD is answered from the stored index. + res, err := testEngine.Fetch(ctx, r, "pkg", p) + if err != nil { + t.Fatal(err) + } + res.Reader.Close() + h, err := testEngine.Head(ctx, r, "pkg", p) + if err != nil || h.Source != "cache" { + t.Errorf("head of cached index: %+v %v", h, err) + } +} + func TestUpstreamErrorUnwrap(t *testing.T) { base := context.DeadlineExceeded ue := &UpstreamError{Err: base} diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 141539e..f744cfb 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -192,6 +192,7 @@ func TestServerLocalUpload(t *testing.T) { defer req(t, "DELETE", "/api/v2/remotes/srv-local", "") rq, _ := http.NewRequest("PUT", testTS.URL+"/api/v2/remotes/srv-local/files/dir/hello.bin", strings.NewReader("local payload")) + rq.Header.Set("Content-Type", "text/plain") // exercise the content-type branch resp, err := http.DefaultClient.Do(rq) if err != nil || resp.StatusCode != 201 { t.Fatalf("upload: %v %d", err, resp.StatusCode)