1
16
17 package fake
18
19 import (
20 "context"
21 "fmt"
22 "testing"
23
24 "github.com/google/go-cmp/cmp"
25 "k8s.io/apimachinery/pkg/api/equality"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/runtime"
28 "k8s.io/apimachinery/pkg/runtime/schema"
29 "k8s.io/apimachinery/pkg/types"
30 )
31
32 const (
33 testGroup = "testgroup"
34 testVersion = "testversion"
35 testResource = "testkinds"
36 testNamespace = "testns"
37 testName = "testname"
38 testKind = "TestKind"
39 testAPIVersion = "testgroup/testversion"
40 )
41
42 func newPartialObjectMetadata(apiVersion, kind, namespace, name string) *metav1.PartialObjectMetadata {
43 return &metav1.PartialObjectMetadata{
44 TypeMeta: metav1.TypeMeta{
45 APIVersion: apiVersion,
46 Kind: kind,
47 },
48 ObjectMeta: metav1.ObjectMeta{
49 Namespace: namespace,
50 Name: name,
51 },
52 }
53 }
54
55 func newPartialObjectMetadataWithAnnotations(annotations map[string]string) *metav1.PartialObjectMetadata {
56 u := newPartialObjectMetadata(testAPIVersion, testKind, testNamespace, testName)
57 u.Annotations = annotations
58 return u
59 }
60
61 func TestList(t *testing.T) {
62 scheme := NewTestScheme()
63 metav1.AddMetaToScheme(scheme)
64 client := NewSimpleMetadataClient(scheme,
65 newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-foo"),
66 newPartialObjectMetadata("group2/version", "TheKind", "ns-foo", "name2-foo"),
67 newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-bar"),
68 newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-baz"),
69 newPartialObjectMetadata("group2/version", "TheKind", "ns-foo", "name2-baz"),
70 )
71 listFirst, err := client.Resource(schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}).List(context.TODO(), metav1.ListOptions{})
72 if err != nil {
73 t.Fatal(err)
74 }
75
76 expected := []metav1.PartialObjectMetadata{
77 *newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-bar"),
78 *newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-baz"),
79 *newPartialObjectMetadata("group/version", "TheKind", "ns-foo", "name-foo"),
80 }
81 if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
82 t.Fatal(cmp.Diff(expected, listFirst.Items))
83 }
84 }
85
86 type patchTestCase struct {
87 name string
88 object runtime.Object
89 patchType types.PatchType
90 patchBytes []byte
91 wantErrMsg string
92 expectedPatchedObject runtime.Object
93 }
94
95 func (tc *patchTestCase) runner(t *testing.T) {
96 scheme := NewTestScheme()
97 metav1.AddMetaToScheme(scheme)
98 client := NewSimpleMetadataClient(scheme, tc.object)
99 resourceInterface := client.Resource(schema.GroupVersionResource{Group: testGroup, Version: testVersion, Resource: testResource}).Namespace(testNamespace)
100
101 got, recErr := resourceInterface.Patch(context.TODO(), testName, tc.patchType, tc.patchBytes, metav1.PatchOptions{})
102
103 if err := tc.verifyErr(recErr); err != nil {
104 t.Error(err)
105 }
106
107 if err := tc.verifyResult(got); err != nil {
108 t.Error(err)
109 }
110
111 }
112
113
114
115 func (tc *patchTestCase) verifyErr(err error) error {
116 if tc.wantErrMsg != "" && err == nil {
117 return fmt.Errorf("want error, got nil")
118 }
119
120 if tc.wantErrMsg == "" && err != nil {
121 return fmt.Errorf("want no error, got %v", err)
122 }
123
124 if err != nil {
125 if want, got := tc.wantErrMsg, err.Error(); want != got {
126 return fmt.Errorf("incorrect error: want: %q got: %q", want, got)
127 }
128 }
129 return nil
130 }
131
132 func (tc *patchTestCase) verifyResult(result *metav1.PartialObjectMetadata) error {
133 if tc.expectedPatchedObject == nil && result == nil {
134 return nil
135 }
136 if !equality.Semantic.DeepEqual(result, tc.expectedPatchedObject) {
137 return fmt.Errorf("unexpected diff in received object: %s", cmp.Diff(tc.expectedPatchedObject, result))
138 }
139 return nil
140 }
141
142 func TestPatch(t *testing.T) {
143 testCases := []patchTestCase{
144 {
145 name: "jsonpatch fails with merge type",
146 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
147 patchType: types.StrategicMergePatchType,
148 patchBytes: []byte(`[]`),
149 wantErrMsg: "invalid JSON document",
150 }, {
151 name: "jsonpatch works with empty patch",
152 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
153 patchType: types.JSONPatchType,
154
155 patchBytes: []byte(`[]`),
156 expectedPatchedObject: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
157 }, {
158 name: "jsonpatch works with simple change patch",
159 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
160 patchType: types.JSONPatchType,
161
162 patchBytes: []byte(`[{"op": "replace", "path": "/metadata/annotations/foo", "value": "foobar"}]`),
163 expectedPatchedObject: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "foobar"}),
164 }, {
165 name: "jsonpatch works with simple addition",
166 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
167 patchType: types.JSONPatchType,
168
169 patchBytes: []byte(`[{"op": "add", "path": "/metadata/annotations/newvalue", "value": "dummy"}]`),
170 expectedPatchedObject: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar", "newvalue": "dummy"}),
171 }, {
172 name: "jsonpatch works with simple deletion",
173 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar", "toremove": "shouldnotbehere"}),
174 patchType: types.JSONPatchType,
175
176 patchBytes: []byte(`[{"op": "remove", "path": "/metadata/annotations/toremove"}]`),
177 expectedPatchedObject: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
178 }, {
179 name: "strategic merge patch fails with JSONPatch",
180 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
181 patchType: types.StrategicMergePatchType,
182
183 patchBytes: []byte(`[{"op": "add", "path": "/metadata/annotations/newvalue", "value": "dummy"}]`),
184 wantErrMsg: "invalid JSON document",
185 }, {
186 name: "merge patch works with simple replacement",
187 object: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "bar"}),
188 patchType: types.MergePatchType,
189 patchBytes: []byte(`{ "metadata": {"annotations": { "foo": "baz" } } }`),
190 expectedPatchedObject: newPartialObjectMetadataWithAnnotations(map[string]string{"foo": "baz"}),
191 },
192
193
194 }
195
196 for _, tc := range testCases {
197 t.Run(tc.name, tc.runner)
198 }
199 }
200
View as plain text