From 20805f652c977e08cb0c9d829999676961e9b52b Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 9 May 2024 07:27:59 -0700 Subject: [PATCH] Stop validating output of closed channel in Validate (#265) Currently, Validate and ValidateWithContext always returns a result with status `Empty` and a `missing 'kind' key` error as the final item in the returned slice. This is because ValidateWithContext currently will parse the output of `resourcesChan`, even when the context is finished and we get back a default `Resource` struct. This PR modifies the code to skip validating this case. --- pkg/validator/validator.go | 5 +-- pkg/validator/validator_test.go | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index 82056f6..0f8e85a 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -223,8 +223,9 @@ func (val *v) ValidateWithContext(ctx context.Context, filename string, r io.Rea for { select { case res, ok := <-resourcesChan: - validationResults = append(validationResults, val.ValidateResource(res)) - if !ok { + if ok { + validationResults = append(validationResults, val.ValidateResource(res)) + } else { resourcesChan = nil } diff --git a/pkg/validator/validator_test.go b/pkg/validator/validator_test.go index 0776253..902621a 100644 --- a/pkg/validator/validator_test.go +++ b/pkg/validator/validator_test.go @@ -1,6 +1,8 @@ package validator import ( + "bytes" + "io" "reflect" "testing" @@ -435,3 +437,65 @@ age: not a number t.Errorf("Expected %+v, got %+v", expectedErrors, got.ValidationErrors) } } + +func TestValidateFile(t *testing.T) { + inputData := []byte(` +kind: name +apiVersion: v1 +firstName: bar +lastName: qux +--- +kind: name +apiVersion: v1 +firstName: foo +`) + + schema := []byte(`{ + "title": "Example Schema", + "type": "object", + "properties": { + "kind": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + }, + "required": ["firstName", "lastName"] +}`) + + val := v{ + opts: Opts{ + SkipKinds: map[string]struct{}{}, + RejectKinds: map[string]struct{}{}, + }, + schemaCache: nil, + schemaDownload: downloadSchema, + regs: []registry.Registry{ + newMockRegistry(func() (string, []byte, error) { + return "", schema, nil + }), + }, + } + + gotStatuses := []Status{} + gotValidationErrors := []ValidationError{} + for _, got := range val.Validate("test-file", io.NopCloser(bytes.NewReader(inputData))) { + gotStatuses = append(gotStatuses, got.Status) + gotValidationErrors = append(gotValidationErrors, got.ValidationErrors...) + } + + expectedStatuses := []Status{Valid, Invalid} + expectedValidationErrors := []ValidationError{ + {Path: "", Msg: "missing properties: 'lastName'"}, + } + if !reflect.DeepEqual(expectedStatuses, gotStatuses) { + t.Errorf("Expected %+v, got %+v", expectedStatuses, gotStatuses) + } + if !reflect.DeepEqual(expectedValidationErrors, gotValidationErrors) { + t.Errorf("Expected %+v, got %+v", expectedValidationErrors, gotValidationErrors) + } +}