From 46a545d1917383e969b70e27e96a49089d7571b4 Mon Sep 17 00:00:00 2001 From: jtucci Date: Tue, 7 Nov 2023 21:29:33 -0800 Subject: [PATCH] Update list to filter resources using label selectors (#488) Signed-off-by: jtucci --- pkg/test/step.go | 37 ++++++++++++++++++--------- pkg/test/step_test.go | 58 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 22 deletions(-) diff --git a/pkg/test/step.go b/pkg/test/step.go index ba73c9bc..70662183 100644 --- a/pkg/test/step.go +++ b/pkg/test/step.go @@ -11,6 +11,7 @@ import ( "time" k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -230,7 +231,7 @@ func (s *Step) GetTimeout() int { return timeout } -func list(cl client.Client, gvk schema.GroupVersionKind, namespace string) ([]unstructured.Unstructured, error) { +func list(cl client.Client, gvk schema.GroupVersionKind, namespace string, labelsMap map[string]string) ([]unstructured.Unstructured, error) { list := unstructured.UnstructuredList{} list.SetGroupVersionKind(gvk) @@ -239,6 +240,10 @@ func list(cl client.Client, gvk schema.GroupVersionKind, namespace string) ([]un listOptions = append(listOptions, client.InNamespace(namespace)) } + if len(labelsMap) > 0 { + listOptions = append(listOptions, client.MatchingLabels(labelsMap)) + } + if err := cl.List(context.TODO(), &list, listOptions...); err != nil { return []unstructured.Unstructured{}, err } @@ -268,27 +273,32 @@ func (s *Step) CheckResource(expected runtime.Object, namespace string) []error gvk := expected.GetObjectKind().GroupVersionKind() actuals := []unstructured.Unstructured{} - if name != "" { actual := unstructured.Unstructured{} actual.SetGroupVersionKind(gvk) - err = cl.Get(context.TODO(), client.ObjectKey{ + if err := cl.Get(context.TODO(), client.ObjectKey{ Namespace: namespace, Name: name, - }, &actual) + }, &actual); err != nil { + return append(testErrors, err) + } actuals = append(actuals, actual) } else { - actuals, err = list(cl, gvk, namespace) - if len(actuals) == 0 { + m, err := meta.Accessor(expected) + if err != nil { + return append(testErrors, err) + } + matches, err := list(cl, gvk, namespace, m.GetLabels()) + if err != nil { + return append(testErrors, err) + } + if len(matches) == 0 { testErrors = append(testErrors, fmt.Errorf("no resources matched of kind: %s", gvk.String())) } + actuals = append(actuals, matches...) } - if err != nil { - return append(testErrors, err) - } - expectedObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(expected) if err != nil { return append(testErrors, err) @@ -296,7 +306,6 @@ func (s *Step) CheckResource(expected runtime.Object, namespace string) []error for _, actual := range actuals { actual := actual - tmpTestErrors := []error{} if err := testutils.IsSubset(expectedObj, actual.UnstructuredContent()); err != nil { @@ -358,7 +367,11 @@ func (s *Step) CheckResourceAbsent(expected runtime.Object, namespace string) er actuals = []unstructured.Unstructured{actual} } else { - actuals, err = list(cl, gvk, namespace) + m, err := meta.Accessor(expected) + if err != nil { + return err + } + actuals, err = list(cl, gvk, namespace, m.GetLabels()) if err != nil { return err } diff --git a/pkg/test/step_test.go b/pkg/test/step_test.go index 6a97745a..f6ca3985 100644 --- a/pkg/test/step_test.go +++ b/pkg/test/step_test.go @@ -136,34 +136,71 @@ func TestStepDeleteExisting(t *testing.T) { func TestCheckResource(t *testing.T) { for _, test := range []struct { testName string - actual runtime.Object + actual []runtime.Object expected runtime.Object shouldError bool }{ { testName: "resource matches", - actual: testutils.NewPod("hello", ""), + actual: []runtime.Object{ + testutils.NewPod("hello", ""), + }, expected: testutils.NewPod("hello", ""), }, + { + testName: "resource matches with labels", + actual: []runtime.Object{ + testutils.WithSpec(t, testutils.NewPod("deploy-8b2d", ""), + map[string]interface{}{ + "containers": nil, + "serviceAccountName": "invalid", + }), + testutils.WithSpec( + t, + testutils.WithLabels( + t, + testutils.NewPod("deploy-8c2z", ""), + map[string]string{"label": "my-label"}, + ), + map[string]interface{}{ + "containers": nil, + "serviceAccountName": "valid", + }, + ), + }, + + expected: testutils.WithSpec( + t, + testutils.WithLabels( + t, + testutils.NewPod("", ""), + map[string]string{"label": "my-label"}, + ), + map[string]interface{}{ + "containers": nil, + "serviceAccountName": "valid", + }, + ), + }, { testName: "resource mis-match", - actual: testutils.NewPod("hello", ""), + actual: []runtime.Object{testutils.NewPod("hello", "")}, expected: testutils.WithSpec(t, testutils.NewPod("hello", ""), map[string]interface{}{"invalid": "key"}), shouldError: true, }, { testName: "resource subset match", - actual: testutils.WithSpec(t, testutils.NewPod("hello", ""), map[string]interface{}{ + actual: []runtime.Object{testutils.WithSpec(t, testutils.NewPod("hello", ""), map[string]interface{}{ "containers": nil, "restartPolicy": "OnFailure", - }), + })}, expected: testutils.WithSpec(t, testutils.NewPod("hello", ""), map[string]interface{}{ "restartPolicy": "OnFailure", }), }, { testName: "resource does not exist", - actual: testutils.NewPod("other", ""), + actual: []runtime.Object{testutils.NewPod("other", "")}, expected: testutils.NewPod("hello", ""), shouldError: true, }, @@ -174,19 +211,20 @@ func TestCheckResource(t *testing.T) { fakeDiscovery := testutils.FakeDiscoveryClient() namespace := testNamespace - _, _, err := testutils.Namespaced(fakeDiscovery, test.actual, namespace) - assert.Nil(t, err) + for _, actualObj := range test.actual { + _, _, err := testutils.Namespaced(fakeDiscovery, actualObj, namespace) + assert.Nil(t, err) + } step := Step{ Logger: testutils.NewTestLogger(t, ""), Client: func(bool) (client.Client, error) { - return fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(test.actual).Build(), nil + return fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(test.actual...).Build(), nil }, DiscoveryClient: func() (discovery.DiscoveryInterface, error) { return fakeDiscovery, nil }, } errors := step.CheckResource(test.expected, namespace) - if test.shouldError { assert.NotEqual(t, []error{}, errors) } else {