Skip to content

Commit b96a83a

Browse files
committed
pkg/client/actionclient_test.go: add tests for createPatch
1 parent 935dc3f commit b96a83a

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed

pkg/client/actionclient_test.go

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package client
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"strconv"
@@ -9,14 +10,20 @@ import (
910
. "github.com/onsi/gomega"
1011
"helm.sh/helm/v3/pkg/action"
1112
"helm.sh/helm/v3/pkg/chartutil"
13+
"helm.sh/helm/v3/pkg/kube"
1214
"helm.sh/helm/v3/pkg/release"
1315
"helm.sh/helm/v3/pkg/releaseutil"
1416
"helm.sh/helm/v3/pkg/storage/driver"
17+
appsv1 "k8s.io/api/apps/v1"
1518
v1 "k8s.io/api/core/v1"
1619
apierrors "k8s.io/apimachinery/pkg/api/errors"
1720
"k8s.io/apimachinery/pkg/api/meta"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1822
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1923
"k8s.io/apimachinery/pkg/runtime"
24+
"k8s.io/apimachinery/pkg/runtime/schema"
25+
apitypes "k8s.io/apimachinery/pkg/types"
26+
"k8s.io/cli-runtime/pkg/resource"
2027
"sigs.k8s.io/controller-runtime/pkg/client"
2128
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2229
"sigs.k8s.io/yaml"
@@ -40,6 +47,21 @@ var _ = Describe("ActionClient", func() {
4047
})
4148
})
4249

50+
var _ = Describe("ActionClientGetterFunc", func() {
51+
It("implements the ActionClientGetter interface", func() {
52+
gvk := schema.GroupVersionKind{Group: "test", Version: "v1alpha1", Kind: "Test"}
53+
expectedObj := &unstructured.Unstructured{}
54+
expectedObj.SetGroupVersionKind(gvk)
55+
var actualObj Object
56+
f := ActionClientGetterFunc(func(obj Object) (ActionInterface, error) {
57+
actualObj = obj
58+
return nil, nil
59+
})
60+
_, _ = f.ActionClientFor(expectedObj)
61+
Expect(actualObj.GetObjectKind().GroupVersionKind()).To(Equal(gvk))
62+
})
63+
})
64+
4365
var _ = Describe("ActionClientFor", func() {
4466
var obj Object
4567
BeforeEach(func() {
@@ -310,6 +332,201 @@ var _ = Describe("ActionClient", func() {
310332
})
311333
})
312334
})
335+
336+
var _ = Describe("createPatch", func() {
337+
It("ignores extra fields in custom resource types", func() {
338+
o1 := newTestUnstructured([]interface{}{
339+
map[string]interface{}{
340+
"name": "test1",
341+
},
342+
map[string]interface{}{
343+
"name": "test2",
344+
},
345+
})
346+
o2 := &resource.Info{
347+
Object: newTestUnstructured([]interface{}{
348+
map[string]interface{}{
349+
"name": "test1",
350+
},
351+
}),
352+
}
353+
patch, patchType, err := createPatch(o1, o2)
354+
Expect(err).To(BeNil())
355+
Expect(string(patch)).To(Equal(``))
356+
Expect(patchType).To(Equal(apitypes.JSONPatchType))
357+
})
358+
It("patches missing fields in custom resource types", func() {
359+
o1 := newTestUnstructured([]interface{}{
360+
map[string]interface{}{
361+
"name": "test1",
362+
},
363+
})
364+
o2 := &resource.Info{
365+
Object: newTestUnstructured([]interface{}{
366+
map[string]interface{}{
367+
"name": "test1",
368+
},
369+
map[string]interface{}{
370+
"name": "test2",
371+
},
372+
}),
373+
}
374+
patch, patchType, err := createPatch(o1, o2)
375+
Expect(err).To(BeNil())
376+
Expect(string(patch)).To(Equal(`[{"op":"add","path":"/spec/template/spec/containers/1","value":{"name":"test2"}}]`))
377+
Expect(patchType).To(Equal(apitypes.JSONPatchType))
378+
})
379+
It("ignores nil fields in custom resource types", func() {
380+
o1 := newTestUnstructured([]interface{}{
381+
map[string]interface{}{
382+
"name": "test1",
383+
},
384+
})
385+
o2 := &resource.Info{
386+
Object: newTestUnstructured([]interface{}{
387+
map[string]interface{}{
388+
"name": "test1",
389+
"test": nil,
390+
},
391+
}),
392+
}
393+
patch, patchType, err := createPatch(o1, o2)
394+
Expect(err).To(BeNil())
395+
Expect(string(patch)).To(Equal(``))
396+
Expect(patchType).To(Equal(apitypes.JSONPatchType))
397+
})
398+
It("replaces incorrect fields in custom resource types", func() {
399+
o1 := newTestUnstructured([]interface{}{
400+
map[string]interface{}{
401+
"name": "test1",
402+
},
403+
})
404+
o2 := &resource.Info{
405+
Object: newTestUnstructured([]interface{}{
406+
map[string]interface{}{
407+
"name": "test2",
408+
},
409+
}),
410+
}
411+
patch, patchType, err := createPatch(o1, o2)
412+
Expect(err).To(BeNil())
413+
Expect(string(patch)).To(Equal(`[{"op":"replace","path":"/spec/template/spec/containers/0/name","value":"test2"}]`))
414+
Expect(patchType).To(Equal(apitypes.JSONPatchType))
415+
})
416+
It("ignores extra fields in core types", func() {
417+
o1 := newTestDeployment([]v1.Container{
418+
{Name: "test1"},
419+
{Name: "test2"},
420+
})
421+
o2 := &resource.Info{
422+
Object: newTestDeployment([]v1.Container{
423+
{Name: "test1"},
424+
}),
425+
}
426+
patch, patchType, err := createPatch(o1, o2)
427+
Expect(err).To(BeNil())
428+
Expect(string(patch)).To(Equal(`{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"test1"}]}}}}`))
429+
Expect(patchType).To(Equal(apitypes.StrategicMergePatchType))
430+
})
431+
It("patches missing fields in core types", func() {
432+
o1 := newTestDeployment([]v1.Container{
433+
{Name: "test1"},
434+
})
435+
o2 := &resource.Info{
436+
Object: newTestDeployment([]v1.Container{
437+
{Name: "test1"},
438+
{Name: "test2"},
439+
}),
440+
}
441+
patch, patchType, err := createPatch(o1, o2)
442+
Expect(err).To(BeNil())
443+
Expect(string(patch)).To(Equal(`{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"test1"},{"name":"test2"}],"containers":[{"name":"test2","resources":{}}]}}}}`))
444+
Expect(patchType).To(Equal(apitypes.StrategicMergePatchType))
445+
})
446+
It("ignores nil fields in core types", func() {
447+
o1 := newTestDeployment([]v1.Container{
448+
{Name: "test1"},
449+
})
450+
o2 := &resource.Info{
451+
Object: newTestDeployment([]v1.Container{
452+
{Name: "test1", LivenessProbe: nil},
453+
}),
454+
}
455+
patch, patchType, err := createPatch(o1, o2)
456+
Expect(err).To(BeNil())
457+
Expect(string(patch)).To(Equal(`{}`))
458+
Expect(patchType).To(Equal(apitypes.StrategicMergePatchType))
459+
})
460+
It("replaces incorrect fields in core types", func() {
461+
o1 := newTestDeployment([]v1.Container{
462+
{Name: "test1"},
463+
})
464+
o2 := &resource.Info{
465+
Object: newTestDeployment([]v1.Container{
466+
{Name: "test2"},
467+
}),
468+
}
469+
patch, patchType, err := createPatch(o1, o2)
470+
Expect(err).To(BeNil())
471+
Expect(string(patch)).To(Equal(`{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"test2"}],"containers":[{"name":"test2","resources":{}}]}}}}`))
472+
Expect(patchType).To(Equal(apitypes.StrategicMergePatchType))
473+
})
474+
It("does not remove extra annotations in core types", func() {
475+
o1 := &appsv1.Deployment{
476+
TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "apps/v1"},
477+
ObjectMeta: metav1.ObjectMeta{
478+
Name: "test",
479+
Namespace: "ns",
480+
Annotations: map[string]string{
481+
"testannotation": "testvalue",
482+
},
483+
},
484+
Spec: appsv1.DeploymentSpec{},
485+
}
486+
o2 := &resource.Info{
487+
Object: &appsv1.Deployment{
488+
TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "apps/v1"},
489+
ObjectMeta: metav1.ObjectMeta{
490+
Name: "test",
491+
Namespace: "ns",
492+
},
493+
Spec: appsv1.DeploymentSpec{},
494+
},
495+
}
496+
patch, patchType, err := createPatch(o1, o2)
497+
Expect(err).To(BeNil())
498+
Expect(string(patch)).To(Equal(`{}`))
499+
Expect(patchType).To(Equal(apitypes.StrategicMergePatchType))
500+
})
501+
})
502+
503+
var _ = Describe("ownerPostRenderer", func() {
504+
var (
505+
pr ownerPostRenderer
506+
owner Object
507+
)
508+
509+
BeforeEach(func() {
510+
rm, err := apiutil.NewDynamicRESTMapper(cfg)
511+
Expect(err).To(BeNil())
512+
513+
owner = newTestUnstructured([]interface{}{
514+
map[string]interface{}{
515+
"name": "test1",
516+
},
517+
})
518+
pr = ownerPostRenderer{
519+
owner: owner,
520+
rm: rm,
521+
kubeClient: kube.New(newRESTClientGetter(cfg, rm, owner.GetNamespace())),
522+
}
523+
})
524+
525+
It("fails on invalid input", func() {
526+
_, err := pr.Run(bytes.NewBufferString("test"))
527+
Expect(err).NotTo(BeNil())
528+
})
529+
})
313530
})
314531

315532
func manifestToObjects(manifest string) []runtime.Object {
@@ -378,3 +595,37 @@ func verifyNoRelease(cl client.Client, ns string, name string, rel *release.Rele
378595
}
379596
})
380597
}
598+
599+
func newTestUnstructured(containers []interface{}) *unstructured.Unstructured {
600+
return &unstructured.Unstructured{
601+
Object: map[string]interface{}{
602+
"kind": "MyResource",
603+
"apiVersion": "myApi",
604+
"metadata": map[string]interface{}{
605+
"name": "test",
606+
"namespace": "ns",
607+
},
608+
"spec": map[string]interface{}{
609+
"template": map[string]interface{}{
610+
"spec": map[string]interface{}{
611+
"containers": containers,
612+
},
613+
},
614+
},
615+
},
616+
}
617+
}
618+
619+
func newTestDeployment(containers []v1.Container) *appsv1.Deployment {
620+
return &appsv1.Deployment{
621+
TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "apps/v1"},
622+
ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "ns"},
623+
Spec: appsv1.DeploymentSpec{
624+
Template: v1.PodTemplateSpec{
625+
Spec: v1.PodSpec{
626+
Containers: containers,
627+
},
628+
},
629+
},
630+
}
631+
}

0 commit comments

Comments
 (0)