Skip to content

Commit

Permalink
Merge pull request #193 from quintush/feature/CodeQualityCorrections
Browse files Browse the repository at this point in the history
Feature/code quality corrections
  • Loading branch information
quintush authored Jan 2, 2023
2 parents 9f8295d + 83cff9e commit 9ff4455
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 110 deletions.
1 change: 1 addition & 0 deletions DOCUMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ Available assertion types are listed below:
| `isNotNull` | **path**: *string*. The `set` path to assert. | Assert the value of specified **path** is NOT `null`. |<pre>isNotNull:<br/> path: spec.replicas</pre> |
| `isSubset` | **path**: *string*. The `set` path to assert, the value must be an *object*. <br/>**content**: *any*. The content to be contained. | Assert the object as the value of specified **path** that contains the **content**. |<pre>isSubset:<br/> path: spec.template<br/> content:<br/> metadata: <br/> labels: <br/> app: basic<br/> release: MY-RELEASE<br/></pre> |
| `isNotSubset` | **path**: *string*. The `set` path to assert, the value must be an *object*. <br/>**content**: *any*. The content NOT to be contained. | Assert the object as the value of specified **path** that NOT contains the **content**. |<pre>isSubset:<br/> path: spec.template<br/> content:<br/> metadata: <br/> labels: <br/> app: basic<br/> release: MY-RELEASE<br/></pre> |
| `lengthEqual` | **path**: *string, optional*. The `set` path to assert the count of array values. <br/>**paths**: *string, optional*. The `set` array of paths to assert the count validation of the founded arrays. <br/>**count**: *int, optional*. The count of the values in the array. | Assert the **count** of the **path** or **paths**. |<pre>lengthEqual:<br/> path: spec.tls<br/> count: 1<br/></pre> |
| `matchRegex` | **path**: *string*. The `set` path to assert, the value must be a *string*. <br/>**pattern**: *string*. The regex pattern to match (without quoting `/`). | Assert the value of specified **path** match **pattern**. | <pre>matchRegex:<br/> path: metadata.name<br/> pattern: -my-chart$</pre> |
| `notMatchRegex` | **path**: *string*. The `set` path to assert, the value must be a *string*. <br/>**pattern**: *string*. The regex pattern NOT to match (without quoting `/`). | Assert the value of specified **path** NOT match **pattern**. | <pre>notMatchRegex:<br/> path: metadata.name<br/> pattern: -my-chat$</pre> |
| `matchRegexRaw` | **pattern**: *string*. The regex pattern to match (without quoting `/`) in a NOTES.txt file. | Assert the value match **pattern**. | <pre>matchRegexRaw:<br/> pattern: -my-notes$</pre> |
Expand Down
14 changes: 11 additions & 3 deletions pkg/unittest/assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,16 @@ func TestAssertionUnmarshaledFromYAML(t *testing.T) {
- isAPIVersion:
- hasDocuments:
- isSubset:
- isNotSubset:
- failedTemplate:
- notFailedTemplate:
- containsDocument:
- lengthEqual:
`

assertionsAsMap := make([]map[string]interface{}, 19)
assertionsAsMap := make([]map[string]interface{}, 23)
yaml.Unmarshal([]byte(assertionsYAML), &assertionsAsMap)
assertions := make([]Assertion, 19)
assertions := make([]Assertion, 23)
yaml.Unmarshal([]byte(assertionsYAML), &assertions)

a := assert.New(t)
Expand Down Expand Up @@ -238,8 +242,12 @@ e:
path: e
content:
f: g
- template: t.yaml
lengthEqual:
path: c
count: 1
`
validateSucceededTestAssertions(t, assertionsYAML, 14, renderedMap)
validateSucceededTestAssertions(t, assertionsYAML, 15, renderedMap)
}

func TestAssertionRawAssertWhenOk(t *testing.T) {
Expand Down
83 changes: 45 additions & 38 deletions pkg/unittest/validators/contains_document_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package validators
import (
"fmt"

"github.com/lrills/helm-unittest/internal/common"
"github.com/lrills/helm-unittest/pkg/unittest/valueutils"
)

Expand All @@ -23,58 +24,64 @@ func (v ContainsDocumentValidator) failInfo(actual interface{}, index int, not b
)
}

