github.com/tetrafolium/tflint@v0.8.0/tflint/config_test.go (about) 1 package tflint 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/wata727/tflint/client" 11 ) 12 13 func Test_LoadConfig(t *testing.T) { 14 currentDir, err := os.Getwd() 15 if err != nil { 16 t.Fatal(err) 17 } 18 19 cases := []struct { 20 Name string 21 File string 22 Fallback string 23 Expected *Config 24 }{ 25 { 26 Name: "load file", 27 File: filepath.Join(currentDir, "test-fixtures", "config", "config.hcl"), 28 Expected: &Config{ 29 DeepCheck: true, 30 AwsCredentials: client.AwsCredentials{ 31 AccessKey: "AWS_ACCESS_KEY", 32 SecretKey: "AWS_SECRET_KEY", 33 Region: "us-east-1", 34 }, 35 IgnoreRule: map[string]bool{ 36 "aws_instance_invalid_type": true, 37 "aws_instance_previous_type": true, 38 }, 39 IgnoreModule: map[string]bool{ 40 "github.com/wata727/example-module": true, 41 }, 42 Varfile: []string{"example1.tfvars", "example2.tfvars"}, 43 TerraformVersion: "0.9.11", 44 Rules: map[string]*RuleConfig{ 45 "aws_instance_invalid_type": { 46 Name: "aws_instance_invalid_type", 47 Enabled: false, 48 }, 49 "aws_instance_previous_type": { 50 Name: "aws_instance_previous_type", 51 Enabled: false, 52 }, 53 }, 54 }, 55 }, 56 { 57 Name: "empty file", 58 File: filepath.Join(currentDir, "test-fixtures", "config", "empty.hcl"), 59 Expected: EmptyConfig(), 60 }, 61 { 62 Name: "fallback", 63 File: filepath.Join(currentDir, "test-fixtures", "config", "not_found.hcl"), 64 Fallback: filepath.Join(currentDir, "test-fixtures", "config", "fallback.hcl"), 65 Expected: &Config{ 66 DeepCheck: true, 67 AwsCredentials: client.AwsCredentials{ 68 AccessKey: "AWS_ACCESS_KEY", 69 SecretKey: "AWS_SECRET_KEY", 70 Region: "us-east-1", 71 }, 72 IgnoreRule: map[string]bool{}, 73 IgnoreModule: map[string]bool{}, 74 Varfile: []string{}, 75 TerraformVersion: "0.9.11", 76 Rules: map[string]*RuleConfig{}, 77 }, 78 }, 79 { 80 Name: "fallback file not found", 81 File: filepath.Join(currentDir, "test-fixtures", "config", "not_found.hcl"), 82 Fallback: filepath.Join(currentDir, "test-fixtures", "config", "fallback_not_found.hcl"), 83 Expected: EmptyConfig(), 84 }, 85 } 86 87 for _, tc := range cases { 88 originalDefault := defaultConfigFile 89 defaultConfigFile = filepath.Join(currentDir, "test-fixtures", "config", "not_found.hcl") 90 originalFallback := fallbackConfigFile 91 fallbackConfigFile = tc.Fallback 92 93 ret, err := LoadConfig(tc.File) 94 if err != nil { 95 t.Fatalf("Failed `%s` test: Unexpected error occurred: %s", tc.Name, err) 96 } 97 98 if !cmp.Equal(tc.Expected, ret) { 99 t.Fatalf("Failed `%s` test: diff=%s", tc.Name, cmp.Diff(tc.Expected, ret)) 100 } 101 102 defaultConfigFile = originalDefault 103 fallbackConfigFile = originalFallback 104 } 105 } 106 107 func Test_LoadConfig_error(t *testing.T) { 108 currentDir, err := os.Getwd() 109 if err != nil { 110 t.Fatal(err) 111 } 112 113 cases := []struct { 114 Name string 115 File string 116 Expected string 117 }{ 118 { 119 Name: "file not found", 120 File: filepath.Join(currentDir, "test-fixtures", "config", "not_found.hcl"), 121 Expected: fmt.Sprintf( 122 "`%s` is not found", 123 filepath.Join(currentDir, "test-fixtures", "config", "not_found.hcl"), 124 ), 125 }, 126 { 127 Name: "syntax error", 128 File: filepath.Join(currentDir, "test-fixtures", "config", "syntax_error.hcl"), 129 Expected: fmt.Sprintf( 130 "%s:1,1-2: Invalid character; The \"`\" character is not valid. To create a multi-line string, use the \"heredoc\" syntax, like \"<<EOT\"., and 1 other diagnostic(s)", 131 filepath.Join(currentDir, "test-fixtures", "config", "syntax_error.hcl"), 132 ), 133 }, 134 { 135 Name: "invalid config", 136 File: filepath.Join(currentDir, "test-fixtures", "config", "invalid.hcl"), 137 Expected: fmt.Sprintf( 138 "%s:1,34-42: Extraneous label for rule; Only 1 labels (name) are expected for rule blocks.", 139 filepath.Join(currentDir, "test-fixtures", "config", "invalid.hcl"), 140 ), 141 }, 142 } 143 144 for _, tc := range cases { 145 _, err := LoadConfig(tc.File) 146 if err == nil { 147 t.Fatalf("Failed `%s` test: Expected error does not occurred", tc.Name) 148 } 149 150 if err.Error() != tc.Expected { 151 t.Fatalf("Failed `%s` test: expected error is `%s`, but get `%s`", tc.Name, tc.Expected, err.Error()) 152 } 153 } 154 } 155 156 func Test_Merge(t *testing.T) { 157 cfg := &Config{ 158 DeepCheck: true, 159 AwsCredentials: client.AwsCredentials{ 160 AccessKey: "access_key", 161 SecretKey: "secret_key", 162 Region: "us-east-1", 163 }, 164 IgnoreModule: map[string]bool{ 165 "github.com/wata727/example-1": true, 166 "github.com/wata727/example-2": false, 167 }, 168 IgnoreRule: map[string]bool{ 169 "aws_instance_invalid_type": false, 170 "aws_instance_invalid_ami": true, 171 }, 172 Varfile: []string{"example1.tfvars", "example2.tfvars"}, 173 TerraformVersion: "0.11.1", 174 Rules: map[string]*RuleConfig{ 175 "aws_instance_invalid_type": { 176 Name: "aws_instance_invalid_type", 177 Enabled: false, 178 }, 179 "aws_instance_invalid_ami": { 180 Name: "aws_instance_invalid_ami", 181 Enabled: true, 182 }, 183 }, 184 } 185 186 cases := []struct { 187 Name string 188 Base *Config 189 Other *Config 190 Expected *Config 191 }{ 192 { 193 Name: "empty", 194 Base: EmptyConfig(), 195 Other: EmptyConfig(), 196 Expected: EmptyConfig(), 197 }, 198 { 199 Name: "prefer base", 200 Base: cfg, 201 Other: EmptyConfig(), 202 Expected: cfg, 203 }, 204 { 205 Name: "prefer other", 206 Base: EmptyConfig(), 207 Other: cfg, 208 Expected: cfg, 209 }, 210 { 211 Name: "override and merge", 212 Base: &Config{ 213 DeepCheck: true, 214 AwsCredentials: client.AwsCredentials{ 215 AccessKey: "access_key", 216 SecretKey: "secret_key", 217 Profile: "production", 218 Region: "us-east-1", 219 }, 220 IgnoreModule: map[string]bool{ 221 "github.com/wata727/example-1": true, 222 "github.com/wata727/example-2": false, 223 }, 224 IgnoreRule: map[string]bool{ 225 "aws_instance_invalid_type": false, 226 "aws_instance_invalid_ami": true, 227 }, 228 Varfile: []string{"example1.tfvars", "example2.tfvars"}, 229 TerraformVersion: "0.11.1", 230 Rules: map[string]*RuleConfig{ 231 "aws_instance_invalid_type": { 232 Name: "aws_instance_invalid_type", 233 Enabled: false, 234 }, 235 "aws_instance_invalid_ami": { 236 Name: "aws_instance_invalid_ami", 237 Enabled: true, 238 }, 239 }, 240 }, 241 Other: &Config{ 242 DeepCheck: false, 243 AwsCredentials: client.AwsCredentials{ 244 AccessKey: "ACCESS_KEY", 245 SecretKey: "SECRET_KEY", 246 Region: "ap-northeast-1", 247 }, 248 IgnoreModule: map[string]bool{ 249 "github.com/wata727/example-2": true, 250 "github.com/wata727/example-3": false, 251 }, 252 IgnoreRule: map[string]bool{ 253 "aws_instance_invalid_ami": false, 254 "aws_instance_previous_type": true, 255 }, 256 Varfile: []string{"example3.tfvars"}, 257 TerraformVersion: "0.12.0", 258 Rules: map[string]*RuleConfig{ 259 "aws_instance_invalid_ami": { 260 Name: "aws_instance_invalid_ami", 261 Enabled: false, 262 }, 263 "aws_instance_previous_type": { 264 Name: "aws_instance_previous_type", 265 Enabled: false, 266 }, 267 }, 268 }, 269 Expected: &Config{ 270 DeepCheck: true, // DeepCheck will not override 271 AwsCredentials: client.AwsCredentials{ 272 AccessKey: "ACCESS_KEY", 273 SecretKey: "SECRET_KEY", 274 Profile: "production", 275 Region: "ap-northeast-1", 276 }, 277 IgnoreModule: map[string]bool{ 278 "github.com/wata727/example-1": true, 279 "github.com/wata727/example-2": true, 280 "github.com/wata727/example-3": false, 281 }, 282 IgnoreRule: map[string]bool{ 283 "aws_instance_invalid_type": false, 284 "aws_instance_invalid_ami": false, 285 "aws_instance_previous_type": true, 286 }, 287 Varfile: []string{"example1.tfvars", "example2.tfvars", "example3.tfvars"}, 288 TerraformVersion: "0.12.0", 289 Rules: map[string]*RuleConfig{ 290 "aws_instance_invalid_type": { 291 Name: "aws_instance_invalid_type", 292 Enabled: false, 293 }, 294 "aws_instance_invalid_ami": { 295 Name: "aws_instance_invalid_ami", 296 Enabled: false, 297 }, 298 "aws_instance_previous_type": { 299 Name: "aws_instance_previous_type", 300 Enabled: false, 301 }, 302 }, 303 }, 304 }, 305 } 306 307 for _, tc := range cases { 308 ret := tc.Base.Merge(tc.Other) 309 if !cmp.Equal(tc.Expected, ret) { 310 t.Fatalf("Failed `%s` test: diff=%s", tc.Name, cmp.Diff(tc.Expected, ret)) 311 } 312 } 313 } 314 315 func Test_copy(t *testing.T) { 316 cfg := &Config{ 317 DeepCheck: true, 318 AwsCredentials: client.AwsCredentials{ 319 AccessKey: "access_key", 320 SecretKey: "secret_key", 321 Region: "us-east-1", 322 }, 323 IgnoreModule: map[string]bool{ 324 "github.com/wata727/example-1": true, 325 "github.com/wata727/example-2": false, 326 }, 327 IgnoreRule: map[string]bool{ 328 "aws_instance_invalid_type": false, 329 "aws_instance_invalid_ami": true, 330 }, 331 Varfile: []string{"example1.tfvars", "example2.tfvars"}, 332 TerraformVersion: "0.11.1", 333 Rules: map[string]*RuleConfig{ 334 "aws_instance_invalid_type": { 335 Name: "aws_instance_invalid_type", 336 Enabled: false, 337 }, 338 "aws_instance_invalid_ami": { 339 Name: "aws_instance_invalid_ami", 340 Enabled: true, 341 }, 342 }, 343 } 344 345 cases := []struct { 346 Name string 347 SideEffect func(*Config) 348 }{ 349 { 350 Name: "DeepCheck", 351 SideEffect: func(c *Config) { 352 c.DeepCheck = false 353 }, 354 }, 355 { 356 Name: "AwsCredentials", 357 SideEffect: func(c *Config) { 358 c.AwsCredentials = client.AwsCredentials{ 359 Profile: "production", 360 Region: "us-east-1", 361 } 362 }, 363 }, 364 { 365 Name: "IgnoreModule", 366 SideEffect: func(c *Config) { 367 c.IgnoreModule["github.com/wata727/example-1"] = false 368 }, 369 }, 370 { 371 Name: "IgnoreRule", 372 SideEffect: func(c *Config) { 373 c.IgnoreRule["aws_instance_invalid_type"] = true 374 }, 375 }, 376 { 377 Name: "Varfile", 378 SideEffect: func(c *Config) { 379 c.Varfile = append(c.Varfile, "new.tfvars") 380 }, 381 }, 382 { 383 Name: "TerraformVersion", 384 SideEffect: func(c *Config) { 385 c.TerraformVersion = "0.12.0" 386 }, 387 }, 388 { 389 Name: "Rules", 390 SideEffect: func(c *Config) { 391 c.Rules["aws_instance_invalid_type"].Enabled = true 392 }, 393 }, 394 } 395 396 for _, tc := range cases { 397 ret := cfg.copy() 398 if !cmp.Equal(cfg, ret) { 399 t.Fatalf("The copied config doesn't match original: Diff=%s", cmp.Diff(cfg, ret)) 400 } 401 402 tc.SideEffect(ret) 403 if cmp.Equal(cfg, ret) { 404 t.Fatalf("The original was changed when updating `%s`", tc.Name) 405 } 406 } 407 }