mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
test: add test case for duplicate check and report unused resources (#6653)
* add test case Signed-off-by: bakito <github@bakito.ch> * also print obsolete resources Signed-off-by: bakito <github@bakito.ch> --------- Signed-off-by: bakito <github@bakito.ch> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
893c22b96b
commit
cdf79daa44
9 changed files with 292 additions and 12 deletions
|
@ -230,7 +230,7 @@ type testFilter struct {
|
|||
enabled bool
|
||||
}
|
||||
|
||||
var ftable = []Table{}
|
||||
var ftable []Table
|
||||
|
||||
func testCommandExecute(dirPath []string, fileName string, gitBranch string, testCase string, failOnly bool, removeColor bool) (rc *resultCounts, err error) {
|
||||
var errors []error
|
||||
|
@ -756,7 +756,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
|||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("\nExecuting %s...", values.Name)
|
||||
fmt.Printf("\nExecuting %s...\n", values.Name)
|
||||
valuesFile := values.Variables
|
||||
userInfoFile := values.UserInfo
|
||||
|
||||
|
@ -802,7 +802,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
filteredPolicies := []kyvernov1.PolicyInterface{}
|
||||
var filteredPolicies []kyvernov1.PolicyInterface
|
||||
for _, p := range policies {
|
||||
for _, res := range values.Results {
|
||||
if p.GetName() == res.Policy {
|
||||
|
@ -814,7 +814,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
|||
|
||||
ruleToCloneSourceResource := map[string]string{}
|
||||
for _, p := range filteredPolicies {
|
||||
filteredRules := []kyvernov1.Rule{}
|
||||
var filteredRules []kyvernov1.Rule
|
||||
|
||||
for _, rule := range autogen.ComputeRules(p) {
|
||||
for _, res := range values.Results {
|
||||
|
@ -869,7 +869,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
|||
}
|
||||
|
||||
if len(policies) > 0 && len(checkableResources) > 0 {
|
||||
fmt.Printf("\napplying %s to %s... \n", msgPolicies, msgResources)
|
||||
fmt.Printf("applying %s to %s... \n", msgPolicies, msgResources)
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
|
@ -929,6 +929,14 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, isGit bool,
|
|||
}
|
||||
|
||||
func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api.Test) []*unstructured.Unstructured {
|
||||
res, _, _ := selectResourcesForCheckInternal(resources, values)
|
||||
return res
|
||||
}
|
||||
|
||||
// selectResourcesForCheckInternal internal method to test duplicates and unused
|
||||
func selectResourcesForCheckInternal(resources []*unstructured.Unstructured, values *api.Test) ([]*unstructured.Unstructured, int, int) {
|
||||
var duplicates int
|
||||
var unused int
|
||||
uniqResources := make(map[string]*unstructured.Unstructured)
|
||||
|
||||
for i := range resources {
|
||||
|
@ -936,6 +944,7 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
|||
key := fmt.Sprintf("%s/%s/%s", r.GetKind(), r.GetName(), r.GetNamespace())
|
||||
if _, ok := uniqResources[key]; ok {
|
||||
fmt.Println("skipping duplicate resource, resource :", r)
|
||||
duplicates++
|
||||
} else {
|
||||
uniqResources[key] = r
|
||||
}
|
||||
|
@ -945,14 +954,16 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
|||
for key := range uniqResources {
|
||||
r := uniqResources[key]
|
||||
for _, res := range values.Results {
|
||||
for _, testr := range res.Resources {
|
||||
if r.GetName() == testr {
|
||||
if res.Kind == r.GetKind() {
|
||||
for _, testr := range res.Resources {
|
||||
if r.GetName() == testr {
|
||||
selectedResources[key] = r
|
||||
}
|
||||
}
|
||||
if r.GetName() == res.Resource {
|
||||
selectedResources[key] = r
|
||||
}
|
||||
}
|
||||
if r.GetName() == res.Resource {
|
||||
selectedResources[key] = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -960,13 +971,18 @@ func selectResourcesForCheck(resources []*unstructured.Unstructured, values *api
|
|||
|
||||
for key := range selectedResources {
|
||||
checkableResources = append(checkableResources, selectedResources[key])
|
||||
delete(uniqResources, key)
|
||||
}
|
||||
return checkableResources
|
||||
for _, r := range uniqResources {
|
||||
fmt.Println("skipping unused resource, resource :", r)
|
||||
unused++
|
||||
}
|
||||
return checkableResources, duplicates, unused
|
||||
}
|
||||
|
||||
func printTestResult(resps map[string]policyreportv1alpha2.PolicyReportResult, testResults []api.TestResults, rc *resultCounts, failOnly, removeColor bool) error {
|
||||
printer := newTablePrinter(removeColor)
|
||||
table := []Table{}
|
||||
var table []Table
|
||||
|
||||
var countDeprecatedResource int
|
||||
testCount := 1
|
||||
|
|
92
cmd/cli/kubectl-kyverno/test/test_command_test.go
Normal file
92
cmd/cli/kubectl-kyverno/test/test_command_test.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
|
||||
"gotest.tools/assert"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
func Test_selectResourcesForCheck(t *testing.T) {
|
||||
|
||||
type TestCase struct {
|
||||
testFile string
|
||||
expectedResources int
|
||||
expectedDuplicates int
|
||||
expectedUnused int
|
||||
}
|
||||
baseTestDir := "../../../../test/cli/test-unit/selectResourcesForCheck/"
|
||||
testcases := []*TestCase{
|
||||
{
|
||||
|
||||
testFile: "kyverno-test-duplicated-with-resource.yaml",
|
||||
expectedResources: 3,
|
||||
expectedDuplicates: 1,
|
||||
expectedUnused: 3,
|
||||
},
|
||||
{
|
||||
testFile: "kyverno-test-duplicated-with-resources.yaml",
|
||||
expectedResources: 3,
|
||||
expectedDuplicates: 1,
|
||||
expectedUnused: 3,
|
||||
},
|
||||
{
|
||||
testFile: "kyverno-test-uniq-with-resource.yaml",
|
||||
expectedResources: 3,
|
||||
expectedDuplicates: 0,
|
||||
expectedUnused: 3,
|
||||
},
|
||||
{
|
||||
testFile: "kyverno-test-uniq-with-resources.yaml",
|
||||
expectedResources: 3,
|
||||
expectedDuplicates: 0,
|
||||
expectedUnused: 3,
|
||||
},
|
||||
}
|
||||
fs := memfs.New()
|
||||
for _, tc := range testcases {
|
||||
|
||||
// read test spec
|
||||
values := &api.Test{}
|
||||
testBytes, err := os.ReadFile(filepath.Join(baseTestDir, tc.testFile))
|
||||
assert.NilError(t, err)
|
||||
err = yaml.Unmarshal(testBytes, values)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// read policies
|
||||
policies, err := common.GetPoliciesFromPaths(
|
||||
fs,
|
||||
[]string{filepath.Join(baseTestDir, values.Policies[0])},
|
||||
false,
|
||||
filepath.Join(baseTestDir, values.Resources[0]),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// read resources
|
||||
resources, err := common.GetResourceAccordingToResourcePath(
|
||||
fs,
|
||||
[]string{filepath.Join(baseTestDir, values.Resources[0])},
|
||||
false,
|
||||
policies,
|
||||
nil,
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
filepath.Join(baseTestDir, values.Policies[0]),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
selected, duplicates, unused := selectResourcesForCheckInternal(resources, values)
|
||||
assert.Equal(t, len(selected), tc.expectedResources,
|
||||
"Did not get the expected number of resources for test %s", tc.testFile)
|
||||
assert.Equal(t, duplicates, tc.expectedDuplicates,
|
||||
"Did not get the expected number of duplicates for test %s", tc.testFile)
|
||||
assert.Equal(t, unused, tc.expectedUnused,
|
||||
"Did not get the expected number of unused resources for test %s", tc.testFile)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: just a dummy policy
|
||||
spec:
|
||||
rules:
|
||||
- name: dummy-rule-1
|
||||
- name: dummy-rule-2
|
|
@ -0,0 +1,17 @@
|
|||
name: dummy-policy
|
||||
policies:
|
||||
- dummy-policy.yaml
|
||||
resources:
|
||||
- resource-duplicates.yaml
|
||||
|
||||
results:
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resource: myapp-pod1
|
||||
kind: Pod
|
||||
result: pass
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resource: myapp-pod2
|
||||
kind: Pod
|
||||
result: pass
|
|
@ -0,0 +1,19 @@
|
|||
name: dummy-policy
|
||||
policies:
|
||||
- dummy-policy.yaml
|
||||
resources:
|
||||
- resource-duplicates.yaml
|
||||
|
||||
results:
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod1
|
||||
kind: Pod
|
||||
result: pass
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod2
|
||||
kind: Pod
|
||||
result: pass
|
|
@ -0,0 +1,19 @@
|
|||
name: dummy-policy
|
||||
policies:
|
||||
- dummy-policy.yaml
|
||||
resources:
|
||||
- resource-uniq.yaml
|
||||
|
||||
results:
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod1
|
||||
kind: Pod
|
||||
result: pass
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod2
|
||||
kind: Pod
|
||||
result: pass
|
|
@ -0,0 +1,19 @@
|
|||
name: dummy-policy
|
||||
policies:
|
||||
- dummy-policy.yaml
|
||||
resources:
|
||||
- resource-uniq.yaml
|
||||
|
||||
results:
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod1
|
||||
kind: Pod
|
||||
result: pass
|
||||
- policy: dummy-policy
|
||||
rule: require-image-tag
|
||||
resources:
|
||||
- myapp-pod2
|
||||
kind: Pod
|
||||
result: pass
|
|
@ -0,0 +1,49 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod1
|
||||
namespace: foo
|
||||
|
||||
---
|
||||
# duplicate pod
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod1
|
||||
namespace: foo
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod2
|
||||
namespace: foo
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod2
|
||||
namespace: bar
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod3
|
||||
namespace: bar
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: myapp-pod2 # reuse the name of the pod to check duplicate check
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: myns
|
|
@ -0,0 +1,41 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod1
|
||||
namespace: foo
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod2
|
||||
namespace: foo
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod2
|
||||
namespace: bar
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod3
|
||||
namespace: bar
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: myapp-pod2 # reuse the name of the pod to check duplicate check
|
||||
|
||||
---
|
||||
# will not be used
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: myns
|
Loading…
Reference in a new issue