Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-14 01:59:23 -05:00
pkg-proxy/internal/config/mirror_test.go

188 lines
7.9 KiB
Go
Raw Permalink Normal View History

package config
import (
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestMirrorConfigValidate(t *testing.T) {
const digest = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
tests := []struct {
name string
schedule MirrorSchedule
wantErr bool
}{
{name: "docker tags", schedule: MirrorSchedule{Images: []string{"pkg:docker/library/alpine@3.20", "pkg:docker/nginx@stable"}, Interval: "6h"}},
{name: "oci with tag", schedule: MirrorSchedule{Images: []string{"pkg:oci/app@v1?repository_url=ghcr.io/acme/app"}, Interval: "1m"}},
{name: "oci digest with tag", schedule: MirrorSchedule{Images: []string{"pkg:oci/app@" + digest + "?repository_url=ghcr.io/acme/app&tag=v1"}, Interval: "1h"}},
{name: "platforms", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}, Interval: "1h", Platforms: []string{"linux/amd64", "linux/arm64/v8"}}},
{name: "missing interval", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}}, wantErr: true},
{name: "bad interval", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}, Interval: "often"}, wantErr: true},
{name: "interval under a minute", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}, Interval: "30s"}, wantErr: true},
{name: "no images", schedule: MirrorSchedule{Interval: "1h"}, wantErr: true},
{name: "unparsable purl", schedule: MirrorSchedule{Images: []string{"alpine:3"}, Interval: "1h"}, wantErr: true},
{name: "not an image", schedule: MirrorSchedule{Images: []string{"pkg:npm/lodash@4.17.21"}, Interval: "1h"}, wantErr: true},
{name: "no tag", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine"}, Interval: "1h"}, wantErr: true},
{name: "docker digest", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@" + digest}, Interval: "1h"}, wantErr: true},
{name: "docker digest with tag qualifier", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@" + digest + "?tag=3"}, Interval: "1h"}, wantErr: true},
{name: "oci digest only", schedule: MirrorSchedule{Images: []string{"pkg:oci/app@" + digest + "?repository_url=ghcr.io/acme/app"}, Interval: "1h"}, wantErr: true},
{name: "oci without repository_url", schedule: MirrorSchedule{Images: []string{"pkg:oci/app@v1"}, Interval: "1h"}, wantErr: true},
{name: "platform without architecture", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}, Interval: "1h", Platforms: []string{"linux"}}, wantErr: true},
{name: "platform list in one entry", schedule: MirrorSchedule{Images: []string{"pkg:docker/alpine@3"}, Interval: "1h", Platforms: []string{"linux/amd64,linux/arm64"}}, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := MirrorConfig{Schedules: []MirrorSchedule{tt.schedule}}
err := m.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestMirrorScheduleIntervalDuration(t *testing.T) {
m := MirrorConfig{Schedules: []MirrorSchedule{{Images: []string{"pkg:docker/alpine@3"}, Interval: "6h"}}}
if err := m.Validate(); err != nil {
t.Fatalf("Validate: %v", err)
}
if got := m.Schedules[0].IntervalDuration(); got != 6*time.Hour {
t.Errorf("IntervalDuration() = %v, want 6h", got)
}
}
func TestValidateRejectsMirrorSchedulesWithoutCachedArtifacts(t *testing.T) {
cfg := Default()
cfg.Mirror.Schedules = []MirrorSchedule{{Images: []string{"pkg:docker/alpine@3"}, Interval: "1h"}}
cfg.Storage.CacheArtifacts = false
if err := cfg.Validate(); err == nil {
t.Error("Validate() accepted mirror.schedules with storage.cache_artifacts: false")
}
}
func TestLoadYAMLMirrorSchedules(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.yaml")
data := `
mirror:
schedules:
- images: [pkg:docker/library/alpine@3.20]
interval: 6h
platforms: [linux/amd64]
- images: [pkg:docker/nginx@stable]
interval: 30s
`
if err := os.WriteFile(path, []byte(data), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := Load(path)
if err != nil {
t.Fatalf("Load: %v", err)
}
if len(cfg.Mirror.Schedules) != 2 || cfg.Mirror.Schedules[0].Platforms[0] != "linux/amd64" {
t.Fatalf("schedules = %+v", cfg.Mirror.Schedules)
}
if err := cfg.Validate(); err == nil {
t.Error("Validate() accepted a 30s interval in the second schedule")
}
}
func TestMirrorRefreshValidate(t *testing.T) {
tests := []struct {
name string
refresh *MirrorRefresh
wantErr bool
}{
{name: "defaults", refresh: &MirrorRefresh{Interval: "24h"}},
{name: "all fields", refresh: &MirrorRefresh{Interval: "12h", Top: 20, Since: "14d", MaxVersions: 100, MaxBytes: "2GB"}},
{name: "missing interval", refresh: &MirrorRefresh{}, wantErr: true},
{name: "interval under a minute", refresh: &MirrorRefresh{Interval: "10s"}, wantErr: true},
{name: "negative top", refresh: &MirrorRefresh{Interval: "1h", Top: -1}, wantErr: true},
{name: "bad since", refresh: &MirrorRefresh{Interval: "1h", Since: "recently"}, wantErr: true},
{name: "negative since", refresh: &MirrorRefresh{Interval: "1h", Since: "-1d"}, wantErr: true},
{name: "negative max_versions", refresh: &MirrorRefresh{Interval: "1h", MaxVersions: -1}, wantErr: true},
{name: "bad max_bytes", refresh: &MirrorRefresh{Interval: "1h", MaxBytes: "lots"}, wantErr: true},
{name: "negative max_bytes", refresh: &MirrorRefresh{Interval: "1h", MaxBytes: "-1GB"}, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := MirrorConfig{Refresh: tt.refresh}
err := m.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestMirrorRefreshDefaults(t *testing.T) {
m := MirrorConfig{Refresh: &MirrorRefresh{Interval: "24h"}}
if err := m.Validate(); err != nil {
t.Fatalf("Validate: %v", err)
}
r := m.Refresh
if r.IntervalDuration() != 24*time.Hour || r.TopPackages() != 50 || r.SinceDuration() != 14*24*time.Hour ||
r.MaxVersionsPerRun() != 0 || r.MaxBytesPerRun() != 0 {
t.Errorf("got interval %v top %d since %v max_versions %d max_bytes %d, want 24h 50 336h 0 0",
r.IntervalDuration(), r.TopPackages(), r.SinceDuration(), r.MaxVersionsPerRun(), r.MaxBytesPerRun())
}
}
func TestValidateRejectsMirrorRefreshWithoutCachedArtifacts(t *testing.T) {
cfg := Default()
cfg.Mirror.Refresh = &MirrorRefresh{Interval: "24h"}
cfg.Storage.CacheArtifacts = false
if err := cfg.Validate(); err == nil {
t.Error("Validate() accepted mirror.refresh with storage.cache_artifacts: false")
}
}
func TestLoadYAMLMirrorRefresh(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.yaml")
data := `
mirror:
refresh:
interval: 12h
top: 10
since: 7d
max_versions: 200
max_bytes: 1GB
`
if err := os.WriteFile(path, []byte(data), 0o600); err != nil {
t.Fatal(err)
}
cfg, err := Load(path)
if err != nil {
t.Fatalf("Load: %v", err)
}
r := cfg.Mirror.Refresh
if r == nil {
t.Fatal("mirror.refresh not loaded")
}
if err := cfg.Validate(); err != nil {
t.Fatalf("Validate: %v", err)
}
if r.IntervalDuration() != 12*time.Hour || r.TopPackages() != 10 || r.SinceDuration() != 7*24*time.Hour ||
r.MaxVersionsPerRun() != 200 || r.MaxBytesPerRun() != 1<<30 {
t.Errorf("got interval %v top %d since %v max_versions %d max_bytes %d",
r.IntervalDuration(), r.TopPackages(), r.SinceDuration(), r.MaxVersionsPerRun(), r.MaxBytesPerRun())
}
}
func TestWarningsMirrorRefreshWithoutCacheMetadata(t *testing.T) {
cfg := Default()
cfg.Mirror.Refresh = &MirrorRefresh{Interval: "24h"}
cfg.CacheMetadata = false
if err := cfg.Validate(); err != nil {
t.Fatalf("Validate() = %v, want mirror.refresh accepted for the other ecosystems", err)
}
if got := cfg.Warnings(); len(got) != 1 || !strings.Contains(got[0], "cache_metadata") {
t.Errorf("Warnings() = %q, want one about cache_metadata", got)
}
cfg.CacheMetadata = true
if got := cfg.Warnings(); len(got) != 0 {
t.Errorf("Warnings() with cache_metadata = %q, want none", got)
}
}