mirror of
https://github.com/yannh/kubeconform.git
synced 2026-02-19 18:07:02 +00:00
tap plan can be at the end, that way we can stream the output and not buffer
This commit is contained in:
parent
706488cafb
commit
07dec90112
4 changed files with 107 additions and 37 deletions
|
|
@ -13,6 +13,7 @@ type tapo struct {
|
||||||
verbose bool
|
verbose bool
|
||||||
results []validator.Result
|
results []validator.Result
|
||||||
nValid, nInvalid, nErrors, nSkipped int
|
nValid, nInvalid, nErrors, nSkipped int
|
||||||
|
index int
|
||||||
}
|
}
|
||||||
|
|
||||||
func tapOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output {
|
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
|
// JSON.Write will only write when JSON.Flush has been called
|
||||||
func (o *tapo) Write(result validator.Result) error {
|
func (o *tapo) Write(res validator.Result) error {
|
||||||
o.results = append(o.results, result)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush outputs the results as JSON
|
// Flush outputs the results as JSON
|
||||||
func (o *tapo) Flush() error {
|
func (o *tapo) Flush() error {
|
||||||
var err error
|
fmt.Fprintf(o.w, "1..%d\n", o.index)
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
pkg/output/tap_test.go
Normal file
75
pkg/output/tap_test.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/yannh/kubeconform/pkg/validator"
|
"github.com/yannh/kubeconform/pkg/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTextWrite(t *testing.T) {
|
func TestTapWrite(t *testing.T) {
|
||||||
for _, testCase := range []struct {
|
for _, testCase := range []struct {
|
||||||
name string
|
name string
|
||||||
withSummary bool
|
withSummary bool
|
||||||
|
|
|
||||||
|
|
@ -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)}
|
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)
|
sig, err := res.SignatureFromMap(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Result{Resource: res, Err: fmt.Errorf("error while parsing: %s", err), Status: Error}
|
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) {
|
if skip(*sig) {
|
||||||
return Result{Resource: res, Err: nil, Status: Skipped}
|
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}
|
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
|
cached := false
|
||||||
var schema *gojsonschema.Schema
|
var schema *gojsonschema.Schema
|
||||||
cacheKey := ""
|
cacheKey := ""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue