@@ -39,9 +39,14 @@ import (
39
39
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
40
40
"k8s.io/apimachinery/pkg/runtime"
41
41
"k8s.io/apimachinery/pkg/types"
42
+ "k8s.io/apimachinery/pkg/util/intstr"
42
43
"k8s.io/apimachinery/pkg/util/wait"
43
44
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
45
+ appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
46
+ corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
47
+ metav1ac "k8s.io/client-go/applyconfigurations/meta/v1"
44
48
clientset "k8s.io/client-go/kubernetes"
49
+ "k8s.io/client-go/kubernetes/fake"
45
50
restclient "k8s.io/client-go/rest"
46
51
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
47
52
"k8s.io/kubernetes/test/integration/framework"
@@ -4421,6 +4426,109 @@ spec:
4421
4426
` )
4422
4427
}
4423
4428
4429
+ func TestApplyMatchesFakeClientsetApply (t * testing.T ) {
4430
+ client , closeFn := setup (t )
4431
+ defer closeFn ()
4432
+ fakeClient := fake .NewClientset ()
4433
+
4434
+ // The fake client does not default fields, so we set all defaulted fields directly.
4435
+ deployment := appsv1ac .Deployment ("deployment" , "default" ).
4436
+ WithLabels (map [string ]string {"app" : "nginx" }).
4437
+ WithSpec (appsv1ac .DeploymentSpec ().
4438
+ WithReplicas (3 ).
4439
+ WithStrategy (appsv1ac .DeploymentStrategy ().
4440
+ WithType (appsv1 .RollingUpdateDeploymentStrategyType ).
4441
+ WithRollingUpdate (appsv1ac .RollingUpdateDeployment ().
4442
+ WithMaxUnavailable (intstr .FromString ("25%" )).
4443
+ WithMaxSurge (intstr .FromString ("25%" )))).
4444
+ WithRevisionHistoryLimit (10 ).
4445
+ WithProgressDeadlineSeconds (600 ).
4446
+ WithSelector (metav1ac .LabelSelector ().
4447
+ WithMatchLabels (map [string ]string {"app" : "nginx" })).
4448
+ WithTemplate (corev1ac .PodTemplateSpec ().
4449
+ WithLabels (map [string ]string {"app" : "nginx" }).
4450
+ WithSpec (corev1ac .PodSpec ().
4451
+ WithRestartPolicy (v1 .RestartPolicyAlways ).
4452
+ WithTerminationGracePeriodSeconds (30 ).
4453
+ WithDNSPolicy (v1 .DNSClusterFirst ).
4454
+ WithSecurityContext (corev1ac .PodSecurityContext ()).
4455
+ WithSchedulerName ("default-scheduler" ).
4456
+ WithContainers (corev1ac .Container ().
4457
+ WithName ("nginx" ).
4458
+ WithImage ("nginx:latest" ).
4459
+ WithTerminationMessagePath ("/dev/termination-log" ).
4460
+ WithTerminationMessagePolicy ("File" ).
4461
+ WithImagePullPolicy (v1 .PullAlways )))))
4462
+ fieldManager := "m-1"
4463
+
4464
+ realCreated , err := client .AppsV1 ().Deployments ("default" ).Apply (context .TODO (), deployment , metav1.ApplyOptions {FieldManager : fieldManager })
4465
+ if err != nil {
4466
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
4467
+ }
4468
+
4469
+ fakeCreated , err := fakeClient .AppsV1 ().Deployments ("default" ).Apply (context .TODO (), deployment , metav1.ApplyOptions {FieldManager : fieldManager })
4470
+ if err != nil {
4471
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
4472
+ }
4473
+
4474
+ // wipe metadata except name, namespace, labels and managedFields (but wipe timestamps in managedFields)
4475
+ realCreated .ObjectMeta = wipeMetadataForFakeClientTests (realCreated .ObjectMeta )
4476
+ fakeCreated .ObjectMeta = wipeMetadataForFakeClientTests (fakeCreated .ObjectMeta )
4477
+ // wipe status
4478
+ realCreated .Status = appsv1.DeploymentStatus {}
4479
+ fakeCreated .Status = appsv1.DeploymentStatus {}
4480
+ // TODO: Remove once https://github.com/kubernetes/kubernetes/issues/125671 is fixed.
4481
+ fakeCreated .TypeMeta = metav1.TypeMeta {}
4482
+
4483
+ if diff := cmp .Diff (realCreated , fakeCreated ); diff != "" {
4484
+ t .Errorf ("Unexpected fake created: (-want +got): %v" , diff )
4485
+ }
4486
+
4487
+ // Force apply with a different field manager
4488
+ deploymentUpdate := appsv1ac .Deployment ("deployment" , "default" ).
4489
+ WithSpec (appsv1ac .DeploymentSpec ().
4490
+ WithReplicas (4 ))
4491
+ updateManager := "m-2"
4492
+ realUpdated , err := client .AppsV1 ().Deployments ("default" ).Apply (context .TODO (), deploymentUpdate , metav1.ApplyOptions {FieldManager : updateManager , Force : true })
4493
+ if err != nil {
4494
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
4495
+ }
4496
+
4497
+ fakeUpdated , err := fakeClient .AppsV1 ().Deployments ("default" ).Apply (context .TODO (), deploymentUpdate , metav1.ApplyOptions {FieldManager : updateManager , Force : true })
4498
+ if err != nil {
4499
+ t .Fatalf ("Failed to create object using Apply patch: %v" , err )
4500
+ }
4501
+
4502
+ // wipe metadata except name, namespace, labels and managedFields (but wipe timestamps in managedFields)
4503
+ realUpdated .ObjectMeta = wipeMetadataForFakeClientTests (realUpdated .ObjectMeta )
4504
+ fakeUpdated .ObjectMeta = wipeMetadataForFakeClientTests (fakeUpdated .ObjectMeta )
4505
+ // wipe status
4506
+ realUpdated .Status = appsv1.DeploymentStatus {}
4507
+ fakeUpdated .Status = appsv1.DeploymentStatus {}
4508
+ // TODO: Remove once https://github.com/kubernetes/kubernetes/issues/125671 is fixed.
4509
+ fakeUpdated .TypeMeta = metav1.TypeMeta {}
4510
+
4511
+ if diff := cmp .Diff (realUpdated , fakeUpdated ); diff != "" {
4512
+ t .Errorf ("Unexpected fake updated: (-want +got): %v" , diff )
4513
+ }
4514
+ }
4515
+
4516
+ var wipeTime = metav1 .NewTime (time .Date (2000 , 1 , 1 , 0 , 0 , 0 , 0 , time .FixedZone ("EDT" , - 4 * 60 * 60 )))
4517
+
4518
+ func wipeMetadataForFakeClientTests (meta metav1.ObjectMeta ) metav1.ObjectMeta {
4519
+ wipedManagedFields := make ([]metav1.ManagedFieldsEntry , len (meta .ManagedFields ))
4520
+ copy (meta .ManagedFields , wipedManagedFields )
4521
+ for _ , mf := range wipedManagedFields {
4522
+ mf .Time = & wipeTime
4523
+ }
4524
+ return metav1.ObjectMeta {
4525
+ Name : meta .Name ,
4526
+ Namespace : meta .Namespace ,
4527
+ Labels : meta .Labels ,
4528
+ ManagedFields : wipedManagedFields ,
4529
+ }
4530
+ }
4531
+
4424
4532
func expectManagedFields (t * testing.T , managedFields []metav1.ManagedFieldsEntry , expect string ) {
4425
4533
t .Helper ()
4426
4534
for i := range managedFields {
0 commit comments