func TestEtcdUpdateNotScheduled(t *testing.T) { storage, _, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() if _, err := storage.Create(ctx, validNewPod()); err != nil { t.Fatalf("unexpected error: %v", err) } podIn := validChangedPod() _, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, validNewPod().ObjectMeta.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } podOut := obj.(*api.Pod) // validChangedPod only changes the Labels, so were checking the update was valid if !api.Semantic.DeepEqual(podIn.Labels, podOut.Labels) { t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, podIn)) } }
func runTest(t *testing.T, source interface{}) { name := reflect.TypeOf(source).Elem().Name() TestObjectFuzzer.Fuzz(source) _, codec := GetTestScheme() data, err := runtime.Encode(codec, source.(runtime.Object)) if err != nil { t.Errorf("%v: %v (%#v)", name, err, source) return } obj2, err := runtime.Decode(codec, data) if err != nil { t.Errorf("%v: %v (%v)", name, err, string(data)) return } if !semantic.DeepEqual(source, obj2) { t.Errorf("1: %v: diff: %v", name, diff.ObjectGoPrintSideBySide(source, obj2)) return } obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface() if err := runtime.DecodeInto(codec, data, obj3.(runtime.Object)); err != nil { t.Errorf("2: %v: %v", name, err) return } if !semantic.DeepEqual(source, obj3) { t.Errorf("3: %v: diff: %v", name, diff.ObjectDiff(source, obj3)) return } }
// checkClaims compares all expectedClaims with set of claims at the end of the // test and reports differences. func (r *volumeReactor) checkClaims(expectedClaims []*v1.PersistentVolumeClaim) error { r.lock.Lock() defer r.lock.Unlock() expectedMap := make(map[string]*v1.PersistentVolumeClaim) gotMap := make(map[string]*v1.PersistentVolumeClaim) for _, c := range expectedClaims { c.ResourceVersion = "" expectedMap[c.Name] = c } for _, c := range r.claims { // We must clone the claim because of golang race check - it was // written by the controller without any locks on it. clone, _ := api.Scheme.DeepCopy(c) c = clone.(*v1.PersistentVolumeClaim) c.ResourceVersion = "" gotMap[c.Name] = c } if !reflect.DeepEqual(expectedMap, gotMap) { // Print ugly but useful diff of expected and received objects for // easier debugging. return fmt.Errorf("Claim check failed [A-expected, B-got result]: %s", diff.ObjectDiff(expectedMap, gotMap)) } return nil }
func BenchmarkNodeConversion(b *testing.B) { data, err := ioutil.ReadFile("node_example.json") if err != nil { b.Fatalf("Unexpected error while reading file: %v", err) } var node api.Node if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil { b.Fatalf("Unexpected error decoding node: %v", err) } scheme := api.Scheme var result *api.Node b.ResetTimer() for i := 0; i < b.N; i++ { versionedObj, err := scheme.UnsafeConvertToVersion(&node, api.Registry.GroupOrDie(api.GroupName).GroupVersion) if err != nil { b.Fatalf("Conversion error: %v", err) } obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion()) if err != nil { b.Fatalf("Conversion error: %v", err) } result = obj.(*api.Node) } b.StopTimer() if !api.Semantic.DeepDerivative(node, *result) { b.Fatalf("Incorrect conversion: %s", diff.ObjectDiff(node, *result)) } }
// checkVolumes compares all expectedVolumes with set of volumes at the end of // the test and reports differences. func (r *volumeReactor) checkVolumes(expectedVolumes []*v1.PersistentVolume) error { r.lock.Lock() defer r.lock.Unlock() expectedMap := make(map[string]*v1.PersistentVolume) gotMap := make(map[string]*v1.PersistentVolume) // Clear any ResourceVersion from both sets for _, v := range expectedVolumes { v.ResourceVersion = "" expectedMap[v.Name] = v } for _, v := range r.volumes { // We must clone the volume because of golang race check - it was // written by the controller without any locks on it. clone, _ := api.Scheme.DeepCopy(v) v = clone.(*v1.PersistentVolume) v.ResourceVersion = "" if v.Spec.ClaimRef != nil { v.Spec.ClaimRef.ResourceVersion = "" } gotMap[v.Name] = v } if !reflect.DeepEqual(expectedMap, gotMap) { // Print ugly but useful diff of expected and received objects for // easier debugging. return fmt.Errorf("Volume check failed [A-expected, B-got]: %s", diff.ObjectDiff(expectedMap, gotMap)) } return nil }
func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewContext() key, _ := storage.KeyFunc(ctx, "foo") pvStart := validNewPersistentVolume("foo") err := storage.Storage.Create(ctx, key, pvStart, nil, 0) if err != nil { t.Errorf("unexpected error: %v", err) } pvIn := &api.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, Status: api.PersistentVolumeStatus{ Phase: api.VolumeBound, }, } _, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } pvOut := obj.(*api.PersistentVolume) // only compare the relevant change b/c metadata will differ if !api.Semantic.DeepEqual(pvIn.Status, pvOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(pvIn.Status, pvOut.Status)) } }
func verifyEvents(t *testing.T, expected, actual []*PodLifecycleEvent) { sort.Sort(sortableEvents(expected)) sort.Sort(sortableEvents(actual)) if !reflect.DeepEqual(expected, actual) { t.Errorf("Actual events differ from the expected; diff:\n %v", diff.ObjectDiff(expected, actual)) } }
// needsReconcile compares the given status with the status in the pod manager (which // in fact comes from apiserver), returns whether the status needs to be reconciled with // the apiserver. Now when pod status is inconsistent between apiserver and kubelet, // kubelet should forcibly send an update to reconclie the inconsistence, because kubelet // should be the source of truth of pod status. // NOTE(random-liu): It's simpler to pass in mirror pod uid and get mirror pod by uid, but // now the pod manager only supports getting mirror pod by static pod, so we have to pass // static pod uid here. // TODO(random-liu): Simplify the logic when mirror pod manager is added. func (m *manager) needsReconcile(uid types.UID, status v1.PodStatus) bool { // The pod could be a static pod, so we should translate first. pod, ok := m.podManager.GetPodByUID(uid) if !ok { glog.V(4).Infof("Pod %q has been deleted, no need to reconcile", string(uid)) return false } // If the pod is a static pod, we should check its mirror pod, because only status in mirror pod is meaningful to us. if kubepod.IsStaticPod(pod) { mirrorPod, ok := m.podManager.GetMirrorPodByPod(pod) if !ok { glog.V(4).Infof("Static pod %q has no corresponding mirror pod, no need to reconcile", format.Pod(pod)) return false } pod = mirrorPod } podStatus, err := copyStatus(&pod.Status) if err != nil { return false } normalizeStatus(pod, &podStatus) if isStatusEqual(&podStatus, &status) { // If the status from the source is the same with the cached status, // reconcile is not needed. Just return. return false } glog.V(3).Infof("Pod status is inconsistent with cached status for pod %q, a reconciliation should be triggered:\n %+v", format.Pod(pod), diff.ObjectDiff(podStatus, status)) return true }
// TestEncodePtr tests that a pointer to a golang type can be encoded and // decoded without information loss or mutation. func TestEncodePtr(t *testing.T) { grace := int64(30) pod := &api.Pod{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"name": "foo"}, }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, SchedulerName: api.DefaultSchedulerName, }, } obj := runtime.Object(pod) data, err := runtime.Encode(testapi.Default.Codec(), obj) obj2, err2 := runtime.Decode(testapi.Default.Codec(), data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*api.Pod); !ok { t.Fatalf("Got wrong type") } if !api.Semantic.DeepEqual(obj2, pod) { t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod)) } }
func TestLoadRESTClientConfig(t *testing.T) { testData := []byte(` apiVersion: v1 kind: Config clusters: - cluster: certificate-authority: ca-a.crt server: https://cluster-a.com name: cluster-a - cluster: certificate-authority-data: VGVzdA== server: https://cluster-b.com name: cluster-b contexts: - context: cluster: cluster-a namespace: ns-a user: user-a name: context-a - context: cluster: cluster-b namespace: ns-b user: user-b name: context-b current-context: context-b users: - name: user-a user: token: mytoken-a - name: user-b user: token: mytoken-b `) f, err := ioutil.TempFile("", "kubeconfig") if err != nil { t.Fatal(err) } defer os.Remove(f.Name()) ioutil.WriteFile(f.Name(), testData, os.FileMode(0755)) config, err := loadRESTClientConfig(f.Name()) if err != nil { t.Fatal(err) } expectedConfig := &restclient.Config{ Host: "https://cluster-b.com", TLSClientConfig: restclient.TLSClientConfig{ CAData: []byte(`Test`), }, BearerToken: "mytoken-b", } if !reflect.DeepEqual(config, expectedConfig) { t.Errorf("Unexpected config: %s", diff.ObjectDiff(config, expectedConfig)) } }
func TestGet_NoError(t *testing.T) { r := NewTestREST(testResponse{result: probe.Success, data: "ok"}) got, err := r.Get(genericapirequest.NewContext(), "test1", &metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } expect := createTestStatus("test1", api.ConditionTrue, "ok", "") if e, a := expect, got; !reflect.DeepEqual(e, a) { t.Errorf("Got unexpected object. Diff: %s", diff.ObjectDiff(e, a)) } }
func TestList_NoError(t *testing.T) { r := NewTestREST(testResponse{result: probe.Success, data: "ok"}) got, err := r.List(genericapirequest.NewContext(), nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } expect := &api.ComponentStatusList{ Items: []api.ComponentStatus{*(createTestStatus("test1", api.ConditionTrue, "ok", ""))}, } if e, a := expect, got; !reflect.DeepEqual(e, a) { t.Errorf("Got unexpected object. Diff: %s", diff.ObjectDiff(e, a)) } }
func TestUpdateStatus(t *testing.T) { storage, status, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") resourcequotaStart := validNewResourceQuota() err := storage.Storage.Create(ctx, key, resourcequotaStart, nil, 0) if err != nil { t.Fatalf("Unexpected error: %v", err) } resourcequotaIn := &api.ResourceQuota{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Status: api.ResourceQuotaStatus{ Used: api.ResourceList{ api.ResourceCPU: resource.MustParse("1"), api.ResourceMemory: resource.MustParse("1Gi"), api.ResourcePods: resource.MustParse("1"), api.ResourceServices: resource.MustParse("1"), api.ResourceReplicationControllers: resource.MustParse("1"), api.ResourceQuotas: resource.MustParse("1"), }, Hard: api.ResourceList{ api.ResourceCPU: resource.MustParse("100"), api.ResourceMemory: resource.MustParse("4Gi"), api.ResourcePods: resource.MustParse("10"), api.ResourceServices: resource.MustParse("10"), api.ResourceReplicationControllers: resource.MustParse("10"), api.ResourceQuotas: resource.MustParse("1"), }, }, } _, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) rqOut := obj.(*api.ResourceQuota) // only compare the meaningful update b/c we can't compare due to metadata if !api.Semantic.DeepEqual(resourcequotaIn.Status, rqOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(resourcequotaIn, rqOut)) } }
func (test configCommandTest) run(t *testing.T) string { out, actualConfig := testConfigCommand(test.args, test.startingConfig, t) testSetNilMapsToEmpties(reflect.ValueOf(&test.expectedConfig)) testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig)) testClearLocationOfOrigin(&actualConfig) if !api.Semantic.DeepEqual(test.expectedConfig, actualConfig) { t.Errorf("diff: %v", diff.ObjectDiff(test.expectedConfig, actualConfig)) t.Errorf("expected: %#v\n actual: %#v", test.expectedConfig, actualConfig) } test.checkOutput(out, test.expectedOutputs, t) return out }
func TestConverter_MapElemAddr(t *testing.T) { type Foo struct { A map[int]int } type Bar struct { A map[string]string } c := NewConverter(DefaultNameFunc) c.Debug = testLogger(t) err := c.RegisterConversionFunc( func(in *int, out *string, s Scope) error { *out = fmt.Sprintf("%v", *in) return nil }, ) if err != nil { t.Fatalf("Unexpected error: %v", err) } err = c.RegisterConversionFunc( func(in *string, out *int, s Scope) error { if str, err := strconv.Atoi(*in); err != nil { return err } else { *out = str return nil } }, ) if err != nil { t.Fatalf("Unexpected error: %v", err) } f := fuzz.New().NilChance(0).NumElements(3, 3) first := Foo{} second := Bar{} f.Fuzz(&first) err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } third := Foo{} err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil) if e, a := first, third; !reflect.DeepEqual(e, a) { t.Errorf("Unexpected diff: %v", diff.ObjectDiff(e, a)) } }
func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") pvcStart := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) err := storage.Storage.Create(ctx, key, pvcStart, nil, 0) pvc := &api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("3Gi"), }, }, }, Status: api.PersistentVolumeClaimStatus{ Phase: api.ClaimBound, }, } _, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } pvcOut := obj.(*api.PersistentVolumeClaim) // only compare relevant changes b/c of difference in metadata if !api.Semantic.DeepEqual(pvc.Status, pvcOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(pvc.Status, pvcOut.Status)) } }
func TestSetListToMatchingType(t *testing.T) { pl := &unstructured.UnstructuredList{} list := []runtime.Object{ &unstructured.Unstructured{Object: map[string]interface{}{"foo": 1}}, &unstructured.Unstructured{Object: map[string]interface{}{"foo": 2}}, &unstructured.Unstructured{Object: map[string]interface{}{"foo": 3}}, } err := meta.SetList(pl, list) if err != nil { t.Fatalf("Unexpected error %v", err) } if e, a := len(list), len(pl.Items); e != a { t.Fatalf("Expected %v, got %v", e, a) } for i := range list { if e, a := list[i], pl.Items[i]; e != a { t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a)) } } }
func TestSetListToRuntimeObjectArray(t *testing.T) { pl := &api.List{} list := []runtime.Object{ &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "1"}}, &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "2"}}, &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "3"}}, } err := meta.SetList(pl, list) if err != nil { t.Fatalf("Unexpected error %v", err) } if e, a := len(list), len(pl.Items); e != a { t.Fatalf("Expected %v, got %v", e, a) } for i := range list { if e, a := list[i], pl.Items[i]; e != a { t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a)) } } }
func TestConverter_fuzz(t *testing.T) { // Use the same types from the scheme test. table := []struct { from, to, check interface{} }{ {&TestType1{}, &ExternalTestType1{}, &TestType1{}}, {&ExternalTestType1{}, &TestType1{}, &ExternalTestType1{}}, } f := fuzz.New().NilChance(.5).NumElements(0, 100) c := NewConverter(DefaultNameFunc) c.nameFunc = func(t reflect.Type) string { // Hide the fact that we don't have separate packages for these things. return map[reflect.Type]string{ reflect.TypeOf(TestType1{}): "TestType1", reflect.TypeOf(ExternalTestType1{}): "TestType1", reflect.TypeOf(TestType2{}): "TestType2", reflect.TypeOf(ExternalTestType2{}): "TestType2", }[t] } c.Debug = testLogger(t) for i, item := range table { for j := 0; j < *fuzzIters; j++ { f.Fuzz(item.from) err := c.Convert(item.from, item.to, 0, nil) if err != nil { t.Errorf("(%v, %v): unexpected error: %v", i, j, err) continue } err = c.Convert(item.to, item.check, 0, nil) if err != nil { t.Errorf("(%v, %v): unexpected error: %v", i, j, err) continue } if e, a := item.from, item.check; !reflect.DeepEqual(e, a) { t.Errorf("(%v, %v): unexpected diff: %v", i, j, diff.ObjectDiff(e, a)) } } } }
func (d *defaultCacheMutationDetector) CompareObjects() { d.lock.Lock() defer d.lock.Unlock() altered := false for i, obj := range d.cachedObjs { if !reflect.DeepEqual(obj.cached, obj.copied) { fmt.Printf("CACHE %s[%d] ALTERED!\n%v\n", d.name, i, diff.ObjectDiff(obj.cached, obj.copied)) altered = true } } if altered { msg := fmt.Sprintf("cache %s modified", d.name) if d.failureFunc != nil { d.failureFunc(msg) return } panic(msg) } }
func (test stepParserTest) run(t *testing.T) { actualSteps, err := newNavigationSteps(test.path) if len(test.expectedError) != 0 { if err == nil { t.Errorf("Did not get %v", test.expectedError) } else { if !strings.Contains(err.Error(), test.expectedError) { t.Errorf("Expected %v, but got %v", test.expectedError, err) } } return } if err != nil { t.Errorf("Unexpected error: %v", err) } if !reflect.DeepEqual(test.expectedNavigationSteps, *actualSteps) { t.Errorf("diff: %v", diff.ObjectDiff(test.expectedNavigationSteps, *actualSteps)) t.Errorf("expected: %#v\n actual: %#v", test.expectedNavigationSteps, *actualSteps) } }
func TestScaleGet(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.ReplicaSet.Store.DestroyFunc() name := "foo" var rs extensions.ReplicaSet ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), api.NamespaceDefault) key := "/replicasets/" + api.NamespaceDefault + "/" + name if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0); err != nil { t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err) } want := &extensions.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: api.NamespaceDefault, UID: rs.UID, ResourceVersion: rs.ResourceVersion, CreationTimestamp: rs.CreationTimestamp, }, Spec: extensions.ScaleSpec{ Replicas: validReplicaSet.Spec.Replicas, }, Status: extensions.ScaleStatus{ Replicas: validReplicaSet.Status.Replicas, Selector: validReplicaSet.Spec.Selector, }, } obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) got := obj.(*extensions.Scale) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } if !api.Semantic.DeepEqual(got, want) { t.Errorf("unexpected scale: %s", diff.ObjectDiff(got, want)) } }
func TestGetAttrs(t *testing.T) { eventA := &api.Event{ ObjectMeta: metav1.ObjectMeta{ Name: "f0118", Namespace: "default", }, InvolvedObject: api.ObjectReference{ Kind: "Pod", Name: "foo", Namespace: "baz", UID: "long uid string", APIVersion: api.Registry.GroupOrDie(api.GroupName).GroupVersion.String(), ResourceVersion: "0", FieldPath: "", }, Reason: "ForTesting", Source: api.EventSource{Component: "test"}, Type: api.EventTypeNormal, } field := EventToSelectableFields(eventA) expect := fields.Set{ "metadata.name": "f0118", "metadata.namespace": "default", "involvedObject.kind": "Pod", "involvedObject.name": "foo", "involvedObject.namespace": "baz", "involvedObject.uid": "long uid string", "involvedObject.apiVersion": api.Registry.GroupOrDie(api.GroupName).GroupVersion.String(), "involvedObject.resourceVersion": "0", "involvedObject.fieldPath": "", "reason": "ForTesting", "source": "test", "type": api.EventTypeNormal, } if e, a := expect, field; !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", diff.ObjectDiff(e, a)) } }
func TestScaleGet(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.Controller.Store.DestroyFunc() ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace) rc, err := createController(storage.Controller, *validController, t) if err != nil { t.Fatalf("error setting new replication controller %v: %v", *validController, err) } want := &autoscaling.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, UID: rc.UID, ResourceVersion: rc.ResourceVersion, CreationTimestamp: rc.CreationTimestamp, }, Spec: autoscaling.ScaleSpec{ Replicas: validController.Spec.Replicas, }, Status: autoscaling.ScaleStatus{ Replicas: validController.Status.Replicas, Selector: labels.SelectorFromSet(validController.Spec.Template.Labels).String(), }, } obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } got := obj.(*autoscaling.Scale) if !api.Semantic.DeepEqual(want, got) { t.Errorf("unexpected scale: %s", diff.ObjectDiff(want, got)) } }
func TestScaleGet(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.Deployment.Store.DestroyFunc() var deployment extensions.Deployment ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace) key := "/deployments/" + namespace + "/" + name if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, &deployment, 0); err != nil { t.Fatalf("error setting new deployment (key: %s) %v: %v", key, validDeployment, err) } want := &extensions.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, UID: deployment.UID, ResourceVersion: deployment.ResourceVersion, CreationTimestamp: deployment.CreationTimestamp, }, Spec: extensions.ScaleSpec{ Replicas: validDeployment.Spec.Replicas, }, Status: extensions.ScaleStatus{ Replicas: validDeployment.Status.Replicas, Selector: validDeployment.Spec.Selector, }, } obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } got := obj.(*extensions.Scale) if !api.Semantic.DeepEqual(want, got) { t.Errorf("unexpected scale: %s", diff.ObjectDiff(want, got)) } }
func TestConverter_FieldRename(t *testing.T) { type WeirdMeta struct { Name string Type string } type NameMeta struct { Name string } type TypeMeta struct { Type string } type A struct { WeirdMeta } type B struct { TypeMeta NameMeta } c := NewConverter(DefaultNameFunc) err := c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", TypeMeta{}, "TypeMeta") if err != nil { t.Fatalf("unexpected error %v", err) } err = c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", NameMeta{}, "NameMeta") if err != nil { t.Fatalf("unexpected error %v", err) } err = c.SetStructFieldCopy(TypeMeta{}, "TypeMeta", WeirdMeta{}, "WeirdMeta") if err != nil { t.Fatalf("unexpected error %v", err) } err = c.SetStructFieldCopy(NameMeta{}, "NameMeta", WeirdMeta{}, "WeirdMeta") if err != nil { t.Fatalf("unexpected error %v", err) } c.Debug = testLogger(t) aVal := &A{ WeirdMeta: WeirdMeta{ Name: "Foo", Type: "Bar", }, } bVal := &B{ TypeMeta: TypeMeta{"Bar"}, NameMeta: NameMeta{"Foo"}, } table := map[string]struct { from, to, expect interface{} flags FieldMatchingFlags }{ "to": { aVal, &B{}, bVal, AllowDifferentFieldTypeNames | SourceToDest | IgnoreMissingFields, }, "from": { bVal, &A{}, aVal, AllowDifferentFieldTypeNames | SourceToDest, }, "toDestFirst": { aVal, &B{}, bVal, AllowDifferentFieldTypeNames, }, "fromDestFirst": { bVal, &A{}, aVal, AllowDifferentFieldTypeNames | IgnoreMissingFields, }, } for name, item := range table { err := c.Convert(item.from, item.to, item.flags, nil) if err != nil { t.Errorf("%v: unexpected error: %v", name, err) continue } if e, a := item.expect, item.to; !reflect.DeepEqual(e, a) { t.Errorf("%v: unexpected diff: %v", name, diff.ObjectDiff(e, a)) } } }
func TestDefaultRuleResolver(t *testing.T) { ruleReadPods := rbac.PolicyRule{ Verbs: []string{"GET", "WATCH"}, APIGroups: []string{"v1"}, Resources: []string{"pods"}, } ruleReadServices := rbac.PolicyRule{ Verbs: []string{"GET", "WATCH"}, APIGroups: []string{"v1"}, Resources: []string{"services"}, } ruleWriteNodes := rbac.PolicyRule{ Verbs: []string{"PUT", "CREATE", "UPDATE"}, APIGroups: []string{"v1"}, Resources: []string{"nodes"}, } ruleAdmin := rbac.PolicyRule{ Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}, } staticRoles1 := StaticRoles{ roles: []*rbac.Role{ { ObjectMeta: metav1.ObjectMeta{Namespace: "namespace1", Name: "readthings"}, Rules: []rbac.PolicyRule{ruleReadPods, ruleReadServices}, }, }, clusterRoles: []*rbac.ClusterRole{ { ObjectMeta: metav1.ObjectMeta{Name: "cluster-admin"}, Rules: []rbac.PolicyRule{ruleAdmin}, }, { ObjectMeta: metav1.ObjectMeta{Name: "write-nodes"}, Rules: []rbac.PolicyRule{ruleWriteNodes}, }, }, roleBindings: []*rbac.RoleBinding{ { ObjectMeta: metav1.ObjectMeta{Namespace: "namespace1"}, Subjects: []rbac.Subject{ {Kind: rbac.UserKind, Name: "foobar"}, {Kind: rbac.GroupKind, Name: "group1"}, }, RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "readthings"}, }, }, clusterRoleBindings: []*rbac.ClusterRoleBinding{ { Subjects: []rbac.Subject{ {Kind: rbac.UserKind, Name: "admin"}, {Kind: rbac.GroupKind, Name: "admin"}, }, RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "cluster-admin"}, }, }, } tests := []struct { StaticRoles // For a given context, what are the rules that apply? user user.Info namespace string effectiveRules []rbac.PolicyRule }{ { StaticRoles: staticRoles1, user: &user.DefaultInfo{Name: "foobar"}, namespace: "namespace1", effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices}, }, { StaticRoles: staticRoles1, user: &user.DefaultInfo{Name: "foobar"}, namespace: "namespace2", effectiveRules: []rbac.PolicyRule{}, }, { StaticRoles: staticRoles1, // Same as above but without a namespace. Only cluster rules should apply. user: &user.DefaultInfo{Name: "foobar", Groups: []string{"admin"}}, effectiveRules: []rbac.PolicyRule{ruleAdmin}, }, { StaticRoles: staticRoles1, user: &user.DefaultInfo{}, effectiveRules: []rbac.PolicyRule{}, }, } for i, tc := range tests { ruleResolver := newMockRuleResolver(&tc.StaticRoles) rules, err := ruleResolver.RulesFor(tc.user, tc.namespace) if err != nil { t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err) continue } // Sort for deep equals sort.Sort(byHash(rules)) sort.Sort(byHash(tc.effectiveRules)) if !reflect.DeepEqual(rules, tc.effectiveRules) { ruleDiff := diff.ObjectDiff(rules, tc.effectiveRules) t.Errorf("case %d: %s", i, ruleDiff) } } }
func TestEtcdUpdateStatus(t *testing.T) { storage, _, statusStorage, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") podStart := api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{ { Image: "foo:v1", SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(), }, }, SecurityContext: &api.PodSecurityContext{}, SchedulerName: api.DefaultSchedulerName, }, } err := storage.Storage.Create(ctx, key, &podStart, nil, 0) if err != nil { t.Errorf("unexpected error: %v", err) } podIn := api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Labels: map[string]string{ "foo": "bar", }, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{ { Image: "foo:v2", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePath: api.TerminationMessagePathDefault, }, }, SecurityContext: &api.PodSecurityContext{}, SchedulerName: api.DefaultSchedulerName, }, Status: api.PodStatus{ Phase: api.PodRunning, PodIP: "127.0.0.1", Message: "is now scheduled", }, } expected := podStart expected.ResourceVersion = "2" grace := int64(30) expected.Spec.TerminationGracePeriodSeconds = &grace expected.Spec.RestartPolicy = api.RestartPolicyAlways expected.Spec.DNSPolicy = api.DNSClusterFirst expected.Spec.Containers[0].ImagePullPolicy = api.PullIfNotPresent expected.Spec.Containers[0].TerminationMessagePath = api.TerminationMessagePathDefault expected.Labels = podIn.Labels expected.Status = podIn.Status _, _, err = statusStorage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } podOut := obj.(*api.Pod) // Check to verify the Label, and Status updates match from change above. Those are the fields changed. if !api.Semantic.DeepEqual(podOut.Spec, expected.Spec) || !api.Semantic.DeepEqual(podOut.Labels, expected.Labels) || !api.Semantic.DeepEqual(podOut.Status, expected.Status) { t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, expected)) } }
func TestEtcdUpdateScheduled(t *testing.T) { storage, _, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") err := storage.Storage.Create(ctx, key, &api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{ { Name: "foobar", Image: "foo:v1", SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(), }, }, SecurityContext: &api.PodSecurityContext{}, SchedulerName: api.DefaultSchedulerName, }, }, nil, 1) if err != nil { t.Errorf("Unexpected error: %v", err) } grace := int64(30) podIn := api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Labels: map[string]string{ "foo": "bar", }, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{{ Name: "foobar", Image: "foo:v2", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePath: api.TerminationMessagePathDefault, SecurityContext: securitycontext.ValidInternalSecurityContextWithContainerDefaults(), }}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, SchedulerName: api.DefaultSchedulerName, }, } _, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Errorf("Unexpected error: %v", err) } podOut := obj.(*api.Pod) // Check to verify the Spec and Label updates match from change above. Those are the fields changed. if !api.Semantic.DeepEqual(podOut.Spec, podIn.Spec) || !api.Semantic.DeepEqual(podOut.Labels, podIn.Labels) { t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, podIn)) } }
func TestAPIs(t *testing.T) { tests := []struct { name string apiservices []*apiregistration.APIService expected *metav1.APIGroupList }{ { name: "empty", apiservices: []*apiregistration.APIService{}, expected: &metav1.APIGroupList{ TypeMeta: metav1.TypeMeta{Kind: "APIGroupList", APIVersion: "v1"}, Groups: []metav1.APIGroup{ discoveryGroup, }, }, }, { name: "simple add", apiservices: []*apiregistration.APIService{ { ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "foo", Version: "v1", Priority: 10, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "v1.bar"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "bar", Version: "v1", Priority: 11, }, }, }, expected: &metav1.APIGroupList{ TypeMeta: metav1.TypeMeta{Kind: "APIGroupList", APIVersion: "v1"}, Groups: []metav1.APIGroup{ discoveryGroup, { Name: "foo", Versions: []metav1.GroupVersionForDiscovery{ { GroupVersion: "foo/v1", Version: "v1", }, }, PreferredVersion: metav1.GroupVersionForDiscovery{ GroupVersion: "foo/v1", Version: "v1", }, }, { Name: "bar", Versions: []metav1.GroupVersionForDiscovery{ { GroupVersion: "bar/v1", Version: "v1", }, }, PreferredVersion: metav1.GroupVersionForDiscovery{ GroupVersion: "bar/v1", Version: "v1", }, }, }, }, }, { name: "sorting", apiservices: []*apiregistration.APIService{ { ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "foo", Version: "v1", Priority: 20, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "v2.bar"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "bar", Version: "v2", Priority: 11, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "v2.foo"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "foo", Version: "v2", Priority: 1, }, }, { ObjectMeta: metav1.ObjectMeta{Name: "v1.bar"}, Spec: apiregistration.APIServiceSpec{ Service: apiregistration.ServiceReference{ Namespace: "ns", Name: "api", }, Group: "bar", Version: "v1", Priority: 11, }, }, }, expected: &metav1.APIGroupList{ TypeMeta: metav1.TypeMeta{Kind: "APIGroupList", APIVersion: "v1"}, Groups: []metav1.APIGroup{ discoveryGroup, { Name: "foo", Versions: []metav1.GroupVersionForDiscovery{ { GroupVersion: "foo/v2", Version: "v2", }, { GroupVersion: "foo/v1", Version: "v1", }, }, PreferredVersion: metav1.GroupVersionForDiscovery{ GroupVersion: "foo/v2", Version: "v2", }, }, { Name: "bar", Versions: []metav1.GroupVersionForDiscovery{ { GroupVersion: "bar/v1", Version: "v1", }, { GroupVersion: "bar/v2", Version: "v2", }, }, PreferredVersion: metav1.GroupVersionForDiscovery{ GroupVersion: "bar/v1", Version: "v1", }, }, }, }, }, } for _, tc := range tests { indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) endpointsIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) delegate := &delegationHTTPHandler{} handler := &apisHandler{ serviceLister: v1listers.NewServiceLister(serviceIndexer), endpointsLister: v1listers.NewEndpointsLister(endpointsIndexer), lister: listers.NewAPIServiceLister(indexer), delegate: delegate, } for _, o := range tc.apiservices { indexer.Add(o) } serviceIndexer.Add(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "api"}}) endpointsIndexer.Add(&corev1.Endpoints{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "api"}, Subsets: []corev1.EndpointSubset{ {Addresses: []corev1.EndpointAddress{{}}}, }, }, ) server := httptest.NewServer(handler) defer server.Close() resp, err := http.Get(server.URL + "/apis") if err != nil { t.Errorf("%s: %v", tc.name, err) continue } bytes, err := ioutil.ReadAll(resp.Body) if err != nil { t.Errorf("%s: %v", tc.name, err) continue } actual := &metav1.APIGroupList{} if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), bytes, actual); err != nil { t.Errorf("%s: %v", tc.name, err) continue } if !api.Semantic.DeepEqual(tc.expected, actual) { t.Errorf("%s: %v", tc.name, diff.ObjectDiff(tc.expected, actual)) continue } } }