1
2
3
4 package statusreaders
5
6 import (
7 "context"
8 "fmt"
9 "sort"
10 "testing"
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14 appsv1 "k8s.io/api/apps/v1"
15 "k8s.io/apimachinery/pkg/api/errors"
16 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
17 "k8s.io/apimachinery/pkg/runtime/schema"
18 fakecr "sigs.k8s.io/cli-utils/pkg/kstatus/polling/clusterreader/fake"
19 fakesr "sigs.k8s.io/cli-utils/pkg/kstatus/polling/statusreaders/fake"
20 "sigs.k8s.io/cli-utils/pkg/kstatus/polling/testutil"
21 "sigs.k8s.io/cli-utils/pkg/object"
22 fakemapper "sigs.k8s.io/cli-utils/pkg/testutil"
23 )
24
25 var (
26 deploymentGVK = appsv1.SchemeGroupVersion.WithKind("Deployment")
27 deploymentGVR = appsv1.SchemeGroupVersion.WithResource("deployments")
28 replicaSetGVK = appsv1.SchemeGroupVersion.WithKind("ReplicaSet")
29
30 rsGVK = appsv1.SchemeGroupVersion.WithKind("ReplicaSet")
31 )
32
33 func TestLookupResource(t *testing.T) {
34 deploymentIdentifier := object.ObjMetadata{
35 GroupKind: deploymentGVK.GroupKind(),
36 Name: "Foo",
37 Namespace: "Bar",
38 }
39
40 testCases := map[string]struct {
41 identifier object.ObjMetadata
42 readerErr error
43 expectErr bool
44 expectedErrMessage string
45 }{
46 "unknown GVK": {
47 identifier: object.ObjMetadata{
48 GroupKind: schema.GroupKind{
49 Group: "custom.io",
50 Kind: "Custom",
51 },
52 Name: "Bar",
53 Namespace: "default",
54 },
55 expectErr: true,
56 expectedErrMessage: `no matches for kind "Custom" in group "custom.io"`,
57 },
58 "resource does not exist": {
59 identifier: deploymentIdentifier,
60 readerErr: errors.NewNotFound(deploymentGVR.GroupResource(), "Foo"),
61 expectErr: true,
62 expectedErrMessage: `deployments.apps "Foo" not found`,
63 },
64 "getting resource fails": {
65 identifier: deploymentIdentifier,
66 readerErr: errors.NewInternalError(fmt.Errorf("this is a test")),
67 expectErr: true,
68 expectedErrMessage: "Internal error occurred: this is a test",
69 },
70 "getting resource succeeds": {
71 identifier: deploymentIdentifier,
72 },
73 "context cancelled": {
74 identifier: deploymentIdentifier,
75 readerErr: context.Canceled,
76 expectErr: true,
77 expectedErrMessage: context.Canceled.Error(),
78 },
79 }
80
81 for tn, tc := range testCases {
82 t.Run(tn, func(t *testing.T) {
83 fakeReader := &fakecr.ClusterReader{
84 GetErr: tc.readerErr,
85 }
86 fakeMapper := fakemapper.NewFakeRESTMapper(deploymentGVK)
87
88 statusReader := &baseStatusReader{
89 mapper: fakeMapper,
90 }
91
92 u, err := statusReader.lookupResource(context.Background(), fakeReader, tc.identifier)
93
94 if tc.expectErr {
95 if err == nil {
96 t.Errorf("expected error, but didn't get one")
97 } else {
98 assert.EqualError(t, err, tc.expectedErrMessage)
99 }
100 return
101 }
102
103 require.NoError(t, err)
104
105 assert.Equal(t, deploymentGVK, u.GroupVersionKind())
106 })
107 }
108 }
109
110 func TestStatusForGeneratedResources(t *testing.T) {
111 testCases := map[string]struct {
112 manifest string
113 listObjects []unstructured.Unstructured
114 listErr error
115 gk schema.GroupKind
116 path []string
117 expectError bool
118 errMessage string
119 }{
120 "invalid selector": {
121 manifest: `
122 apiVersion: apps/v1
123 kind: Deployment
124 metadata:
125 name: Foo
126 spec:
127 replicas: 1
128 `,
129 gk: appsv1.SchemeGroupVersion.WithKind("ReplicaSet").GroupKind(),
130 path: []string{"spec", "selector"},
131 expectError: true,
132 errMessage: "no selector found",
133 },
134 "Invalid GVK": {
135 manifest: `
136 apiVersion: apps/v1
137 kind: Deployment
138 metadata:
139 name: Foo
140 spec:
141 replicas: 1
142 selector:
143 matchLabels:
144 app: nginx
145 `,
146 gk: schema.GroupKind{
147 Group: "custom.io",
148 Kind: "Custom",
149 },
150 path: []string{"spec", "selector"},
151 expectError: true,
152 errMessage: `no matches for kind "Custom" in group "custom.io"`,
153 },
154 "error listing replicasets": {
155 manifest: `
156 apiVersion: apps/v1
157 kind: Deployment
158 metadata:
159 name: Foo
160 spec:
161 replicas: 1
162 selector:
163 matchLabels:
164 app: nginx
165 `,
166 listErr: fmt.Errorf("this is a test"),
167 gk: appsv1.SchemeGroupVersion.WithKind("ReplicaSet").GroupKind(),
168 path: []string{"spec", "selector"},
169 expectError: true,
170 errMessage: "this is a test",
171 },
172 "successfully lists and polling the generated resources": {
173 manifest: `
174 apiVersion: apps/v1
175 kind: Deployment
176 metadata:
177 name: Foo
178 spec:
179 replicas: 1
180 selector:
181 matchLabels:
182 app: nginx
183 `,
184 listObjects: []unstructured.Unstructured{
185 {
186 Object: map[string]interface{}{
187 "apiVersion": "apps/v1",
188 "kind": "ReplicaSet",
189 "metadata": map[string]interface{}{
190 "name": "Foo-12345",
191 "namespace": "default",
192 },
193 },
194 },
195 },
196 gk: appsv1.SchemeGroupVersion.WithKind("ReplicaSet").GroupKind(),
197 path: []string{"spec", "selector"},
198 expectError: false,
199 },
200 }
201
202 for tn, tc := range testCases {
203 t.Run(tn, func(t *testing.T) {
204 fakeClusterReader := &fakecr.ClusterReader{
205 ListResources: &unstructured.UnstructuredList{
206 Items: tc.listObjects,
207 },
208 ListErr: tc.listErr,
209 }
210 fakeMapper := fakemapper.NewFakeRESTMapper(rsGVK)
211 fakeStatusReader := &fakesr.StatusReader{}
212
213 object := testutil.YamlToUnstructured(t, tc.manifest)
214
215 resourceStatuses, err := statusForGeneratedResources(context.Background(), fakeMapper, fakeClusterReader,
216 fakeStatusReader, object, tc.gk, tc.path...)
217
218 if tc.expectError {
219 if err == nil {
220 t.Errorf("expected an error, but didn't get one")
221 return
222 }
223 assert.EqualError(t, err, tc.errMessage)
224 return
225 }
226 if !tc.expectError && err != nil {
227 t.Errorf("did not expect an error, but got %v", err)
228 }
229
230 assert.Len(t, resourceStatuses, len(tc.listObjects))
231 assert.True(t, sort.IsSorted(resourceStatuses))
232 })
233 }
234 }
235
View as plain text