Go · 4673 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package config
4
5 import (
6 "strings"
7 "testing"
8 "time"
9 )
10
11 func TestDefaults_Validate(t *testing.T) {
12 t.Parallel()
13 cfg := Defaults()
14 if err := Validate(&cfg); err != nil {
15 t.Fatalf("Validate(Defaults()): %v", err)
16 }
17 }
18
19 func TestValidate_RejectsBadEnv(t *testing.T) {
20 t.Parallel()
21 cfg := Defaults()
22 cfg.Env = "production" // typo of "prod"
23 if err := Validate(&cfg); err == nil {
24 t.Errorf("expected validation error for env=production")
25 }
26 }
27
28 func TestValidate_RejectsTracingWithoutEndpoint(t *testing.T) {
29 t.Parallel()
30 cfg := Defaults()
31 cfg.Tracing.Enabled = true
32 if err := Validate(&cfg); err == nil {
33 t.Errorf("expected validation error when tracing.enabled=true and endpoint empty")
34 }
35 }
36
37 func TestValidate_RejectsBadSampleRate(t *testing.T) {
38 t.Parallel()
39 cfg := Defaults()
40 cfg.Tracing.Enabled = true
41 cfg.Tracing.Endpoint = "http://otel:4318"
42 cfg.Tracing.SampleRate = 2.0
43 if err := Validate(&cfg); err == nil {
44 t.Errorf("expected validation error for sample_rate=2.0")
45 }
46 }
47
48 func TestMergeEnv_AppliesNestedKeys(t *testing.T) {
49 t.Parallel()
50 cfg := Defaults()
51 env := []string{
52 "SHITHUB_WEB__ADDR=:9090",
53 "SHITHUB_DB__MAX_CONNS=42",
54 "SHITHUB_TRACING__ENABLED=true",
55 "SHITHUB_TRACING__ENDPOINT=http://otel:4318",
56 "SHITHUB_DB__CONNECT_TIMEOUT=8s",
57 }
58 if err := mergeEnv(&cfg, env); err != nil {
59 t.Fatalf("mergeEnv: %v", err)
60 }
61 if cfg.Web.Addr != ":9090" {
62 t.Errorf("Web.Addr: got %q", cfg.Web.Addr)
63 }
64 if cfg.DB.MaxConns != 42 {
65 t.Errorf("DB.MaxConns: got %d", cfg.DB.MaxConns)
66 }
67 if !cfg.Tracing.Enabled {
68 t.Errorf("Tracing.Enabled: not set")
69 }
70 if cfg.DB.ConnectTimeout != 8*time.Second {
71 t.Errorf("DB.ConnectTimeout: got %v", cfg.DB.ConnectTimeout)
72 }
73 }
74
75 func TestPrintRedacted_HidesSecrets(t *testing.T) {
76 t.Parallel()
77 cfg := Defaults()
78 cfg.DB.URL = "postgres://shithub:hunter2@localhost/shithub"
79 cfg.Session.KeyB64 = "supersecretkey"
80 cfg.Metrics.BasicAuthPass = "metrics-pass"
81 cfg.ErrorReporting.DSN = "https://abc@sentry.example/1"
82
83 out, err := PrintRedacted(cfg)
84 if err != nil {
85 t.Fatalf("PrintRedacted: %v", err)
86 }
87
88 for _, leak := range []string{"hunter2", "supersecretkey", "metrics-pass", "https://abc@sentry"} {
89 if strings.Contains(out, leak) {
90 t.Errorf("PrintRedacted leaked %q\noutput: %s", leak, out)
91 }
92 }
93 if !strings.Contains(out, "***") {
94 t.Errorf("PrintRedacted produced no *** redactions; output:\n%s", out)
95 }
96 }
97
98 func TestMergeFlags_OverridesEnv(t *testing.T) {
99 t.Parallel()
100 cfg := Defaults()
101 if err := mergeEnv(&cfg, []string{"SHITHUB_WEB__ADDR=:9090"}); err != nil {
102 t.Fatalf("mergeEnv: %v", err)
103 }
104 if err := mergeFlags(&cfg, map[string]string{"web.addr": ":7777"}); err != nil {
105 t.Fatalf("mergeFlags: %v", err)
106 }
107 if cfg.Web.Addr != ":7777" {
108 t.Errorf("Web.Addr: got %q, want :7777", cfg.Web.Addr)
109 }
110 }
111
112 func TestDefaults_RateLimitAPI(t *testing.T) {
113 t.Parallel()
114 cfg := Defaults()
115 if cfg.RateLimit.API.AuthedPerHour != 5000 {
116 t.Errorf("RateLimit.API.AuthedPerHour: got %d, want 5000", cfg.RateLimit.API.AuthedPerHour)
117 }
118 if cfg.RateLimit.API.AnonPerHour != 60 {
119 t.Errorf("RateLimit.API.AnonPerHour: got %d, want 60", cfg.RateLimit.API.AnonPerHour)
120 }
121 }
122
123 func TestValidate_RejectsNegativeRateLimit(t *testing.T) {
124 t.Parallel()
125 cfg := Defaults()
126 cfg.RateLimit.API.AuthedPerHour = -1
127 if err := Validate(&cfg); err == nil {
128 t.Errorf("expected validation error for ratelimit.api.authed_per_hour=-1")
129 }
130 cfg = Defaults()
131 cfg.RateLimit.API.AnonPerHour = -5
132 if err := Validate(&cfg); err == nil {
133 t.Errorf("expected validation error for ratelimit.api.anon_per_hour=-5")
134 }
135 }
136
137 func TestValidate_RateLimitZeroFillsDefault(t *testing.T) {
138 t.Parallel()
139 cfg := Defaults()
140 cfg.RateLimit.API.AuthedPerHour = 0
141 cfg.RateLimit.API.AnonPerHour = 0
142 if err := Validate(&cfg); err != nil {
143 t.Fatalf("Validate: %v", err)
144 }
145 if cfg.RateLimit.API.AuthedPerHour != 5000 {
146 t.Errorf("zero-fill authed: got %d, want 5000", cfg.RateLimit.API.AuthedPerHour)
147 }
148 if cfg.RateLimit.API.AnonPerHour != 60 {
149 t.Errorf("zero-fill anon: got %d, want 60", cfg.RateLimit.API.AnonPerHour)
150 }
151 }
152
153 func TestMergeEnv_RateLimitAPI(t *testing.T) {
154 t.Parallel()
155 cfg := Defaults()
156 env := []string{
157 "SHITHUB_RATELIMIT__API__AUTHED_PER_HOUR=10000",
158 "SHITHUB_RATELIMIT__API__ANON_PER_HOUR=120",
159 }
160 if err := mergeEnv(&cfg, env); err != nil {
161 t.Fatalf("mergeEnv: %v", err)
162 }
163 if cfg.RateLimit.API.AuthedPerHour != 10000 {
164 t.Errorf("AuthedPerHour: got %d, want 10000", cfg.RateLimit.API.AuthedPerHour)
165 }
166 if cfg.RateLimit.API.AnonPerHour != 120 {
167 t.Errorf("AnonPerHour: got %d, want 120", cfg.RateLimit.API.AnonPerHour)
168 }
169 }
170