diff --git a/pkg/output/tap.go b/pkg/output/tap.go index 774f307..9803f5f 100644 --- a/pkg/output/tap.go +++ b/pkg/output/tap.go @@ -13,6 +13,7 @@ type tapo struct { verbose bool results []validator.Result nValid, nInvalid, nErrors, nSkipped int + index int } func tapOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output { @@ -29,39 +30,33 @@ func tapOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output { } // JSON.Write will only write when JSON.Flush has been called -func (o *tapo) Write(result validator.Result) error { - o.results = append(o.results, result) +func (o *tapo) Write(res validator.Result) error { + o.index++ + switch res.Status { + case validator.Valid: + sig, _ := res.Resource.Signature() + fmt.Fprintf(o.w, "ok %d - %s (%s)\n", o.index, res.Resource.Path, sig.Kind) + + case validator.Invalid: + sig, _ := res.Resource.Signature() + fmt.Fprintf(o.w, "not ok %d - %s (%s): %s\n", o.index, res.Resource.Path, sig.Kind, res.Err.Error()) + + case validator.Empty: + fmt.Fprintf(o.w, "ok %d - %s (empty)\n", o.index, res.Resource.Path) + + case validator.Error: + fmt.Fprintf(o.w, "not ok %d - %s: %s\n", o.index, res.Resource.Path, res.Err.Error()) + + case validator.Skipped: + fmt.Fprintf(o.w, "ok %d #skip - %s\n", o.index, res.Resource.Path) + } + return nil } // Flush outputs the results as JSON func (o *tapo) Flush() error { - var err error - - fmt.Fprintf(o.w, "1..%d\n", len(o.results)) - for i, res := range o.results { - switch res.Status { - case validator.Valid: - sig, _ := res.Resource.Signature() - fmt.Fprintf(o.w, "ok %d - %s (%s)\n", i, res.Resource.Path, sig.Kind) - - case validator.Invalid: - sig, _ := res.Resource.Signature() - fmt.Fprintf(o.w, "not ok %d - %s (%s): %s\n", i, res.Resource.Path, sig.Kind, res.Err.Error()) - - case validator.Empty: - fmt.Fprintf(o.w, "ok %d - %s (empty)\n", i, res.Resource.Path) - - case validator.Error: - fmt.Fprintf(o.w, "not ok %d - %s: %s\n", i, res.Resource.Path, res.Err.Error()) - - case validator.Skipped: - fmt.Fprintf(o.w, "ok %d #skip - %s\n", i, res.Resource.Path) - } - } - if err != nil { - return err - } + fmt.Fprintf(o.w, "1..%d\n", o.index) return nil } diff --git a/pkg/output/tap_test.go b/pkg/output/tap_test.go new file mode 100644 index 0000000..1a8b632 --- /dev/null +++ b/pkg/output/tap_test.go @@ -0,0 +1,75 @@ +package output + +import ( + "bytes" + "testing" + + "github.com/yannh/kubeconform/pkg/resource" + "github.com/yannh/kubeconform/pkg/validator" +) + +func TestTextWrite(t *testing.T) { + for _, testCase := range []struct { + name string + withSummary bool + isStdin bool + verbose bool + results []validator.Result + expect string + }{ + { + "a single deployment, summary, no verbose", + true, + false, + false, + []validator.Result{ + { + Resource: resource.Resource{ + Path: "deployment.yml", + Bytes: []byte(`apiVersion: apps/v1 +kind: Deployment +metadata: + name: "my-app" +`), + }, + Status: validator.Valid, + Err: nil, + }, + }, + "ok 1 - deployment.yml (Deployment)\n1..1\n", + }, + { + "a single deployment, verbose, with summary", + true, + false, + true, + []validator.Result{ + { + Resource: resource.Resource{ + Path: "deployment.yml", + Bytes: []byte(`apiVersion: apps/v1 +kind: Deployment +metadata: + name: "my-app" +`), + }, + Status: validator.Valid, + Err: nil, + }, + }, + "ok 1 - deployment.yml (Deployment)\n1..1\n", + }, + } { + w := new(bytes.Buffer) + o := tapOutput(w, testCase.withSummary, testCase.isStdin, testCase.verbose) + + for _, res := range testCase.results { + o.Write(res) + } + o.Flush() + + if w.String() != testCase.expect { + t.Errorf("%s - expected:, got:\n%s\n%s", testCase.name, testCase.expect, w) + } + } +} diff --git a/pkg/output/text_test.go b/pkg/output/text_test.go index 39df12a..a3ca187 100644 --- a/pkg/output/text_test.go +++ b/pkg/output/text_test.go @@ -8,7 +8,7 @@ import ( "github.com/yannh/kubeconform/pkg/validator" ) -func TestTextWrite(t *testing.T) { +func TestTapWrite(t *testing.T) { for _, testCase := range []struct { name string withSummary bool diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index c2c2984..571a4d2 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -114,11 +114,19 @@ func (val *v) ValidateResource(res resource.Resource) Result { return Result{Resource: res, Status: Error, Err: fmt.Errorf("error unmarshalling resource: %s", err)} } + if r == nil { // Resource is empty + return Result{Resource: res, Err: nil, Status: Empty} + } + sig, err := res.SignatureFromMap(r) if err != nil { return Result{Resource: res, Err: fmt.Errorf("error while parsing: %s", err), Status: Error} } + if sig.Kind == "" { // Resource contains key/values but no Kind + return Result{Resource: res, Err: fmt.Errorf("resource missing a Kind"), Status: Error} + } + if skip(*sig) { return Result{Resource: res, Err: nil, Status: Skipped} } @@ -127,14 +135,6 @@ func (val *v) ValidateResource(res resource.Resource) Result { return Result{Resource: res, Err: fmt.Errorf("prohibited resource kind %s", sig.Kind), Status: Error} } - if r == nil { // Resource is empty - return Result{Resource: res, Err: nil, Status: Empty} - } - - if sig.Kind == "" && r != nil { // Resource contains key/values but no Kind - return Result{Resource: res, Err: fmt.Errorf("resource missing a Kind"), Status: Error} - } - cached := false var schema *gojsonschema.Schema cacheKey := ""