app/config_test.go
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}