app/config_test.go

v1.5.4
skunky-art/app/config_test.go history · blame · raw

109 lines · 3257 bytes

  1package app
  2
  3import (
  4	"os"
  5	"testing"
  6	"time"
  7)
  8
  9func TestParseLifetimeUnits(t *testing.T) {
 10	cases := map[string]time.Duration{
 11		"5i":  5 * time.Minute,
 12		"2h":  2 * time.Hour,
 13		"3d":  72 * time.Hour,
 14		"1w":  7 * 24 * time.Hour,
 15		"1m":  30 * 24 * time.Hour,
 16		"1y":  360 * 24 * time.Hour,
 17		"12i": 12 * time.Minute,
 18	}
 19	for in, want := range cases {
 20		got, err := parseLifetime(in)
 21		if err != nil || got != want {
 22			t.Errorf("parseLifetime(%q) = %v, %v; want %v", in, got, err, want)
 23		}
 24	}
 25}
 26
 27func TestParseLifetimeRejectsBadInput(t *testing.T) {
 28	for _, in := range []string{"", "5", "5x", "h"} {
 29		if _, err := parseLifetime(in); err == nil {
 30			t.Errorf("parseLifetime(%q) accepted, want an error", in)
 31		}
 32	}
 33}
 34
 35func TestAPICacheDefaults(t *testing.T) {
 36	if !CFG.APICache.Enabled || CFG.APICache.MaxSize != 64 || CFG.APICache.TTL != "5i" || CFG.APICache.Stale != "1h" {
 37		t.Errorf("defaults are %+v, want enabled, 64 MB, 5i, stale 1h", CFG.APICache)
 38	}
 39}
 40
 41func TestMediaCacheDefaults(t *testing.T) {
 42	c := CFG.Cache
 43	if !c.Enabled || c.Lifetime != "1w" || c.MaxSize != 200 || c.MemCache {
 44		t.Errorf("defaults are %+v, want enabled, 1w, 200 MB, memcache off", c)
 45	}
 46}
 47
 48// withScratchConfig points CFG at a config path under a temporary directory,
 49// with the media cache off so no rotation goroutine starts, and restores the
 50// whole configuration afterwards.
 51func withScratchConfig(t *testing.T, path string, explicit bool) {
 52	t.Helper()
 53	cfg, limiter, exp := CFG, daLimiter, cfgExplicit
 54	CFG.cfg = path
 55	CFG.Cache.Enabled = false
 56	cfgExplicit = explicit
 57	t.Cleanup(func() { CFG, daLimiter, cfgExplicit = cfg, limiter, exp })
 58}
 59
 60func TestExecuteConfigRunsWithoutTheDefaultFile(t *testing.T) {
 61	withScratchConfig(t, t.TempDir()+"/config.json", false)
 62	msgs := captureExit(t)
 63
 64	ExecuteConfig()
 65
 66	if len(*msgs) != 0 {
 67		t.Errorf("exit called with %v; want a start on the built-in defaults", *msgs)
 68	}
 69	if CFG.Listen != "127.0.0.1:3003" || CFG.Nsfw {
 70		t.Errorf("defaults not in effect: listen %q nsfw %v", CFG.Listen, CFG.Nsfw)
 71	}
 72}
 73
 74func TestExecuteConfigExitsOnAMissingExplicitFile(t *testing.T) {
 75	withScratchConfig(t, t.TempDir()+"/named.json", true)
 76	msgs := captureExit(t)
 77
 78	ExecuteConfig()
 79
 80	if len(*msgs) == 0 {
 81		t.Error("a missing file named with -c started the instance, want an exit")
 82	}
 83}
 84
 85func TestUpstreamDefaults(t *testing.T) {
 86	if CFG.Upstream.MinIntervalMS != 400 || CFG.Upstream.MaxConcurrent != 2 {
 87		t.Errorf("defaults are %+v, want 400 ms and 2 in flight", CFG.Upstream)
 88	}
 89}
 90
 91// TestUpstreamConfigSetsTheThrottle pins that the file's values reach the
 92// throttle: the tunables used to be source constants.
 93func TestUpstreamConfigSetsTheThrottle(t *testing.T) {
 94	dir := t.TempDir()
 95	path := dir + "/config.json"
 96	if err := os.WriteFile(path, []byte(`{"upstream": {"min-interval-ms": 1500, "max-concurrent": 1}}`), 0600); err != nil {
 97		t.Fatal(err)
 98	}
 99	withScratchConfig(t, path, true)
100	interval, concurrent := daMinInterval, daMaxConcurrent
101	t.Cleanup(func() { daMinInterval, daMaxConcurrent = interval, concurrent })
102	captureExit(t)
103
104	ExecuteConfig()
105
106	if daMinInterval != 1500*time.Millisecond || daMaxConcurrent != 1 {
107		t.Errorf("throttle is %v / %d, want 1.5s / 1 from the file", daMinInterval, daMaxConcurrent)
108	}
109}