mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-20 21:23:07 +08:00
Simplifies cmd/containerboot env var parsing. Most of the private helpers did not earn their abstraction: defaultEnv(name, "") is just os.Getenv(name), and the rest collapse into cmp.Or and the existing def.Bool. defaultEnv, defaultEnvs and defaultBool are gone. Adds def.LookupEnv, the env companion to def.Bool, for the one case that needs it: TS_KUBE_SECRET, where an explicit "" disables Kubernetes secret storage and must stay distinct from unset (cmp.Or cannot express that). Updates #20018 Signed-off-by: Nick Rossi <[email protected]>
149 lines
4.0 KiB
Go
149 lines
4.0 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package def_test
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"tailscale.com/util/def"
|
|
)
|
|
|
|
func TestLookupEnv(t *testing.T) {
|
|
const key = "TS_DEF_TEST_LOOKUPENV"
|
|
tests := []struct {
|
|
name string
|
|
unset bool
|
|
value string
|
|
def string
|
|
want string
|
|
}{
|
|
{name: "unset", unset: true, def: "fallback", want: "fallback"},
|
|
{name: "set", value: "value", def: "fallback", want: "value"},
|
|
{name: "empty", value: "", def: "fallback", want: ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv(key, tt.value)
|
|
if tt.unset {
|
|
os.Unsetenv(key)
|
|
}
|
|
if got := def.LookupEnv(key, tt.def); got != tt.want {
|
|
t.Errorf("LookupEnv(%q, %q) = %q; want %q", key, tt.def, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBool(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
def bool
|
|
want bool
|
|
}{
|
|
{name: "empty_true", in: "", def: true, want: true},
|
|
{name: "empty_false", in: "", def: false, want: false},
|
|
{name: "valid_1", in: "1", def: false, want: true},
|
|
{name: "valid_t", in: "t", def: false, want: true},
|
|
{name: "valid_T", in: "T", def: false, want: true},
|
|
{name: "valid_TRUE", in: "TRUE", def: false, want: true},
|
|
{name: "valid_true", in: "true", def: false, want: true},
|
|
{name: "valid_True", in: "True", def: false, want: true},
|
|
{name: "valid_true_default_true", in: "true", def: true, want: true},
|
|
{name: "valid_0", in: "0", def: true, want: false},
|
|
{name: "valid_f", in: "f", def: true, want: false},
|
|
{name: "valid_F", in: "F", def: true, want: false},
|
|
{name: "valid_FALSE", in: "FALSE", def: true, want: false},
|
|
{name: "valid_false", in: "false", def: true, want: false},
|
|
{name: "valid_False", in: "False", def: true, want: false},
|
|
{name: "valid_false_default_false", in: "false", def: false, want: false},
|
|
{name: "invalid_true", in: "sure", def: true, want: true},
|
|
{name: "invalid_false", in: "sure", def: false, want: false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := def.Bool(tt.in, tt.def); got != tt.want {
|
|
t.Errorf("Bool(%q, %v) = %v; want %v", tt.in, tt.def, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDuration(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
def time.Duration
|
|
want time.Duration
|
|
}{
|
|
{name: "empty_second", in: "", def: time.Second, want: time.Second},
|
|
{name: "empty_zero", in: "", def: 0, want: 0},
|
|
{name: "valid", in: "2m30s", def: time.Second, want: 2*time.Minute + 30*time.Second},
|
|
{name: "valid_zero", in: "0s", def: time.Second, want: 0},
|
|
{name: "invalid_second", in: "soon", def: time.Second, want: time.Second},
|
|
{name: "invalid_minute", in: "soon", def: time.Minute, want: time.Minute},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := def.Duration(tt.in, tt.def); got != tt.want {
|
|
t.Errorf("Duration(%q, %v) = %v; want %v", tt.in, tt.def, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func FuzzBool(f *testing.F) {
|
|
for _, tc := range []struct {
|
|
in string
|
|
def bool
|
|
}{
|
|
{in: "", def: true},
|
|
{in: "", def: false},
|
|
{in: "true", def: false},
|
|
{in: "false", def: true},
|
|
{in: "sure", def: true},
|
|
{in: "sure", def: false},
|
|
} {
|
|
f.Add(tc.in, tc.def)
|
|
}
|
|
f.Fuzz(func(t *testing.T, in string, fallback bool) {
|
|
got := def.Bool(in, fallback)
|
|
want, err := strconv.ParseBool(in)
|
|
if in == "" || err != nil {
|
|
want = fallback
|
|
}
|
|
if got != want {
|
|
t.Fatalf("Bool(%q, %v) = %v; want %v", in, fallback, got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func FuzzDuration(f *testing.F) {
|
|
for _, tc := range []struct {
|
|
in string
|
|
def time.Duration
|
|
}{
|
|
{in: "", def: time.Second},
|
|
{in: "", def: 0},
|
|
{in: "2m30s", def: time.Second},
|
|
{in: "soon", def: time.Second},
|
|
} {
|
|
f.Add(tc.in, int64(tc.def))
|
|
}
|
|
f.Fuzz(func(t *testing.T, in string, fallbackN int64) {
|
|
fallback := time.Duration(fallbackN)
|
|
got := def.Duration(in, fallback)
|
|
want, err := time.ParseDuration(in)
|
|
if in == "" || err != nil {
|
|
want = fallback
|
|
}
|
|
if got != want {
|
|
t.Fatalf("Duration(%q, %v) = %v; want %v", in, fallback, got, want)
|
|
}
|
|
})
|
|
}
|