github.com/tetrafolium/tflint@v0.8.0/cmd/cli_test.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/golang/mock/gomock" 13 "github.com/hashicorp/hcl2/hcl" 14 "github.com/hashicorp/terraform/configs" 15 "github.com/hashicorp/terraform/terraform" 16 "github.com/wata727/tflint/issue" 17 "github.com/wata727/tflint/mock" 18 "github.com/wata727/tflint/project" 19 "github.com/wata727/tflint/rules" 20 "github.com/wata727/tflint/tflint" 21 ) 22 23 func TestCLIRun__noIssuesFound(t *testing.T) { 24 cases := []struct { 25 Name string 26 Command string 27 LoadErr error 28 Status int 29 Stdout string 30 Stderr string 31 }{ 32 { 33 Name: "print version", 34 Command: "./tflint --version", 35 Status: ExitCodeOK, 36 Stdout: fmt.Sprintf("TFLint version %s", project.Version), 37 }, 38 { 39 Name: "print help", 40 Command: "./tflint --help", 41 Status: ExitCodeOK, 42 Stdout: "Application Options:", 43 }, 44 { 45 Name: "no options", 46 Command: "./tflint", 47 Status: ExitCodeOK, 48 Stdout: "Awesome! Your code is following the best practices :)", 49 }, 50 { 51 Name: "specify format", 52 Command: "./tflint --format json", 53 Status: ExitCodeOK, 54 Stdout: "[]", 55 }, 56 { 57 Name: "`--error-with-issues` option", 58 Command: "./tflint --error-with-issues", 59 Status: ExitCodeOK, 60 Stdout: "Awesome! Your code is following the best practices :)", 61 }, 62 { 63 Name: "`--quiet` option", 64 Command: "./tflint --quiet", 65 Status: ExitCodeOK, 66 Stdout: "", 67 }, 68 { 69 Name: "loading errors are occurred", 70 Command: "./tflint", 71 LoadErr: errors.New("Load error occurred"), 72 Status: ExitCodeError, 73 Stderr: "Load error occurred", 74 }, 75 { 76 Name: "deprecated options", 77 Command: "./tflint --debug", 78 Status: ExitCodeError, 79 Stderr: "`debug` option was removed in v0.8.0. Please set `TFLINT_LOG` environment variables instead", 80 }, 81 { 82 Name: "invalid options", 83 Command: "./tflint --unknown", 84 Status: ExitCodeError, 85 Stderr: "`unknown` is unknown option. Please run `tflint --help`", 86 }, 87 { 88 Name: "invalid format", 89 Command: "./tflint --format awesome", 90 Status: ExitCodeError, 91 Stderr: "Invalid value `awesome' for option", 92 }, 93 } 94 95 ctrl := gomock.NewController(t) 96 defer ctrl.Finish() 97 98 for _, tc := range cases { 99 outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 100 cli := &CLI{ 101 outStream: outStream, 102 errStream: errStream, 103 testMode: true, 104 } 105 106 loader := mock.NewMockAbstractLoader(ctrl) 107 loader.EXPECT().LoadConfig().Return(configs.NewEmptyConfig(), tc.LoadErr).AnyTimes() 108 loader.EXPECT().LoadValuesFiles().Return([]terraform.InputValues{}, tc.LoadErr).AnyTimes() 109 cli.loader = loader 110 111 status := cli.Run(strings.Split(tc.Command, " ")) 112 113 if status != tc.Status { 114 t.Fatalf("Failed `%s`: Expected status is `%d`, but get `%d`", tc.Name, tc.Status, status) 115 } 116 if !strings.Contains(outStream.String(), tc.Stdout) { 117 t.Fatalf("Failed `%s`: Expected to contain `%s` in stdout, but get `%s`", tc.Name, tc.Stdout, outStream.String()) 118 } 119 if !strings.Contains(errStream.String(), tc.Stderr) { 120 t.Fatalf("Failed `%s`: Expected to contain `%s` in stderr, but get `%s`", tc.Name, tc.Stderr, errStream.String()) 121 } 122 } 123 } 124 125 type testRule struct{} 126 type errorRule struct{} 127 128 func (r *testRule) Name() string { 129 return "test_rule" 130 } 131 func (r *errorRule) Name() string { 132 return "error_rule" 133 } 134 135 func (r *testRule) Enabled() bool { 136 return true 137 } 138 func (r *errorRule) Enabled() bool { 139 return true 140 } 141 142 func (r *testRule) Type() string { 143 return issue.ERROR 144 } 145 func (r *errorRule) Type() string { 146 return issue.ERROR 147 } 148 149 func (r *testRule) Link() string { 150 return "" 151 } 152 func (r *errorRule) Link() string { 153 return "" 154 } 155 156 func (r *testRule) Check(runner *tflint.Runner) error { 157 runner.EmitIssue( 158 r, 159 "This is test error", 160 hcl.Range{ 161 Filename: "test.tf", 162 Start: hcl.Pos{Line: 1}, 163 }, 164 ) 165 return nil 166 } 167 func (r *errorRule) Check(runner *tflint.Runner) error { 168 return errors.New("Check failed") 169 } 170 171 func TestCLIRun__issuesFound(t *testing.T) { 172 cases := []struct { 173 Name string 174 Command string 175 Rule rules.Rule 176 Status int 177 Stdout string 178 Stderr string 179 }{ 180 { 181 Name: "issues found", 182 Command: "./tflint", 183 Rule: &testRule{}, 184 Status: ExitCodeOK, 185 Stdout: "This is test error (test_rule)", 186 }, 187 { 188 Name: "`--error-with-issues` option", 189 Command: "./tflint --error-with-issues", 190 Rule: &testRule{}, 191 Status: ExitCodeIssuesFound, 192 Stdout: "This is test error (test_rule)", 193 }, 194 { 195 Name: "`--quiet` option", 196 Command: "./tflint --quiet", 197 Rule: &testRule{}, 198 Status: ExitCodeOK, 199 Stdout: "This is test error (test_rule)", 200 }, 201 { 202 Name: "checking errors are occurred", 203 Command: "./tflint", 204 Rule: &errorRule{}, 205 Status: ExitCodeError, 206 Stderr: "Check failed", 207 }, 208 } 209 210 ctrl := gomock.NewController(t) 211 originalRules := rules.DefaultRules 212 defer func() { 213 rules.DefaultRules = originalRules 214 ctrl.Finish() 215 }() 216 217 for _, tc := range cases { 218 // Mock rules 219 rules.DefaultRules = []rules.Rule{tc.Rule} 220 221 outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 222 cli := &CLI{ 223 outStream: outStream, 224 errStream: errStream, 225 testMode: true, 226 } 227 228 loader := mock.NewMockAbstractLoader(ctrl) 229 loader.EXPECT().LoadConfig().Return(configs.NewEmptyConfig(), nil).AnyTimes() 230 loader.EXPECT().LoadValuesFiles().Return([]terraform.InputValues{}, nil).AnyTimes() 231 cli.loader = loader 232 233 status := cli.Run(strings.Split(tc.Command, " ")) 234 235 if status != tc.Status { 236 t.Fatalf("Failed `%s`: Expected status is `%d`, but get `%d`", tc.Name, tc.Status, status) 237 } 238 if !strings.Contains(outStream.String(), tc.Stdout) { 239 t.Fatalf("Failed `%s`: Expected to contain `%s` in stdout, but get `%s`", tc.Name, tc.Stdout, outStream.String()) 240 } 241 if !strings.Contains(errStream.String(), tc.Stderr) { 242 t.Fatalf("Failed `%s`: Expected to contain `%s` in stderr, but get `%s`", tc.Name, tc.Stderr, errStream.String()) 243 } 244 } 245 } 246 247 func TestCLIRun__withArguments(t *testing.T) { 248 cases := []struct { 249 Name string 250 Command string 251 IsConfigFile bool 252 Status int 253 Stdout string 254 Stderr string 255 }{ 256 { 257 Name: "no arguments", 258 Command: "./tflint", 259 Status: ExitCodeOK, 260 Stdout: "This is test error (test_rule)", 261 }, 262 { 263 Name: "files arguments", 264 Command: "./tflint template.tf", 265 IsConfigFile: true, 266 Status: ExitCodeOK, 267 Stdout: "Awesome! Your code is following the best practices :)", 268 }, 269 { 270 Name: "directories arguments", 271 Command: "./tflint ./", 272 IsConfigFile: true, 273 Status: ExitCodeError, 274 Stderr: "Failed to load `./`: TFLint doesn't accept directories as arguments", 275 }, 276 { 277 Name: "file not found", 278 Command: "./tflint not_found.tf", 279 IsConfigFile: true, 280 Status: ExitCodeError, 281 Stderr: "Failed to load `not_found.tf`: File not found", 282 }, 283 { 284 Name: "not Terraform configuration", 285 Command: "./tflint README", 286 IsConfigFile: false, 287 Status: ExitCodeError, 288 Stderr: "Failed to load `README`: File is not a target of Terraform", 289 }, 290 } 291 292 currentDir, err := os.Getwd() 293 if err != nil { 294 t.Fatal(err) 295 } 296 err = os.Chdir(filepath.Join(currentDir, "test-fixtures", "arguments")) 297 if err != nil { 298 t.Fatal(err) 299 } 300 301 ctrl := gomock.NewController(t) 302 originalRules := rules.DefaultRules 303 304 defer func() { 305 os.Chdir(currentDir) 306 rules.DefaultRules = originalRules 307 ctrl.Finish() 308 }() 309 310 for _, tc := range cases { 311 // Mock rules 312 rules.DefaultRules = []rules.Rule{&testRule{}} 313 314 outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 315 cli := &CLI{ 316 outStream: outStream, 317 errStream: errStream, 318 testMode: true, 319 } 320 321 loader := mock.NewMockAbstractLoader(ctrl) 322 loader.EXPECT().IsConfigFile(gomock.Any()).Return(tc.IsConfigFile).AnyTimes() 323 loader.EXPECT().LoadConfig().Return(configs.NewEmptyConfig(), nil).AnyTimes() 324 loader.EXPECT().LoadValuesFiles().Return([]terraform.InputValues{}, nil).AnyTimes() 325 cli.loader = loader 326 327 status := cli.Run(strings.Split(tc.Command, " ")) 328 329 if status != tc.Status { 330 t.Fatalf("Failed `%s`: Expected status is `%d`, but get `%d`", tc.Name, tc.Status, status) 331 } 332 if !strings.Contains(outStream.String(), tc.Stdout) { 333 t.Fatalf("Failed `%s`: Expected to contain `%s` in stdout, but get `%s`", tc.Name, tc.Stdout, outStream.String()) 334 } 335 if !strings.Contains(errStream.String(), tc.Stderr) { 336 t.Fatalf("Failed `%s`: Expected to contain `%s` in stderr, but get `%s`", tc.Name, tc.Stderr, errStream.String()) 337 } 338 } 339 }