mirror of
https://github.com/regclient/regclient.git
synced 2025-04-17 11:37:11 +03:00
- Use "any" instead of an empty interface. - Use range over an integer for for loops. - Remove shadow variables in loops now that Go no longer reuses the variable. - Use "slices.Contains", "slices.Delete", "slices.Equal", "slices.Index", "slices.SortFunc". - Use "cmp.Or", "min", and "max". - Use "fmt.Appendf" instead of "Sprintf" for generating a byte slice. - Use "errors.Join" or "fmt.Errorf" with multiple "%w" for multiple errors. Additionally, use modern regclient features: - Use "ref.SetTag", "ref.SetDigest", and "ref.AddDigest". - Call "regclient.ManifestGet" using "WithManifestDesc" instead of setting the digest on the reference. Signed-off-by: Brandon Mitchell <git@bmitch.net>
205 lines
5.5 KiB
Go
205 lines
5.5 KiB
Go
package regclient
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/olareg/olareg"
|
|
oConfig "github.com/olareg/olareg/config"
|
|
|
|
"github.com/regclient/regclient/config"
|
|
"github.com/regclient/regclient/internal/copyfs"
|
|
"github.com/regclient/regclient/scheme"
|
|
"github.com/regclient/regclient/types/descriptor"
|
|
"github.com/regclient/regclient/types/ref"
|
|
)
|
|
|
|
func TestReferrerList(t *testing.T) {
|
|
// setup: copy testdata to tempdir and also start two olareg instances in memory backed by testdata, one with referrers api enabled
|
|
ctx := context.Background()
|
|
t.Parallel()
|
|
testRepo := "testrepo"
|
|
externalRepo := "external"
|
|
testTag := "v2"
|
|
boolT := true
|
|
boolF := false
|
|
tempDir := t.TempDir()
|
|
err := copyfs.Copy(tempDir+"/"+testRepo, "./testdata/"+testRepo)
|
|
if err != nil {
|
|
t.Fatalf("failed to copy %s to tempDir: %v", testRepo, err)
|
|
}
|
|
err = copyfs.Copy(tempDir+"/"+externalRepo, "./testdata/"+externalRepo)
|
|
if err != nil {
|
|
t.Fatalf("failed to copy %s to tempDir: %v", externalRepo, err)
|
|
}
|
|
regRefHandler := olareg.New(oConfig.Config{
|
|
Storage: oConfig.ConfigStorage{
|
|
StoreType: oConfig.StoreMem,
|
|
RootDir: "./testdata",
|
|
},
|
|
API: oConfig.ConfigAPI{
|
|
Referrer: oConfig.ConfigAPIReferrer{
|
|
Enabled: &boolT,
|
|
},
|
|
},
|
|
})
|
|
regNoRefHandler := olareg.New(oConfig.Config{
|
|
Storage: oConfig.ConfigStorage{
|
|
StoreType: oConfig.StoreMem,
|
|
RootDir: "./testdata",
|
|
},
|
|
API: oConfig.ConfigAPI{
|
|
Referrer: oConfig.ConfigAPIReferrer{
|
|
Enabled: &boolF,
|
|
},
|
|
},
|
|
})
|
|
tsRef := httptest.NewServer(regRefHandler)
|
|
tsRefURL, _ := url.Parse(tsRef.URL)
|
|
tsRefHost := tsRefURL.Host
|
|
tsNoRef := httptest.NewServer(regNoRefHandler)
|
|
tsNoRefURL, _ := url.Parse(tsNoRef.URL)
|
|
tsNoRefHost := tsNoRefURL.Host
|
|
t.Cleanup(func() {
|
|
tsRef.Close()
|
|
tsNoRef.Close()
|
|
_ = regRefHandler.Close()
|
|
_ = regNoRefHandler.Close()
|
|
})
|
|
rcHosts := []config.Host{
|
|
{
|
|
Name: tsRefHost,
|
|
Hostname: tsRefHost,
|
|
TLS: config.TLSDisabled,
|
|
},
|
|
{
|
|
Name: tsNoRefHost,
|
|
Hostname: tsNoRefHost,
|
|
TLS: config.TLSDisabled,
|
|
},
|
|
}
|
|
log := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelWarn}))
|
|
rc := New(
|
|
WithConfigHost(rcHosts...),
|
|
WithSlog(log),
|
|
)
|
|
// top level table of three registry refs, also include a remote ref for each
|
|
ttServers := []struct {
|
|
name string
|
|
reg string
|
|
external string
|
|
}{
|
|
{
|
|
name: "ocidir",
|
|
reg: "ocidir://" + tempDir,
|
|
external: tsRefHost,
|
|
},
|
|
{
|
|
name: "reg-with-referrer",
|
|
reg: tsRefHost,
|
|
external: tsNoRefHost,
|
|
},
|
|
{
|
|
name: "reg-wo-referrer",
|
|
reg: tsNoRefHost,
|
|
external: "ocidir://" + tempDir,
|
|
},
|
|
}
|
|
for _, tcServer := range ttServers {
|
|
t.Run(tcServer.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
refTag, err := ref.New(fmt.Sprintf("%s/%s:%s", tcServer.reg, testRepo, testTag))
|
|
if err != nil {
|
|
t.Fatalf("failed to generate refTag: %v", err)
|
|
}
|
|
refExt, err := ref.New(fmt.Sprintf("%s/%s", tcServer.external, externalRepo))
|
|
if err != nil {
|
|
t.Fatalf("failed to generate refExt: %v", err)
|
|
}
|
|
tt := []struct {
|
|
name string
|
|
ref ref.Ref
|
|
opts []scheme.ReferrerOpts
|
|
count int
|
|
firstAT string
|
|
expectSource ref.Ref
|
|
expectErr error
|
|
}{
|
|
{
|
|
name: "resolve-tag",
|
|
ref: refTag,
|
|
count: 2,
|
|
},
|
|
{
|
|
name: "resolve-platform",
|
|
ref: refTag,
|
|
opts: []scheme.ReferrerOpts{
|
|
scheme.WithReferrerPlatform("linux/amd64"),
|
|
},
|
|
count: 1,
|
|
firstAT: "application/example.arms",
|
|
},
|
|
{
|
|
name: "filter",
|
|
ref: refTag,
|
|
opts: []scheme.ReferrerOpts{
|
|
scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: "application/example.signature"}),
|
|
},
|
|
count: 1,
|
|
firstAT: "application/example.signature",
|
|
},
|
|
{
|
|
name: "external-repo",
|
|
ref: refTag,
|
|
opts: []scheme.ReferrerOpts{
|
|
scheme.WithReferrerSource(refExt),
|
|
scheme.WithReferrerMatchOpt(descriptor.MatchOpt{SortAnnotation: "preference"}),
|
|
},
|
|
count: 2,
|
|
firstAT: "application/example.sbom",
|
|
expectSource: refExt,
|
|
},
|
|
}
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
rl, err := rc.ReferrerList(ctx, tc.ref, tc.opts...)
|
|
if tc.expectErr != nil {
|
|
if err == nil {
|
|
t.Fatalf("ReferrerList did not fail")
|
|
}
|
|
if !errors.Is(err, tc.expectErr) && err.Error() != tc.expectErr.Error() {
|
|
t.Fatalf("unexpected error, expected %v, received %v", tc.expectErr, err)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !ref.EqualRepository(rl.Subject, tc.ref) {
|
|
t.Errorf("unexpected subject: expected %s, received %s", tc.ref.CommonName(), rl.Subject.CommonName())
|
|
}
|
|
if tc.expectSource.IsSet() && !ref.EqualRepository(rl.Source, tc.expectSource) {
|
|
t.Errorf("unexpected source: expected %s, received %s", tc.expectSource.CommonName(), rl.Source.CommonName())
|
|
}
|
|
if tc.expectSource.IsZero() && !rl.Source.IsZero() {
|
|
t.Errorf("source should not be set: received %s", rl.Source.CommonName())
|
|
}
|
|
if tc.count != len(rl.Descriptors) {
|
|
t.Errorf("unexpected number of responses, expected %d, received response %v", tc.count, rl.Descriptors)
|
|
}
|
|
if tc.firstAT != "" && (len(rl.Descriptors) == 0 || rl.Descriptors[0].ArtifactType != tc.firstAT) {
|
|
t.Errorf("unexpected first entry, expected %s, received response %v", tc.firstAT, rl.Descriptors)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|