1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package livestate_test
16
17 import (
18 "testing"
19
20 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/livestate"
21 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test"
22
23 "github.com/google/go-cmp/cmp"
24 "github.com/nasa9084/go-openapi"
25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
26 )
27
28 var testDCLSchema = &openapi.Schema{
29 Type: "object",
30 Properties: map[string]*openapi.Schema{
31 "project": &openapi.Schema{
32 Type: "string",
33 },
34 "name": &openapi.Schema{
35 Type: "string",
36 },
37 "labels": &openapi.Schema{
38 Type: "object",
39 AdditionalProperties: &openapi.Schema{
40 Type: "string",
41 },
42 },
43 "stringKey": {
44 Type: "string",
45 },
46 "intKey": {
47 Type: "integer",
48 },
49 "boolKey": {
50 Type: "boolean",
51 },
52 "floatKey": {
53 Type: "number",
54 },
55 "numberKey": {
56 Type: "number",
57 },
58 "nestedObjectKey": {
59 Type: "object",
60 Properties: map[string]*openapi.Schema{
61 "nestedField1": {
62 Type: "boolean",
63 },
64 "nestedField2": {
65 Type: "string",
66 },
67 "nestedReferenceKey": {
68 Type: "string",
69 Extension: map[string]interface{}{
70 "x-dcl-references": []interface{}{
71 map[interface{}]interface{}{
72 "resource": "Test1/Bar",
73 "path": "statusField",
74 },
75 },
76 },
77 },
78 "nestedSensitiveField": {
79 Type: "string",
80 Extension: map[string]interface{}{
81 "x-dcl-sensitive": true,
82 },
83 },
84 "nestedStatusField": {
85 Type: "string",
86 ReadOnly: true,
87 },
88 "nestedStatusArrayString": {
89 Type: "array",
90 ReadOnly: true,
91 Items: &openapi.Schema{
92 Type: "string",
93 ReadOnly: true,
94 },
95 },
96 },
97 Required: []string{"nestedField1"},
98 },
99 "sensitiveField": {
100 Type: "string",
101 Extension: map[string]interface{}{
102 "x-dcl-sensitive": true,
103 },
104 },
105 "referenceKey": {
106 Type: "string",
107 Extension: map[string]interface{}{
108 "x-dcl-references": []interface{}{
109 map[interface{}]interface{}{
110 "resource": "test1/Bar",
111 "path": "name",
112 },
113 },
114 },
115 },
116 "mapKey": {
117 Type: "object",
118 AdditionalProperties: &openapi.Schema{
119 Type: "string",
120 },
121 },
122 "stringObjectMapKey": {
123 Type: "object",
124 AdditionalProperties: &openapi.Schema{
125 Type: "object",
126 Properties: map[string]*openapi.Schema{
127 "objectField1": {
128 Type: "number",
129 },
130 "objectField2": {
131 Type: "string",
132 },
133 "state": {
134 ReadOnly: true,
135 Type: "string",
136 },
137 "objectReferenceArrayKey": {
138 Type: "array",
139 Items: &openapi.Schema{
140 Type: "string",
141 Extension: map[string]interface{}{
142 "x-dcl-references": []interface{}{
143 map[interface{}]interface{}{
144 "resource": "test1/Bar",
145 "path": "name",
146 },
147 },
148 },
149 },
150 },
151 },
152 },
153 },
154 "primitiveArrayKey": {
155 Type: "array",
156 Items: &openapi.Schema{
157 Type: "string",
158 },
159 },
160 "objectArrayKey": {
161 Type: "array",
162 Items: &openapi.Schema{
163 Type: "object",
164 Properties: map[string]*openapi.Schema{
165 "field1": {
166 Type: "number",
167 },
168 "field2": {
169 Type: "string",
170 },
171 "sensitiveFieldInArray": {
172 Type: "string",
173 Extension: map[string]interface{}{
174 "x-dcl-sensitive": true,
175 },
176 },
177 "bar": {
178 Type: "string",
179 Extension: map[string]interface{}{
180 "x-dcl-references": []interface{}{
181 map[interface{}]interface{}{
182 "resource": "test1/Bar",
183 "path": "name",
184 },
185 },
186 },
187 },
188 },
189 },
190 },
191 "referenceArrayKey": {
192 Type: "array",
193 Items: &openapi.Schema{
194 Type: "string",
195 Extension: map[string]interface{}{
196 "x-dcl-references": []interface{}{
197 map[interface{}]interface{}{
198 "resource": "test1/Bar",
199 "path": "name",
200 },
201 },
202 },
203 },
204 },
205 "statusField": {
206 Type: "string",
207 ReadOnly: true,
208 },
209 },
210 Extension: map[string]interface{}{
211 "x-dcl-parent-container": "project",
212 },
213 }
214
215 func TestSetMutableButUnreadableFields(t *testing.T) {
216 tests := []struct {
217 name string
218 krmObj *unstructured.Unstructured
219 mutableButUnreadableSpec map[string]interface{}
220 path []string
221 schema *openapi.Schema
222 expectedResult *unstructured.Unstructured
223 hasError bool
224 }{
225 {
226 name: "set primitive fields",
227 krmObj: &unstructured.Unstructured{
228 Object: map[string]interface{}{},
229 },
230 mutableButUnreadableSpec: map[string]interface{}{
231 "boolKey": true,
232 "floatKey": 1.1,
233 "intKey": 10,
234 "stringKey": "testValue",
235 },
236 path: []string{"spec"},
237 schema: testDCLSchema,
238 expectedResult: &unstructured.Unstructured{
239 Object: map[string]interface{}{
240 "spec": map[string]interface{}{
241 "boolKey": true,
242 "floatKey": 1.1,
243 "intKey": 10,
244 "stringKey": "testValue",
245 },
246 },
247 },
248 },
249 {
250 name: "set primitive array",
251 krmObj: &unstructured.Unstructured{
252 Object: map[string]interface{}{},
253 },
254 mutableButUnreadableSpec: map[string]interface{}{
255 "primitiveArrayKey": []interface{}{"test1", "test2"},
256 },
257 path: []string{"spec"},
258 schema: testDCLSchema,
259 expectedResult: &unstructured.Unstructured{
260 Object: map[string]interface{}{
261 "spec": map[string]interface{}{
262 "primitiveArrayKey": []interface{}{"test1", "test2"},
263 },
264 },
265 },
266 },
267 {
268 name: "set nested fields",
269 krmObj: &unstructured.Unstructured{
270 Object: map[string]interface{}{},
271 },
272 mutableButUnreadableSpec: map[string]interface{}{
273 "nestedObjectKey": map[string]interface{}{
274 "nestedField1": true,
275 "nestedField2": "test",
276 },
277 },
278 path: []string{"spec"},
279 schema: testDCLSchema,
280 expectedResult: &unstructured.Unstructured{
281 Object: map[string]interface{}{
282 "spec": map[string]interface{}{
283 "nestedObjectKey": map[string]interface{}{
284 "nestedField1": true,
285 "nestedField2": "test",
286 },
287 },
288 },
289 },
290 },
291 {
292 name: "set map",
293 krmObj: &unstructured.Unstructured{
294 Object: map[string]interface{}{},
295 },
296 mutableButUnreadableSpec: map[string]interface{}{
297 "mapKey": map[string]interface{}{
298 "label1": "value1",
299 "label2": "value2",
300 },
301 },
302 path: []string{"spec"},
303 schema: testDCLSchema,
304 expectedResult: &unstructured.Unstructured{
305 Object: map[string]interface{}{
306 "spec": map[string]interface{}{
307 "mapKey": map[string]interface{}{
308 "label1": "value1",
309 "label2": "value2",
310 },
311 },
312 },
313 },
314 },
315 {
316 name: "non primitive array should return an error",
317 krmObj: &unstructured.Unstructured{
318 Object: map[string]interface{}{},
319 },
320 mutableButUnreadableSpec: map[string]interface{}{
321 "objectArrayKey": map[string]interface{}{
322 "field1": 10,
323 },
324 },
325 path: []string{"spec"},
326 schema: testDCLSchema,
327 hasError: true,
328 },
329 {
330 name: "overwrite the existent value in krmObj with the value in" +
331 "mutableButUnreadableSpec",
332 krmObj: &unstructured.Unstructured{
333 Object: map[string]interface{}{
334 "spec": map[string]interface{}{
335 "nestedObjectKey": map[string]interface{}{
336 "nestedField1": true,
337 "nestedField2": "oldVal",
338 },
339 },
340 },
341 },
342 mutableButUnreadableSpec: map[string]interface{}{
343 "nestedObjectKey": map[string]interface{}{
344 "nestedField2": "newVal",
345 },
346 },
347 path: []string{"spec"},
348 schema: testDCLSchema,
349 expectedResult: &unstructured.Unstructured{
350 Object: map[string]interface{}{
351 "spec": map[string]interface{}{
352 "nestedObjectKey": map[string]interface{}{
353 "nestedField1": true,
354 "nestedField2": "newVal",
355 },
356 },
357 },
358 },
359 },
360 {
361 name: "set sensitive path with a plain text value",
362 krmObj: &unstructured.Unstructured{
363 Object: map[string]interface{}{},
364 },
365 mutableButUnreadableSpec: map[string]interface{}{
366 "sensitiveField": map[string]interface{}{
367 "value": "sensitive-value",
368 },
369 },
370 path: []string{"spec"},
371 schema: testDCLSchema,
372 expectedResult: &unstructured.Unstructured{
373 Object: map[string]interface{}{
374 "spec": map[string]interface{}{
375 "sensitiveField": map[string]interface{}{
376 "value": "sensitive-value",
377 },
378 },
379 },
380 },
381 },
382 }
383
384 for _, tc := range tests {
385 tc := tc
386 t.Run(tc.name, func(t *testing.T) {
387 t.Parallel()
388 result, err := livestate.SetMutableButUnreadableFields(tc.krmObj, tc.mutableButUnreadableSpec, tc.path, tc.schema, nil, "", nil)
389 if tc.hasError {
390 if err == nil {
391 t.Fatalf("got nil, but want an error setting mutable-but-unreadable fields")
392 }
393 return
394 }
395 if err != nil {
396 t.Fatalf("error setting mutable-but-unreadable fields: %v", err)
397 }
398
399 if got, want := result, tc.expectedResult; !test.Equals(t, got, want) {
400 t.Fatalf("unexpected spec diff (-want +got): \n%v", cmp.Diff(want, got))
401 }
402 })
403 }
404 }
405
View as plain text