From a8d3dd79eef198039803a063c77b1d6f3b1fa4c5 Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Tue, 11 Jun 2019 14:35:26 -0700 Subject: [PATCH 1/6] initial client & controller test --- pkg/controller/controller_test.go | 104 ++++++++++++++++++++ pkg/dclient/client.go | 58 +++++------ pkg/dclient/client_test.go | 154 ++++++++++++++++++++++++++++++ pkg/dclient/utils.go | 49 ++++++++++ pkg/sharedinformer/utils.go | 15 +++ 5 files changed, 352 insertions(+), 28 deletions(-) create mode 100644 pkg/sharedinformer/utils.go diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index b0b429f899..8a300f1683 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -1 +1,105 @@ package controller + +import ( + "testing" + + "github.com/golang/glog" + types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" + client "github.com/nirmata/kyverno/pkg/dclient" + "github.com/nirmata/kyverno/pkg/sharedinformer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/sample-controller/pkg/signals" +) + +func TestCreatePolicy(t *testing.T) { + f := newFixture(t) + // new policy is added to policy lister and explictly passed to sync-handler + // to process the existing + policy := newPolicy("test-policy") + f.policyLister = append(f.policyLister, policy) + f.objects = append(f.objects, policy) + // run controller + f.runControler("test-policy") +} + +func (f *fixture) runControler(policyName string) { + policyInformerFactory, err := sharedinformer.NewFakeSharedInformerFactory() + if err != nil { + f.t.Fatal(err) + } + // new controller + policyController := NewPolicyController( + f.Client, + policyInformerFactory, + nil, + nil) + + stopCh := signals.SetupSignalHandler() + // start informer & controller + policyInformerFactory.Run(stopCh) + if err = policyController.Run(stopCh); err != nil { + glog.Fatalf("Error running PolicyController: %v\n", err) + } + // add policy to the informer + for _, p := range f.policyLister { + policyInformerFactory.GetInfomer().GetIndexer().Add(p) + } + + // sync handler + // reads the policy from the policy lister and processes them + err = policyController.syncHandler(policyName) + if err != nil { + f.t.Fatal(err) + } + policyController.Stop() + +} + +type fixture struct { + t *testing.T + Client *client.Client + policyLister []*types.Policy + objects []runtime.Object +} + +func newFixture(t *testing.T) *fixture { + f := &fixture{} + f.t = t + return f +} + +// create mock client with initial resouces +// set registered resources for gvr +func (f *fixture) setupFixture() { + scheme := runtime.NewScheme() + fclient, err := client.NewMockClient(scheme, f.objects...) + if err != nil { + f.t.Fatal(err) + } + regresource := map[string]string{"kyverno.io/v1alpha1": "policys"} + fclient.SetDiscovery(client.NewFakeDiscoveryClient(regresource)) +} + +func newPolicy(name string) *types.Policy { + return &types.Policy{ + TypeMeta: metav1.TypeMeta{APIVersion: types.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } +} + +func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "namespace": namespace, + "name": name, + }, + }, + } +} diff --git a/pkg/dclient/client.go b/pkg/dclient/client.go index ee504644ed..fae5c44793 100644 --- a/pkg/dclient/client.go +++ b/pkg/dclient/client.go @@ -27,15 +27,16 @@ import ( //Client enables interaction with k8 resource type Client struct { - client dynamic.Interface - cachedClient discovery.CachedDiscoveryInterface - clientConfig *rest.Config - kclient *kubernetes.Clientset + client dynamic.Interface + cachedClient discovery.CachedDiscoveryInterface + clientConfig *rest.Config + kclient kubernetes.Interface + discoveryClient IDiscovery } //NewClient creates new instance of client func NewClient(config *rest.Config) (*Client, error) { - client, err := dynamic.NewForConfig(config) + dclient, err := dynamic.NewForConfig(config) if err != nil { return nil, err } @@ -44,13 +45,15 @@ func NewClient(config *rest.Config) (*Client, error) { if err != nil { return nil, err } - - return &Client{ - client: client, + client := Client{ + client: dclient, clientConfig: config, kclient: kclient, - cachedClient: memory.NewMemCacheClient(kclient.Discovery()), - }, nil + } + // Set discovery client + discoveryClient := ServerPreferredResources{memory.NewMemCacheClient(kclient.Discovery())} + client.SetDiscovery(discoveryClient) + return &client, nil } //GetKubePolicyDeployment returns kube policy depoyment value @@ -100,7 +103,7 @@ func (c *Client) getGroupVersionMapper(resource string) schema.GroupVersionResou //TODO: add checks to see if the resource is supported //TODO: build the resource list dynamically( by querying the registered resources) //TODO: the error scenarios - return c.getGVR(resource) + return c.discoveryClient.getGVR(resource) } // GetResource returns the resource in unstructured/json format @@ -156,24 +159,10 @@ func convertToUnstructured(obj interface{}) *unstructured.Unstructured { return &unstructured.Unstructured{Object: unstructuredObj} } -//ConvertToRuntimeObject converts unstructed to runtime.Object runtime instance -func ConvertToRuntimeObject(obj *unstructured.Unstructured) (*runtime.Object, error) { - scheme := runtime.NewScheme() - gvk := obj.GroupVersionKind() - runtimeObj, err := scheme.New(gvk) - if err != nil { - return nil, err - } - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &runtimeObj); err != nil { - return nil, err - } - return &runtimeObj, nil -} - // GenerateResource creates resource of the specified kind(supports 'clone' & 'data') func (c *Client) GenerateResource(generator types.Generation, namespace string) error { var err error - rGVR := c.getGVRFromKind(generator.Kind) + rGVR := c.discoveryClient.getGVRFromKind(generator.Kind) resource := &unstructured.Unstructured{} var rdata map[string]interface{} @@ -244,7 +233,20 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error { return lastError } -func (c *Client) getGVR(resource string) schema.GroupVersionResource { +type IDiscovery interface { + getGVR(resource string) schema.GroupVersionResource + getGVRFromKind(kind string) schema.GroupVersionResource +} + +func (c *Client) SetDiscovery(discoveryClient IDiscovery) { + c.discoveryClient = discoveryClient +} + +type ServerPreferredResources struct { + cachedClient discovery.CachedDiscoveryInterface +} + +func (c ServerPreferredResources) getGVR(resource string) schema.GroupVersionResource { emptyGVR := schema.GroupVersionResource{} serverresources, err := c.cachedClient.ServerPreferredResources() if err != nil { @@ -268,7 +270,7 @@ func (c *Client) getGVR(resource string) schema.GroupVersionResource { //To-do: measure performance //To-do: evaluate DefaultRESTMapper to fetch kind->resource mapping -func (c *Client) getGVRFromKind(kind string) schema.GroupVersionResource { +func (c ServerPreferredResources) getGVRFromKind(kind string) schema.GroupVersionResource { emptyGVR := schema.GroupVersionResource{} serverresources, err := c.cachedClient.ServerPreferredResources() if err != nil { diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 75f509ff84..984c316203 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -1,6 +1,160 @@ package client +import ( + "fmt" + "testing" + + policytypes "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" + + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" +) + // GetResource // ListResource // CreateResource // getGroupVersionMapper (valid and invalid resources) + +//NewMockClient creates a mock client +// - dynamic client +// - kubernetes client +// - objects to initialize the client + +func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "namespace": namespace, + "name": name, + }, + }, + } +} + +func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[string]interface{}) *unstructured.Unstructured { + u := newUnstructured(apiVersion, kind, namespace, name) + u.Object["spec"] = spec + return u +} + +func TestClient(t *testing.T) { + scheme := runtime.NewScheme() + // init groupversion + regresource := map[string]string{"group/version": "thekinds", + "group2/version": "thekinds", + "v1": "namespaces", + "apps/v1": "deployments"} + // init resources + objects := []runtime.Object{newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"), + newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"), + newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"), + newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"), + newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"), + newUnstructured("apps/v1", "Deployment", "kyverno", "kyverno-deployment"), + } + + // Mock Client + client, err := NewMockClient(scheme, objects...) + if err != nil { + t.Fatal(err) + } + + // set discovery Client + client.SetDiscovery(NewFakeDiscoveryClient(regresource)) + // Get Resource + res, err := client.GetResource("thekinds", "ns-foo", "name-foo") + if err != nil { + t.Fatal(err) + } + fmt.Println(res) + // List Resources + list, err := client.ListResource("thekinds", "ns-foo") + if err != nil { + t.Fatal(err) + } + fmt.Println(len(list.Items)) + // DeleteResouce + err = client.DeleteResouce("thekinds", "ns-foo", "name-bar") + if err != nil { + t.Fatal(err) + } + // CreateResource + res, err = client.CreateResource("thekinds", "ns-foo", newUnstructured("group/version", "TheKind", "ns-foo", "name-foo1")) + if err != nil { + t.Fatal(err) + } + // UpdateResource + res, err = client.UpdateResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "bar"})) + if err != nil { + t.Fatal(err) + } + + // UpdateStatusResource + res, err = client.UpdateStatusResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "status"})) + if err != nil { + t.Fatal(err) + } + + iEvent, err := client.GetEventsInterface() + if err != nil { + t.Fatal(err) + } + eventList, err := iEvent.List(meta.ListOptions{}) + if err != nil { + t.Fatal(err) + } + fmt.Println(eventList.Items) + + iCSR, err := client.GetCSRInterface() + if err != nil { + t.Fatal(err) + } + csrList, err := iCSR.List(meta.ListOptions{}) + if err != nil { + t.Fatal(err) + } + fmt.Println(csrList.Items) + + //GenerateResource -> copy From + // 1 create namespace + // 2 generate resource + + // create namespace + ns, err := client.CreateResource("namespaces", "", newUnstructured("v1", "Namespace", "", "ns1")) + if err != nil { + t.Fatal(err) + } + gen := policytypes.Generation{Kind: "TheKind", + Name: "gen-kind", + Clone: &policytypes.CloneFrom{Namespace: "ns-foo", Name: "name-foo"}} + err = client.GenerateResource(gen, ns.GetName()) + if err != nil { + t.Fatal(err) + } + res, err = client.GetResource("thekinds", "ns1", "gen-kind") + if err != nil { + t.Fatal(err) + } + // GenerateResource -> data + gen = policytypes.Generation{Kind: "TheKind", + Name: "name2-baz-new", + Data: newUnstructured("group2/version", "TheKind", "ns1", "name2-baz-new")} + err = client.GenerateResource(gen, ns.GetName()) + if err != nil { + t.Fatal(err) + } + res, err = client.GetResource("thekinds", "ns1", "name2-baz-new") + if err != nil { + t.Fatal(err) + } + + // Get Kube Policy Deployment + deploy, err := client.GetKubePolicyDeployment() + if err != nil { + t.Fatal(err) + } + fmt.Println(deploy.GetName()) +} diff --git a/pkg/dclient/utils.go b/pkg/dclient/utils.go index 5057e797c1..080f2739c6 100644 --- a/pkg/dclient/utils.go +++ b/pkg/dclient/utils.go @@ -1,7 +1,13 @@ package client import ( + "strings" "time" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic/fake" + kubernetesfake "k8s.io/client-go/kubernetes/fake" ) const ( @@ -16,3 +22,46 @@ const ( ) const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second const namespaceCreationWaitInterval time.Duration = 100 * time.Millisecond + +//---testing utilities +func NewMockClient(scheme *runtime.Scheme, objects ...runtime.Object) (*Client, error) { + client := fake.NewSimpleDynamicClient(scheme, objects...) + // the typed and dynamic client are initalized with similar resources + kclient := kubernetesfake.NewSimpleClientset(objects...) + return &Client{ + client: client, + kclient: kclient, + }, nil + +} + +// NewFakeDiscoveryClient returns a fakediscovery client +func NewFakeDiscoveryClient(regResources map[string]string) *fakeDiscoveryClient { + registeredResources := make([]schema.GroupVersionResource, len(regResources)) + for groupVersion, resource := range regResources { + gv, err := schema.ParseGroupVersion(groupVersion) + if err != nil { + continue + } + registeredResources = append(registeredResources, gv.WithResource(resource)) + } + return &fakeDiscoveryClient{registeredResouces: registeredResources} +} + +type fakeDiscoveryClient struct { + registeredResouces []schema.GroupVersionResource +} + +func (c *fakeDiscoveryClient) getGVR(resource string) schema.GroupVersionResource { + for _, gvr := range c.registeredResouces { + if gvr.Resource == resource { + return gvr + } + } + return schema.GroupVersionResource{} +} + +func (c *fakeDiscoveryClient) getGVRFromKind(kind string) schema.GroupVersionResource { + resource := strings.ToLower(kind) + "s" + return c.getGVR(resource) +} diff --git a/pkg/sharedinformer/utils.go b/pkg/sharedinformer/utils.go new file mode 100644 index 0000000000..804be21665 --- /dev/null +++ b/pkg/sharedinformer/utils.go @@ -0,0 +1,15 @@ +package sharedinformer + +import ( + "github.com/nirmata/kyverno/pkg/client/clientset/versioned/fake" + informers "github.com/nirmata/kyverno/pkg/client/informers/externalversions" + "k8s.io/apimachinery/pkg/runtime" +) + +func NewFakeSharedInformerFactory(objects ...runtime.Object) (SharedInfomer, error) { + fakePolicyClient := fake.NewSimpleClientset(objects...) + policyInformerFactory := informers.NewSharedInformerFactory(fakePolicyClient, 0) + return &sharedInfomer{ + policyInformerFactory: policyInformerFactory, + }, nil +} From 45d44cef88d557e193ad1d58d1ec77451d077c88 Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Fri, 14 Jun 2019 16:02:28 -0700 Subject: [PATCH 2/6] re-structure unit tests --- pkg/dclient/client_test.go | 136 ++++++++++++++++++------------------- pkg/dclient/utils.go | 20 ++++++ 2 files changed, 88 insertions(+), 68 deletions(-) diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 984c316203..b3a7c7df6f 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -1,13 +1,11 @@ package client import ( - "fmt" "testing" policytypes "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" ) @@ -21,33 +19,19 @@ import ( // - kubernetes client // - objects to initialize the client -func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": apiVersion, - "kind": kind, - "metadata": map[string]interface{}{ - "namespace": namespace, - "name": name, - }, - }, - } +type fixture struct { + t *testing.T + regresources map[string]string + objects []runtime.Object + client *Client } -func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[string]interface{}) *unstructured.Unstructured { - u := newUnstructured(apiVersion, kind, namespace, name) - u.Object["spec"] = spec - return u -} - -func TestClient(t *testing.T) { - scheme := runtime.NewScheme() - // init groupversion +func newFixture(t *testing.T) *fixture { regresource := map[string]string{"group/version": "thekinds", "group2/version": "thekinds", "v1": "namespaces", "apps/v1": "deployments"} - // init resources + objects := []runtime.Object{newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"), newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"), newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"), @@ -55,8 +39,8 @@ func TestClient(t *testing.T) { newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"), newUnstructured("apps/v1", "Deployment", "kyverno", "kyverno-deployment"), } - - // Mock Client + scheme := runtime.NewScheme() + // Create mock client client, err := NewMockClient(scheme, objects...) if err != nil { t.Fatal(err) @@ -64,77 +48,92 @@ func TestClient(t *testing.T) { // set discovery Client client.SetDiscovery(NewFakeDiscoveryClient(regresource)) + + f := fixture{ + t: t, + regresources: regresource, + objects: objects, + client: client, + } + return &f + +} + +func TestCRUDResource(t *testing.T) { + f := newFixture(t) // Get Resource - res, err := client.GetResource("thekinds", "ns-foo", "name-foo") + _, err := f.client.GetResource("thekinds", "ns-foo", "name-foo") if err != nil { - t.Fatal(err) + t.Errorf("GetResource not working: %s", err) } - fmt.Println(res) // List Resources - list, err := client.ListResource("thekinds", "ns-foo") + _, err = f.client.ListResource("thekinds", "ns-foo") if err != nil { - t.Fatal(err) + t.Errorf("ListResource not working: %s", err) } - fmt.Println(len(list.Items)) // DeleteResouce - err = client.DeleteResouce("thekinds", "ns-foo", "name-bar") + err = f.client.DeleteResouce("thekinds", "ns-foo", "name-bar") if err != nil { - t.Fatal(err) + t.Errorf("DeleteResouce not working: %s", err) } // CreateResource - res, err = client.CreateResource("thekinds", "ns-foo", newUnstructured("group/version", "TheKind", "ns-foo", "name-foo1")) + _, err = f.client.CreateResource("thekinds", "ns-foo", newUnstructured("group/version", "TheKind", "ns-foo", "name-foo1")) if err != nil { - t.Fatal(err) + t.Errorf("CreateResource not working: %s", err) } // UpdateResource - res, err = client.UpdateResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "bar"})) + _, err = f.client.UpdateResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "bar"})) if err != nil { - t.Fatal(err) + t.Errorf("UpdateResource not working: %s", err) } - // UpdateStatusResource - res, err = client.UpdateStatusResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "status"})) + _, err = f.client.UpdateStatusResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "status"})) if err != nil { - t.Fatal(err) + t.Errorf("UpdateStatusResource not working: %s", err) } +} - iEvent, err := client.GetEventsInterface() +func TestEventInterface(t *testing.T) { + f := newFixture(t) + iEvent, err := f.client.GetEventsInterface() if err != nil { - t.Fatal(err) + t.Errorf("GetEventsInterface not working: %s", err) } - eventList, err := iEvent.List(meta.ListOptions{}) + _, err = iEvent.List(meta.ListOptions{}) if err != nil { - t.Fatal(err) + t.Errorf("Testing Event interface not working: %s", err) } - fmt.Println(eventList.Items) - - iCSR, err := client.GetCSRInterface() - if err != nil { - t.Fatal(err) - } - csrList, err := iCSR.List(meta.ListOptions{}) - if err != nil { - t.Fatal(err) - } - fmt.Println(csrList.Items) +} +func TestCSRInterface(t *testing.T) { + f := newFixture(t) + iCSR, err := f.client.GetCSRInterface() + if err != nil { + t.Errorf("GetCSRInterface not working: %s", err) + } + _, err = iCSR.List(meta.ListOptions{}) + if err != nil { + t.Errorf("Testing CSR interface not working: %s", err) + } +} +func TestGenerateResource(t *testing.T) { + f := newFixture(t) //GenerateResource -> copy From // 1 create namespace // 2 generate resource - // create namespace - ns, err := client.CreateResource("namespaces", "", newUnstructured("v1", "Namespace", "", "ns1")) + ns, err := f.client.CreateResource("namespaces", "", newUnstructured("v1", "Namespace", "", "ns1")) if err != nil { t.Fatal(err) } gen := policytypes.Generation{Kind: "TheKind", Name: "gen-kind", Clone: &policytypes.CloneFrom{Namespace: "ns-foo", Name: "name-foo"}} - err = client.GenerateResource(gen, ns.GetName()) + err = f.client.GenerateResource(gen, ns.GetName()) if err != nil { t.Fatal(err) } - res, err = client.GetResource("thekinds", "ns1", "gen-kind") + _, err = f.client.GetResource("thekinds", "ns1", "gen-kind") if err != nil { t.Fatal(err) } @@ -142,19 +141,20 @@ func TestClient(t *testing.T) { gen = policytypes.Generation{Kind: "TheKind", Name: "name2-baz-new", Data: newUnstructured("group2/version", "TheKind", "ns1", "name2-baz-new")} - err = client.GenerateResource(gen, ns.GetName()) + err = f.client.GenerateResource(gen, ns.GetName()) if err != nil { t.Fatal(err) } - res, err = client.GetResource("thekinds", "ns1", "name2-baz-new") + _, err = f.client.GetResource("thekinds", "ns1", "name2-baz-new") + if err != nil { + t.Fatal(err) + } +} + +func TestKubePolicyDeployment(t *testing.T) { + f := newFixture(t) + _, err := f.client.GetKubePolicyDeployment() if err != nil { t.Fatal(err) } - - // Get Kube Policy Deployment - deploy, err := client.GetKubePolicyDeployment() - if err != nil { - t.Fatal(err) - } - fmt.Println(deploy.GetName()) } diff --git a/pkg/dclient/utils.go b/pkg/dclient/utils.go index 080f2739c6..1650f20081 100644 --- a/pkg/dclient/utils.go +++ b/pkg/dclient/utils.go @@ -4,6 +4,7 @@ import ( "strings" "time" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic/fake" @@ -65,3 +66,22 @@ func (c *fakeDiscoveryClient) getGVRFromKind(kind string) schema.GroupVersionRes resource := strings.ToLower(kind) + "s" return c.getGVR(resource) } + +func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]interface{}{ + "namespace": namespace, + "name": name, + }, + }, + } +} + +func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[string]interface{}) *unstructured.Unstructured { + u := newUnstructured(apiVersion, kind, namespace, name) + u.Object["spec"] = spec + return u +} From b3bf9b02d27938ecf37ad6e8c89c469d387bc2ff Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Fri, 14 Jun 2019 16:15:23 -0700 Subject: [PATCH 3/6] skip test due to random fails --- pkg/dclient/client_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index b3a7c7df6f..5c7cd6577e 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -60,6 +60,7 @@ func newFixture(t *testing.T) *fixture { } func TestCRUDResource(t *testing.T) { + t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") f := newFixture(t) // Get Resource _, err := f.client.GetResource("thekinds", "ns-foo", "name-foo") @@ -117,6 +118,8 @@ func TestCSRInterface(t *testing.T) { } func TestGenerateResource(t *testing.T) { + t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") + f := newFixture(t) //GenerateResource -> copy From // 1 create namespace @@ -124,18 +127,18 @@ func TestGenerateResource(t *testing.T) { // create namespace ns, err := f.client.CreateResource("namespaces", "", newUnstructured("v1", "Namespace", "", "ns1")) if err != nil { - t.Fatal(err) + t.Errorf("CreateResource not working: %s", err) } gen := policytypes.Generation{Kind: "TheKind", Name: "gen-kind", Clone: &policytypes.CloneFrom{Namespace: "ns-foo", Name: "name-foo"}} err = f.client.GenerateResource(gen, ns.GetName()) if err != nil { - t.Fatal(err) + t.Errorf("GenerateResource not working: %s", err) } _, err = f.client.GetResource("thekinds", "ns1", "gen-kind") if err != nil { - t.Fatal(err) + t.Errorf("GetResource not working: %s", err) } // GenerateResource -> data gen = policytypes.Generation{Kind: "TheKind", @@ -143,11 +146,11 @@ func TestGenerateResource(t *testing.T) { Data: newUnstructured("group2/version", "TheKind", "ns1", "name2-baz-new")} err = f.client.GenerateResource(gen, ns.GetName()) if err != nil { - t.Fatal(err) + t.Errorf("GenerateResource not working: %s", err) } _, err = f.client.GetResource("thekinds", "ns1", "name2-baz-new") if err != nil { - t.Fatal(err) + t.Errorf("GetResource not working: %s", err) } } From 640ffd7258edb7ad765117b4dfd8260a4bd24afb Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Mon, 17 Jun 2019 10:31:51 -0700 Subject: [PATCH 4/6] re factor --- pkg/dclient/client_test.go | 33 +++++++++++++++--------------- pkg/dclient/utils.go | 42 ++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 5c7cd6577e..62b798382e 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -7,6 +7,7 @@ import ( meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) // GetResource @@ -20,18 +21,19 @@ import ( // - objects to initialize the client type fixture struct { - t *testing.T - regresources map[string]string - objects []runtime.Object - client *Client + t *testing.T + objects []runtime.Object + client *Client } func newFixture(t *testing.T) *fixture { - regresource := map[string]string{"group/version": "thekinds", - "group2/version": "thekinds", - "v1": "namespaces", - "apps/v1": "deployments"} - + // init groupversion + regResource := []schema.GroupVersionResource{ + schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}, + schema.GroupVersionResource{Group: "group2", Version: "version", Resource: "thekinds"}, + schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"}, + schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, + } objects := []runtime.Object{newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"), newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"), newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"), @@ -47,20 +49,19 @@ func newFixture(t *testing.T) *fixture { } // set discovery Client - client.SetDiscovery(NewFakeDiscoveryClient(regresource)) + client.SetDiscovery(NewFakeDiscoveryClient(regResource)) f := fixture{ - t: t, - regresources: regresource, - objects: objects, - client: client, + t: t, + objects: objects, + client: client, } return &f } func TestCRUDResource(t *testing.T) { - t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") + // t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") f := newFixture(t) // Get Resource _, err := f.client.GetResource("thekinds", "ns-foo", "name-foo") @@ -118,7 +119,7 @@ func TestCSRInterface(t *testing.T) { } func TestGenerateResource(t *testing.T) { - t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") + // t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") f := newFixture(t) //GenerateResource -> copy From diff --git a/pkg/dclient/utils.go b/pkg/dclient/utils.go index 1650f20081..c87030a563 100644 --- a/pkg/dclient/utils.go +++ b/pkg/dclient/utils.go @@ -37,16 +37,21 @@ func NewMockClient(scheme *runtime.Scheme, objects ...runtime.Object) (*Client, } // NewFakeDiscoveryClient returns a fakediscovery client -func NewFakeDiscoveryClient(regResources map[string]string) *fakeDiscoveryClient { - registeredResources := make([]schema.GroupVersionResource, len(regResources)) - for groupVersion, resource := range regResources { - gv, err := schema.ParseGroupVersion(groupVersion) - if err != nil { - continue - } - registeredResources = append(registeredResources, gv.WithResource(resource)) +func NewFakeDiscoveryClient(registeredResouces []schema.GroupVersionResource) *fakeDiscoveryClient { + // Load some-preregistd resources + res := []schema.GroupVersionResource{ + schema.GroupVersionResource{Version: "v1", Resource: "configmaps"}, + schema.GroupVersionResource{Version: "v1", Resource: "endpoints"}, + schema.GroupVersionResource{Version: "v1", Resource: "namespaces"}, + schema.GroupVersionResource{Version: "v1", Resource: "resourcequotas"}, + schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, + schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, + schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "daemonsets"}, + schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, + schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}, } - return &fakeDiscoveryClient{registeredResouces: registeredResources} + registeredResouces = append(registeredResouces, res...) + return &fakeDiscoveryClient{registeredResouces: registeredResouces} } type fakeDiscoveryClient struct { @@ -85,3 +90,22 @@ func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[ u.Object["spec"] = spec return u } + +func retry(attempts int, sleep time.Duration, fn func() error) error { + if err := fn(); err != nil { + if s, ok := err.(stop); ok { + return s.error + } + if attempts--; attempts > 0 { + time.Sleep(sleep) + return retry(attempts, 2*sleep, fn) + } + return err + } + return nil +} + +// Custom error +type stop struct { + error +} From 860d2f8df18b5a8ff2e81af3817cdd65af95c3cf Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Mon, 17 Jun 2019 18:35:40 -0700 Subject: [PATCH 5/6] enable test --- pkg/dclient/client_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 62b798382e..a7526c2c51 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -61,7 +61,6 @@ func newFixture(t *testing.T) *fixture { } func TestCRUDResource(t *testing.T) { - // t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") f := newFixture(t) // Get Resource _, err := f.client.GetResource("thekinds", "ns-foo", "name-foo") @@ -119,8 +118,6 @@ func TestCSRInterface(t *testing.T) { } func TestGenerateResource(t *testing.T) { - // t.Skip("Under Development. Reason: delay in generation of resources, so test fails at times") - f := newFixture(t) //GenerateResource -> copy From // 1 create namespace From ba43509b4390ca5317f2750b59bcdb2c14cf26f5 Mon Sep 17 00:00:00 2001 From: shivdudhani <shivkumar@nirmata.com> Date: Mon, 17 Jun 2019 18:42:23 -0700 Subject: [PATCH 6/6] fix format --- pkg/controller/controller_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 8a300f1683..95223e0ffb 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -10,6 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/sample-controller/pkg/signals" ) @@ -78,7 +79,10 @@ func (f *fixture) setupFixture() { if err != nil { f.t.Fatal(err) } - regresource := map[string]string{"kyverno.io/v1alpha1": "policys"} + regresource := []schema.GroupVersionResource{ + schema.GroupVersionResource{Group: "kyverno.io", + Version: "v1alpha1", + Resource: "policys"}} fclient.SetDiscovery(client.NewFakeDiscoveryClient(regresource)) }