func TestConditionalDelete(t *testing.T) { ctx, store, cluster := testSetup(t) defer cluster.Terminate(t) key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", UID: "A"}}) tests := []struct { precondition *storage.Preconditions expectInvalidObjErr bool }{{ // test conditional delete with UID match precondition: storage.NewUIDPreconditions("A"), expectInvalidObjErr: false, }, { // test conditional delete with UID mismatch precondition: storage.NewUIDPreconditions("B"), expectInvalidObjErr: true, }} for i, tt := range tests { out := &api.Pod{} err := store.Delete(ctx, key, out, tt.precondition) if tt.expectInvalidObjErr { if err == nil || !storage.IsInvalidObj(err) { t.Errorf("#%d: expecting invalid UID error, but get: %s", i, err) } continue } if err != nil { t.Fatalf("Delete failed: %v", err) } if !reflect.DeepEqual(storedObj, out) { t.Errorf("#%d: pod want=%#v, get=%#v", i, storedObj, out) } key, storedObj = testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", UID: "A"}}) } }
// InterpretDeleteError converts a generic error on a delete // operation into the appropriate API error. func InterpretDeleteError(err error, qualifiedResource schema.GroupResource, name string) error { switch { case storage.IsNotFound(err): return errors.NewNotFound(qualifiedResource, name) case storage.IsUnreachable(err): return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level case storage.IsConflict(err), storage.IsNodeExist(err), storage.IsInvalidObj(err): return errors.NewConflict(qualifiedResource, name, err) case storage.IsInternalError(err): return errors.NewInternalError(err) default: return err } }
func TestDeleteUIDMismatch(t *testing.T) { server := etcdtesting.NewEtcdTestClientServer(t) defer server.Terminate(t) prefix := path.Join("/", etcdtest.PathPrefix()) helper := newEtcdHelper(server.Client, testapi.Default.Codec(), prefix) obj := &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}} podPtr := &api.Pod{} err := helper.Create(context.TODO(), "/some/key", obj, podPtr, 0) if err != nil { t.Fatalf("Unexpected error %#v", err) } err = helper.Delete(context.TODO(), "/some/key", obj, storage.NewUIDPreconditions("B")) if !storage.IsInvalidObj(err) { t.Fatalf("Expect a Test Failed (write conflict) error, got: %v", err) } }
func TestGuaranteedUpdate(t *testing.T) { ctx, store, cluster := testSetup(t) defer cluster.Terminate(t) key, storeObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", UID: "A"}}) tests := []struct { key string name string ignoreNotFound bool precondition *storage.Preconditions expectNotFoundErr bool expectInvalidObjErr bool expectNoUpdate bool }{{ // GuaranteedUpdate on non-existing key with ignoreNotFound=false key: "/non-existing", ignoreNotFound: false, precondition: nil, expectNotFoundErr: true, expectInvalidObjErr: false, expectNoUpdate: false, }, { // GuaranteedUpdate on non-existing key with ignoreNotFound=true key: "/non-existing", ignoreNotFound: true, precondition: nil, expectNotFoundErr: false, expectInvalidObjErr: false, expectNoUpdate: false, }, { // GuaranteedUpdate on existing key key: key, ignoreNotFound: false, precondition: nil, expectNotFoundErr: false, expectInvalidObjErr: false, expectNoUpdate: false, }, { // GuaranteedUpdate with same data key: key, ignoreNotFound: false, precondition: nil, expectNotFoundErr: false, expectInvalidObjErr: false, expectNoUpdate: true, }, { // GuaranteedUpdate with UID match key: key, ignoreNotFound: false, precondition: storage.NewUIDPreconditions("A"), expectNotFoundErr: false, expectInvalidObjErr: false, expectNoUpdate: true, }, { // GuaranteedUpdate with UID mismatch key: key, ignoreNotFound: false, precondition: storage.NewUIDPreconditions("B"), expectNotFoundErr: false, expectInvalidObjErr: true, expectNoUpdate: true, }} for i, tt := range tests { out := &api.Pod{} name := fmt.Sprintf("foo-%d", i) if tt.expectNoUpdate { name = storeObj.Name } version := storeObj.ResourceVersion err := store.GuaranteedUpdate(ctx, tt.key, out, tt.ignoreNotFound, tt.precondition, storage.SimpleUpdate(func(obj runtime.Object) (runtime.Object, error) { if tt.expectNotFoundErr && tt.ignoreNotFound { if pod := obj.(*api.Pod); pod.Name != "" { t.Errorf("#%d: expecting zero value, but get=%#v", i, pod) } } pod := *storeObj pod.Name = name return &pod, nil })) if tt.expectNotFoundErr { if err == nil || !storage.IsNotFound(err) { t.Errorf("#%d: expecting not found error, but get: %v", i, err) } continue } if tt.expectInvalidObjErr { if err == nil || !storage.IsInvalidObj(err) { t.Errorf("#%d: expecting invalid UID error, but get: %s", i, err) } continue } if err != nil { t.Fatalf("GuaranteedUpdate failed: %v", err) } if out.ObjectMeta.Name != name { t.Errorf("#%d: pod name want=%s, get=%s", i, name, out.ObjectMeta.Name) } switch tt.expectNoUpdate { case true: if version != out.ResourceVersion { t.Errorf("#%d: expect no version change, before=%s, after=%s", i, version, out.ResourceVersion) } case false: if version == out.ResourceVersion { t.Errorf("#%d: expect version change, but get the same version=%s", i, version) } } storeObj = out } }