github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/test/api_meta_meta_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package test 18 19 import ( 20 "reflect" 21 "testing" 22 23 fuzz "github.com/google/gofuzz" 24 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/api/meta" 25 metafuzzer "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/fuzzer" 26 metav1 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/v1" 27 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/testapigroup" 28 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime" 29 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 30 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer" 31 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/types" 32 ) 33 34 func TestAPIObjectMeta(t *testing.T) { 35 j := &testapigroup.Carp{ 36 TypeMeta: metav1.TypeMeta{APIVersion: "/a", Kind: "b"}, 37 ObjectMeta: metav1.ObjectMeta{ 38 Namespace: "bar", 39 Name: "foo", 40 GenerateName: "prefix", 41 UID: "uid", 42 ResourceVersion: "1", 43 SelfLink: "some/place/only/we/know", 44 Labels: map[string]string{"foo": "bar"}, 45 Annotations: map[string]string{"x": "y"}, 46 Finalizers: []string{ 47 "finalizer.1", 48 "finalizer.2", 49 }, 50 }, 51 } 52 var _ metav1.Object = &j.ObjectMeta 53 var _ metav1.ObjectMetaAccessor = j 54 accessor, err := meta.Accessor(j) 55 if err != nil { 56 t.Fatalf("unexpected error: %v", err) 57 } 58 if accessor != metav1.Object(j) { 59 t.Fatalf("should have returned the same pointer: %#v\n\n%#v", accessor, j) 60 } 61 if e, a := "bar", accessor.GetNamespace(); e != a { 62 t.Errorf("expected %v, got %v", e, a) 63 } 64 if e, a := "foo", accessor.GetName(); e != a { 65 t.Errorf("expected %v, got %v", e, a) 66 } 67 if e, a := "prefix", accessor.GetGenerateName(); e != a { 68 t.Errorf("expected %v, got %v", e, a) 69 } 70 if e, a := "uid", string(accessor.GetUID()); e != a { 71 t.Errorf("expected %v, got %v", e, a) 72 } 73 if e, a := "1", accessor.GetResourceVersion(); e != a { 74 t.Errorf("expected %v, got %v", e, a) 75 } 76 if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a { 77 t.Errorf("expected %v, got %v", e, a) 78 } 79 if e, a := []string{"finalizer.1", "finalizer.2"}, accessor.GetFinalizers(); !reflect.DeepEqual(e, a) { 80 t.Errorf("expected %v, got %v", e, a) 81 } 82 83 typeAccessor, err := meta.TypeAccessor(j) 84 if err != nil { 85 t.Fatalf("unexpected error: %v", err) 86 } 87 if e, a := "a", typeAccessor.GetAPIVersion(); e != a { 88 t.Errorf("expected %v, got %v", e, a) 89 } 90 if e, a := "b", typeAccessor.GetKind(); e != a { 91 t.Errorf("expected %v, got %v", e, a) 92 } 93 94 accessor.SetNamespace("baz") 95 accessor.SetName("bar") 96 accessor.SetGenerateName("generate") 97 accessor.SetUID("other") 98 typeAccessor.SetAPIVersion("c") 99 typeAccessor.SetKind("d") 100 accessor.SetResourceVersion("2") 101 accessor.SetSelfLink("google.com") 102 accessor.SetFinalizers([]string{"finalizer.3"}) 103 104 // Prove that accessor changes the original object. 105 if e, a := "baz", j.Namespace; e != a { 106 t.Errorf("expected %v, got %v", e, a) 107 } 108 if e, a := "bar", j.Name; e != a { 109 t.Errorf("expected %v, got %v", e, a) 110 } 111 if e, a := "generate", j.GenerateName; e != a { 112 t.Errorf("expected %v, got %v", e, a) 113 } 114 if e, a := types.UID("other"), j.UID; e != a { 115 t.Errorf("expected %v, got %v", e, a) 116 } 117 if e, a := "c", j.APIVersion; e != a { 118 t.Errorf("expected %v, got %v", e, a) 119 } 120 if e, a := "d", j.Kind; e != a { 121 t.Errorf("expected %v, got %v", e, a) 122 } 123 if e, a := "2", j.ResourceVersion; e != a { 124 t.Errorf("expected %v, got %v", e, a) 125 } 126 if e, a := "google.com", j.SelfLink; e != a { 127 t.Errorf("expected %v, got %v", e, a) 128 } 129 if e, a := []string{"finalizer.3"}, j.Finalizers; !reflect.DeepEqual(e, a) { 130 t.Errorf("expected %v, got %v", e, a) 131 } 132 133 typeAccessor.SetAPIVersion("d") 134 typeAccessor.SetKind("e") 135 if e, a := "d", j.APIVersion; e != a { 136 t.Errorf("expected %v, got %v", e, a) 137 } 138 if e, a := "e", j.Kind; e != a { 139 t.Errorf("expected %v, got %v", e, a) 140 } 141 } 142 143 func TestGenericTypeMeta(t *testing.T) { 144 type TypeMeta struct { 145 Kind string `json:"kind,omitempty"` 146 Namespace string `json:"namespace,omitempty"` 147 Name string `json:"name,omitempty"` 148 GenerateName string `json:"generateName,omitempty"` 149 UID string `json:"uid,omitempty"` 150 CreationTimestamp metav1.Time `json:"creationTimestamp,omitempty"` 151 SelfLink string `json:"selfLink,omitempty"` 152 ResourceVersion string `json:"resourceVersion,omitempty"` 153 APIVersion string `json:"apiVersion,omitempty"` 154 Labels map[string]string `json:"labels,omitempty"` 155 Annotations map[string]string `json:"annotations,omitempty"` 156 OwnerReferences []metav1.OwnerReference `json:"ownerReferences,omitempty"` 157 Finalizers []string `json:"finalizers,omitempty"` 158 } 159 160 j := struct{ TypeMeta }{TypeMeta{APIVersion: "a", Kind: "b"}} 161 162 typeAccessor, err := meta.TypeAccessor(&j) 163 if err != nil { 164 t.Fatalf("unexpected error: %v", err) 165 } 166 if e, a := "a", typeAccessor.GetAPIVersion(); e != a { 167 t.Errorf("expected %v, got %v", e, a) 168 } 169 if e, a := "b", typeAccessor.GetKind(); e != a { 170 t.Errorf("expected %v, got %v", e, a) 171 } 172 173 typeAccessor.SetAPIVersion("c") 174 typeAccessor.SetKind("d") 175 176 if e, a := "c", j.APIVersion; e != a { 177 t.Errorf("expected %v, got %v", e, a) 178 } 179 if e, a := "d", j.Kind; e != a { 180 t.Errorf("expected %v, got %v", e, a) 181 } 182 183 typeAccessor.SetAPIVersion("d") 184 typeAccessor.SetKind("e") 185 186 if e, a := "d", j.APIVersion; e != a { 187 t.Errorf("expected %v, got %v", e, a) 188 } 189 if e, a := "e", j.Kind; e != a { 190 t.Errorf("expected %v, got %v", e, a) 191 } 192 } 193 194 type InternalTypeMeta struct { 195 Kind string `json:"kind,omitempty"` 196 Namespace string `json:"namespace,omitempty"` 197 Name string `json:"name,omitempty"` 198 GenerateName string `json:"generateName,omitempty"` 199 UID string `json:"uid,omitempty"` 200 CreationTimestamp metav1.Time `json:"creationTimestamp,omitempty"` 201 SelfLink string `json:"selfLink,omitempty"` 202 ResourceVersion string `json:"resourceVersion,omitempty"` 203 Continue string `json:"next,omitempty"` 204 RemainingItemCount *int64 `json:"remainingItemCount,omitempty"` 205 APIVersion string `json:"apiVersion,omitempty"` 206 Labels map[string]string `json:"labels,omitempty"` 207 Annotations map[string]string `json:"annotations,omitempty"` 208 Finalizers []string `json:"finalizers,omitempty"` 209 OwnerReferences []metav1.OwnerReference `json:"ownerReferences,omitempty"` 210 } 211 212 func (m *InternalTypeMeta) GetResourceVersion() string { return m.ResourceVersion } 213 func (m *InternalTypeMeta) SetResourceVersion(rv string) { m.ResourceVersion = rv } 214 func (m *InternalTypeMeta) GetSelfLink() string { return m.SelfLink } 215 func (m *InternalTypeMeta) SetSelfLink(link string) { m.SelfLink = link } 216 func (m *InternalTypeMeta) GetContinue() string { return m.Continue } 217 func (m *InternalTypeMeta) SetContinue(c string) { m.Continue = c } 218 func (m *InternalTypeMeta) GetRemainingItemCount() *int64 { return m.RemainingItemCount } 219 func (m *InternalTypeMeta) SetRemainingItemCount(c *int64) { m.RemainingItemCount = c } 220 221 type MyAPIObject struct { 222 TypeMeta InternalTypeMeta `json:",inline"` 223 } 224 225 func (obj *MyAPIObject) GetListMeta() metav1.ListInterface { return &obj.TypeMeta } 226 227 func (obj *MyAPIObject) GetObjectKind() schema.ObjectKind { return obj } 228 func (obj *MyAPIObject) SetGroupVersionKind(gvk schema.GroupVersionKind) { 229 obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind() 230 } 231 func (obj *MyAPIObject) GroupVersionKind() schema.GroupVersionKind { 232 return schema.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind) 233 } 234 func (obj *MyAPIObject) DeepCopyObject() runtime.Object { 235 panic("MyAPIObject does not support DeepCopy") 236 } 237 238 type MyIncorrectlyMarkedAsAPIObject struct{} 239 240 func (obj *MyIncorrectlyMarkedAsAPIObject) GetObjectKind() schema.ObjectKind { 241 return schema.EmptyObjectKind 242 } 243 func (obj *MyIncorrectlyMarkedAsAPIObject) DeepCopyObject() runtime.Object { 244 panic("MyIncorrectlyMarkedAsAPIObject does not support DeepCopy") 245 } 246 247 func TestResourceVersionerOfAPI(t *testing.T) { 248 type T struct { 249 runtime.Object 250 Expected string 251 } 252 testCases := map[string]T{ 253 "empty api object": {&MyAPIObject{}, ""}, 254 "api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"}, 255 "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"}, 256 } 257 versioning := meta.NewAccessor() 258 for key, testCase := range testCases { 259 actual, err := versioning.ResourceVersion(testCase.Object) 260 if err != nil { 261 t.Errorf("%s: unexpected error %#v", key, err) 262 } 263 if actual != testCase.Expected { 264 t.Errorf("%s: expected %v, got %v", key, testCase.Expected, actual) 265 } 266 } 267 268 failingCases := map[string]struct { 269 runtime.Object 270 Expected string 271 }{ 272 "not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, "1"}, 273 } 274 for key, testCase := range failingCases { 275 _, err := versioning.ResourceVersion(testCase.Object) 276 if err == nil { 277 t.Errorf("%s: expected error, got nil", key) 278 } 279 } 280 281 setCases := map[string]struct { 282 runtime.Object 283 Expected string 284 }{ 285 "pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"}, 286 } 287 for key, testCase := range setCases { 288 if err := versioning.SetResourceVersion(testCase.Object, "5"); err != nil { 289 t.Errorf("%s: unexpected error %#v", key, err) 290 } 291 actual, err := versioning.ResourceVersion(testCase.Object) 292 if err != nil { 293 t.Errorf("%s: unexpected error %#v", key, err) 294 } 295 if actual != "5" { 296 t.Errorf("%s: expected %v, got %v", key, "5", actual) 297 } 298 } 299 } 300 301 type MyAPIObject2 struct { 302 metav1.TypeMeta 303 metav1.ObjectMeta 304 } 305 306 func getObjectMetaAndOwnerReferences() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metav1.OwnerReference) { 307 scheme := runtime.NewScheme() 308 codecs := serializer.NewCodecFactory(scheme) 309 fuzz.New().NilChance(.5).NumElements(1, 5).Funcs(metafuzzer.Funcs(codecs)...).MaxDepth(10).Fuzz(&myAPIObject2) 310 references := myAPIObject2.ObjectMeta.OwnerReferences 311 // This is necessary for the test to pass because the getter will return a 312 // non-nil slice. 313 metaOwnerReferences = make([]metav1.OwnerReference, 0) 314 for i := 0; i < len(references); i++ { 315 metaOwnerReferences = append(metaOwnerReferences, metav1.OwnerReference{ 316 Kind: references[i].Kind, 317 Name: references[i].Name, 318 UID: references[i].UID, 319 APIVersion: references[i].APIVersion, 320 Controller: references[i].Controller, 321 BlockOwnerDeletion: references[i].BlockOwnerDeletion, 322 }) 323 } 324 if len(references) == 0 { 325 // This is necessary for the test to pass because the setter will make a 326 // non-nil slice. 327 myAPIObject2.ObjectMeta.OwnerReferences = make([]metav1.OwnerReference, 0) 328 } 329 return myAPIObject2, metaOwnerReferences 330 } 331 332 func testGetOwnerReferences(t *testing.T) { 333 obj, expected := getObjectMetaAndOwnerReferences() 334 accessor, err := meta.Accessor(&obj) 335 if err != nil { 336 t.Error(err) 337 } 338 references := accessor.GetOwnerReferences() 339 if !reflect.DeepEqual(references, expected) { 340 t.Errorf("expect %#v\n got %#v", expected, references) 341 } 342 } 343 344 func testSetOwnerReferences(t *testing.T) { 345 expected, references := getObjectMetaAndOwnerReferences() 346 obj := MyAPIObject2{} 347 accessor, err := meta.Accessor(&obj) 348 if err != nil { 349 t.Error(err) 350 } 351 accessor.SetOwnerReferences(references) 352 if e, a := expected.ObjectMeta.OwnerReferences, obj.ObjectMeta.OwnerReferences; !reflect.DeepEqual(e, a) { 353 t.Errorf("expect %#v\n got %#v", e, a) 354 } 355 } 356 357 func TestAccessOwnerReferences(t *testing.T) { 358 fuzzIter := 5 359 for i := 0; i < fuzzIter; i++ { 360 testGetOwnerReferences(t) 361 testSetOwnerReferences(t) 362 } 363 } 364 365 // BenchmarkAccessorSetFastPath shows the interface fast path 366 func BenchmarkAccessorSetFastPath(b *testing.B) { 367 obj := &testapigroup.Carp{ 368 TypeMeta: metav1.TypeMeta{APIVersion: "/a", Kind: "b"}, 369 ObjectMeta: metav1.ObjectMeta{ 370 Namespace: "bar", 371 Name: "foo", 372 GenerateName: "prefix", 373 UID: "uid", 374 ResourceVersion: "1", 375 SelfLink: "some/place/only/we/know", 376 Labels: map[string]string{"foo": "bar"}, 377 Annotations: map[string]string{"x": "y"}, 378 }, 379 } 380 381 b.ResetTimer() 382 for i := 0; i < b.N; i++ { 383 acc, err := meta.Accessor(obj) 384 if err != nil { 385 b.Fatal(err) 386 } 387 acc.SetNamespace("something") 388 } 389 b.StopTimer() 390 }