2026-10-13 12:35:22 +02:00
|
|
|
package config
|
|
|
|
|
|
2026-10-13 13:42:34 +02:00
|
|
|
import (
|
|
|
|
|
"slices"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
2026-10-13 12:35:22 +02:00
|
|
|
|
|
|
|
|
func TestHostedConfigValidate(t *testing.T) {
|
|
|
|
|
t.Setenv("HOSTED_TEST_TOKEN", "from-env")
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
hosted HostedConfig
|
|
|
|
|
wantErr bool
|
|
|
|
|
}{
|
|
|
|
|
{name: "disabled without token", hosted: HostedConfig{}},
|
|
|
|
|
{name: "enabled without token", hosted: HostedConfig{Enabled: true}, wantErr: true},
|
|
|
|
|
{name: "enabled with token", hosted: HostedConfig{Enabled: true, Token: "s3cret"}},
|
|
|
|
|
{name: "token from env reference", hosted: HostedConfig{Enabled: true, Token: "${HOSTED_TEST_TOKEN}"}},
|
|
|
|
|
{name: "token env reference unset", hosted: HostedConfig{Enabled: true, Token: "${HOSTED_TEST_UNSET}"}, wantErr: true},
|
|
|
|
|
{name: "invalid upload size", hosted: HostedConfig{Enabled: true, Token: "s3cret", MaxUploadSize: "lots"}, wantErr: true},
|
|
|
|
|
{name: "zero upload size", hosted: HostedConfig{Enabled: true, Token: "s3cret", MaxUploadSize: "0"}, wantErr: true},
|
2026-10-13 13:42:34 +02:00
|
|
|
{name: "npm scopes", hosted: HostedConfig{Enabled: true, Token: "s3cret", NPMScopes: []string{"@acme", "@acme-internal"}}},
|
|
|
|
|
{name: "npm scope without @", hosted: HostedConfig{Enabled: true, Token: "s3cret", NPMScopes: []string{"acme"}}, wantErr: true},
|
|
|
|
|
{name: "npm scope with package", hosted: HostedConfig{Enabled: true, Token: "s3cret", NPMScopes: []string{"@acme/private"}}, wantErr: true},
|
|
|
|
|
{name: "bare @", hosted: HostedConfig{Enabled: true, Token: "s3cret", NPMScopes: []string{"@"}}, wantErr: true},
|
|
|
|
|
{name: "composer vendors", hosted: HostedConfig{Enabled: true, Token: "s3cret", ComposerVendors: []string{"acme", "acme-internal"}}},
|
|
|
|
|
{name: "composer vendor with package", hosted: HostedConfig{Enabled: true, Token: "s3cret", ComposerVendors: []string{"acme/private"}}, wantErr: true},
|
|
|
|
|
{name: "empty composer vendor", hosted: HostedConfig{Enabled: true, Token: "s3cret", ComposerVendors: []string{""}}, wantErr: true},
|
2026-10-13 12:35:22 +02:00
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
err := tt.hosted.Validate()
|
|
|
|
|
if (err != nil) != tt.wantErr {
|
|
|
|
|
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestHostedConfigDefaults(t *testing.T) {
|
|
|
|
|
h := HostedConfig{Enabled: true, Token: "${HOSTED_TEST_TOKEN}"}
|
|
|
|
|
t.Setenv("HOSTED_TEST_TOKEN", "from-env")
|
|
|
|
|
if err := h.Validate(); err != nil {
|
|
|
|
|
t.Fatalf("Validate: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if got := h.TokenExpanded(); got != "from-env" {
|
|
|
|
|
t.Errorf("TokenExpanded() = %q, want from-env", got)
|
|
|
|
|
}
|
|
|
|
|
if got := h.MaxUploadBytes(); got != 100<<20 {
|
|
|
|
|
t.Errorf("MaxUploadBytes() = %d, want %d", got, 100<<20)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h.MaxUploadSize = "2GB"
|
|
|
|
|
if err := h.Validate(); err != nil {
|
|
|
|
|
t.Fatalf("Validate: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if got := h.MaxUploadBytes(); got != 2<<30 {
|
|
|
|
|
t.Errorf("MaxUploadBytes() = %d, want %d", got, int64(2)<<30)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestValidateRejectsHostedWithoutCachedArtifacts(t *testing.T) {
|
|
|
|
|
cfg := Default()
|
|
|
|
|
cfg.Hosted = HostedConfig{Enabled: true, Token: "s3cret"}
|
|
|
|
|
cfg.Storage.CacheArtifacts = false
|
|
|
|
|
if err := cfg.Validate(); err == nil {
|
|
|
|
|
t.Error("Validate() accepted hosted.enabled with storage.cache_artifacts: false")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLoadFromEnvHosted(t *testing.T) {
|
|
|
|
|
cfg := Default()
|
|
|
|
|
t.Setenv("PROXY_HOSTED_ENABLED", "true")
|
|
|
|
|
t.Setenv("PROXY_HOSTED_TOKEN", "env-token")
|
|
|
|
|
t.Setenv("PROXY_HOSTED_MAX_UPLOAD_SIZE", "50MB")
|
2026-10-13 13:42:34 +02:00
|
|
|
t.Setenv("PROXY_HOSTED_NPM_SCOPES", "@acme, @acme-internal")
|
|
|
|
|
t.Setenv("PROXY_HOSTED_COMPOSER_VENDORS", "acme")
|
2026-10-13 12:35:22 +02:00
|
|
|
|
|
|
|
|
cfg.LoadFromEnv()
|
|
|
|
|
|
|
|
|
|
if !cfg.Hosted.Enabled {
|
|
|
|
|
t.Error("Hosted.Enabled not loaded from PROXY_HOSTED_ENABLED")
|
|
|
|
|
}
|
|
|
|
|
if cfg.Hosted.Token != "env-token" {
|
|
|
|
|
t.Errorf("Hosted.Token = %q, want env-token", cfg.Hosted.Token)
|
|
|
|
|
}
|
|
|
|
|
if cfg.Hosted.MaxUploadSize != "50MB" {
|
|
|
|
|
t.Errorf("Hosted.MaxUploadSize = %q, want 50MB", cfg.Hosted.MaxUploadSize)
|
|
|
|
|
}
|
2026-10-13 13:42:34 +02:00
|
|
|
if !slices.Equal(cfg.Hosted.NPMScopes, []string{"@acme", "@acme-internal"}) {
|
|
|
|
|
t.Errorf("Hosted.NPMScopes = %q", cfg.Hosted.NPMScopes)
|
|
|
|
|
}
|
|
|
|
|
if !slices.Equal(cfg.Hosted.ComposerVendors, []string{"acme"}) {
|
|
|
|
|
t.Errorf("Hosted.ComposerVendors = %q", cfg.Hosted.ComposerVendors)
|
|
|
|
|
}
|
2026-10-13 12:35:22 +02:00
|
|
|
}
|