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