check / check (push) Canceled after 0s
The new package internal/providers builds the cache, the fetcher, the processor, the image service, the session manager and the encrypted URL generator from the config. pixad's fx graph provides them with providers.Constructors(), and handlers.New receives them built. The server tests build the same graph, with only the fetcher's dial function replaced. database.New opens the database, so these parts can read it while fx builds them; the cache's stop hook still runs before the database's. Each setting's default is declared in internal/config, and internal/providers works out the default cache_max_bytes. The cache's MaxBytes is the one value for the disk cache limit, and 0 turns the disk cache off. The fetcher and the processor take explicit values. Model: opus-5-5
193 lines
5.5 KiB
Go
193 lines
5.5 KiB
Go
package config
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestCacheMaxBytesExplicitValueUsedWithoutFloor verifies that an
|
|
// explicitly configured cache_max_bytes value is used exactly as
|
|
// given: the 500 MiB floor applies only to the computed default, never
|
|
// to explicit values.
|
|
func TestCacheMaxBytesExplicitValueUsedWithoutFloor(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
yamlContent := "signing_key: " + validTestSigningKey + "\ncache_max_bytes: 1024\n"
|
|
|
|
c, err := configFromYAML(t, yamlContent)
|
|
if err != nil {
|
|
t.Fatalf("explicit cache_max_bytes must be accepted, got error: %v", err)
|
|
}
|
|
|
|
if c.CacheMaxBytes != 1024 {
|
|
t.Errorf("CacheMaxBytes = %d, want 1024 (no floor for explicit values)",
|
|
c.CacheMaxBytes)
|
|
}
|
|
}
|
|
|
|
// TestCacheMaxBytesZeroIsValidAndDisablesCache verifies that an
|
|
// explicit zero is a valid value (it disables the disk cache), not an
|
|
// error.
|
|
func TestCacheMaxBytesZeroIsValidAndDisablesCache(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
yamlContent := "signing_key: " + validTestSigningKey + "\ncache_max_bytes: 0\n"
|
|
|
|
c, err := configFromYAML(t, yamlContent)
|
|
if err != nil {
|
|
t.Fatalf("cache_max_bytes: 0 must be accepted, got error: %v", err)
|
|
}
|
|
|
|
if c.CacheMaxBytes != 0 {
|
|
t.Errorf("CacheMaxBytes = %d, want 0", c.CacheMaxBytes)
|
|
}
|
|
}
|
|
|
|
// TestCacheMaxBytesLargeExplicitValueParses verifies that values above
|
|
// 32-bit range parse correctly (the field is an int64 byte count).
|
|
func TestCacheMaxBytesLargeExplicitValueParses(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
yamlContent := "signing_key: " + validTestSigningKey +
|
|
"\ncache_max_bytes: 10737418240\n"
|
|
|
|
c, err := configFromYAML(t, yamlContent)
|
|
if err != nil {
|
|
t.Fatalf("large cache_max_bytes must be accepted, got error: %v", err)
|
|
}
|
|
|
|
if c.CacheMaxBytes != 10737418240 {
|
|
t.Errorf("CacheMaxBytes = %d, want 10737418240", c.CacheMaxBytes)
|
|
}
|
|
}
|
|
|
|
// TestCacheMaxBytesInvalidValuesAbortStartup verifies that a SET but
|
|
// invalid cache_max_bytes value aborts startup naming the key and the
|
|
// offending value, per the no-silent-fallback rule: defaults apply
|
|
// only to omitted keys.
|
|
func TestCacheMaxBytesInvalidValuesAbortStartup(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
signingKeyLine := "signing_key: " + validTestSigningKey + "\n"
|
|
|
|
cases := []struct {
|
|
name string
|
|
yaml string
|
|
// wantErrSubstrings must all appear in the error message.
|
|
wantErrSubstrings []string
|
|
}{
|
|
{
|
|
name: "negative",
|
|
yaml: signingKeyLine + "cache_max_bytes: -1024\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "-1024"},
|
|
},
|
|
{
|
|
name: "float",
|
|
yaml: signingKeyLine + "cache_max_bytes: 3.5\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "3.5"},
|
|
},
|
|
{
|
|
name: "non-numeric string",
|
|
yaml: signingKeyLine + "cache_max_bytes: banana\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "banana"},
|
|
},
|
|
{
|
|
name: "explicit null",
|
|
yaml: signingKeyLine + "cache_max_bytes: null\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "null"},
|
|
},
|
|
{
|
|
name: "bare key no value",
|
|
yaml: signingKeyLine + "cache_max_bytes:\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "null"},
|
|
},
|
|
{
|
|
name: "boolean",
|
|
yaml: signingKeyLine + "cache_max_bytes: true\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes, "true"},
|
|
},
|
|
{
|
|
name: "list",
|
|
yaml: signingKeyLine + "cache_max_bytes:\n - 1\n",
|
|
wantErrSubstrings: []string{keyCacheMaxBytes},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
c, err := configFromYAML(t, tc.yaml)
|
|
if err == nil {
|
|
t.Fatalf(
|
|
"config with %s cache_max_bytes must abort startup, got config: %+v",
|
|
tc.name, c)
|
|
}
|
|
|
|
t.Logf("got expected error: %v", err)
|
|
|
|
for _, want := range tc.wantErrSubstrings {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("error %q does not mention %q", err.Error(), want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestDefaultCacheMaxBytesAppliesFloor verifies that when 75% of the
|
|
// free space plus what the cache holds is below 500 MiB, the default is
|
|
// floored at DefaultCacheMaxBytesFloor.
|
|
func TestDefaultCacheMaxBytesAppliesFloor(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cases := []struct {
|
|
name string
|
|
freeBytes uint64
|
|
}{
|
|
{name: "100 MiB free", freeBytes: 104857600},
|
|
{name: "zero free", freeBytes: 0},
|
|
{name: "just below floor threshold", freeBytes: 699050665},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got := DefaultCacheMaxBytes(tc.freeBytes, 0)
|
|
if got != DefaultCacheMaxBytesFloor {
|
|
t.Errorf("DefaultCacheMaxBytes = %d, want floor %d",
|
|
got, DefaultCacheMaxBytesFloor)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCacheMaxBytesExplicitIsRecorded verifies that an omitted
|
|
// cache_max_bytes is recorded as not explicit, so pixad works out the
|
|
// default when it builds the cache, and that an explicit zero is recorded
|
|
// as explicit, so it disables the disk cache instead.
|
|
func TestCacheMaxBytesExplicitIsRecorded(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
signingKeyLine := "signing_key: " + validTestSigningKey + "\n"
|
|
|
|
omitted, err := configFromYAML(t, signingKeyLine)
|
|
if err != nil {
|
|
t.Fatalf("minimal config should be valid, got error: %v", err)
|
|
}
|
|
|
|
if omitted.CacheMaxBytesExplicit {
|
|
t.Error("omitted cache_max_bytes recorded as explicit")
|
|
}
|
|
|
|
zero, err := configFromYAML(t, signingKeyLine+"cache_max_bytes: 0\n")
|
|
if err != nil {
|
|
t.Fatalf("cache_max_bytes: 0 must be accepted, got error: %v", err)
|
|
}
|
|
|
|
if !zero.CacheMaxBytesExplicit {
|
|
t.Error("cache_max_bytes: 0 not recorded as explicit")
|
|
}
|
|
}
|