Skip to content

Commit e1b577e

Browse files
authored
Fix "env var overrides config file setting" behavior for bool options. (#4653)
* Fix "env var overrides config file setting" behavior for bool options. The previous logic was incorrect and would not allow turning synthetics and sending metrics off via an env var, as the true value set earlier (either from hardcoded default or the subsequent conf file override) would always take precedence. * Add tests
1 parent 778a18f commit e1b577e

File tree

2 files changed

+176
-2
lines changed

2 files changed

+176
-2
lines changed

internal/config/config.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,13 @@ func (cfg *Config) applyEnv() {
164164
cfg.FlapsBaseURL = env.FirstOrDefault(cfg.FlapsBaseURL, flapsBaseURLEnvKey)
165165
cfg.MetricsBaseURL = env.FirstOrDefault(cfg.MetricsBaseURL, metricsBaseURLEnvKey)
166166
cfg.MetricsToken = env.FirstOrDefault(cfg.MetricsToken, MetricsTokenEnvKey, AccessTokenEnvKey, APITokenEnvKey)
167+
if env.FirstOrDefault("", SendMetricsEnvKey) != "" {
168+
cfg.SendMetrics = env.IsTruthy(SendMetricsEnvKey)
169+
}
170+
if env.FirstOrDefault("", SyntheticsAgentEnvKey) != "" {
171+
cfg.SyntheticsAgent = env.IsTruthy(SyntheticsAgentEnvKey)
172+
}
167173
cfg.SyntheticsBaseURL = env.FirstOrDefault(cfg.SyntheticsBaseURL, syntheticsBaseURLEnvKey)
168-
cfg.SendMetrics = env.IsTruthy(SendMetricsEnvKey) || cfg.SendMetrics
169-
cfg.SyntheticsAgent = env.IsTruthy(SyntheticsAgentEnvKey) || cfg.SyntheticsAgent
170174
}
171175

172176
// applyFile sets the properties of cfg which may be set via configuration file

internal/config/config_test.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package config
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/spf13/pflag"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
"github.com/superfly/flyctl/internal/flag/flagctx"
13+
)
14+
15+
// TestSendMetricsPrecedence tests that the env var overrides the config file if present
16+
func TestSendMetricsPrecedence(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
envValue string
20+
setEnv bool
21+
configValue bool
22+
expectedValue bool
23+
}{
24+
{
25+
name: "env=1, config=true -> true",
26+
envValue: "1",
27+
setEnv: true,
28+
configValue: true,
29+
expectedValue: true,
30+
},
31+
{
32+
name: "env=1, config=false -> true",
33+
envValue: "1",
34+
setEnv: true,
35+
configValue: false,
36+
expectedValue: true,
37+
},
38+
{
39+
name: "env=0, config=true -> false",
40+
envValue: "0",
41+
setEnv: true,
42+
configValue: true,
43+
expectedValue: false,
44+
},
45+
{
46+
name: "env=0, config=false -> false",
47+
envValue: "0",
48+
setEnv: true,
49+
configValue: false,
50+
expectedValue: false,
51+
},
52+
{
53+
name: "env=unset, config=false -> false",
54+
envValue: "1",
55+
setEnv: false,
56+
configValue: false,
57+
expectedValue: false,
58+
},
59+
}
60+
61+
for _, tt := range tests {
62+
t.Run(tt.name, func(t *testing.T) {
63+
tmpDir := t.TempDir()
64+
configPath := filepath.Join(tmpDir, FileName)
65+
66+
// Set environment variable if asked to
67+
if tt.setEnv {
68+
t.Setenv(SendMetricsEnvKey, tt.envValue)
69+
}
70+
71+
// Create config file
72+
configContent := "send_metrics: " + boolToYAML(tt.configValue) + "\n"
73+
err := os.WriteFile(configPath, []byte(configContent), 0644)
74+
require.NoError(t, err)
75+
76+
// Load config
77+
ctx := flagctx.NewContext(context.Background(), pflag.NewFlagSet("test", pflag.ContinueOnError))
78+
cfg, err := Load(ctx, configPath)
79+
require.NoError(t, err)
80+
81+
// Verify result
82+
assert.Equal(t, tt.expectedValue, cfg.SendMetrics,
83+
"Expected SendMetrics=%v with env=%s, env set=%v and config=%v",
84+
tt.expectedValue, tt.envValue, tt.setEnv, tt.configValue)
85+
})
86+
}
87+
}
88+
89+
// TestSyntheticsAgentPrecedence tests that the env var overrides the config file if present
90+
func TestSyntheticsAgentPrecedence(t *testing.T) {
91+
tests := []struct {
92+
name string
93+
envValue string
94+
setEnv bool
95+
configValue bool
96+
expectedValue bool
97+
}{
98+
{
99+
name: "env=1, config=true -> true",
100+
envValue: "1",
101+
setEnv: true,
102+
configValue: true,
103+
expectedValue: true,
104+
},
105+
{
106+
name: "env=1, config=false -> true",
107+
envValue: "1",
108+
setEnv: true,
109+
configValue: false,
110+
expectedValue: true,
111+
},
112+
{
113+
name: "env=0, config=true -> false",
114+
envValue: "0",
115+
setEnv: true,
116+
configValue: true,
117+
expectedValue: false,
118+
},
119+
{
120+
name: "env=0, config=false -> false",
121+
envValue: "0",
122+
setEnv: true,
123+
configValue: false,
124+
expectedValue: false,
125+
},
126+
{
127+
name: "env=unset, config=false -> false",
128+
envValue: "1",
129+
setEnv: false,
130+
configValue: false,
131+
expectedValue: false,
132+
},
133+
}
134+
135+
for _, tt := range tests {
136+
t.Run(tt.name, func(t *testing.T) {
137+
tmpDir := t.TempDir()
138+
configPath := filepath.Join(tmpDir, FileName)
139+
140+
// Set environment variable if asked to
141+
if tt.setEnv {
142+
t.Setenv(SyntheticsAgentEnvKey, tt.envValue)
143+
}
144+
145+
// Create config file
146+
configContent := "synthetics_agent: " + boolToYAML(tt.configValue) + "\n"
147+
err := os.WriteFile(configPath, []byte(configContent), 0644)
148+
require.NoError(t, err)
149+
150+
// Load config
151+
ctx := flagctx.NewContext(context.Background(), pflag.NewFlagSet("test", pflag.ContinueOnError))
152+
cfg, err := Load(ctx, configPath)
153+
require.NoError(t, err)
154+
155+
// Verify result
156+
assert.Equal(t, tt.expectedValue, cfg.SyntheticsAgent,
157+
"Expected SyntheticsAgent=%v with env=%s, env set=%v and config=%v",
158+
tt.expectedValue, tt.envValue, tt.setEnv, tt.configValue)
159+
})
160+
}
161+
}
162+
163+
// Helper functions
164+
165+
func boolToYAML(b bool) string {
166+
if b {
167+
return "true"
168+
}
169+
return "false"
170+
}

0 commit comments

Comments
 (0)