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 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 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 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 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 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 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 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 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) } } }