@@ -17,7 +17,9 @@ limitations under the License.
17
17
package dynamic_test
18
18
19
19
import (
20
+ "bufio"
20
21
"context"
22
+ "encoding/json"
21
23
"fmt"
22
24
"net"
23
25
"net/http"
@@ -32,6 +34,7 @@ import (
32
34
"github.com/google/go-cmp/cmp"
33
35
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34
36
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
37
+ "k8s.io/apimachinery/pkg/runtime"
35
38
"k8s.io/apimachinery/pkg/runtime/schema"
36
39
"k8s.io/apimachinery/pkg/types"
37
40
"k8s.io/client-go/dynamic"
@@ -246,3 +249,157 @@ func TestGoldenRequest(t *testing.T) {
246
249
})
247
250
}
248
251
}
252
+
253
+ type RoundTripperFunc func (* http.Request ) (* http.Response , error )
254
+
255
+ func (f RoundTripperFunc ) RoundTrip (r * http.Request ) (* http.Response , error ) {
256
+ return f (r )
257
+ }
258
+
259
+ // TestGoldenResponse tests that the objects returned from dynamic client methods, given a fixed
260
+ // HTTP response, are not changed unintentionally by changes to the client.
261
+ func TestGoldenResponse (t * testing.T ) {
262
+ for _ , tc := range []struct {
263
+ name string
264
+ response string // name of fixture containing a serialized HTTP1.1 response
265
+ do func (t * testing.T , client dynamic.ResourceInterface ) interface {}
266
+ }{
267
+ {
268
+ name : "create" ,
269
+ response : "nonlist" ,
270
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
271
+ got , err := client .Create (context .Background (), & unstructured.Unstructured {}, metav1.CreateOptions {})
272
+ if err != nil {
273
+ t .Fatal (err )
274
+ }
275
+
276
+ return got .UnstructuredContent ()
277
+ },
278
+ },
279
+ {
280
+ name : "update" ,
281
+ response : "nonlist" ,
282
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
283
+ got , err := client .Update (context .Background (), & unstructured.Unstructured {Object : map [string ]interface {}{"metadata" : map [string ]interface {}{"name" : "name" }}}, metav1.UpdateOptions {})
284
+ if err != nil {
285
+ t .Fatal (err )
286
+ }
287
+
288
+ return got .UnstructuredContent ()
289
+ },
290
+ },
291
+ {
292
+ name : "updatestatus" ,
293
+ response : "nonlist" ,
294
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
295
+ got , err := client .UpdateStatus (context .Background (), & unstructured.Unstructured {Object : map [string ]interface {}{"metadata" : map [string ]interface {}{"name" : "name" }}}, metav1.UpdateOptions {})
296
+
297
+ if err != nil {
298
+ t .Fatal (err )
299
+ }
300
+
301
+ return got .UnstructuredContent ()
302
+ },
303
+ },
304
+ {
305
+ name : "get" ,
306
+ response : "nonlist" ,
307
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
308
+ got , err := client .Get (context .Background (), "name" , metav1.GetOptions {})
309
+ if err != nil {
310
+ t .Fatal (err )
311
+ }
312
+
313
+ return got .UnstructuredContent ()
314
+ },
315
+ },
316
+ {
317
+ name : "list" ,
318
+ response : "list" ,
319
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
320
+ got , err := client .List (context .Background (), metav1.ListOptions {})
321
+ if err != nil {
322
+ t .Fatal (err )
323
+ }
324
+
325
+ return got .UnstructuredContent ()
326
+
327
+ },
328
+ },
329
+ {
330
+ name : "watch" ,
331
+ response : "events" ,
332
+ do : func (t * testing.T , client dynamic.ResourceInterface ) interface {} {
333
+ w , err := client .Watch (context .Background (), metav1.ListOptions {})
334
+ if err != nil {
335
+ t .Fatal (err )
336
+ }
337
+ defer w .Stop ()
338
+
339
+ var got []interface {}
340
+ for e := range w .ResultChan () {
341
+ u , err := runtime .DefaultUnstructuredConverter .ToUnstructured (& e )
342
+ if err != nil {
343
+ t .Fatalf ("failed to convert watch event to unstructured content: %v" , err )
344
+ }
345
+ got = append (got , u )
346
+ }
347
+
348
+ return got
349
+ },
350
+ },
351
+ } {
352
+ parentTestName := t .Name ()
353
+ t .Run (tc .name , func (t * testing.T ) {
354
+ client , err := dynamic .NewForConfig (& rest.Config {
355
+
356
+ Transport : RoundTripperFunc (func (request * http.Request ) (* http.Response , error ) {
357
+ fd , err := os .Open (filepath .Join ("testdata" , filepath .FromSlash (parentTestName ), "responses" , tc .response ))
358
+ if err != nil {
359
+ t .Fatal (err )
360
+ }
361
+ defer func () {
362
+ if err := fd .Close (); err != nil {
363
+ t .Fatal (err )
364
+ }
365
+ }()
366
+
367
+ response , err := http .ReadResponse (bufio .NewReader (fd ), request )
368
+ if err != nil {
369
+ t .Fatal (err )
370
+ }
371
+ return response , nil
372
+ }),
373
+ })
374
+ if err != nil {
375
+ t .Fatal (err )
376
+ }
377
+
378
+ got := tc .do (t , client .Resource (schema.GroupVersionResource {}))
379
+
380
+ path := filepath .Join ("testdata" , filepath .FromSlash (t .Name ()))
381
+ if os .Getenv ("UPDATE_DYNAMIC_CLIENT_FIXTURES" ) == "true" {
382
+ fixture , err := json .Marshal (got )
383
+ if err != nil {
384
+ t .Fatal (err )
385
+ }
386
+ if err := os .WriteFile (path , fixture , os .FileMode (0644 )); err != nil {
387
+ t .Fatalf ("failed to update fixture: %v" , err )
388
+ }
389
+ }
390
+ fixture , err := os .ReadFile (path )
391
+ if err != nil {
392
+ t .Fatal (err )
393
+ }
394
+
395
+ var want interface {}
396
+ if err := json .Unmarshal (fixture , & want ); err != nil {
397
+ t .Fatal (err )
398
+ }
399
+
400
+ if diff := cmp .Diff (want , got ); diff != "" {
401
+ t .Errorf ("unexpected diff:\n %s" , diff )
402
+ }
403
+ })
404
+ }
405
+ }
0 commit comments