func TestUpdateImageStreamOK(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data["/imagestreams/default/bar"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"}, }), ModifiedIndex: 2, }, }, } storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) obj, created, err := storage.Update(ctx, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "1"}}) if !errors.IsConflict(err) { t.Fatalf("unexpected non-error: %v", err) } obj, created, err = storage.Update(ctx, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "2"}}) if err != nil || created { t.Fatalf("Unexpected non-nil error: %#v", err) } stream, ok := obj.(*api.ImageStream) if !ok { t.Errorf("Expected image stream, got %#v", obj) } if stream.Name != "bar" { t.Errorf("Unexpected stream returned: %#v", stream) } }
func TestEtcdControllerValidatesUpdate(t *testing.T) { ctx := api.NewDefaultContext() storage, _ := newStorage(t) updateController, err := createController(storage, validController, t) if err != nil { t.Errorf("Failed to create controller, cannot proceed with test.") } updaters := []func(rc api.ReplicationController) (runtime.Object, bool, error){ func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.UID = "newUID" return storage.Update(ctx, &rc) }, func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.Name = "" return storage.Update(ctx, &rc) }, func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.Spec.Selector = map[string]string{} return storage.Update(ctx, &rc) }, } for _, u := range updaters { c, updated, err := u(updateController) if c != nil || updated { t.Errorf("Expected nil object and not created") } if !errors.IsInvalid(err) && !errors.IsBadRequest(err) { t.Errorf("Expected invalid or bad request error, got %v of type %T", err, err) } } }
func TestGenerationNumber(t *testing.T) { storage, _ := newStorage(t) modifiedSno := validController modifiedSno.Generation = 100 modifiedSno.Status.ObservedGeneration = 10 ctx := api.NewDefaultContext() rc, err := createController(storage, modifiedSno, t) ctrl, err := storage.Get(ctx, rc.Name) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ := ctrl.(*api.ReplicationController) // Generation initialization if controller.Generation != 1 && controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number %v, status generation %v", controller.Generation, controller.Status.ObservedGeneration) } // Updates to spec should increment the generation number controller.Spec.Replicas += 1 storage.Update(ctx, controller) if err != nil { t.Errorf("unexpected error: %v", err) } ctrl, err = storage.Get(ctx, rc.Name) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ = ctrl.(*api.ReplicationController) if controller.Generation != 2 || controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation, spec: %v, status: %v", controller.Generation, controller.Status.ObservedGeneration) } // Updates to status should not increment either spec or status generation numbers controller.Status.Replicas += 1 storage.Update(ctx, controller) if err != nil { t.Errorf("unexpected error: %v", err) } ctrl, err = storage.Get(ctx, rc.Name) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ = ctrl.(*api.ReplicationController) if controller.Generation != 2 || controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number, spec: %v, status: %v", controller.Generation, controller.Status.ObservedGeneration) } }
func TestEtcdUpdateEndpoints(t *testing.T) { ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t) endpoints := validChangedEndpoints() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewEndpoints()), 0) _, _, err := storage.Update(ctx, endpoints) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error %v", err) } var endpointsOut api.Endpoints err = latest.Codec.DecodeInto([]byte(response.Node.Value), &endpointsOut) if err != nil { t.Errorf("unexpected error: %v", err) } endpoints.ObjectMeta.ResourceVersion = endpointsOut.ObjectMeta.ResourceVersion if !api.Semantic.DeepEqual(endpoints, &endpointsOut) { t.Errorf("Unexpected endpoints: %#v, expected %#v", &endpointsOut, endpoints) } }
func TestEtcdUpdateEndpoints(t *testing.T) { ctx := api.NewContext() storage, fakeClient := newStorage(t) node := validChangedNode() key, _ := storage.KeyFunc(ctx, node.Name) key = etcdtest.AddPrefix(key) fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewNode()), 0) _, _, err := storage.Update(ctx, node) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error %v", err) } var nodeOut api.Node err = latest.Codec.DecodeInto([]byte(response.Node.Value), &nodeOut) if err != nil { t.Errorf("unexpected error: %v", err) } node.ObjectMeta.ResourceVersion = nodeOut.ObjectMeta.ResourceVersion if !api.Semantic.DeepEqual(node, &nodeOut) { t.Errorf("Unexpected node: %#v, expected %#v", &nodeOut, node) } }
func TestEtcdUpdateNotScheduled(t *testing.T) { storage, _, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := api.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) 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) 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 TestUpdateWithConflictingNamespace(t *testing.T) { fakeEtcdClient, etcdStorage := newEtcdStorage(t) storage := NewStorage(etcdStorage, nil).Pod ctx := api.NewDefaultContext() key, _ := storage.Etcd.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: api.PodSpec{NodeName: "machine"}, }), ModifiedIndex: 1, }, }, } pod := validChangedPod() pod.Namespace = "not-default" obj, created, err := storage.Update(api.NewDefaultContext(), pod) if obj != nil || created { t.Error("Expected a nil channel, but we got a value or created") } if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if strings.Index(err.Error(), "the namespace of the provided object does not match the namespace sent on the request") == -1 { t.Errorf("Expected 'Pod.Namespace does not match the provided context' error, got '%v'", err.Error()) } }
func TestUpdateImageStreamConflictingNamespace(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data["/imagestreams/legal-name/bar"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"}, }), ModifiedIndex: 2, }, }, } storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "legal-name"), &fakeUser{}) obj, created, err := storage.Update(ctx, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "some-value", ResourceVersion: "2"}, }) if obj != nil || created { t.Error("Expected a nil obj, but we got a value") } checkExpectedNamespaceError(t, err) }
func TestStrategyPrepareMethods(t *testing.T) { _, helper := newHelper(t) storage, _ := NewREST(helper, testDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) stream := validNewStream() strategy := fakeStrategy{imagestream.NewStrategy(testDefaultRegistry, &fakeSubjectAccessReviewRegistry{})} storage.store.CreateStrategy = strategy storage.store.UpdateStrategy = strategy ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) obj, err := storage.Create(ctx, stream) if err != nil { t.Fatalf("Unexpected error: %v", err) } updatedStream := obj.(*api.ImageStream) if updatedStream.Annotations["test"] != "PrepareForCreate" { t.Errorf("Expected PrepareForCreate annotation") } obj, _, err = storage.Update(ctx, updatedStream) if err != nil { t.Errorf("Unexpected error: %v", err) } updatedStream = obj.(*api.ImageStream) if updatedStream.Annotations["test"] != "PrepareForUpdate" { t.Errorf("Expected PrepareForUpdate annotation") } }
func TestEtcdUpdatePersistentVolumes(t *testing.T) { ctx := api.NewContext() storage, _, fakeClient, _ := newStorage(t) persistentVolume := validChangedPersistentVolume() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewPersistentVolume("foo")), 0) _, _, err := storage.Update(ctx, persistentVolume) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error %v", err) } var persistentVolumeOut api.PersistentVolume err = latest.Codec.DecodeInto([]byte(response.Node.Value), &persistentVolumeOut) if err != nil { t.Errorf("unexpected error: %v", err) } persistentVolume.ObjectMeta.ResourceVersion = persistentVolumeOut.ObjectMeta.ResourceVersion if !api.Semantic.DeepEqual(persistentVolume, &persistentVolumeOut) { t.Errorf("Unexpected persistentVolume: %#v, expected %#v", &persistentVolumeOut, persistentVolume) } }
func TestUpdate(t *testing.T) { storage, _, si, destroyFunc := newStorage(t) defer destroyFunc() ctx := api.WithNamespace(api.NewContext(), "test") key := "/controllers/test/foo" if err := si.Create(ctx, key, &validController, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := int32(12) update := extensions.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } updated := obj.(*extensions.Scale) if updated.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, updated.Spec.Replicas) } }
func TestUpdate(t *testing.T) { storage, fakeClient := newStorage(t) ctx := api.WithNamespace(api.NewContext(), "test") key := etcdtest.AddPrefix("/controllers/test/foo") if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &validController), 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := 12 update := extensions.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("unexpected error: %v", err) } var controller api.ReplicationController testapi.Extensions.Codec().DecodeInto([]byte(response.Node.Value), &controller) if controller.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, controller.Spec.Replicas) } }
func TestUpdate(t *testing.T) { storage, server, si := newStorage(t) defer server.Terminate(t) ctx := api.WithNamespace(api.NewContext(), "test") key := etcdtest.AddPrefix("/controllers/test/foo") if err := si.Set(ctx, key, &validController, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := 12 update := extensions.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, &update); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo") if err != nil { t.Fatalf("unexpected error: %v", err) } updated := obj.(*extensions.Scale) if updated.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, updated.Spec.Replicas) } }
func TestUpdateRegistryErrorSaving(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Err = fmt.Errorf("foo") storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) _, created, err := storage.Update(kapi.NewDefaultContext(), &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar"}}) if err != fakeEtcdClient.Err || created { t.Fatalf("Unexpected non-nil error: %#v", err) } }
func TestUpdateImageStreamMissingID(t *testing.T) { _, helper := newHelper(t) storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) obj, created, err := storage.Update(kapi.NewDefaultContext(), &api.ImageStream{}) if obj != nil || created { t.Fatalf("Expected nil, got %v", obj) } if strings.Index(err.Error(), "Name parameter required") == -1 { t.Errorf("Expected 'Name parameter required' error, got %v", err) } }
func TestEtcdControllerValidatesNamespaceOnUpdate(t *testing.T) { storage, _ := newStorage(t) ns := "newnamespace" // The update should fail if the namespace on the controller is set to something // other than the namespace on the given context, even if the namespace on the // controller is valid. updateController, err := createController(storage, validController, t) newNamespaceController := validController newNamespaceController.Namespace = ns _, err = createController(storage, newNamespaceController, t) c, updated, err := storage.Update(api.WithNamespace(api.NewContext(), ns), &updateController) if c != nil || updated { t.Errorf("Expected nil object and not created") } // TODO: Be more paranoid about the type of error and make sure it has the substring // "namespace" in it, once #5684 is fixed. Ideally this would be a NewBadRequest. if err == nil { t.Errorf("Expected an error, but we didn't get one") } }
func TestEtcdUpdateNotScheduled(t *testing.T) { storage, _, _, fakeClient := newStorage(t) ctx := api.NewDefaultContext() fakeClient.TestIndex = true key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), validNewPod()), 1) podIn := validChangedPod() _, _, err := storage.Update(ctx, podIn) if err != nil { t.Errorf("Unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } podOut := &api.Pod{} testapi.Default.Codec().DecodeInto([]byte(response.Node.Value), podOut) if !api.Semantic.DeepEqual(podOut, podIn) { t.Errorf("objects differ: %v", util.ObjectDiff(podOut, podIn)) } }
func TestEtcdUpdateController(t *testing.T) { ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t) key, _ := makeControllerKey(ctx, validController.Name) key = etcdtest.AddPrefix(key) // set a key, then retrieve the current resource version and try updating it resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0) update := validController update.ResourceVersion = strconv.FormatUint(resp.Node.ModifiedIndex, 10) update.Spec.Replicas = validController.Spec.Replicas + 1 _, created, err := storage.Update(ctx, &update) if err != nil { t.Errorf("unexpected error: %v", err) } if created { t.Errorf("expected an update but created flag was returned") } ctrl, err := storage.Get(ctx, validController.Name) updatedController, _ := ctrl.(*api.ReplicationController) if updatedController.Spec.Replicas != validController.Spec.Replicas+1 { t.Errorf("Unexpected controller: %#v", ctrl) } }
func TestUpdate(t *testing.T) { fakeEtcdClient, etcdStorage := newEtcdStorage(t) storage := NewStorage(etcdStorage).Scale key := etcdtest.AddPrefix("/controllers/test/foo") fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &validController), ModifiedIndex: 1, }, }, } replicas := 12 update := expapi.Scale{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: expapi.ScaleSpec{ Replicas: replicas, }, } _, _, err := storage.Update(api.WithNamespace(api.NewContext(), "test"), &update) if err != nil { t.Fatalf("Unexpected error: %v", err) } response, err := fakeEtcdClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } var controller api.ReplicationController latest.Codec.DecodeInto([]byte(response.Node.Value), &controller) if controller.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, controller.Spec.Replicas) } }
func TestEtcdUpdateScheduled(t *testing.T) { storage, _, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := api.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) err := storage.Storage.Create(ctx, key, &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{ { Name: "foobar", Image: "foo:v1", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }, }, SecurityContext: &api.PodSecurityContext{}, }, }, nil, 1) if err != nil { t.Errorf("Unexpected error: %v", err) } grace := int64(30) podIn := api.Pod{ ObjectMeta: api.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.ValidSecurityContextWithContainerDefaults(), }}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, }, } _, _, 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") 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 TestUpdateResetsMetadata(t *testing.T) { testCases := []struct { image *api.Image existing *api.Image expect func(*api.Image) bool }{ // manifest changes are ignored { expect: func(image *api.Image) bool { if image.Labels["a"] != "b" { t.Errorf("unexpected labels: %s", image.Labels) return false } if image.DockerImageManifest != "" { t.Errorf("unexpected manifest: %s", image.DockerImageManifest) return false } if image.DockerImageMetadata.ID != "foo" { t.Errorf("unexpected docker image: %#v", image.DockerImageMetadata) return false } if image.DockerImageReference != "openshift/ruby-19-centos-2" { t.Errorf("image reference changed: %s", image.DockerImageReference) return false } if image.DockerImageMetadata.Size != 0 { t.Errorf("image had size %d", image.DockerImageMetadata.Size) return false } if len(image.DockerImageLayers) != 1 && image.DockerImageLayers[0].Size != 10 { t.Errorf("unexpected layers: %#v", image.DockerImageLayers) return false } return true }, existing: &api.Image{ ObjectMeta: kapi.ObjectMeta{Name: "foo", ResourceVersion: "1"}, DockerImageReference: "openshift/ruby-19-centos-2", DockerImageLayers: []api.ImageLayer{{Name: "test", Size: 10}}, DockerImageMetadata: api.DockerImage{ID: "foo"}, }, image: &api.Image{ ObjectMeta: kapi.ObjectMeta{Name: "foo", ResourceVersion: "1", Labels: map[string]string{"a": "b"}}, DockerImageReference: "openshift/ruby-19-centos", DockerImageManifest: etcdManifest, }, }, // existing manifest is preserved, and unpacked { expect: func(image *api.Image) bool { if image.DockerImageManifest != etcdManifest { t.Errorf("unexpected manifest: %s", image.DockerImageManifest) return false } if image.DockerImageMetadata.ID != "fe50ac14986497fa6b5d2cc24feb4a561d01767bc64413752c0988cb70b0b8b9" { t.Errorf("unexpected docker image: %#v", image.DockerImageMetadata) return false } if image.DockerImageReference != "openshift/ruby-19-centos-2" { t.Errorf("image reference changed: %s", image.DockerImageReference) return false } if image.DockerImageMetadata.Size != 28643712 { t.Errorf("image had size %d", image.DockerImageMetadata.Size) return false } if len(image.DockerImageLayers) != 4 || image.DockerImageLayers[0].Name != "sha256:744b46d0ac8636c45870a03830d8d82c20b75fbfb9bc937d5e61005d23ad4cfe" || image.DockerImageLayers[0].Size != 15141568 { t.Errorf("unexpected layers: %#v", image.DockerImageLayers) return false } return true }, existing: &api.Image{ ObjectMeta: kapi.ObjectMeta{Name: "foo", ResourceVersion: "1"}, DockerImageReference: "openshift/ruby-19-centos-2", DockerImageLayers: []api.ImageLayer{}, DockerImageManifest: etcdManifest, }, image: &api.Image{ ObjectMeta: kapi.ObjectMeta{Name: "foo", ResourceVersion: "1"}, DockerImageReference: "openshift/ruby-19-centos", DockerImageMetadata: api.DockerImage{ID: "foo"}, }, }, } for i, test := range testCases { fakeEtcdClient, helper := newHelper(t) storage := NewREST(helper) fakeEtcdClient.Data[etcdtest.AddPrefix("/images/foo")] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, test.existing), CreatedIndex: 1, ModifiedIndex: 1, }, }, } obj, _, err := storage.Update(kapi.NewDefaultContext(), test.image) if err != nil { t.Errorf("%d: Unexpected non-nil error: %#v", i, err) continue } if obj == nil { t.Errorf("%d: Expected nil obj, got %v", i, obj) continue } image, ok := obj.(*api.Image) if !ok { t.Errorf("%d: Expected image type, got: %#v", i, obj) continue } if test.expect != nil && !test.expect(image) { t.Errorf("%d: Unexpected image: %#v", i, obj) } } }
func TestEtcdUpdateScheduled(t *testing.T) { storage, _, _, fakeClient := newStorage(t) ctx := api.NewDefaultContext() fakeClient.TestIndex = true key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) fakeClient.Set(key, runtime.EncodeOrDie(testapi.Default.Codec(), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PodSpec{ NodeName: "machine", Containers: []api.Container{ { Name: "foobar", Image: "foo:v1", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }, }, SecurityContext: &api.PodSecurityContext{}, }, }), 1) grace := int64(30) podIn := api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "foo", ResourceVersion: "1", 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.ValidSecurityContextWithContainerDefaults(), }}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, }, } _, _, err := storage.Update(ctx, &podIn) if err != nil { t.Errorf("Unexpected error: %v", err) } response, err := fakeClient.Get(key, false, false) if err != nil { t.Fatalf("Unexpected error: %v", err) } var podOut api.Pod testapi.Default.Codec().DecodeInto([]byte(response.Node.Value), &podOut) if !api.Semantic.DeepEqual(podOut, podIn) { t.Errorf("expected: %#v, got: %#v", podOut, podIn) } }
func TestUpdateImageStreamTags(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data[etcdtest.AddPrefix("/imagestreams/default/test")] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "default"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "another": { From: &kapi.ObjectReference{ Kind: "ImageStreamTag", Name: "test:another", }, }, api.DefaultImageTag: { From: &kapi.ObjectReference{ Kind: "ImageStreamTag", Name: "test:latest", }, }, }, }, Status: api.ImageStreamStatus{ DockerImageRepository: "registry.default.local/default/test", Tags: map[string]api.TagEventList{ api.DefaultImageTag: { Items: []api.TagEvent{ { DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f", Image: "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f", }, }, }, }, }, }), ModifiedIndex: 1, }, }, } _, _, storage := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) stream := &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Namespace: "default", Name: "test", ResourceVersion: "1", }, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "another": { From: &kapi.ObjectReference{ Kind: "ImageStreamTag", Name: "test:another", }, }, api.DefaultImageTag: { From: &kapi.ObjectReference{ Kind: "ImageStreamTag", Name: "test:latest", }, }, }, }, Status: api.ImageStreamStatus{ DockerImageRepository: "registry.default.local/default/test", Tags: map[string]api.TagEventList{ api.DefaultImageTag: { Items: []api.TagEvent{ { DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f", Image: "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f", }, }, }, }, }, } delete(stream.Spec.Tags, api.DefaultImageTag) delete(stream.Status.Tags, api.DefaultImageTag) ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) obj, created, err := storage.Update(ctx, stream) if err != nil { t.Fatalf("Unexpected non-nil error: %#v", err) } if created { t.Fatal("Unexpected stream creation") } updated, ok := obj.(*api.ImageStream) if !ok { t.Errorf("Expected image stream, got %#v", obj) } if _, ok := updated.Spec.Tags[api.DefaultImageTag]; ok { t.Errorf("Expected deleted spec tag: %s", api.DefaultImageTag) } if _, ok := updated.Status.Tags[api.DefaultImageTag]; ok { t.Errorf("Expected deleted status tag: %s", api.DefaultImageTag) } }
func TestUpdateImageStreamSpecTagsFromSet(t *testing.T) { tests := map[string]struct { otherNamespace string sarExpected bool sarAllowed bool }{ "same namespace (blank), no sar": { otherNamespace: "", sarExpected: false, }, "same namespace (set), no sar": { otherNamespace: "default", sarExpected: false, }, "different namespace, sar allowed": { otherNamespace: "otherns", sarExpected: true, sarAllowed: true, }, "different namespace, sar denied": { otherNamespace: "otherns", sarExpected: true, sarAllowed: false, }, } for name, test := range tests { fakeEtcdClient, helper := newHelper(t) sarRegistry := &fakeSubjectAccessReviewRegistry{ allow: test.sarAllowed, } storage, _ := NewREST(helper, noDefaultRegistry, sarRegistry) fakeEtcdClient.Data["/imagestreams/default/foo"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "default"}, }), ModifiedIndex: 1, }, }, } otherNamespace := test.otherNamespace if len(otherNamespace) == 0 { otherNamespace = "default" } fakeEtcdClient.Data[fmt.Sprintf("/imagestreams/%s/other", otherNamespace)] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "other", Namespace: otherNamespace}, Status: api.ImageStreamStatus{ Tags: map[string]api.TagEventList{ "latest": { Items: []api.TagEvent{ { DockerImageReference: fmt.Sprintf("%s/other:latest", otherNamespace), }, }, }, }, }, }), ModifiedIndex: 1, }, }, } stream := &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "foo", ResourceVersion: "1"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "other": { From: &kapi.ObjectReference{ Kind: "ImageStreamTag", Namespace: test.otherNamespace, Name: "other:latest", }, }, }, }, } ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) _, _, err := storage.Update(ctx, stream) if test.sarExpected { if sarRegistry.request == nil { t.Errorf("%s: expected sar request", name) continue } if e, a := test.sarAllowed, err == nil; e != a { t.Errorf("%s: expected sarAllowed=%t, got error %t: %v", name, e, a, err) continue } continue } // sar not expected if err != nil { t.Fatalf("%s: unexpected error: %v", name, err) } actual := &api.ImageStream{} if err := helper.Get("/imagestreams/default/foo", actual, false); err != nil { t.Fatalf("%s: unexpected extraction error: %v", name, err) } if e, a := fmt.Sprintf("%s/other:latest", otherNamespace), actual.Status.Tags["other"].Items[0].DockerImageReference; e != a { t.Errorf("%s: dockerImageReference: expected %q, got %q", name, e, a) } } }