github.com/yandex/pandora@v0.5.32/core/config/config_test.go (about) 1 package config 2 3 import ( 4 "net" 5 "testing" 6 "time" 7 8 "github.com/facebookgo/stack" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 "github.com/yandex/pandora/lib/confutil" 12 ) 13 14 type M map[string]interface{} 15 16 type IPStruct struct { 17 Val string `validate:"ip"` 18 } 19 20 func TestDecodeValidate(t *testing.T) { 21 var data IPStruct 22 err := DecodeAndValidate(M{"val": "192.300.200.100"}, &data) 23 assert.Error(t, err) 24 } 25 26 type NoTagStruct struct { 27 Val string 28 } 29 30 const testVal = "test" 31 32 func TestNilInputIsEmptyInput(t *testing.T) { 33 require.NotPanics(t, func() { 34 var data NoTagStruct 35 err := Decode(nil, &data) 36 assert.NoError(t, err) 37 }) 38 } 39 40 func TestNilResultNotPanic(t *testing.T) { 41 require.NotPanics(t, func() { 42 err := Decode(M{"val": testVal}, (*NoTagStruct)(nil)) 43 assert.Error(t, err) 44 }) 45 } 46 47 func TestFieldNameDecode(t *testing.T) { 48 var data NoTagStruct 49 err := Decode(M{"val": testVal}, &data) 50 require.NoError(t, err) 51 assert.Equal(t, testVal, data.Val) 52 } 53 54 type TagStruct struct { 55 Val string `config:"valAlias"` 56 } 57 58 func TestTagDecode(t *testing.T) { 59 var data TagStruct 60 err := Decode(M{"ValAlias": testVal}, &data) 61 require.NoError(t, err) 62 assert.Equal(t, testVal, data.Val) 63 } 64 65 func TestErrorUnused(t *testing.T) { 66 var data NoTagStruct 67 err := Decode(M{"val": testVal, "unused": testVal}, &data) 68 require.Error(t, err) 69 70 err = Decode(M{"vval": testVal}, &data) 71 assert.Error(t, err) 72 } 73 74 func TestNoWeakTypedInput(t *testing.T) { 75 var data NoTagStruct 76 err := Decode(M{"val": 123}, &data) 77 assert.Error(t, err) 78 } 79 80 type TimeoutStruct struct { 81 Timeout time.Duration `validate:"min-time=1s,max-time=20m"` 82 } 83 84 func TestValidDurationDecode(t *testing.T) { 85 var data TimeoutStruct 86 expectedDuration := time.Second * 666 87 88 err := DecodeAndValidate(M{"timeout": "666s"}, &data) 89 require.NoError(t, err) 90 assert.Equal(t, expectedDuration, data.Timeout) 91 } 92 93 func TestInvalidDurationError(t *testing.T) { 94 var data TimeoutStruct 95 96 invalidTimeouts := []string{"ssss", "1ss", "1", "1s1", "1.s", "0x50"} 97 for _, invalid := range invalidTimeouts { 98 err := DecodeAndValidate(M{"timeout": "ssss"}, &data) 99 assert.Error(t, err, "invalid case: ", invalid) 100 } 101 } 102 103 type Level1 struct { 104 Val1 string 105 Val2 string 106 } 107 108 type Level2 struct { 109 Val1 Level1 110 Val2 Level1 111 } 112 113 func TestNestedStructDecode(t *testing.T) { 114 const ( 115 iniVal1 = "val1" 116 iniVal2 = "val2" 117 newVal = "newVal" 118 ) 119 l2 := Level2{ 120 Level1{ 121 iniVal1, 122 iniVal2, 123 }, 124 Level1{ 125 iniVal1, 126 iniVal2, 127 }, 128 } 129 130 err := DecodeAndValidate(M{ 131 "val1": M{"val1": newVal}, 132 "val2": M{"val1": ""}, 133 }, &l2) 134 require.NoError(t, err) 135 assert.Equal(t, newVal, l2.Val1.Val1) 136 assert.Equal(t, iniVal2, l2.Val1.Val2, "one field in intput, but entire struct rewrited") 137 assert.Equal(t, "", l2.Val2.Val1, "zero value not override default") 138 } 139 140 type MultiStrings struct { 141 A string 142 B string 143 } 144 145 type SingleString struct { 146 B string 147 } 148 149 func TestMapFlat(t *testing.T) { 150 a := &MultiStrings{} 151 Map(a, &SingleString{B: "b"}) 152 assert.Equal(t, &MultiStrings{B: "b"}, a) 153 154 a = &MultiStrings{A: "a", B: "not b"} 155 Map(a, &SingleString{B: "b"}) 156 assert.Equal(t, &MultiStrings{A: "a", B: "b"}, a) 157 } 158 159 func TestMapRecursive(t *testing.T) { 160 type N struct { 161 MultiStrings 162 A string 163 } 164 type M struct { 165 MultiStrings 166 } 167 n := &N{MultiStrings: MultiStrings{B: "b"}, A: "a"} 168 Map(n, &M{MultiStrings: MultiStrings{A: "a"}}) 169 assert.Equal(t, &N{A: "a", MultiStrings: MultiStrings{A: "a", B: ""}}, n) 170 } 171 172 func TestMapTagged(t *testing.T) { 173 type N struct { 174 MultiStrings 175 A string 176 } 177 type M struct { 178 SomeOtherFieldName MultiStrings `map:"MultiStrings"` 179 } 180 n := &N{MultiStrings: MultiStrings{B: "b"}, A: "a"} 181 Map(n, &M{SomeOtherFieldName: MultiStrings{A: "a"}}) 182 assert.Equal(t, &N{A: "a", MultiStrings: MultiStrings{A: "a", B: ""}}, n) 183 } 184 func TestDeltaUpdate(t *testing.T) { 185 var l2 Level2 186 err := Decode(M{ 187 "val1": M{"val1": "val1", "val2": "val2"}, 188 "val2": M{"val1": "val3"}, 189 }, &l2) 190 require.NoError(t, err) 191 assert.Equal(t, "val1", l2.Val1.Val1) 192 assert.Equal(t, "val2", l2.Val1.Val2) 193 assert.Equal(t, "val3", l2.Val2.Val1) 194 assert.Equal(t, "", l2.Val2.Val2) 195 196 err = DecodeAndValidate(M{ 197 "val1": M{"val1": "val4"}, 198 "val2": M{"val2": "val5"}, 199 }, &l2) 200 require.NoError(t, err) 201 assert.Equal(t, "val4", l2.Val1.Val1) 202 assert.Equal(t, "val2", l2.Val1.Val2) 203 assert.Equal(t, "val3", l2.Val2.Val1) 204 assert.Equal(t, "val5", l2.Val2.Val2) 205 } 206 207 func TestNextSquash(t *testing.T) { 208 data := &struct { 209 Level1 struct { 210 Level2 struct { 211 Foo string 212 } `config:",squash"` 213 } `config:",squash"` 214 }{} 215 216 defer func() { 217 r := recover() 218 if r == nil { 219 return 220 } 221 t.Fatalf("panic: %s\n %s", r, stack.Callers(3)) 222 }() 223 224 err := Decode(M{ 225 "foo": "baz", 226 }, &data) 227 require.NoError(t, err) 228 assert.Equal(t, "baz", data.Level1.Level2.Foo) 229 } 230 231 func TestConfigEnvVarReplacement(t *testing.T) { 232 confutil.RegisterTagResolver("", confutil.EnvTagResolver) 233 confutil.RegisterTagResolver("ENV", confutil.EnvTagResolver) 234 235 t.Setenv("ENV_VAR_1", "value1") 236 t.Setenv("VAR_2", "value2") 237 t.Setenv("INT_VAR_3", "15") 238 t.Setenv("IP_SEQ", "1.2") 239 t.Setenv("DURATION", "30s") 240 var l1 struct { 241 Val1 string 242 Val2 string 243 Val3 int 244 Val4 net.IP 245 Val5 time.Duration 246 } 247 248 err := Decode(M{ 249 "val1": "aa-${ENV_VAR_1}", 250 "val2": "${ENV:VAR_2}", 251 "val3": "${INT_VAR_3}", 252 "val4": "1.1.${ENV:IP_SEQ}", 253 "val5": "${DURATION}", 254 }, &l1) 255 assert.NoError(t, err) 256 assert.Equal(t, "aa-value1", l1.Val1) 257 assert.Equal(t, "value2", l1.Val2) 258 assert.Equal(t, 15, l1.Val3) 259 assert.Equal(t, net.IPv4(1, 1, 1, 2), l1.Val4) 260 assert.Equal(t, 30*time.Second, l1.Val5) 261 }