1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

refactor: finish refactoring generate e2e tests (#4090)

* refactor: generate e2e GeneratePolicyDeletionforCloneTests

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* refactor: generate e2e test GenerateNetworkPolicyOnNamespaceWithoutLabelTests

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* chore: cleanup

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* finish refactoring tests

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* refactor: is not found

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* refactor expectations part 1

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* fix: repeat update on conflict

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-07-05 17:34:09 +02:00 committed by GitHub
parent 210a709bb3
commit 24e96884c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 351 additions and 912 deletions

View file

@ -1,9 +1,11 @@
package generate
import (
"time"
"github.com/kyverno/kyverno/test/e2e"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/yaml"
. "github.com/onsi/gomega"
)
@ -32,50 +34,9 @@ var (
// NetworkPolicy GVR
npGVR = e2e.GetGVR("networking.k8s.io", "v1", "networkpolicies")
// ClusterPolicy Namespace
clPolNS = ""
// NetworkPolicy Namespace
npPolNS = ""
)
type resource struct {
gvr schema.GroupVersionResource
ns string
raw []byte
}
func clusteredResource(gvr schema.GroupVersionResource, raw []byte) resource {
return resource{gvr, "", raw}
}
func namespacedResource(gvr schema.GroupVersionResource, ns string, raw []byte) resource {
return resource{gvr, ns, raw}
}
type existingResource struct {
gvr schema.GroupVersionResource
ns string
name string
}
func existing(gvr schema.GroupVersionResource, ns string, name string) existingResource {
return existingResource{gvr, ns, name}
}
type expectedResource struct {
existingResource
validate []func(*unstructured.Unstructured)
}
func expected(gvr schema.GroupVersionResource, ns string, name string, validate ...func(*unstructured.Unstructured)) expectedResource {
return expectedResource{existing(gvr, ns, name), validate}
}
// RoleTests is E2E Test Config for Role and RoleBinding
// TODO:- Clone for Role and RoleBinding
var RoleTests = []struct {
type testCase struct {
// TestName - Name of the Test
TestName string
// ClusterPolicy - ClusterPolicy yaml file
@ -86,252 +47,219 @@ var RoleTests = []struct {
TriggerResource resource
// ExpectedResources - Expected resources to pass the test
ExpectedResources []expectedResource
}{
// Steps - Test case steps
Steps []testCaseStep
}
// roleTests is E2E Test Config for Role and RoleBinding
// TODO:- Clone for Role and RoleBinding
var roleTests = []testCase{
{
TestName: "test-role-rolebinding-without-clone",
ClusterPolicy: clusteredResource(clPolGVR, roleRoleBindingYamlWithSync),
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(rGVR, "test", "ns-role"),
expected(rbGVR, "test", "ns-role-binding"),
},
ClusterPolicy: clusterPolicy(roleRoleBindingYamlWithSync),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idRole("test", "ns-role")),
expectation(idRoleBinding("test", "ns-role-binding")),
),
},
{
TestName: "test-role-rolebinding-withsync-without-clone",
ClusterPolicy: clusteredResource(clPolGVR, roleRoleBindingYamlWithSync),
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(rGVR, "test", "ns-role"),
expected(rbGVR, "test", "ns-role-binding"),
},
ClusterPolicy: clusterPolicy(roleRoleBindingYamlWithSync),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idRole("test", "ns-role")),
expectation(idRoleBinding("test", "ns-role-binding")),
),
},
{
TestName: "test-role-rolebinding-with-clone",
ClusterPolicy: clusteredResource(clPolGVR, roleRoleBindingYamlWithClone),
SourceResources: []resource{
namespacedResource(rGVR, "default", sourceRoleYaml),
namespacedResource(rbGVR, "default", sourceRoleBindingYaml),
},
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(rGVR, "test", "ns-role"),
expected(rbGVR, "test", "ns-role-binding"),
},
ClusterPolicy: clusterPolicy(roleRoleBindingYamlWithClone),
SourceResources: resources(
role("default", sourceRoleYaml),
roleBinding("default", sourceRoleBindingYaml),
),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idRole("test", "ns-role")),
expectation(idRoleBinding("test", "ns-role-binding")),
),
},
}
// ClusterRoleTests - E2E Test Config for ClusterRole and ClusterRoleBinding
var ClusterRoleTests = []struct {
// TestName - Name of the Test
TestName string
// ClusterPolicy - ClusterPolicy yaml file
ClusterPolicy resource
// SourceResources - Source resources yaml files
SourceResources []resource
// TriggerResource - Trigger resource yaml files
TriggerResource resource
// ExpectedResources - Expected resources to pass the test
ExpectedResources []expectedResource
}{
// clusterRoleTests - E2E Test Config for ClusterRole and ClusterRoleBinding
var clusterRoleTests = []testCase{
{
TestName: "test-clusterrole-clusterrolebinding-without-clone",
ClusterPolicy: clusteredResource(clPolGVR, genClusterRoleYamlWithSync),
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(crGVR, "", "ns-cluster-role"),
expected(crbGVR, "", "ns-cluster-role-binding"),
},
ClusterPolicy: clusterPolicy(genClusterRoleYamlWithSync),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idClusterRole("ns-cluster-role")),
expectation(idClusterRoleBinding("ns-cluster-role-binding")),
),
},
{
TestName: "test-clusterrole-clusterrolebinding-with-sync-without-clone",
ClusterPolicy: clusteredResource(clPolGVR, genClusterRoleYamlWithSync),
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(crGVR, "", "ns-cluster-role"),
expected(crbGVR, "", "ns-cluster-role-binding"),
},
ClusterPolicy: clusterPolicy(genClusterRoleYamlWithSync),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idClusterRole("ns-cluster-role")),
expectation(idClusterRoleBinding("ns-cluster-role-binding")),
),
},
{
TestName: "test-clusterrole-clusterrolebinding-with-sync-with-clone",
ClusterPolicy: clusteredResource(clPolGVR, clusterRoleRoleBindingYamlWithClone),
SourceResources: []resource{
clusteredResource(crGVR, baseClusterRoleData),
clusteredResource(crbGVR, baseClusterRoleBindingData),
},
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(crGVR, "", "cloned-cluster-role"),
expected(crbGVR, "", "cloned-cluster-role-binding"),
},
ClusterPolicy: clusterPolicy(clusterRoleRoleBindingYamlWithClone),
SourceResources: resources(
clusterRole(baseClusterRoleData),
clusterRoleBinding(baseClusterRoleBindingData),
),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idClusterRole("cloned-cluster-role")),
expectation(idClusterRoleBinding("cloned-cluster-role-binding")),
),
},
}
// NetworkPolicyGenerateTests - E2E Test Config for NetworkPolicyGenerateTests
var NetworkPolicyGenerateTests = []struct {
// TestName - Name of the Test
TestName string
// ClusterPolicy - ClusterPolicy yaml file
ClusterPolicy resource
// SourceResources - Source resources yaml files
SourceResources []resource
// TriggerResource - Trigger resource yaml files
TriggerResource resource
// ExpectedResources - Expected resources to pass the test
ExpectedResources []expectedResource
}{
// networkPolicyGenerateTests - E2E Test Config for networkPolicyGenerateTests
var networkPolicyGenerateTests = []testCase{
{
TestName: "test-generate-policy-for-namespace-with-label",
ClusterPolicy: clusteredResource(clPolGVR, genNetworkPolicyYaml),
TriggerResource: clusteredResource(nsGVR, namespaceWithLabelYaml),
ExpectedResources: []expectedResource{
expected(npGVR, "test", "allow-dns"),
ClusterPolicy: clusterPolicy(genNetworkPolicyYaml),
TriggerResource: namespace(namespaceWithLabelYaml),
ExpectedResources: expectations(
expectation(idNetworkPolicy("test", "allow-dns")),
),
},
}
var generateNetworkPolicyOnNamespaceWithoutLabelTests = []testCase{
{
TestName: "test-generate-policy-for-namespace-label-actions",
ClusterPolicy: clusterPolicy(genNetworkPolicyYaml),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idNetworkPolicy("test", "allow-dns")),
),
Steps: []testCaseStep{
stepResourceNotFound(npGVR, "test", "allow-dns"),
stepUpateResource(nsGVR, "", "test", func(resource *unstructured.Unstructured) error {
element, _, err := unstructured.NestedMap(resource.UnstructuredContent(), "metadata", "labels")
if err != nil {
return err
}
element["security"] = "standard"
return unstructured.SetNestedMap(resource.UnstructuredContent(), element, "metadata", "labels")
}),
stepExpectResource(npGVR, "test", "allow-dns"),
stepUpateResource(clPolGVR, "", "add-networkpolicy", func(resource *unstructured.Unstructured) error {
return yaml.Unmarshal(updatGenNetworkPolicyYaml, resource)
}),
stepWaitResource(npGVR, "test", "allow-dns", time.Second, 30, func(resource *unstructured.Unstructured) bool {
element, found, err := unstructured.NestedMap(resource.UnstructuredContent(), "spec")
if err != nil || !found {
return false
}
return loopElement(false, element)
}),
},
},
}
// NetworkPolicyGenerateTests - E2E Test Config for NetworkPolicyGenerateTests
var GenerateNetworkPolicyOnNamespaceWithoutLabelTests = []struct {
// TestName - Name of the Test
TestName string
// NetworkPolicyName - Name of the NetworkPolicy to be Created
NetworkPolicyName string
// GeneratePolicyName - Name of the Policy to be Created/Updated
GeneratePolicyName string
// ResourceNamespace - Namespace for which Resources are Created
ResourceNamespace string
// Clone - Set Clone Value
Clone bool
// CloneClusterRoleName
ClonerClusterRoleName string
// CloneClusterRoleBindingName
ClonerClusterRoleBindingName string
// CloneSourceRoleData - Source ClusterRole Name from which ClusterRole is Cloned
CloneSourceClusterRoleData []byte
// CloneSourceRoleBindingData - Source ClusterRoleBinding Name from which ClusterRoleBinding is Cloned
CloneSourceClusterRoleBindingData []byte
// CloneNamespace - Namespace where Roles are Cloned
CloneNamespace string
// Sync - Set Synchronize
Sync bool
// Data - The Yaml file of the ClusterPolicy of the ClusterRole and ClusterRoleBinding - ([]byte{})
Data []byte
// Data - The Yaml file of the ClusterPolicy of the ClusterRole and ClusterRoleBinding - ([]byte{})
UpdateData []byte
}{
var generateSynchronizeFlagTests = []testCase{
{
TestName: "test-generate-policy-for-namespace-label-actions",
ResourceNamespace: "test",
NetworkPolicyName: "allow-dns",
GeneratePolicyName: "add-networkpolicy",
Clone: false,
Sync: true,
Data: genNetworkPolicyYaml,
UpdateData: updatGenNetworkPolicyYaml,
},
}
// NetworkPolicyGenerateTests - E2E Test Config for NetworkPolicyGenerateTests
var GenerateSynchronizeFlagTests = []struct {
// TestName - Name of the Test
TestName string
// NetworkPolicyName - Name of the NetworkPolicy to be Created
NetworkPolicyName string
// GeneratePolicyName - Name of the Policy to be Created/Updated
GeneratePolicyName string
// ResourceNamespace - Namespace for which Resources are Created
ResourceNamespace string
// Clone - Set Clone Value
Clone bool
// CloneClusterRoleName
ClonerClusterRoleName string
// CloneClusterRoleBindingName
ClonerClusterRoleBindingName string
// CloneSourceRoleData - Source ClusterRole Name from which ClusterRole is Cloned
CloneSourceClusterRoleData []byte
// CloneSourceRoleBindingData - Source ClusterRoleBinding Name from which ClusterRoleBinding is Cloned
CloneSourceClusterRoleBindingData []byte
// CloneNamespace - Namespace where Roles are Cloned
CloneNamespace string
// Sync - Set Synchronize
Sync bool
// Data - The Yaml file of the ClusterPolicy of the ClusterRole and ClusterRoleBinding - ([]byte{})
Data []byte
// Data - The Yaml file of the ClusterPolicy of the ClusterRole and ClusterRoleBinding - ([]byte{})
UpdateData []byte
}{
{
TestName: "test-generate-policy-for-namespace-with-label",
NetworkPolicyName: "allow-dns",
GeneratePolicyName: "add-networkpolicy",
ResourceNamespace: "test",
Clone: false,
Sync: true,
Data: genNetworkPolicyYaml,
UpdateData: updateSynchronizeInGeneratePolicyYaml,
TestName: "test-generate-policy-for-namespace-with-label",
ClusterPolicy: clusterPolicy(genNetworkPolicyYaml),
TriggerResource: namespace(namespaceWithLabelYaml),
ExpectedResources: expectations(
expectation(idNetworkPolicy("test", "allow-dns")),
),
Steps: []testCaseStep{
stepBy("When synchronize flag is set to true in the policy and someone deletes the generated resource, kyverno generates back the resource"),
stepDeleteResource(npGVR, "test", "allow-dns"),
stepExpectResource(npGVR, "test", "allow-dns"),
stepBy("Change synchronize to false in the policy, the label in generated resource should be updated to policy.kyverno.io/synchronize: disable"),
stepUpateResource(clPolGVR, "", "add-networkpolicy", func(resource *unstructured.Unstructured) error {
return yaml.Unmarshal(updateSynchronizeInGeneratePolicyYaml, resource)
}),
stepWaitResource(npGVR, "test", "allow-dns", time.Second, 30, func(resource *unstructured.Unstructured) bool {
labels := resource.GetLabels()
return labels["policy.kyverno.io/synchronize"] == "disable"
}),
stepBy("With synchronize is false, one should be able to delete the generated resource"),
stepDeleteResource(npGVR, "test", "allow-dns"),
stepResourceNotFound(npGVR, "test", "allow-dns"),
},
},
}
// ClusterRoleTests - E2E Test Config for ClusterRole and ClusterRoleBinding
var SourceResourceUpdateReplicationTests = []struct {
// TestName - Name of the Test
TestName string
// ClusterRoleName - Name of the ClusterRole to be Created
ResourceNamespace string
// Clone - Set Clone Value
Clone bool
// CloneNamespace - Namespace where Roles are Cloned
CloneNamespace string
// Sync - Set Synchronize
Sync bool
// Data - The Yaml file of the ClusterPolicy - ([]byte{})
Data []byte
// ConfigMapName - name of configMap
ConfigMapName string
// CloneSourceConfigMapData - Source ConfigMap Yaml
CloneSourceConfigMapData []byte
// PolicyName - Name of the Policy
PolicyName string
}{
var sourceResourceUpdateReplicationTests = []testCase{
{
TestName: "test-clone-source-resource-update-replication",
ResourceNamespace: "test",
Clone: true,
Sync: true,
Data: genCloneConfigMapPolicyYaml,
ConfigMapName: "game-demo",
CloneNamespace: "default",
CloneSourceConfigMapData: cloneSourceResource,
PolicyName: "generate-policy",
TestName: "test-clone-source-resource-update-replication",
ClusterPolicy: clusterPolicy(genCloneConfigMapPolicyYaml),
SourceResources: resources(
configMap("default", cloneSourceResource),
),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idConfigMap("test", "game-demo")),
),
Steps: []testCaseStep{
stepBy("When a source clone resource is updated, the same changes should be replicated in the generated resource"),
stepUpateResource(cmGVR, "default", "game-demo", func(resource *unstructured.Unstructured) error {
element, _, err := unstructured.NestedMap(resource.UnstructuredContent(), "data")
if err != nil {
return err
}
element["initial_lives"] = "5"
return unstructured.SetNestedMap(resource.UnstructuredContent(), element, "data")
}),
stepWaitResource(cmGVR, "test", "game-demo", time.Second, 15, func(resource *unstructured.Unstructured) bool {
element, found, err := unstructured.NestedMap(resource.UnstructuredContent(), "data")
if err != nil || !found {
return false
}
return element["initial_lives"] == "5"
}),
stepBy("When a generated resource is edited with some conflicting changes (with respect to the clone source resource or generate data), kyverno will regenerate the resource"),
stepUpateResource(cmGVR, "test", "game-demo", func(resource *unstructured.Unstructured) error {
element, _, err := unstructured.NestedMap(resource.UnstructuredContent(), "data")
if err != nil {
return err
}
element["initial_lives"] = "15"
return unstructured.SetNestedMap(resource.UnstructuredContent(), element, "data")
}),
stepWaitResource(cmGVR, "test", "game-demo", time.Second, 30, func(resource *unstructured.Unstructured) bool {
element, found, err := unstructured.NestedMap(resource.UnstructuredContent(), "data")
if err != nil || !found {
return false
}
return element["initial_lives"] == "5"
}),
},
},
}
var GeneratePolicyDeletionforCloneTests = []struct {
// TestName - Name of the Test
TestName string
ClusterPolicy resource
// SourceResources - Source resources yaml files
SourceResources []resource
// TriggerResource - Trigger resource yaml files
TriggerResource resource
// ExpectedResources - Expected resources to pass the test
ExpectedResources []expectedResource
Steps []testCaseStep
}{
var generatePolicyDeletionforCloneTests = []testCase{
{
TestName: "test-clone-source-resource-update-replication",
ClusterPolicy: clusteredResource(clPolGVR, genCloneConfigMapPolicyYaml),
SourceResources: []resource{
namespacedResource(cmGVR, "default", cloneSourceResource),
},
TriggerResource: clusteredResource(nsGVR, namespaceYaml),
ExpectedResources: []expectedResource{
expected(cmGVR, "test", "game-demo"),
},
ClusterPolicy: clusterPolicy(genCloneConfigMapPolicyYaml),
SourceResources: resources(
configMap("default", cloneSourceResource),
),
TriggerResource: namespace(namespaceYaml),
ExpectedResources: expectations(
expectation(idConfigMap("test", "game-demo")),
),
Steps: []testCaseStep{
// delete policy -> generated resource still exists
stepBy("delete policy -> generated resource still exists"),
stepDeleteResource(clPolGVR, "", "generate-policy"),
stepExpectResource(cmGVR, "test", "game-demo"),
// update source -> generated resource not updated
stepBy("update source -> generated resource not updated"),
stepUpateResource(cmGVR, "default", "game-demo", func(resource *unstructured.Unstructured) error {
element, _, err := unstructured.NestedMap(resource.UnstructuredContent(), "data")
if err != nil {
@ -345,7 +273,7 @@ var GeneratePolicyDeletionforCloneTests = []struct {
Expect(err).NotTo(HaveOccurred())
Expect(element["initial_lives"]).To(Equal("2"))
}),
// deleted source -> generated resource not deleted
stepBy("deleted source -> generated resource not deleted"),
stepDeleteResource(cmGVR, "default", "game-demo"),
stepExpectResource(cmGVR, "test", "game-demo"),
},

View file

@ -1,271 +1,73 @@
package generate
import (
"errors"
"fmt"
"testing"
"time"
"github.com/kyverno/kyverno/test/e2e"
commonE2E "github.com/kyverno/kyverno/test/e2e/common"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) {
func runTestCases(t *testing.T, testCases ...testCase) {
setup(t)
for _, tests := range ClusterRoleTests {
t.Run(tests.TestName, func(t *testing.T) {
for _, test := range testCases {
t.Run(test.TestName, func(t *testing.T) {
e2eClient := createClient()
t.Cleanup(func() {
deleteResources(e2eClient, tests.ExpectedResources...)
deleteResources(e2eClient, test.ExpectedResources...)
})
// sanity check
expectResourcesNotExist(e2eClient, tests.ExpectedResources...)
// create policy
policy := createResource(t, e2eClient, tests.ClusterPolicy)
Expect(commonE2E.PolicyCreated(policy.GetName())).To(Succeed())
By("Verifying expected resources do not exist yet in the cluster ...")
expectResourcesNotFound(e2eClient, test.ExpectedResources...)
// create source resources
createResources(t, e2eClient, tests.SourceResources...)
if len(test.SourceResources) > 0 {
By("Creating source resources ...")
createResources(t, e2eClient, test.SourceResources...)
}
// create policy
By("Creating cluster policy ...")
policy := createResource(t, e2eClient, test.ClusterPolicy)
Expect(commonE2E.PolicyCreated(policy.GetName())).To(Succeed())
// create trigger
createResource(t, e2eClient, tests.TriggerResource)
By("Creating trigger resource ...")
createResource(t, e2eClient, test.TriggerResource)
time.Sleep(time.Second * 5)
for _, step := range test.Steps {
Expect(step(e2eClient)).To(Succeed())
}
// verify expected resources
expectResources(e2eClient, tests.ExpectedResources...)
By("Verifying resource expectations ...")
expectResources(e2eClient, test.ExpectedResources...)
})
}
}
func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) {
runTestCases(t, clusterRoleTests...)
}
func Test_Role_RoleBinding_Sets(t *testing.T) {
setup(t)
for _, tests := range RoleTests {
t.Run(tests.TestName, func(t *testing.T) {
e2eClient := createClient()
t.Cleanup(func() {
deleteResources(e2eClient, tests.ExpectedResources...)
})
// sanity check
expectResourcesNotExist(e2eClient, tests.ExpectedResources...)
// create policy
policy := createResource(t, e2eClient, tests.ClusterPolicy)
Expect(commonE2E.PolicyCreated(policy.GetName())).To(Succeed())
// create source resources
createResources(t, e2eClient, tests.SourceResources...)
// create trigger
createResource(t, e2eClient, tests.TriggerResource)
// verify expected resources
expectResources(e2eClient, tests.ExpectedResources...)
})
}
runTestCases(t, roleTests...)
}
func Test_Generate_NetworkPolicy(t *testing.T) {
setup(t)
for _, tests := range NetworkPolicyGenerateTests {
t.Run(tests.TestName, func(t *testing.T) {
e2eClient := createClient()
t.Cleanup(func() {
deleteResources(e2eClient, tests.ExpectedResources...)
})
// sanity check
expectResourcesNotExist(e2eClient, tests.ExpectedResources...)
// create policy
policy := createResource(t, e2eClient, tests.ClusterPolicy)
Expect(commonE2E.PolicyCreated(policy.GetName())).To(Succeed())
// create source resources
createResources(t, e2eClient, tests.SourceResources...)
// create trigger
createResource(t, e2eClient, tests.TriggerResource)
// verify expected resources
expectResources(e2eClient, tests.ExpectedResources...)
})
}
runTestCases(t, networkPolicyGenerateTests...)
}
func Test_Generate_Namespace_Label_Actions(t *testing.T) {
setup(t)
// Generate E2E Client ==================
e2eClient, err := e2e.NewE2EClient()
Expect(err).To(BeNil())
// ======================================
// ====== Range Over RuleTest ==================
for _, test := range GenerateNetworkPolicyOnNamespaceWithoutLabelTests {
By(fmt.Sprintf("Test to generate NetworkPolicy : %s", test.TestName))
By(fmt.Sprintf("synchronize = %v\t clone = %v", test.Sync, test.Clone))
// ======= CleanUp Resources =====
By("Cleaning Cluster Policies")
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
By(fmt.Sprintf("Deleting Namespace : %s", test.ResourceNamespace))
_ = e2eClient.DeleteClusteredResource(nsGVR, test.ResourceNamespace)
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("deleting Namespace")
})
Expect(err).NotTo(HaveOccurred())
// ======== Create Generate NetworkPolicy Policy =============
By("Creating Generate NetworkPolicy Policy")
_, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, npPolNS, test.GeneratePolicyName, test.Data)
Expect(err).NotTo(HaveOccurred())
// ============================================
err = commonE2E.PolicyCreated(test.GeneratePolicyName)
Expect(err).NotTo(HaveOccurred())
// Test: when creating the new namespace without the label, there should not have any generated resource
// ======= Create Namespace ==================
By(fmt.Sprintf("Creating Namespace which should not triggers generate policy %s", npPolNS))
_, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceYaml)
Expect(err).NotTo(HaveOccurred())
// Wait Till Creation of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
// ======== NetworkPolicy Creation =====
By(fmt.Sprintf("Verifying NetworkPolicy in the Namespace : %s", test.ResourceNamespace))
// Wait Till Creation of NetworkPolicy
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
return nil
})
Expect(err).To(HaveOccurred())
_, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).To(HaveOccurred())
// ============================================
// Test: when adding the matched label to the namespace, the target resource should be generated
By(fmt.Sprintf("Updating Namespace which triggers generate policy %s", npPolNS))
// add label to the namespace
_, err = e2eClient.UpdateClusteredResourceYaml(nsGVR, namespaceWithLabelYaml)
Expect(err).NotTo(HaveOccurred())
// ======== NetworkPolicy Creation =====
By(fmt.Sprintf("Verifying NetworkPolicy in the updated Namespace : %s", test.ResourceNamespace))
// Wait Till Creation of NetworkPolicy
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err = e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
_, err = e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
// Test: when changing the content in generate.data, the change should be synced to the generated resource
// check for metadata.resourceVersion in policy - need to add this feild while updating the policy
By(fmt.Sprintf("Update generate policy: %s", test.GeneratePolicyName))
genPolicy, err := e2eClient.GetNamespacedResource(clPolGVR, "", test.GeneratePolicyName)
Expect(err).NotTo(HaveOccurred())
resVer := genPolicy.GetResourceVersion()
unstructGenPol := unstructured.Unstructured{}
err = yaml.Unmarshal(test.UpdateData, &unstructGenPol)
Expect(err).NotTo(HaveOccurred())
unstructGenPol.SetResourceVersion(resVer)
// ======== Update Generate NetworkPolicy =============
By("Updating Generate NetworkPolicy")
_, err = e2eClient.UpdateNamespacedResource(clPolGVR, npPolNS, &unstructGenPol)
Expect(err).NotTo(HaveOccurred())
// ======== Check Updated NetworkPolicy =============
By(fmt.Sprintf("Verifying updated NetworkPolicy in the Namespace : %s", test.ResourceNamespace))
err = e2e.GetWithRetry(1*time.Second, 30, func() error {
// get updated network policy
updatedNetPol, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
// compare updated network policy and updated generate policy
element, _, err := unstructured.NestedMap(updatedNetPol.UnstructuredContent(), "spec")
if err != nil {
return err
}
found := false
found = loopElement(found, element)
if found == false {
return errors.New("not found")
}
return nil
})
Expect(err).NotTo(HaveOccurred())
updatedNetPol, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
element, specFound, err := unstructured.NestedMap(updatedNetPol.UnstructuredContent(), "spec")
found := loopElement(false, element)
Expect(specFound).To(Equal(true))
Expect(found).To(Equal(true))
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
_ = e2eClient.DeleteClusteredResource(nsGVR, test.ResourceNamespace)
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("deleting Namespace")
})
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Test %s Completed \n\n\n", test.TestName))
}
runTestCases(t, generateNetworkPolicyOnNamespaceWithoutLabelTests...)
}
func loopElement(found bool, elementObj interface{}) bool {
@ -298,428 +100,13 @@ func loopElement(found bool, elementObj interface{}) bool {
}
func Test_Generate_Synchronize_Flag(t *testing.T) {
setup(t)
// Generate E2E Client ==================
e2eClient, err := e2e.NewE2EClient()
Expect(err).To(BeNil())
// ======================================
// ====== Range Over RuleTest ==================
for _, test := range GenerateSynchronizeFlagTests {
By(fmt.Sprintf("Test to generate NetworkPolicy : %s", test.TestName))
By(fmt.Sprintf("synchronize = %v\t clone = %v", test.Sync, test.Clone))
// ======= CleanUp Resources =====
By("Cleaning Cluster Policies")
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
By(fmt.Sprintf("Deleting Namespace : %s", test.ResourceNamespace))
_ = e2eClient.DeleteClusteredResource(nsGVR, test.ResourceNamespace)
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("deleting Namespace")
})
Expect(err).NotTo(HaveOccurred())
// ======== Create Generate NetworkPolicy Policy =============
By("Creating Generate NetworkPolicy Policy")
_, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, npPolNS, test.GeneratePolicyName, test.Data)
Expect(err).NotTo(HaveOccurred())
err = commonE2E.PolicyCreated(test.GeneratePolicyName)
Expect(err).NotTo(HaveOccurred())
// ======= Create Namespace ==================
By(fmt.Sprintf("Creating Namespace which triggers generate %s", npPolNS))
_, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceWithLabelYaml)
Expect(err).NotTo(HaveOccurred())
// Wait Till Creation of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
// ======== NetworkPolicy Creation =====
By(fmt.Sprintf("Verifying NetworkPolicy in the Namespace : %s", test.ResourceNamespace))
// Wait Till Creation of NetworkPolicy
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
npRes, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
Expect(npRes.GetName()).To(Equal(test.NetworkPolicyName))
// ============================================
// Test: when synchronize flag is set to true in the policy and someone deletes the generated resource, kyverno generates back the resource
// ======= Delete Networkpolicy =====
By(fmt.Sprintf("Deleting NetworkPolicy %s in the Namespace : %s", test.NetworkPolicyName, test.ResourceNamespace))
err = e2eClient.DeleteNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
// ============================================
// ======= Check Networkpolicy =====
By(fmt.Sprintf("Checking NetworkPolicy %s in the Namespace : %s", test.NetworkPolicyName, test.ResourceNamespace))
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
_, err = e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
// ============================================
// Test: change synchronize to false in the policy, the label in generated resource should be updated to policy.kyverno.io/synchronize: disable
// check for metadata.resourceVersion in policy - need to add this feild while updating the policy
By(fmt.Sprintf("Update synchronize to true in generate policy: %s", test.GeneratePolicyName))
genPolicy, err := e2eClient.GetNamespacedResource(clPolGVR, "", test.GeneratePolicyName)
Expect(err).NotTo(HaveOccurred())
resVer := genPolicy.GetResourceVersion()
unstructGenPol := unstructured.Unstructured{}
err = yaml.Unmarshal(test.UpdateData, &unstructGenPol)
Expect(err).NotTo(HaveOccurred())
unstructGenPol.SetResourceVersion(resVer)
// ======== Update Generate NetworkPolicy =============
_, err = e2eClient.UpdateNamespacedResource(clPolGVR, npPolNS, &unstructGenPol)
Expect(err).NotTo(HaveOccurred())
// ============================================
By(fmt.Sprintf("Verify the label in the updated network policy: %s", test.NetworkPolicyName))
// get updated network policy and verify the label
synchronizeFlagValueGotUpdated := false
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
netpol, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
return err
}
netPolLabels := netpol.GetLabels()
if netPolLabels["policy.kyverno.io/synchronize"] != "disable" {
return errors.New("still enabled")
}
return nil
})
Expect(err).NotTo(HaveOccurred())
netpol, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
netPolLabels := netpol.GetLabels()
if netPolLabels["policy.kyverno.io/synchronize"] == "disable" {
synchronizeFlagValueGotUpdated = true
}
Expect(synchronizeFlagValueGotUpdated).To(Equal(true))
// ============================================
// Test: with synchronize is false, one should be able to delete the generated resource
// ======= Delete Networkpolicy =====
By(fmt.Sprintf("Deleting NetworkPolicy %s in the Namespace : %s", test.NetworkPolicyName, test.ResourceNamespace))
err = e2eClient.DeleteNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
Expect(err).NotTo(HaveOccurred())
// ============================================
// ======= Check Networkpolicy =====
By(fmt.Sprintf("Checking NetworkPolicy %s in the Namespace : %s", test.NetworkPolicyName, test.ResourceNamespace))
netpolGotDeleted := false
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(npGVR, test.ResourceNamespace, test.NetworkPolicyName)
if err != nil {
netpolGotDeleted = true
} else {
return errors.New("network policy still exists")
}
return nil
})
Expect(err).NotTo(HaveOccurred())
Expect(netpolGotDeleted).To(Equal(true))
// ======= CleanUp Resources =====
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
_ = e2eClient.DeleteClusteredResource(nsGVR, test.ResourceNamespace)
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, test.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("deleting Namespace")
})
// Do not fail if waiting fails. Sometimes namespace needs time to be deleted.
if err != nil {
By(err.Error())
}
By(fmt.Sprintf("Test %s Completed \n\n\n", test.TestName))
}
runTestCases(t, generateSynchronizeFlagTests...)
}
func Test_Source_Resource_Update_Replication(t *testing.T) {
setup(t)
// Generate E2E Client ==================
e2eClient, err := e2e.NewE2EClient()
Expect(err).To(BeNil())
// ======================================
// ====== Range Over RuleTest ==================
for _, tests := range SourceResourceUpdateReplicationTests {
By(fmt.Sprintf("Test to check replication of clone source resource: %s", tests.TestName))
By(fmt.Sprintf("synchronize = %v\t clone = %v", tests.Sync, tests.Clone))
// ======= CleanUp Resources =====
By("Cleaning Cluster Policies")
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
By(fmt.Sprintf("Deleting Namespace : %s", tests.ResourceNamespace))
_ = e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// If Clone is true Clear Source Resource and Recreate
if tests.Clone {
By(fmt.Sprintf("Clone = true, Deleting Source Resource from Clone Namespace : %s", tests.CloneNamespace))
// Delete ConfigMap to be cloned
_ = e2eClient.DeleteNamespacedResource(cmGVR, tests.CloneNamespace, tests.ConfigMapName)
}
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
Expect(err).NotTo(HaveOccurred())
// === If Clone is true Create Source Resources ==
if tests.Clone {
By(fmt.Sprintf("Clone = true, Creating Cloner Resources in Namespace : %s", tests.CloneNamespace))
_, err := e2eClient.CreateNamespacedResourceYaml(cmGVR, tests.CloneNamespace, "", tests.CloneSourceConfigMapData)
Expect(err).NotTo(HaveOccurred())
}
// ================================================
// ======== Create Generate Policy =============
By(fmt.Sprintf("\nCreating Generate Policy in %s", clPolNS))
_, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, clPolNS, tests.PolicyName, tests.Data)
Expect(err).NotTo(HaveOccurred())
err = commonE2E.PolicyCreated(tests.PolicyName)
Expect(err).NotTo(HaveOccurred())
// ======= Create Namespace ==================
By(fmt.Sprintf("Creating Namespace which triggers generate %s", clPolNS))
_, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceYaml)
Expect(err).NotTo(HaveOccurred())
// Wait Till Creation of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
// ======== Verify Configmap Creation =====
By(fmt.Sprintf("Verifying Configmap in the Namespace : %s", tests.ResourceNamespace))
// Wait Till Creation of Configmap
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
if err != nil {
return err
}
return nil
})
Expect(err).NotTo(HaveOccurred())
// test: when a source clone resource is updated, the same changes should be replicated in the generated resource
// ======= Update Configmap in default Namespace ========
By(fmt.Sprintf("Updating Source Resource(Configmap) in Clone Namespace : %s", tests.CloneNamespace))
// Update the configmap in default namespace
sourceRes, err := e2eClient.GetNamespacedResource(cmGVR, tests.CloneNamespace, tests.ConfigMapName)
Expect(err).NotTo(HaveOccurred())
Expect(sourceRes.GetName()).To(Equal(tests.ConfigMapName))
element, _, err := unstructured.NestedMap(sourceRes.UnstructuredContent(), "data")
Expect(err).NotTo(HaveOccurred())
element["initial_lives"] = "5"
err = unstructured.SetNestedMap(sourceRes.UnstructuredContent(), element, "data")
Expect(err).NotTo(HaveOccurred())
_, err = e2eClient.UpdateNamespacedResource(cmGVR, tests.CloneNamespace, sourceRes)
Expect(err).NotTo(HaveOccurred())
// ============================================
// ======= Verifying Configmap Data Replication in Namespace ========
By(fmt.Sprintf("Verifying Configmap Data Replication in the Namespace : %s", tests.ResourceNamespace))
err = e2e.GetWithRetry(1*time.Second, 30, func() error {
// get updated configmap in test namespace
updatedGenRes, err := e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
if err != nil {
return err
}
// compare updated configmapdata
element, _, err := unstructured.NestedMap(updatedGenRes.UnstructuredContent(), "data")
if err != nil {
return err
}
if element["initial_lives"] != "5" {
return fmt.Errorf("config map value not updated, found %v expected map[initial_lives:5]", element)
}
return nil
})
Expect(err).NotTo(HaveOccurred())
updatedGenRes, err := e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
Expect(err).NotTo(HaveOccurred())
element, _, err = unstructured.NestedMap(updatedGenRes.UnstructuredContent(), "data")
Expect(err).NotTo(HaveOccurred())
Expect(element["initial_lives"]).To(Equal("5"))
// ============================================
// test: when a generated resource is edited with some conflicting changes (with respect to the
// clone source resource or generate data), kyverno will regenerate the resource
// ======= Update Configmap in test Namespace ========
By(fmt.Sprintf("Updating Generated ConfigMap in Resource Namespace : %s", tests.ResourceNamespace))
// Get the configmap from test namespace
genRes, err := e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
Expect(err).NotTo(HaveOccurred())
Expect(genRes.GetName()).To(Equal(tests.ConfigMapName))
element, _, err = unstructured.NestedMap(genRes.UnstructuredContent(), "data")
Expect(err).NotTo(HaveOccurred())
element["initial_lives"] = "15"
_ = unstructured.SetNestedMap(genRes.UnstructuredContent(), element, "data")
_, err = e2eClient.UpdateNamespacedResource(cmGVR, tests.ResourceNamespace, genRes)
Expect(err).NotTo(HaveOccurred())
// ============================================
// ======= Verifying Configmap Data in Namespace ========
By(fmt.Sprintf("Verifying Configmap Data in the Namespace : %s", tests.ResourceNamespace))
err = e2e.GetWithRetry(1*time.Second, 30, func() error {
// get updated configmap in test namespace
updatedGenRes, err := e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
if err != nil {
return err
}
// compare updated configmapdata
element, _, err := unstructured.NestedMap(updatedGenRes.UnstructuredContent(), "data")
if err != nil {
return err
}
if element["initial_lives"] != "5" {
return fmt.Errorf("config map value not reset, found %v expected map[initial_lives:5]", element)
}
return nil
})
Expect(err).NotTo(HaveOccurred())
updatedGenRes, err = e2eClient.GetNamespacedResource(cmGVR, tests.ResourceNamespace, tests.ConfigMapName)
Expect(err).NotTo(HaveOccurred())
element, _, err = unstructured.NestedMap(updatedGenRes.UnstructuredContent(), "data")
Expect(err).NotTo(HaveOccurred())
Expect(element["initial_lives"]).To(Equal("5"))
// ============================================
// ======= CleanUp Resources =====
_ = e2eClient.CleanClusterPolicies(clPolGVR)
// === If Clone is true Delete Source Resources ==
if tests.Clone {
By(fmt.Sprintf("Clone = true, Deleting Cloner Resources in Namespace : %s", tests.CloneNamespace))
_ = e2eClient.DeleteNamespacedResource(cmGVR, tests.CloneNamespace, tests.ConfigMapName)
}
// ================================================
// Clear Namespace
_ = e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// Wait Till Deletion of Namespace
err = e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return fmt.Errorf("failed to delete namespace: %v", err)
})
Expect(err).NotTo(HaveOccurred())
By(fmt.Sprintf("Test %s Completed \n\n\n", tests.TestName))
}
runTestCases(t, sourceResourceUpdateReplicationTests...)
}
func Test_Generate_Policy_Deletion_for_Clone(t *testing.T) {
setup(t)
for _, tests := range GeneratePolicyDeletionforCloneTests {
t.Run(tests.TestName, func(t *testing.T) {
e2eClient := createClient()
t.Cleanup(func() {
deleteResources(e2eClient, tests.ExpectedResources...)
})
// sanity check
expectResourcesNotExist(e2eClient, tests.ExpectedResources...)
// create policy
policy := createResource(t, e2eClient, tests.ClusterPolicy)
Expect(commonE2E.PolicyCreated(policy.GetName())).To(Succeed())
// create source resources
createResources(t, e2eClient, tests.SourceResources...)
// create trigger
createResource(t, e2eClient, tests.TriggerResource)
time.Sleep(time.Second * 5)
for _, step := range tests.Steps {
Expect(step(e2eClient)).To(Succeed())
}
// verify expected resources
expectResources(e2eClient, tests.ExpectedResources...)
})
}
runTestCases(t, generatePolicyDeletionforCloneTests...)
}

