github.com/go-maxhub/gremlins@v1.0.1-0.20231227222204-b03a6a1e3e09/core/configuration/configuration_test.go (about) 1 /* 2 * Copyright 2022 The Gremlins Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package configuration 18 19 import ( 20 "os" 21 "path/filepath" 22 "runtime" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 "github.com/mitchellh/go-homedir" 27 "github.com/spf13/viper" 28 29 "github.com/go-maxhub/gremlins/core/mutator" 30 ) 31 32 type envEntry struct { 33 name string 34 value string 35 } 36 37 func TestConfiguration(t *testing.T) { 38 testCases := []struct { 39 wantedConfig map[string]interface{} 40 name string 41 configPaths []string 42 envEntries []envEntry 43 expectErr bool 44 }{ 45 { 46 name: "from single file", 47 configPaths: []string{"testdata/config1/.gremlins.yaml"}, 48 wantedConfig: map[string]interface{}{ 49 "unleash.dry-run": true, 50 "unleash.tags": "tag1,tag2,tag3", 51 }, 52 }, 53 { 54 name: "from returns error if unreadable", 55 configPaths: []string{"testdata/config1/.gremlin"}, 56 wantedConfig: map[string]interface{}{ 57 "unleash.dry-run": true, 58 "unleash.tags": "tag1,tag2,tag3", 59 }, 60 expectErr: true, 61 }, 62 { 63 name: "from cfg", 64 configPaths: []string{"./testdata/config1"}, 65 wantedConfig: map[string]interface{}{ 66 "unleash.dry-run": true, 67 "unleash.tags": "tag1,tag2,tag3", 68 }, 69 }, 70 { 71 name: "from cfg multi", 72 configPaths: []string{"./testdata/config2", "./testdata/config1"}, 73 wantedConfig: map[string]interface{}{ 74 "unleash.dry-run": true, 75 "unleash.tags": "tag1.2,tag2.2,tag3.2", 76 }, 77 }, 78 { 79 name: "from env", 80 envEntries: []envEntry{ 81 {name: "GREMLINS_UNLEASH_DRY_RUN", value: "true"}, 82 {name: "GREMLINS_UNLEASH_TAGS", value: "tag1,tag2,tag3"}, 83 }, 84 wantedConfig: map[string]interface{}{ 85 "unleash.dry-run": "true", 86 "unleash.tags": "tag1,tag2,tag3", 87 }, 88 }, 89 { 90 name: "from cfg override with env", 91 envEntries: []envEntry{ 92 {name: "GREMLINS_UNLEASH_TAGS", value: "tag1env,tag2env,tag3env"}, 93 }, 94 configPaths: []string{"./testdata/config1"}, 95 wantedConfig: map[string]interface{}{ 96 "unleash.dry-run": true, 97 "unleash.tags": "tag1env,tag2env,tag3env", 98 }, 99 }, 100 } 101 102 for _, tc := range testCases { 103 tc := tc 104 t.Run(tc.name, func(t *testing.T) { 105 if tc.envEntries != nil { 106 for _, e := range tc.envEntries { 107 t.Setenv(e.name, e.value) 108 } 109 } 110 err := Init(tc.configPaths) 111 if tc.expectErr && err == nil { 112 t.Fatal("expected error") 113 } 114 if tc.expectErr { 115 return 116 } 117 118 for key, wanted := range tc.wantedConfig { 119 got := Get[any](key) 120 if got != wanted { 121 t.Errorf(cmp.Diff(got, wanted)) 122 } 123 } 124 viper.Reset() 125 }) 126 } 127 } 128 129 func TestConfigPaths(t *testing.T) { 130 home, _ := homedir.Dir() 131 132 t.Run("it lookups in default locations", func(t *testing.T) { 133 oldDir, _ := os.Getwd() 134 _ = os.Chdir("testdata/config1") 135 defer func(dir string) { 136 _ = os.Chdir(dir) 137 }(oldDir) 138 139 var want []string 140 141 // First global 142 if runtime.GOOS != windowsOs { 143 want = append(want, "/etc/gremlins") 144 } 145 146 // Then $XDG_CONFIG_HOME and $HOME 147 want = append(want, 148 filepath.Join(home, ".config", "gremlins", "gremlins"), 149 filepath.Join(home, ".gremlins"), 150 ) 151 152 // Then module root 153 moduleRoot, _ := os.Getwd() 154 want = append(want, moduleRoot) 155 156 // Last current folder 157 want = append(want, ".") 158 159 got := defaultConfigPaths() 160 161 if !cmp.Equal(got, want) { 162 t.Errorf(cmp.Diff(got, want)) 163 } 164 }) 165 166 t.Run("no module root if not in go module", func(t *testing.T) { 167 oldDir, _ := os.Getwd() 168 _ = os.Chdir(t.TempDir()) 169 defer func(dir string) { 170 _ = os.Chdir(dir) 171 }(oldDir) 172 173 var want []string 174 175 // First global 176 if runtime.GOOS != windowsOs { 177 want = append(want, "/etc/gremlins") 178 } 179 180 // Then $XDG_CONFIG_HOME and $HOME 181 want = append(want, 182 filepath.Join(home, ".config", "gremlins", "gremlins"), 183 filepath.Join(home, ".gremlins"), 184 ) 185 186 // Last current folder 187 want = append(want, ".") 188 189 got := defaultConfigPaths() 190 191 if !cmp.Equal(got, want) { 192 t.Errorf(cmp.Diff(got, want)) 193 } 194 }) 195 196 t.Run("when XDG_CONFIG_HOME is set, it lookups in that locations", func(t *testing.T) { 197 oldDir, _ := os.Getwd() 198 _ = os.Chdir("testdata/config1") 199 defer func(dir string) { 200 _ = os.Chdir(dir) 201 }(oldDir) 202 203 customPath := filepath.Join("my", "custom", "path") 204 t.Setenv("XDG_CONFIG_HOME", customPath) 205 206 var want []string 207 208 // First global 209 if runtime.GOOS != windowsOs { 210 want = append(want, "/etc/gremlins") 211 } 212 213 // Then $XDG_CONFIG_HOME and $HOME 214 want = append(want, 215 filepath.Join(customPath, "gremlins", "gremlins"), 216 filepath.Join(home, ".gremlins")) 217 218 // Then Go module root 219 moduleRoot, _ := os.Getwd() 220 want = append(want, moduleRoot) 221 222 // Last the current directory 223 want = append(want, ".") 224 225 got := defaultConfigPaths() 226 227 if !cmp.Equal(got, want) { 228 t.Errorf(cmp.Diff(got, want)) 229 } 230 }) 231 } 232 233 func TestGeneratesMutantTypeEnabledKey(t *testing.T) { 234 mt := mutator.ArithmeticBase 235 want := "mutants.arithmetic-base.enabled" 236 237 got := MutantTypeEnabledKey(mt) 238 239 if got != want { 240 t.Errorf("expected %q, got %q", mt, want) 241 } 242 } 243 244 func TestViperSynchronisedAccess(t *testing.T) { 245 t.Parallel() 246 testCases := []struct { 247 value any 248 name string 249 key string 250 }{ 251 { 252 name: "bool", 253 key: "tvsa.bool.key", 254 value: true, 255 }, 256 { 257 name: "int", 258 key: "tvsa.int.key", 259 value: 10, 260 }, 261 { 262 name: "float64", 263 key: "tvsa.float64.key", 264 value: float64(10), 265 }, 266 { 267 name: "string", 268 key: "tvsa.string.key", 269 value: "test string", 270 }, 271 { 272 name: "char", 273 key: "tvsa.char.key", 274 value: 'a', 275 }, 276 } 277 for _, tc := range testCases { 278 tc := tc 279 t.Run(tc.name, func(t *testing.T) { 280 t.Parallel() 281 282 Set(tc.key, tc.value) 283 284 got := Get[any](tc.key) 285 286 if !cmp.Equal(got, tc.value) { 287 t.Errorf("expected %v, got %v", tc.value, got) 288 } 289 }) 290 } 291 } 292 293 func TestReset(t *testing.T) { 294 Set("test.key", true) 295 296 Reset() 297 298 got := Get[bool]("test.key") 299 300 if got != false { 301 t.Errorf("expected config to be reset") 302 } 303 }