diff --git a/cmd/cli/kubectl-kyverno/commands/test/command.go b/cmd/cli/kubectl-kyverno/commands/test/command.go index 467ab75455..87670876f8 100644 --- a/cmd/cli/kubectl-kyverno/commands/test/command.go +++ b/cmd/cli/kubectl-kyverno/commands/test/command.go @@ -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) diff --git a/cmd/cli/kubectl-kyverno/commands/test/compare.go b/cmd/cli/kubectl-kyverno/commands/test/compare.go index 9452ab9c6c..5feaa28aac 100644 --- a/cmd/cli/kubectl-kyverno/commands/test/compare.go +++ b/cmd/cli/kubectl-kyverno/commands/test/compare.go @@ -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 } diff --git a/go.mod b/go.mod index 773c9638cd..a40e604210 100644 --- a/go.mod +++ b/go.mod @@ -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