// Validate implement Validatable
func (v ContainsDocumentValidator) Validate(context *ValidateContext) (bool, []string) {
manifests, err := context.getManifests()
if err != nil {
return false, splitInfof(errorFormat, -1, err.Error())
func (v ContainsDocumentValidator) validateManifest(manifest common.K8sManifest, negative bool) bool {
if kind, ok := manifest["kind"].(string); (ok && kind == v.Kind) == negative {
// if no match, move onto next document
return false
}

validateSuccess := false
validateErrors := make([]string, 0)
if api, ok := manifest["apiVersion"].(string); (ok && api == v.APIVersion) == negative {
// if no match, move onto next document
return false
}

for _, manifest := range manifests {
if kind, ok := manifest["kind"].(string); (ok && kind == v.Kind) == context.Negative {
// if no match, move onto next document
continue
if v.Name != "" {
actual, err := valueutils.GetValueOfSetPath(manifest, "metadata.name")
if err != nil {
// fail on not found match
return false
}

if api, ok := manifest["apiVersion"].(string); (ok && api == v.APIVersion) == context.Negative {
// if no match, move onto next document
continue
if (actual == v.Name) == negative {
return false
}
}

if v.Name != "" {
actual, err := valueutils.GetValueOfSetPath(manifest, "metadata.name")
if err != nil {
// fail on not found match
continue
}
if v.Namespace != "" {
actual, err := valueutils.GetValueOfSetPath(manifest, "metadata.namespace")
if err != nil {
// fail on not found match
return false
}

if (actual == v.Name) == context.Negative {
continue
}
if (actual == v.Namespace) == negative {
return false
}
}

if v.Namespace != "" {
actual, err := valueutils.GetValueOfSetPath(manifest, "metadata.namespace")
if err != nil {
// fail on not found match
continue
}
return true
}

if (actual == v.Namespace) == context.Negative {
continue
}
}
// Validate implement Validatable
func (v ContainsDocumentValidator) Validate(context *ValidateContext) (bool, []string) {
manifests, err := context.getManifests()
if err != nil {
return false, splitInfof(errorFormat, -1, err.Error())
}

validateSuccess := false
validateErrors := make([]string, 0)

// if we get here the above have held so it is a match
validateSuccess = true
break
for _, manifest := range manifests {
validateSuccess = v.validateManifest(manifest, context.Negative)
if validateSuccess {
break
}
continue
}
if !validateSuccess {
errorMesasge := v.failInfo(v.Kind, 0, context.Negative)
validateErrors = append(validateErrors, errorMesasge...)
errorMessage := v.failInfo(v.Kind, 0, context.Negative)
validateErrors = append(validateErrors, errorMessage...)
}
validateSuccess = determineSuccess(1, validateSuccess, true)

Expand Down
24 changes: 23 additions & 1 deletion pkg/unittest/validators/contains_document_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestContainsDocumentValidatorNoNameNamespaceWhenOk(t *testing.T) {
assert.Equal(t, []string{}, diff)
}

func TestContainsDocumentValidatorWhenFail(t *testing.T) {
func TestContainsDocumentValidatorWhenFailKind(t *testing.T) {
validator := ContainsDocumentValidator{
"Deployment",
"apps/v1",
Expand All @@ -133,3 +133,25 @@ func TestContainsDocumentValidatorWhenFail(t *testing.T) {
"\tKind = Deployment, apiVersion = apps/v1",
}, diff)
}

func TestContainsDocumentValidatorWhenFailAPIVersion(t *testing.T) {
validator := ContainsDocumentValidator{
"Service",
"apps/v1",
"foo",
"bar",
}

pass, diff := validator.Validate(&ValidateContext{
Index: -1,
Docs: []common.K8sManifest{makeManifest(docToTestContainsDocument1),
makeManifest(docToTestContainsDocument2)},
})

assert.False(t, pass)
assert.Equal(t, []string{
"DocumentIndex:\t0",
"Expected to contain document:",
"\tKind = Service, apiVersion = apps/v1",
}, diff)
}
92 changes: 26 additions & 66 deletions pkg/unittest/validators/length_equal_document_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package validators

import (
"fmt"
"github.com/lrills/helm-unittest/pkg/unittest/valueutils"
"strconv"

log "github.com/sirupsen/logrus"
"github.com/lrills/helm-unittest/internal/common"
"github.com/lrills/helm-unittest/pkg/unittest/valueutils"
)

// LengthEqualDocumentsValidator validate whether the count of manifests rendered form template is Count
Expand All @@ -15,27 +14,23 @@ type LengthEqualDocumentsValidator struct {
Count int // optional if paths defined
}

func (v LengthEqualDocumentsValidator) failInfo(actual int, not bool) []string {
expectedCount := strconv.Itoa(v.Count)
actualCount := strconv.Itoa(actual)
customMessage := " documents count to be"

log.WithField("validator", "length_equal").Debugln("expected content:", expectedCount)
log.WithField("validator", "length_equal").Debugln("actual content:", actualCount)

if not {
return splitInfof(
setFailFormat(not, false, false, false, customMessage),
-1,
expectedCount,
)
func (v LengthEqualDocumentsValidator) singleValidateCounts(manifest common.K8sManifest, path string, idx, count int) (bool, []string, int) {
spec, err := valueutils.GetValueOfSetPath(manifest, path)
if err != nil {
return false, splitInfof(errorFormat, idx, err.Error()), 0
}
specArr, ok := spec.([]interface{})
if !ok {
return false, splitInfof(errorFormat, idx, fmt.Sprintf("%s is not array", path)), 0
}
return splitInfof(
setFailFormat(not, false, true, false, customMessage),
-1,
expectedCount,
actualCount,
)
specLen := len(specArr)
if count > -1 {
if specLen != count {
return false, splitInfof(errorFormat, idx, fmt.Sprintf(
"count doesn't match. expected: %d != %d actual", count, specLen)), 0
}
}
return true, []string{}, specLen
}

// Validate implement Validatable
Expand All @@ -55,49 +50,20 @@ func (v LengthEqualDocumentsValidator) Validate(context *ValidateContext) (bool,
validateErrors := make([]string, 0)
for idx, manifest := range manifests {
if singleMode {
spec, err := valueutils.GetValueOfSetPath(manifest, v.Path)
if err != nil {
validateSuccess = false
errorMessage := splitInfof(errorFormat, idx, err.Error())
validateErrors = append(validateErrors, errorMessage...)
continue
}
specArr, ok := spec.([]interface{})
if !ok {
validateSuccess = false
errorMessage := splitInfof(errorFormat, idx, fmt.Sprintf("%s is not array", v.Path))
validateErrors = append(validateErrors, errorMessage...)
continue
}
specLen := len(specArr)
if specLen != v.Count {
validateSuccess = false
errorMessage := splitInfof(errorFormat, idx, fmt.Sprintf(
"count doesn't match. expected: %d != %d actual", v.Count, specLen))
validateErrors = append(validateErrors, errorMessage...)
continue
}
var validateSingleErrors []string
validateSuccess, validateSingleErrors, _ = v.singleValidateCounts(manifest, v.Path, idx, v.Count)
validateErrors = append(validateErrors, validateSingleErrors...)
continue
} else {
px := map[string]int{}
c := true
for _, p := range v.Paths {
sp, err := valueutils.GetValueOfSetPath(manifest, p)
if err != nil {
validateSuccess = false
errorMessage := splitInfof(errorFormat, idx, err.Error())
validateErrors = append(validateErrors, errorMessage...)
var validateSingleErrors []string
validateSuccess, validateSingleErrors, px[p] = v.singleValidateCounts(manifest, p, idx, -1)
if !validateSuccess {
validateErrors = append(validateErrors, validateSingleErrors...)
c = false
break
}
specArr, ok := sp.([]interface{})
if !ok {
validateSuccess = false
errorMessage := splitInfof(errorFormat, idx, fmt.Sprintf("%s is not array", p))
validateErrors = append(validateErrors, errorMessage...)
c = false
break
}
px[p] = len(specArr)
}
if !c {
continue
Expand All @@ -121,11 +87,5 @@ func (v LengthEqualDocumentsValidator) Validate(context *ValidateContext) (bool,
}
validateSuccess = determineSuccess(idx, validateSuccess, true)
}
if !validateSuccess {
//errorMesasge := v.failInfo(v.Kind, 0, context.Negative)
errorMessage := []string{}
validateErrors = append(validateErrors, errorMessage...)
}
validateSuccess = determineSuccess(1, validateSuccess, true)
return validateSuccess, validateErrors
}
36 changes: 34 additions & 2 deletions pkg/unittest/validators/length_equal_document_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func TestLengthEqualDocumentsValidatorOk_Single(t *testing.T) {
assert.True(t, pass)
assert.Equal(t, []string{}, diff)
}

func TestLengthEqualDocumentsValidatorOk_Single2(t *testing.T) {
manifest := makeManifest(testDocLengthEqual2)

Expand Down Expand Up @@ -97,19 +98,50 @@ func TestLengthEqualDocumentsValidatorOk_Multi(t *testing.T) {
assert.Equal(t, []string{}, diff)
}

func TestLengthEqualDocumentsValidatorFail_Single(t *testing.T) {
manifest := makeManifest(testDocLengthEqual2)

validator := LengthEqualDocumentsValidator{
Path: "spec.tls",
Count: 1,
}
pass, diff := validator.Validate(&ValidateContext{
Docs: []common.K8sManifest{manifest},
})

assert.False(t, pass)
assert.Equal(t, []string{"DocumentIndex:\t0", "Error:", "\tcount doesn't match. expected: 1 != 2 actual"}, diff)
}

func TestLengthEqualDocumentsValidatorFail_Multi(t *testing.T) {
manifest := makeManifest(testDocLengthEqual3_Fail)

validator := LengthEqualDocumentsValidator{
Paths: []string{"spec.tls", "spec.rules"},
}
pass, _ := validator.Validate(&ValidateContext{
pass, diff := validator.Validate(&ValidateContext{
Docs: []common.K8sManifest{manifest},
})

assert.False(t, pass)
//assert.Equal(t, []string{}, diff)
assert.Equal(t, []string{"DocumentIndex:\t0", "Error:", "\tspec.rules count is '1'(doesn't match others)"}, diff)
}

func TestLengthEqualDocumentsValidatorWhenPathAndNoCount(t *testing.T) {
manifest := makeManifest(testDocLengthEqual3_Fail)

validator := LengthEqualDocumentsValidator{
Path: "spec.tls",
}
pass, diff := validator.Validate(&ValidateContext{
Docs: []common.K8sManifest{manifest},
Negative: true,
})

assert.False(t, pass)
assert.Equal(t, []string{"Error:", "\t'count' field must be set if 'path' is used"}, diff)
}

func TestLengthEqualDocumentsValidatorWhenBadConfig(t *testing.T) {
manifest := makeManifest(testDocLengthEqual3_Fail)

Expand Down

0 comments on commit 9ff4455

Please sign in to comment.