github.com/snyk/vervet/v3@v3.7.0/internal/linter/sweatercomb/linter_test.go (about) 1 package sweatercomb 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "testing" 11 12 qt "github.com/frankban/quicktest" 13 14 "github.com/snyk/vervet/v3/config" 15 ) 16 17 func TestLinter(t *testing.T) { 18 c := qt.New(t) 19 ctx, cancel := context.WithCancel(context.TODO()) 20 defer cancel() 21 22 // Sanity check constructor 23 l, err := New(ctx, &config.SweaterCombLinter{ 24 Image: "some-image", 25 Rules: []string{"/sweater-comb/rules/rule1", "rule2"}, 26 ExtraArgs: []string{"--some-flag"}, 27 }) 28 c.Assert(err, qt.IsNil) 29 c.Assert(l.image, qt.Equals, "some-image") 30 c.Assert(l.rules, qt.DeepEquals, []string{"/sweater-comb/rules/rule1", "/sweater-comb/target/rule2"}) 31 c.Assert(l.extraArgs, qt.DeepEquals, []string{"--some-flag"}) 32 33 // Verify temp ruleset that joins all the rulesets. 34 rulesetFile := filepath.Join(l.rulesDir, "ruleset.yaml") 35 rulesetContents, err := ioutil.ReadFile(rulesetFile) 36 c.Assert(err, qt.IsNil) 37 c.Assert(string(rulesetContents), qt.Equals, ` 38 extends: 39 - /sweater-comb/rules/rule1 40 - /sweater-comb/target/rule2 41 `[1:]) 42 43 // Capture stdout so we can test the output substitution that replaces 44 // container paths with the current working directory in spectral's output. 45 cwd, err := os.Getwd() 46 c.Assert(err, qt.IsNil) 47 tempDir := c.TempDir() 48 tempFile, err := os.Create(tempDir + "/stdout") 49 c.Assert(err, qt.IsNil) 50 c.Patch(&os.Stdout, tempFile) 51 defer tempFile.Close() 52 53 // Verify mock runner ran what we'd expect 54 runner := &mockRunner{} 55 l.runner = runner 56 err = l.Run(ctx, "my-api", "my-api/**/*.yaml") 57 c.Assert(err, qt.IsNil) 58 c.Assert(runner.runs, qt.DeepEquals, [][]string{{ 59 "docker", "run", "--rm", 60 "-v", l.rulesDir + ":/vervet", 61 "-v", cwd + ":/sweater-comb/target", 62 "some-image", 63 "lint", 64 "-r", "/vervet/ruleset.yaml", 65 "--some-flag", 66 "my-api/**/*.yaml", 67 }}) 68 69 // Verify captured output was substituted. Mainly a convenience that makes 70 // output host-relevant and cmd-clickable if possible. 71 c.Assert(tempFile.Sync(), qt.IsNil) 72 capturedOutput, err := ioutil.ReadFile(tempFile.Name()) 73 c.Assert(err, qt.IsNil) 74 c.Assert(string(capturedOutput), qt.Equals, cwd+" is the path to things in your project\n") 75 76 // Command failed. 77 runner = &mockRunner{err: fmt.Errorf("nope")} 78 l.runner = runner 79 err = l.Run(ctx, "my-api", "my-api/**/*.yaml") 80 c.Assert(err, qt.ErrorMatches, "nope") 81 } 82 83 type mockRunner struct { 84 runs [][]string 85 err error 86 } 87 88 func (r *mockRunner) run(cmd *exec.Cmd) error { 89 fmt.Fprintln(cmd.Stdout, "/sweater-comb/target is the path to things in your project") 90 r.runs = append(r.runs, cmd.Args) 91 return r.err 92 }