@@ -340,6 +340,150 @@ func TestNameInFieldSelector(t *testing.T) {
340
340
}
341
341
}
342
342
343
+ func TestAPICRDProtobuf (t * testing.T ) {
344
+ tearDown , config , _ , err := fixtures .StartDefaultServer (t )
345
+ if err != nil {
346
+ t .Fatal (err )
347
+ }
348
+ defer tearDown ()
349
+
350
+ s , _ , closeFn := setup (t )
351
+ defer closeFn ()
352
+
353
+ apiExtensionClient , err := apiextensionsclient .NewForConfig (config )
354
+ if err != nil {
355
+ t .Fatal (err )
356
+ }
357
+
358
+ dynamicClient , err := dynamic .NewForConfig (config )
359
+ if err != nil {
360
+ t .Fatal (err )
361
+ }
362
+
363
+ fooCRD := & apiextensionsv1beta1.CustomResourceDefinition {
364
+ ObjectMeta : metav1.ObjectMeta {
365
+ Name : "foos.cr.bar.com" ,
366
+ },
367
+ Spec : apiextensionsv1beta1.CustomResourceDefinitionSpec {
368
+ Group : "cr.bar.com" ,
369
+ Version : "v1" ,
370
+ Scope : apiextensionsv1beta1 .NamespaceScoped ,
371
+ Names : apiextensionsv1beta1.CustomResourceDefinitionNames {
372
+ Plural : "foos" ,
373
+ Kind : "Foo" ,
374
+ },
375
+ },
376
+ }
377
+ fooCRD , err = fixtures .CreateNewCustomResourceDefinition (fooCRD , apiExtensionClient , dynamicClient )
378
+ if err != nil {
379
+ t .Fatal (err )
380
+ }
381
+ crdGVR := schema.GroupVersionResource {Group : fooCRD .Spec .Group , Version : fooCRD .Spec .Version , Resource : "foos" }
382
+ crclient := dynamicClient .Resource (crdGVR ).Namespace ("default" )
383
+
384
+ testcases := []struct {
385
+ name string
386
+ accept string
387
+ object func (* testing.T ) (metav1.Object , string , string )
388
+ wantErr func (* testing.T , error )
389
+ wantBody func (* testing.T , io.Reader )
390
+ }{
391
+ {
392
+ name : "server returns 406 when asking for protobuf for CRDs" ,
393
+ accept : "application/vnd.kubernetes.protobuf" ,
394
+ object : func (t * testing.T ) (metav1.Object , string , string ) {
395
+ cr , err := crclient .Create (& unstructured.Unstructured {Object : map [string ]interface {}{"apiVersion" : "cr.bar.com/v1" , "kind" : "Foo" , "metadata" : map [string ]interface {}{"name" : "test-1" }}}, metav1.CreateOptions {})
396
+ if err != nil {
397
+ t .Fatalf ("unable to create cr: %v" , err )
398
+ }
399
+ if _ , err := crclient .Patch ("test-1" , types .MergePatchType , []byte (`{"metadata":{"annotations":{"test":"1"}}}` ), metav1.PatchOptions {}); err != nil {
400
+ t .Fatalf ("unable to patch cr: %v" , err )
401
+ }
402
+ return cr , crdGVR .Group , "foos"
403
+ },
404
+ wantErr : func (t * testing.T , err error ) {
405
+ if ! apierrors .IsNotAcceptable (err ) {
406
+ t .Fatal (err )
407
+ }
408
+ // TODO: this should be a more specific error
409
+ if err .Error () != "only the following media types are accepted: application/json, application/yaml" {
410
+ t .Fatal (err )
411
+ }
412
+ },
413
+ },
414
+ {
415
+ name : "server returns JSON when asking for protobuf and json for CRDs" ,
416
+ accept : "application/vnd.kubernetes.protobuf,application/json" ,
417
+ object : func (t * testing.T ) (metav1.Object , string , string ) {
418
+ cr , err := crclient .Create (& unstructured.Unstructured {Object : map [string ]interface {}{"apiVersion" : "cr.bar.com/v1" , "kind" : "Foo" , "spec" : map [string ]interface {}{"field" : 1 }, "metadata" : map [string ]interface {}{"name" : "test-2" }}}, metav1.CreateOptions {})
419
+ if err != nil {
420
+ t .Fatalf ("unable to create cr: %v" , err )
421
+ }
422
+ if _ , err := crclient .Patch ("test-2" , types .MergePatchType , []byte (`{"metadata":{"annotations":{"test":"1"}}}` ), metav1.PatchOptions {}); err != nil {
423
+ t .Fatalf ("unable to patch cr: %v" , err )
424
+ }
425
+ return cr , crdGVR .Group , "foos"
426
+ },
427
+ wantBody : func (t * testing.T , w io.Reader ) {
428
+ obj := & unstructured.Unstructured {}
429
+ if err := json .NewDecoder (w ).Decode (obj ); err != nil {
430
+ t .Fatal (err )
431
+ }
432
+ v , ok , err := unstructured .NestedInt64 (obj .UnstructuredContent (), "spec" , "field" )
433
+ if ! ok || err != nil {
434
+ data , _ := json .MarshalIndent (obj .UnstructuredContent (), "" , " " )
435
+ t .Fatalf ("err=%v ok=%t json=%s" , err , ok , string (data ))
436
+ }
437
+ if v != 1 {
438
+ t .Fatalf ("unexpected body: %#v" , obj .UnstructuredContent ())
439
+ }
440
+ },
441
+ },
442
+ }
443
+
444
+ for i := range testcases {
445
+ tc := testcases [i ]
446
+ t .Run (tc .name , func (t * testing.T ) {
447
+ obj , group , resource := tc .object (t )
448
+
449
+ cfg := dynamic .ConfigFor (config )
450
+ if len (group ) == 0 {
451
+ cfg = dynamic .ConfigFor (& restclient.Config {Host : s .URL })
452
+ cfg .APIPath = "/api"
453
+ } else {
454
+ cfg .APIPath = "/apis"
455
+ }
456
+ cfg .GroupVersion = & schema.GroupVersion {Group : group , Version : "v1" }
457
+ client , err := restclient .RESTClientFor (cfg )
458
+ if err != nil {
459
+ t .Fatal (err )
460
+ }
461
+
462
+ rv , _ := strconv .Atoi (obj .GetResourceVersion ())
463
+ if rv < 1 {
464
+ rv = 1
465
+ }
466
+
467
+ w , err := client .Get ().
468
+ Resource (resource ).NamespaceIfScoped (obj .GetNamespace (), len (obj .GetNamespace ()) > 0 ).Name (obj .GetName ()).
469
+ SetHeader ("Accept" , tc .accept ).
470
+ Stream ()
471
+ if (tc .wantErr != nil ) != (err != nil ) {
472
+ t .Fatalf ("unexpected error: %v" , err )
473
+ }
474
+ if tc .wantErr != nil {
475
+ tc .wantErr (t , err )
476
+ return
477
+ }
478
+ if err != nil {
479
+ t .Fatal (err )
480
+ }
481
+ defer w .Close ()
482
+ tc .wantBody (t , w )
483
+ })
484
+ }
485
+ }
486
+
343
487
func TestTransformOnWatch (t * testing.T ) {
344
488
tearDown , config , _ , err := fixtures .StartDefaultServer (t )
345
489
if err != nil {
0 commit comments