1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-01-20 18:52:16 +00:00

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

* feat: Show textual diff when generate test fails



* Tweak verbosity level for diff output



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



---------

Signed-off-by: Tomas Aschan <tomasl@spotify.com>
Co-authored-by: Tomas Aschan <1550920+tomasaschan@users.noreply.github.com>
This commit is contained in:
gcp-cherry-pick-bot[bot] 2024-12-04 06:53:24 +00:00 committed by GitHub
parent fee0fadccc
commit ab79afeccf
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