View file

@ -16,6 +16,61 @@ import (
. "github.com/onsi/gomega"
)
type resource struct {
gvr schema.GroupVersionResource
ns string
raw []byte
}
func clustered(gvr schema.GroupVersionResource, raw []byte) resource { return resource{gvr, "", raw} }
func namespaced(gvr schema.GroupVersionResource, ns string, raw []byte) resource {
return resource{gvr, ns, raw}
}
func resources(resources ...resource) []resource { return resources }
func role(ns string, raw []byte) resource { return namespaced(rGVR, ns, raw) }
func roleBinding(ns string, raw []byte) resource { return namespaced(rbGVR, ns, raw) }
func configMap(ns string, raw []byte) resource { return namespaced(cmGVR, ns, raw) }
func clusterPolicy(raw []byte) resource { return clustered(clPolGVR, raw) }
func clusterRole(raw []byte) resource { return clustered(crGVR, raw) }
func clusterRoleBinding(raw []byte) resource { return clustered(crbGVR, raw) }
func namespace(raw []byte) resource { return clustered(nsGVR, raw) }
type _id struct {
gvr schema.GroupVersionResource
ns string
name string
}
func id(gvr schema.GroupVersionResource, ns string, name string) _id {
return _id{gvr, ns, name}
}
func idRole(ns, name string) _id { return id(rGVR, ns, name) }
func idRoleBinding(ns, name string) _id { return id(rbGVR, ns, name) }
func idConfigMap(ns, name string) _id { return id(cmGVR, ns, name) }
func idNetworkPolicy(ns, name string) _id { return id(npGVR, ns, name) }
func idClusterRole(name string) _id { return id(crGVR, "", name) }
func idClusterRoleBinding(name string) _id { return id(crbGVR, "", name) }
type resourceExpectation func(resource *unstructured.Unstructured)
type expectedResource struct {
_id
validate []resourceExpectation
}
func expected(gvr schema.GroupVersionResource, ns string, name string, validate ...resourceExpectation) expectedResource {
return expectedResource{id(gvr, ns, name), validate}
}
func expectations(expectations ...expectedResource) []expectedResource {
return expectations
}
func expectation(id _id, expectations ...resourceExpectation) expectedResource {
return expectedResource{id, expectations}
}
func setup(t *testing.T) {
RegisterTestingT(t)
if os.Getenv("E2E") == "" {
@ -135,29 +190,34 @@ func getResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, ns, nam
}
}
func updateClusteredResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, name string, m func(*unstructured.Unstructured) error) *unstructured.Unstructured {
func updateClusteredResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, name string, m func(*unstructured.Unstructured) error) {
r := getClusteredResource(client, gvr, name)
version := r.GetResourceVersion()
Expect(m(r)).To(Succeed())
By(fmt.Sprintf("Updating %s : %s", gvr.String(), name))
r, err := client.UpdateClusteredResource(gvr, r)
r.SetResourceVersion(version)
_, err := client.UpdateClusteredResource(gvr, r)
Expect(err).NotTo(HaveOccurred())
return r
}
func updateNamespacedResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, ns, name string, m func(*unstructured.Unstructured) error) *unstructured.Unstructured {
r := getNamespacedResource(client, gvr, ns, name)
Expect(m(r)).To(Succeed())
By(fmt.Sprintf("Updating %s : %s/%s", gvr.String(), ns, name))
r, err := client.UpdateNamespacedResource(gvr, ns, r)
func updateNamespacedResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, ns, name string, m func(*unstructured.Unstructured) error) {
err := e2e.GetWithRetry(1*time.Second, 15, func() error {
r := getNamespacedResource(client, gvr, ns, name)
version := r.GetResourceVersion()
Expect(m(r)).To(Succeed())
By(fmt.Sprintf("Updating %s : %s/%s", gvr.String(), ns, name))
r.SetResourceVersion(version)
_, err := client.UpdateNamespacedResource(gvr, ns, r)
return err
})
Expect(err).NotTo(HaveOccurred())
return r
}
func updateResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, ns, name string, m func(*unstructured.Unstructured) error) *unstructured.Unstructured {
func updateResource(client *e2e.E2EClient, gvr schema.GroupVersionResource, ns, name string, m func(*unstructured.Unstructured) error) {
if ns != "" {
return updateNamespacedResource(client, gvr, ns, name, m)
updateNamespacedResource(client, gvr, ns, name, m)
} else {
return updateClusteredResource(client, gvr, name, m)
updateClusteredResource(client, gvr, name, m)
}
}
@ -213,14 +273,20 @@ func expectResources(client *e2e.E2EClient, resources ...expectedResource) {
func expectClusteredResourceNotExists(client *e2e.E2EClient, resource expectedResource) {
By(fmt.Sprintf("Expecting not exists %s : %s", resource.gvr.String(), resource.name))
_, err := client.GetClusteredResource(resource.gvr, resource.name)
Expect(apierrors.IsNotFound(err)).To(BeTrue())
err := e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := client.GetClusteredResource(resource.gvr, resource.name)
return err
})
Expect(err).To(HaveOccurred())
}
func expectNamespacedResourceNotExists(client *e2e.E2EClient, resource expectedResource) {
By(fmt.Sprintf("Expecting not exists %s : %s/%s", resource.gvr.String(), resource.ns, resource.name))
_, err := client.GetNamespacedResource(resource.gvr, resource.ns, resource.name)
Expect(apierrors.IsNotFound(err)).To(BeTrue())
err := e2e.GetWithRetry(1*time.Second, 15, func() error {
_, err := client.GetClusteredResource(resource.gvr, resource.name)
return err
})
Expect(err).To(HaveOccurred())
}
func expectResourceNotExists(client *e2e.E2EClient, resource expectedResource) {
@ -237,8 +303,41 @@ func expectResourcesNotExist(client *e2e.E2EClient, resources ...expectedResourc
}
}
func expectClusteredResourceNotFound(client *e2e.E2EClient, resource expectedResource) {
By(fmt.Sprintf("Expecting not found %s : %s", resource.gvr.String(), resource.name))
_, err := client.GetClusteredResource(resource.gvr, resource.name)
Expect(apierrors.IsNotFound(err)).To(BeTrue())
}
func expectNamespacedResourceNotFound(client *e2e.E2EClient, resource expectedResource) {
By(fmt.Sprintf("Expecting not found %s : %s/%s", resource.gvr.String(), resource.ns, resource.name))
_, err := client.GetClusteredResource(resource.gvr, resource.name)
Expect(apierrors.IsNotFound(err)).To(BeTrue())
}
func expectResourceNotFound(client *e2e.E2EClient, resource expectedResource) {
if resource.ns != "" {
expectNamespacedResourceNotFound(client, resource)
} else {
expectClusteredResourceNotFound(client, resource)
}
}
func expectResourcesNotFound(client *e2e.E2EClient, resources ...expectedResource) {
for _, resource := range resources {
expectResourceNotFound(client, resource)
}
}
type testCaseStep func(*e2e.E2EClient) error
func stepBy(by string) testCaseStep {
return func(*e2e.E2EClient) error {
By(by)
return nil
}
}
func stepDeleteResource(gvr schema.GroupVersionResource, ns string, name string) testCaseStep {
return func(client *e2e.E2EClient) error {
deleteResource(client, expected(gvr, ns, name))
@ -246,16 +345,41 @@ func stepDeleteResource(gvr schema.GroupVersionResource, ns string, name string)
}
}
func stepExpectResource(gvr schema.GroupVersionResource, ns string, name string, validate ...func(*unstructured.Unstructured)) testCaseStep {
func stepExpectResource(gvr schema.GroupVersionResource, ns, name string, validate ...resourceExpectation) testCaseStep {
return func(client *e2e.E2EClient) error {
expectResource(client, expected(gvr, ns, name, validate...))
return nil
}
}
func stepWaitResource(gvr schema.GroupVersionResource, ns, name string, sleepInterval time.Duration, retryCount int, predicate func(*unstructured.Unstructured) bool) testCaseStep {
return func(client *e2e.E2EClient) error {
By(fmt.Sprintf("Waiting %s : %s/%s", gvr.String(), ns, name))
err := e2e.GetWithRetry(sleepInterval, retryCount, func() error {
get, err := client.GetNamespacedResource(gvr, ns, name)
if err != nil {
return err
}
if !predicate(get) {
return fmt.Errorf("predicate didn't validate: %s, %s/%s", gvr.String(), ns, name)
}
return nil
})
Expect(err).NotTo(HaveOccurred())
return nil
}
}
func stepUpateResource(gvr schema.GroupVersionResource, ns, name string, m func(*unstructured.Unstructured) error) testCaseStep {
return func(client *e2e.E2EClient) error {
updateResource(client, gvr, ns, name, m)
return nil
}
}
func stepResourceNotFound(gvr schema.GroupVersionResource, ns string, name string) testCaseStep {
return func(client *e2e.E2EClient) error {
expectResourceNotExists(client, expected(gvr, ns, name))
return nil
}
}