1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: Show textual diff when generate test fails (#11674)

* feat: Show textual diff when generate test fails

Signed-off-by: Tomas Aschan <tomasl@spotify.com>

* Tweak verbosity level for diff output

Signed-off-by: Tomas Aschan <tomasl@spotify.com>

* Display a rich diff of the expected and actual resources with --detailed-results

Signed-off-by: Tomas Aschan <tomasl@spotify.com>

---------

Signed-off-by: Tomas Aschan <tomasl@spotify.com>
This commit is contained in:
Tomas Aschan 2024-12-04 07:09:19 +01:00 committed by GitHub
parent 7223d44327
commit 8746a8ffbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 10 deletions

View file

@ -14,6 +14,7 @@ import (
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/report"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/filter"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/tools/cache"
@ -163,21 +164,25 @@ func checkResult(test v1alpha1.TestResult, fs billy.Filesystem, resoucePath stri
patchedResource = test.PatchedResources
}
if patchedResource != "" {
equals, err := getAndCompareResource([]*unstructured.Unstructured{&response.PatchedResource}, fs, filepath.Join(resoucePath, patchedResource))
equals, diff, err := getAndCompareResource([]*unstructured.Unstructured{&response.PatchedResource}, fs, filepath.Join(resoucePath, patchedResource))
if err != nil {
return false, err.Error(), "Resource error"
}
if !equals {
return false, "Patched resource didn't match the patched resource in the test result", "Resource diff"
dmp := diffmatchpatch.New()
legend := dmp.DiffPrettyText(dmp.DiffMain("only in expected", "only in actual", false))
return false, fmt.Sprintf("Patched resource didn't match the patched resource in the test result\n(%s)\n\n%s", legend, diff), "Resource diff"
}
}
if test.GeneratedResource != "" {
equals, err := getAndCompareResource(rule.GeneratedResources(), fs, filepath.Join(resoucePath, test.GeneratedResource))
equals, diff, err := getAndCompareResource(rule.GeneratedResources(), fs, filepath.Join(resoucePath, test.GeneratedResource))
if err != nil {
return false, err.Error(), "Resource error"
}
if !equals {
return false, "Generated resource didn't match the generated resource in the test result", "Resource diff"
dmp := diffmatchpatch.New()
legend := dmp.DiffPrettyText(dmp.DiffMain("only in expected", "only in actual", false))
return false, fmt.Sprintf("Generated resource didn't match the generated resource in the test result\n(%s)\n\n%s", legend, diff), "Resource diff"
}
}
result := report.ComputePolicyReportResult(false, response, rule)

View file

@ -4,14 +4,17 @@ import (
"fmt"
"github.com/go-git/go-billy/v5"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
"github.com/sergi/go-diff/diffmatchpatch"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func getAndCompareResource(actualResources []*unstructured.Unstructured, fs billy.Filesystem, path string) (bool, error) {
func getAndCompareResource(actualResources []*unstructured.Unstructured, fs billy.Filesystem, path string) (bool, string, error) {
expectedResources, err := resource.GetResourceFromPath(fs, path)
if err != nil {
return false, fmt.Errorf("error: failed to load resource (%s)", err)
return false, "", fmt.Errorf("error: failed to load resource (%s)", err)
}
expectedResourcesMap := map[string]unstructured.Unstructured{}
@ -32,11 +35,17 @@ func getAndCompareResource(actualResources []*unstructured.Unstructured, fs bill
resource.FixupGenerateLabels(r)
equals, err := resource.Compare(r, expectedResourcesMap[r.GetNamespace()+"/"+r.GetName()], true)
if err != nil {
return false, fmt.Errorf("error: failed to compare resources (%s)", err)
return false, "", fmt.Errorf("error: failed to compare resources (%s)", err)
}
if !equals {
return false, nil
log.Log.V(4).Info("Resource diff", "expected", expectedResourcesMap[r.GetNamespace()+"/"+r.GetName()], "actual", r)
es, _ := yaml.Marshal(expectedResourcesMap[r.GetNamespace()+"/"+r.GetName()])
as, _ := yaml.Marshal(r)
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(es), string(as), false)
log.Log.V(4).Info("\n" + dmp.DiffPrettyText(diffs) + "\n")
return false, dmp.DiffPrettyText(diffs), nil
}
}
return true, nil
return true, "", nil
}

2
go.mod
View file

@ -318,7 +318,7 @@ require (
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/fulcio v1.6.3 // indirect