k8s.io/kubernetes@v1.29.3/pkg/registry/core/namespace/storage/storage_test.go (about)

     1  /*
     2  Copyright 2015 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 storage
    18  
    19  import (
    20  	"testing"
    21  
    22  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/fields"
    25  	"k8s.io/apimachinery/pkg/labels"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    28  	"k8s.io/apiserver/pkg/registry/generic"
    29  	genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
    30  	"k8s.io/apiserver/pkg/registry/rest"
    31  	etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
    32  
    33  	api "k8s.io/kubernetes/pkg/apis/core"
    34  	"k8s.io/kubernetes/pkg/registry/registrytest"
    35  )
    36  
    37  func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) {
    38  	etcdStorage, server := registrytest.NewEtcdStorage(t, "")
    39  	restOptions := generic.RESTOptions{StorageConfig: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1, ResourcePrefix: "namespaces"}
    40  	namespaceStorage, _, _, err := NewREST(restOptions)
    41  	if err != nil {
    42  		t.Fatalf("unexpected error from REST storage: %v", err)
    43  	}
    44  	return namespaceStorage, server
    45  }
    46  
    47  func validNewNamespace() *api.Namespace {
    48  	return &api.Namespace{
    49  		ObjectMeta: metav1.ObjectMeta{
    50  			Name: "foo",
    51  		},
    52  	}
    53  }
    54  
    55  func TestCreate(t *testing.T) {
    56  	storage, server := newStorage(t)
    57  	defer server.Terminate(t)
    58  	defer storage.store.DestroyFunc()
    59  	test := genericregistrytest.New(t, storage.store).ClusterScope()
    60  	namespace := validNewNamespace()
    61  	namespace.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
    62  	test.TestCreate(
    63  		// valid
    64  		namespace,
    65  		// invalid
    66  		&api.Namespace{
    67  			ObjectMeta: metav1.ObjectMeta{Name: "bad value"},
    68  		},
    69  	)
    70  }
    71  
    72  func TestCreateSetsFields(t *testing.T) {
    73  	storage, server := newStorage(t)
    74  	defer server.Terminate(t)
    75  	defer storage.store.DestroyFunc()
    76  	namespace := validNewNamespace()
    77  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
    78  	_, err := storage.Create(ctx, namespace, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
    79  	if err != nil {
    80  		t.Fatalf("unexpected error: %v", err)
    81  	}
    82  
    83  	object, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
    84  	if err != nil {
    85  		t.Errorf("unexpected error: %v", err)
    86  	}
    87  	actual := object.(*api.Namespace)
    88  	if actual.Name != namespace.Name {
    89  		t.Errorf("unexpected namespace: %#v", actual)
    90  	}
    91  	if len(actual.UID) == 0 {
    92  		t.Errorf("expected namespace UID to be set: %#v", actual)
    93  	}
    94  	if actual.Status.Phase != api.NamespaceActive {
    95  		t.Errorf("expected namespace phase to be set to active, but %v", actual.Status.Phase)
    96  	}
    97  }
    98  
    99  func TestDelete(t *testing.T) {
   100  	storage, server := newStorage(t)
   101  	defer server.Terminate(t)
   102  	defer storage.store.DestroyFunc()
   103  	test := genericregistrytest.New(t, storage.store).ClusterScope().ReturnDeletedObject()
   104  	test.TestDelete(validNewNamespace())
   105  }
   106  
   107  func TestGet(t *testing.T) {
   108  	storage, server := newStorage(t)
   109  	defer server.Terminate(t)
   110  	defer storage.store.DestroyFunc()
   111  	test := genericregistrytest.New(t, storage.store).ClusterScope()
   112  
   113  	// note that this ultimately may call validation
   114  	test.TestGet(validNewNamespace())
   115  }
   116  
   117  func TestList(t *testing.T) {
   118  	storage, server := newStorage(t)
   119  	defer server.Terminate(t)
   120  	defer storage.store.DestroyFunc()
   121  	test := genericregistrytest.New(t, storage.store).ClusterScope()
   122  	test.TestList(validNewNamespace())
   123  }
   124  
   125  func TestWatch(t *testing.T) {
   126  	storage, server := newStorage(t)
   127  	defer server.Terminate(t)
   128  	defer storage.store.DestroyFunc()
   129  	test := genericregistrytest.New(t, storage.store).ClusterScope()
   130  	test.TestWatch(
   131  		validNewNamespace(),
   132  		// matching labels
   133  		[]labels.Set{},
   134  		// not matching labels
   135  		[]labels.Set{
   136  			{"foo": "bar"},
   137  		},
   138  		// matching fields
   139  		[]fields.Set{
   140  			{"metadata.name": "foo"},
   141  			{"name": "foo"},
   142  		},
   143  		// not matching fields
   144  		[]fields.Set{
   145  			{"metadata.name": "bar"},
   146  		},
   147  	)
   148  }
   149  
   150  func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
   151  	storage, server := newStorage(t)
   152  	defer server.Terminate(t)
   153  	defer storage.store.DestroyFunc()
   154  	key := "namespaces/foo"
   155  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   156  	now := metav1.Now()
   157  	namespace := &api.Namespace{
   158  		ObjectMeta: metav1.ObjectMeta{
   159  			Name:              "foo",
   160  			DeletionTimestamp: &now,
   161  		},
   162  		Spec: api.NamespaceSpec{
   163  			Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
   164  		},
   165  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   166  	}
   167  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   168  		t.Fatalf("unexpected error: %v", err)
   169  	}
   170  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   171  	obj, immediate, err := storage.Delete(ctx, "foo", rest.ValidateAllObjectFunc, nil)
   172  	if err != nil {
   173  		t.Fatalf("unexpected error")
   174  	}
   175  	if immediate {
   176  		t.Fatalf("unexpected immediate flag")
   177  	}
   178  	if ns, ok := obj.(*api.Namespace); !ok || obj == nil || ns == nil || ns.Name != namespace.Name {
   179  		t.Fatalf("object not returned by delete")
   180  	}
   181  	// should still exist
   182  	if _, err := storage.Get(ctx, "foo", &metav1.GetOptions{}); err != nil {
   183  		t.Errorf("unexpected error: %v", err)
   184  	}
   185  }
   186  
   187  func TestUpdateDeletingNamespaceWithIncompleteMetadataFinalizers(t *testing.T) {
   188  	storage, server := newStorage(t)
   189  	defer server.Terminate(t)
   190  	defer storage.store.DestroyFunc()
   191  	key := "namespaces/foo"
   192  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   193  	now := metav1.Now()
   194  	namespace := &api.Namespace{
   195  		ObjectMeta: metav1.ObjectMeta{
   196  			Name:              "foo",
   197  			DeletionTimestamp: &now,
   198  			Finalizers:        []string{"example.com/foo"},
   199  		},
   200  		Spec: api.NamespaceSpec{
   201  			Finalizers: []api.FinalizerName{},
   202  		},
   203  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   204  	}
   205  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   206  		t.Fatalf("unexpected error: %v", err)
   207  	}
   208  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   209  	ns, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   210  	if err != nil {
   211  		t.Fatalf("unexpected error: %v", err)
   212  	}
   213  	if _, _, err = storage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(ns), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
   214  		t.Fatalf("unexpected error: %v", err)
   215  	}
   216  	// should still exist
   217  	_, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
   218  	if err != nil {
   219  		t.Fatalf("unexpected error: %v", err)
   220  	}
   221  }
   222  
   223  func TestUpdateDeletingNamespaceWithIncompleteSpecFinalizers(t *testing.T) {
   224  	storage, server := newStorage(t)
   225  	defer server.Terminate(t)
   226  	defer storage.store.DestroyFunc()
   227  	key := "namespaces/foo"
   228  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   229  	now := metav1.Now()
   230  	namespace := &api.Namespace{
   231  		ObjectMeta: metav1.ObjectMeta{
   232  			Name:              "foo",
   233  			DeletionTimestamp: &now,
   234  		},
   235  		Spec: api.NamespaceSpec{
   236  			Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
   237  		},
   238  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   239  	}
   240  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   241  		t.Fatalf("unexpected error: %v", err)
   242  	}
   243  	ns, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   244  	if err != nil {
   245  		t.Fatalf("unexpected error: %v", err)
   246  	}
   247  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   248  	if _, _, err = storage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(ns), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
   249  		t.Fatalf("unexpected error: %v", err)
   250  	}
   251  	// should still exist
   252  	_, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
   253  	if err != nil {
   254  		t.Fatalf("unexpected error: %v", err)
   255  	}
   256  }
   257  
   258  func TestUpdateDeletingNamespaceWithCompleteFinalizers(t *testing.T) {
   259  	storage, server := newStorage(t)
   260  	defer server.Terminate(t)
   261  	defer storage.store.DestroyFunc()
   262  	key := "namespaces/foo"
   263  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   264  	now := metav1.Now()
   265  	namespace := &api.Namespace{
   266  		ObjectMeta: metav1.ObjectMeta{
   267  			Name:              "foo",
   268  			DeletionTimestamp: &now,
   269  			Finalizers:        []string{"example.com/foo"},
   270  		},
   271  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   272  	}
   273  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   274  		t.Fatalf("unexpected error: %v", err)
   275  	}
   276  	ns, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   277  	if err != nil {
   278  		t.Fatalf("unexpected error: %v", err)
   279  	}
   280  	ns.(*api.Namespace).Finalizers = nil
   281  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   282  	if _, _, err = storage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(ns), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
   283  		t.Fatalf("unexpected error: %v", err)
   284  	}
   285  	// should not exist
   286  	_, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
   287  	if !apierrors.IsNotFound(err) {
   288  		t.Errorf("expected NotFound, got %v", err)
   289  	}
   290  }
   291  
   292  func TestFinalizeDeletingNamespaceWithCompleteFinalizers(t *testing.T) {
   293  	// get finalize storage
   294  	etcdStorage, server := registrytest.NewEtcdStorage(t, "")
   295  	restOptions := generic.RESTOptions{StorageConfig: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1, ResourcePrefix: "namespaces"}
   296  	storage, _, finalizeStorage, err := NewREST(restOptions)
   297  	if err != nil {
   298  		t.Fatalf("unexpected error from REST storage: %v", err)
   299  	}
   300  
   301  	defer server.Terminate(t)
   302  	defer storage.store.DestroyFunc()
   303  	defer finalizeStorage.store.DestroyFunc()
   304  	key := "namespaces/foo"
   305  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   306  	now := metav1.Now()
   307  	namespace := &api.Namespace{
   308  		ObjectMeta: metav1.ObjectMeta{
   309  			Name:              "foo",
   310  			DeletionTimestamp: &now,
   311  		},
   312  		Spec: api.NamespaceSpec{
   313  			Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
   314  		},
   315  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   316  	}
   317  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   318  		t.Fatalf("unexpected error: %v", err)
   319  	}
   320  	ns, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   321  	if err != nil {
   322  		t.Fatalf("unexpected error: %v", err)
   323  	}
   324  	ns.(*api.Namespace).Spec.Finalizers = nil
   325  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   326  	if _, _, err = finalizeStorage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(ns), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
   327  		t.Fatalf("unexpected error: %v", err)
   328  	}
   329  	// should not exist
   330  	_, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
   331  	if !apierrors.IsNotFound(err) {
   332  		t.Errorf("expected NotFound, got %v", err)
   333  	}
   334  }
   335  
   336  func TestFinalizeDeletingNamespaceWithIncompleteMetadataFinalizers(t *testing.T) {
   337  	// get finalize storage
   338  	etcdStorage, server := registrytest.NewEtcdStorage(t, "")
   339  	restOptions := generic.RESTOptions{StorageConfig: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1, ResourcePrefix: "namespaces"}
   340  	storage, _, finalizeStorage, err := NewREST(restOptions)
   341  	if err != nil {
   342  		t.Fatalf("unexpected error from REST storage: %v", err)
   343  	}
   344  
   345  	defer server.Terminate(t)
   346  	defer storage.store.DestroyFunc()
   347  	defer finalizeStorage.store.DestroyFunc()
   348  	key := "namespaces/foo"
   349  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   350  	now := metav1.Now()
   351  	namespace := &api.Namespace{
   352  		ObjectMeta: metav1.ObjectMeta{
   353  			Name:              "foo",
   354  			DeletionTimestamp: &now,
   355  			Finalizers:        []string{"example.com/foo"},
   356  		},
   357  		Spec: api.NamespaceSpec{
   358  			Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
   359  		},
   360  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   361  	}
   362  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   363  		t.Fatalf("unexpected error: %v", err)
   364  	}
   365  	ns, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   366  	if err != nil {
   367  		t.Fatalf("unexpected error: %v", err)
   368  	}
   369  	ns.(*api.Namespace).Spec.Finalizers = nil
   370  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   371  	if _, _, err = finalizeStorage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(ns), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
   372  		t.Fatalf("unexpected error: %v", err)
   373  	}
   374  	// should still exist
   375  	_, err = storage.Get(ctx, "foo", &metav1.GetOptions{})
   376  	if err != nil {
   377  		t.Fatalf("unexpected error: %v", err)
   378  	}
   379  }
   380  
   381  func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
   382  	storage, server := newStorage(t)
   383  	defer server.Terminate(t)
   384  	defer storage.store.DestroyFunc()
   385  	key := "namespaces/foo"
   386  	ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   387  	now := metav1.Now()
   388  	namespace := &api.Namespace{
   389  		ObjectMeta: metav1.ObjectMeta{
   390  			Name:              "foo",
   391  			DeletionTimestamp: &now,
   392  		},
   393  		Spec: api.NamespaceSpec{
   394  			Finalizers: []api.FinalizerName{},
   395  		},
   396  		Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   397  	}
   398  	if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   399  		t.Fatalf("unexpected error: %v", err)
   400  	}
   401  	ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   402  	if _, _, err := storage.Delete(ctx, "foo", rest.ValidateAllObjectFunc, nil); err != nil {
   403  		t.Errorf("unexpected error: %v", err)
   404  	}
   405  	// should not exist
   406  	_, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
   407  	if !apierrors.IsNotFound(err) {
   408  		t.Errorf("expected NotFound, got %v", err)
   409  	}
   410  }
   411  
   412  func TestDeleteWithGCFinalizers(t *testing.T) {
   413  	storage, server := newStorage(t)
   414  	defer server.Terminate(t)
   415  	defer storage.store.DestroyFunc()
   416  
   417  	propagationBackground := metav1.DeletePropagationBackground
   418  	propagationForeground := metav1.DeletePropagationForeground
   419  	propagationOrphan := metav1.DeletePropagationOrphan
   420  	trueVar := true
   421  
   422  	var tests = []struct {
   423  		name          string
   424  		deleteOptions *metav1.DeleteOptions
   425  
   426  		existingFinalizers  []string
   427  		remainingFinalizers map[string]bool
   428  	}{
   429  		{
   430  			name:          "nil-with-orphan",
   431  			deleteOptions: nil,
   432  			existingFinalizers: []string{
   433  				metav1.FinalizerOrphanDependents,
   434  			},
   435  			remainingFinalizers: map[string]bool{
   436  				metav1.FinalizerOrphanDependents: true,
   437  			},
   438  		},
   439  		{
   440  			name:          "nil-with-delete",
   441  			deleteOptions: nil,
   442  			existingFinalizers: []string{
   443  				metav1.FinalizerDeleteDependents,
   444  			},
   445  			remainingFinalizers: map[string]bool{
   446  				metav1.FinalizerDeleteDependents: true,
   447  			},
   448  		},
   449  		{
   450  			name:                "nil-without-finalizers",
   451  			deleteOptions:       nil,
   452  			existingFinalizers:  []string{},
   453  			remainingFinalizers: map[string]bool{},
   454  		},
   455  		{
   456  			name: "propagation-background-with-orphan",
   457  			deleteOptions: &metav1.DeleteOptions{
   458  				PropagationPolicy: &propagationBackground,
   459  			},
   460  			existingFinalizers: []string{
   461  				metav1.FinalizerOrphanDependents,
   462  			},
   463  			remainingFinalizers: map[string]bool{},
   464  		},
   465  		{
   466  			name: "propagation-background-with-delete",
   467  			deleteOptions: &metav1.DeleteOptions{
   468  				PropagationPolicy: &propagationBackground,
   469  			},
   470  			existingFinalizers: []string{
   471  				metav1.FinalizerDeleteDependents,
   472  			},
   473  			remainingFinalizers: map[string]bool{},
   474  		},
   475  		{
   476  			name: "propagation-background-without-finalizers",
   477  			deleteOptions: &metav1.DeleteOptions{
   478  				PropagationPolicy: &propagationBackground,
   479  			},
   480  			existingFinalizers:  []string{},
   481  			remainingFinalizers: map[string]bool{},
   482  		},
   483  		{
   484  			name: "propagation-foreground-with-orphan",
   485  			deleteOptions: &metav1.DeleteOptions{
   486  				PropagationPolicy: &propagationForeground,
   487  			},
   488  			existingFinalizers: []string{
   489  				metav1.FinalizerOrphanDependents,
   490  			},
   491  			remainingFinalizers: map[string]bool{
   492  				metav1.FinalizerDeleteDependents: true,
   493  			},
   494  		},
   495  		{
   496  			name: "propagation-foreground-with-delete",
   497  			deleteOptions: &metav1.DeleteOptions{
   498  				PropagationPolicy: &propagationForeground,
   499  			},
   500  			existingFinalizers: []string{
   501  				metav1.FinalizerDeleteDependents,
   502  			},
   503  			remainingFinalizers: map[string]bool{
   504  				metav1.FinalizerDeleteDependents: true,
   505  			},
   506  		},
   507  		{
   508  			name: "propagation-foreground-without-finalizers",
   509  			deleteOptions: &metav1.DeleteOptions{
   510  				PropagationPolicy: &propagationForeground,
   511  			},
   512  			existingFinalizers: []string{},
   513  			remainingFinalizers: map[string]bool{
   514  				metav1.FinalizerDeleteDependents: true,
   515  			},
   516  		},
   517  		{
   518  			name: "propagation-orphan-with-orphan",
   519  			deleteOptions: &metav1.DeleteOptions{
   520  				PropagationPolicy: &propagationOrphan,
   521  			},
   522  			existingFinalizers: []string{
   523  				metav1.FinalizerOrphanDependents,
   524  			},
   525  			remainingFinalizers: map[string]bool{
   526  				metav1.FinalizerOrphanDependents: true,
   527  			},
   528  		},
   529  		{
   530  			name: "propagation-orphan-with-delete",
   531  			deleteOptions: &metav1.DeleteOptions{
   532  				PropagationPolicy: &propagationOrphan,
   533  			},
   534  			existingFinalizers: []string{
   535  				metav1.FinalizerDeleteDependents,
   536  			},
   537  			remainingFinalizers: map[string]bool{
   538  				metav1.FinalizerOrphanDependents: true,
   539  			},
   540  		},
   541  		{
   542  			name: "propagation-orphan-without-finalizers",
   543  			deleteOptions: &metav1.DeleteOptions{
   544  				PropagationPolicy: &propagationOrphan,
   545  			},
   546  			existingFinalizers: []string{},
   547  			remainingFinalizers: map[string]bool{
   548  				metav1.FinalizerOrphanDependents: true,
   549  			},
   550  		},
   551  		{
   552  			name: "orphan-dependents-with-orphan",
   553  			deleteOptions: &metav1.DeleteOptions{
   554  				OrphanDependents: &trueVar,
   555  			},
   556  			existingFinalizers: []string{
   557  				metav1.FinalizerOrphanDependents,
   558  			},
   559  			remainingFinalizers: map[string]bool{
   560  				metav1.FinalizerOrphanDependents: true,
   561  			},
   562  		},
   563  		{
   564  			name: "orphan-dependents-with-delete",
   565  			deleteOptions: &metav1.DeleteOptions{
   566  				OrphanDependents: &trueVar,
   567  			},
   568  			existingFinalizers: []string{
   569  				metav1.FinalizerDeleteDependents,
   570  			},
   571  			remainingFinalizers: map[string]bool{
   572  				metav1.FinalizerOrphanDependents: true,
   573  			},
   574  		},
   575  		{
   576  			name: "orphan-dependents-without-finalizers",
   577  			deleteOptions: &metav1.DeleteOptions{
   578  				OrphanDependents: &trueVar,
   579  			},
   580  			existingFinalizers: []string{},
   581  			remainingFinalizers: map[string]bool{
   582  				metav1.FinalizerOrphanDependents: true,
   583  			},
   584  		},
   585  	}
   586  
   587  	for _, test := range tests {
   588  		key := "namespaces/" + test.name
   589  		ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
   590  		namespace := &api.Namespace{
   591  			ObjectMeta: metav1.ObjectMeta{
   592  				Name:       test.name,
   593  				Finalizers: test.existingFinalizers,
   594  			},
   595  			Spec: api.NamespaceSpec{
   596  				Finalizers: []api.FinalizerName{},
   597  			},
   598  			Status: api.NamespaceStatus{Phase: api.NamespaceActive},
   599  		}
   600  		if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
   601  			t.Fatalf("unexpected error: %v", err)
   602  		}
   603  		var obj runtime.Object
   604  		var err error
   605  		ctx = genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace.Name)
   606  		if obj, _, err = storage.Delete(ctx, test.name, rest.ValidateAllObjectFunc, test.deleteOptions); err != nil {
   607  			t.Fatalf("unexpected error: %v", err)
   608  		}
   609  		ns, ok := obj.(*api.Namespace)
   610  		if !ok {
   611  			t.Errorf("unexpected object kind: %+v", obj)
   612  		}
   613  		if len(ns.Finalizers) != len(test.remainingFinalizers) {
   614  			t.Errorf("%s: unexpected remaining finalizers: %v", test.name, ns.Finalizers)
   615  		}
   616  		for _, f := range ns.Finalizers {
   617  			if test.remainingFinalizers[f] != true {
   618  				t.Errorf("%s: unexpected finalizer %s", test.name, f)
   619  			}
   620  		}
   621  	}
   622  }
   623  
   624  func TestShortNames(t *testing.T) {
   625  	storage, server := newStorage(t)
   626  	defer server.Terminate(t)
   627  	defer storage.store.DestroyFunc()
   628  	expected := []string{"ns"}
   629  	registrytest.AssertShortNames(t, storage, expected)
   630  }