...

Source file src/k8s.io/kubernetes/pkg/registry/core/persistentvolume/strategy_test.go

Documentation: k8s.io/kubernetes/pkg/registry/core/persistentvolume

     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 persistentvolume
    18  
    19  import (
    20  	"context"
    21  	"github.com/google/go-cmp/cmp"
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    24  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    25  	apitesting "k8s.io/kubernetes/pkg/api/testing"
    26  	api "k8s.io/kubernetes/pkg/apis/core"
    27  	"k8s.io/kubernetes/pkg/features"
    28  	"reflect"
    29  	"testing"
    30  	"time"
    31  
    32  	// ensure types are installed
    33  	_ "k8s.io/kubernetes/pkg/apis/core/install"
    34  )
    35  
    36  func TestSelectableFieldLabelConversions(t *testing.T) {
    37  	apitesting.TestSelectableFieldLabelConversionsOfKind(t,
    38  		"v1",
    39  		"PersistentVolume",
    40  		PersistentVolumeToSelectableFields(&api.PersistentVolume{}),
    41  		map[string]string{"name": "metadata.name"},
    42  	)
    43  }
    44  
    45  func TestStatusUpdate(t *testing.T) {
    46  	now := metav1.Now()
    47  	origin := metav1.NewTime(now.Add(time.Hour))
    48  	later := metav1.NewTime(now.Add(time.Hour * 2))
    49  	NowFunc = func() metav1.Time { return now }
    50  	defer func() {
    51  		NowFunc = metav1.Now
    52  	}()
    53  	tests := []struct {
    54  		name        string
    55  		fg          bool
    56  		oldObj      *api.PersistentVolume
    57  		newObj      *api.PersistentVolume
    58  		expectedObj *api.PersistentVolume
    59  	}{
    60  		{
    61  			name: "feature enabled: timestamp is updated when phase changes",
    62  			fg:   true,
    63  			oldObj: &api.PersistentVolume{
    64  				ObjectMeta: metav1.ObjectMeta{
    65  					Name: "foo",
    66  				},
    67  				Status: api.PersistentVolumeStatus{
    68  					Phase: api.VolumePending,
    69  				},
    70  			},
    71  			newObj: &api.PersistentVolume{
    72  				ObjectMeta: metav1.ObjectMeta{
    73  					Name: "foo",
    74  				},
    75  				Status: api.PersistentVolumeStatus{
    76  					Phase: api.VolumeBound,
    77  				},
    78  			},
    79  			expectedObj: &api.PersistentVolume{
    80  				ObjectMeta: metav1.ObjectMeta{
    81  					Name: "foo",
    82  				},
    83  				Status: api.PersistentVolumeStatus{
    84  					Phase:                   api.VolumeBound,
    85  					LastPhaseTransitionTime: &now,
    86  				},
    87  			},
    88  		},
    89  		{
    90  			name: "feature enabled: timestamp is updated when phase changes and old pv has a timestamp",
    91  			fg:   true,
    92  			oldObj: &api.PersistentVolume{
    93  				ObjectMeta: metav1.ObjectMeta{
    94  					Name: "foo",
    95  				},
    96  				Status: api.PersistentVolumeStatus{
    97  					Phase:                   api.VolumePending,
    98  					LastPhaseTransitionTime: &origin,
    99  				},
   100  			},
   101  			newObj: &api.PersistentVolume{
   102  				ObjectMeta: metav1.ObjectMeta{
   103  					Name: "foo",
   104  				},
   105  				Status: api.PersistentVolumeStatus{
   106  					Phase: api.VolumeBound,
   107  				},
   108  			},
   109  			expectedObj: &api.PersistentVolume{
   110  				ObjectMeta: metav1.ObjectMeta{
   111  					Name: "foo",
   112  				},
   113  				Status: api.PersistentVolumeStatus{
   114  					Phase:                   api.VolumeBound,
   115  					LastPhaseTransitionTime: &now,
   116  				},
   117  			},
   118  		},
   119  		{
   120  			name: "feature enabled: user timestamp change is respected on no phase change",
   121  			fg:   true,
   122  			oldObj: &api.PersistentVolume{
   123  				ObjectMeta: metav1.ObjectMeta{
   124  					Name: "foo",
   125  				},
   126  				Status: api.PersistentVolumeStatus{
   127  					Phase: api.VolumePending,
   128  				},
   129  			},
   130  			newObj: &api.PersistentVolume{
   131  				ObjectMeta: metav1.ObjectMeta{
   132  					Name: "foo",
   133  				},
   134  				Status: api.PersistentVolumeStatus{
   135  					Phase:                   api.VolumePending,
   136  					LastPhaseTransitionTime: &later,
   137  				},
   138  			},
   139  			expectedObj: &api.PersistentVolume{
   140  				ObjectMeta: metav1.ObjectMeta{
   141  					Name: "foo",
   142  				},
   143  				Status: api.PersistentVolumeStatus{
   144  					Phase:                   api.VolumePending,
   145  					LastPhaseTransitionTime: &later,
   146  				},
   147  			},
   148  		},
   149  		{
   150  			name: "feature enabled: user timestamp is respected on phase change",
   151  			fg:   true,
   152  			oldObj: &api.PersistentVolume{
   153  				ObjectMeta: metav1.ObjectMeta{
   154  					Name: "foo",
   155  				},
   156  				Status: api.PersistentVolumeStatus{
   157  					Phase:                   api.VolumePending,
   158  					LastPhaseTransitionTime: &origin,
   159  				},
   160  			},
   161  			newObj: &api.PersistentVolume{
   162  				ObjectMeta: metav1.ObjectMeta{
   163  					Name: "foo",
   164  				},
   165  				Status: api.PersistentVolumeStatus{
   166  					Phase:                   api.VolumeBound,
   167  					LastPhaseTransitionTime: &later,
   168  				},
   169  			},
   170  			expectedObj: &api.PersistentVolume{
   171  				ObjectMeta: metav1.ObjectMeta{
   172  					Name: "foo",
   173  				},
   174  				Status: api.PersistentVolumeStatus{
   175  					Phase:                   api.VolumeBound,
   176  					LastPhaseTransitionTime: &later,
   177  				},
   178  			},
   179  		},
   180  		{
   181  			name: "feature enabled: user timestamp change is respected on no phase change when old pv has a timestamp",
   182  			fg:   true,
   183  			oldObj: &api.PersistentVolume{
   184  				ObjectMeta: metav1.ObjectMeta{
   185  					Name: "foo",
   186  				},
   187  				Status: api.PersistentVolumeStatus{
   188  					Phase:                   api.VolumeBound,
   189  					LastPhaseTransitionTime: &origin,
   190  				},
   191  			},
   192  			newObj: &api.PersistentVolume{
   193  				ObjectMeta: metav1.ObjectMeta{
   194  					Name: "foo",
   195  				},
   196  				Status: api.PersistentVolumeStatus{
   197  					Phase:                   api.VolumeBound,
   198  					LastPhaseTransitionTime: &later,
   199  				},
   200  			},
   201  			expectedObj: &api.PersistentVolume{
   202  				ObjectMeta: metav1.ObjectMeta{
   203  					Name: "foo",
   204  				},
   205  				Status: api.PersistentVolumeStatus{
   206  					Phase:                   api.VolumeBound,
   207  					LastPhaseTransitionTime: &later,
   208  				},
   209  			},
   210  		},
   211  		{
   212  			name: "feature enabled: timestamp is updated when phase changes and both new and old timestamp matches",
   213  			fg:   true,
   214  			oldObj: &api.PersistentVolume{
   215  				ObjectMeta: metav1.ObjectMeta{
   216  					Name: "foo",
   217  				},
   218  				Status: api.PersistentVolumeStatus{
   219  					Phase:                   api.VolumePending,
   220  					LastPhaseTransitionTime: &origin,
   221  				},
   222  			},
   223  			newObj: &api.PersistentVolume{
   224  				ObjectMeta: metav1.ObjectMeta{
   225  					Name: "foo",
   226  				},
   227  				Status: api.PersistentVolumeStatus{
   228  					Phase:                   api.VolumeBound,
   229  					LastPhaseTransitionTime: &origin,
   230  				},
   231  			},
   232  			expectedObj: &api.PersistentVolume{
   233  				ObjectMeta: metav1.ObjectMeta{
   234  					Name: "foo",
   235  				},
   236  				Status: api.PersistentVolumeStatus{
   237  					Phase:                   api.VolumeBound,
   238  					LastPhaseTransitionTime: &now,
   239  				},
   240  			},
   241  		},
   242  		{
   243  			name: "feature disabled: timestamp is not updated",
   244  			fg:   false,
   245  			oldObj: &api.PersistentVolume{
   246  				ObjectMeta: metav1.ObjectMeta{
   247  					Name: "foo",
   248  				},
   249  				Status: api.PersistentVolumeStatus{
   250  					Phase: api.VolumePending,
   251  				},
   252  			},
   253  			newObj: &api.PersistentVolume{
   254  				ObjectMeta: metav1.ObjectMeta{
   255  					Name: "foo",
   256  				},
   257  				Status: api.PersistentVolumeStatus{
   258  					Phase: api.VolumeBound,
   259  				},
   260  			},
   261  			expectedObj: &api.PersistentVolume{
   262  				ObjectMeta: metav1.ObjectMeta{
   263  					Name: "foo",
   264  				},
   265  				Status: api.PersistentVolumeStatus{
   266  					Phase: api.VolumeBound,
   267  				},
   268  			},
   269  		},
   270  		{
   271  			name: "feature disabled: user timestamp is overwritten on phase change to nil",
   272  			fg:   false,
   273  			oldObj: &api.PersistentVolume{
   274  				ObjectMeta: metav1.ObjectMeta{
   275  					Name: "foo",
   276  				},
   277  				Status: api.PersistentVolumeStatus{
   278  					Phase: api.VolumePending,
   279  				},
   280  			},
   281  			newObj: &api.PersistentVolume{
   282  				ObjectMeta: metav1.ObjectMeta{
   283  					Name: "foo",
   284  				},
   285  				Status: api.PersistentVolumeStatus{
   286  					Phase:                   api.VolumePending,
   287  					LastPhaseTransitionTime: &later,
   288  				},
   289  			},
   290  			expectedObj: &api.PersistentVolume{
   291  				ObjectMeta: metav1.ObjectMeta{
   292  					Name: "foo",
   293  				},
   294  				Status: api.PersistentVolumeStatus{
   295  					Phase:                   api.VolumePending,
   296  					LastPhaseTransitionTime: nil,
   297  				},
   298  			},
   299  		},
   300  		{
   301  			name: "feature disabled: user timestamp change is respected on phase change",
   302  			fg:   false,
   303  			oldObj: &api.PersistentVolume{
   304  				ObjectMeta: metav1.ObjectMeta{
   305  					Name: "foo",
   306  				},
   307  				Status: api.PersistentVolumeStatus{
   308  					Phase:                   api.VolumePending,
   309  					LastPhaseTransitionTime: &origin,
   310  				},
   311  			},
   312  			newObj: &api.PersistentVolume{
   313  				ObjectMeta: metav1.ObjectMeta{
   314  					Name: "foo",
   315  				},
   316  				Status: api.PersistentVolumeStatus{
   317  					Phase:                   api.VolumeBound,
   318  					LastPhaseTransitionTime: &later,
   319  				},
   320  			},
   321  			expectedObj: &api.PersistentVolume{
   322  				ObjectMeta: metav1.ObjectMeta{
   323  					Name: "foo",
   324  				},
   325  				Status: api.PersistentVolumeStatus{
   326  					Phase:                   api.VolumeBound,
   327  					LastPhaseTransitionTime: &later,
   328  				},
   329  			},
   330  		},
   331  		{
   332  			name: "feature disabled: user timestamp change is respected on no phase change",
   333  			fg:   false,
   334  			oldObj: &api.PersistentVolume{
   335  				ObjectMeta: metav1.ObjectMeta{
   336  					Name: "foo",
   337  				},
   338  				Status: api.PersistentVolumeStatus{
   339  					Phase:                   api.VolumeBound,
   340  					LastPhaseTransitionTime: &origin,
   341  				},
   342  			},
   343  			newObj: &api.PersistentVolume{
   344  				ObjectMeta: metav1.ObjectMeta{
   345  					Name: "foo",
   346  				},
   347  				Status: api.PersistentVolumeStatus{
   348  					Phase:                   api.VolumeBound,
   349  					LastPhaseTransitionTime: &later,
   350  				},
   351  			},
   352  			expectedObj: &api.PersistentVolume{
   353  				ObjectMeta: metav1.ObjectMeta{
   354  					Name: "foo",
   355  				},
   356  				Status: api.PersistentVolumeStatus{
   357  					Phase:                   api.VolumeBound,
   358  					LastPhaseTransitionTime: &later,
   359  				},
   360  			},
   361  		},
   362  	}
   363  
   364  	for _, tc := range tests {
   365  		t.Run(tc.name, func(t *testing.T) {
   366  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentVolumeLastPhaseTransitionTime, tc.fg)()
   367  
   368  			obj := tc.newObj.DeepCopy()
   369  			StatusStrategy.PrepareForUpdate(context.TODO(), obj, tc.oldObj.DeepCopy())
   370  			if !reflect.DeepEqual(obj, tc.expectedObj) {
   371  				t.Errorf("object diff: %s", cmp.Diff(obj, tc.expectedObj))
   372  			}
   373  		})
   374  	}
   375  }
   376  
   377  func TestStatusCreate(t *testing.T) {
   378  	now := metav1.Now()
   379  	NowFunc = func() metav1.Time { return now }
   380  	defer func() {
   381  		NowFunc = metav1.Now
   382  	}()
   383  	tests := []struct {
   384  		name        string
   385  		fg          bool
   386  		newObj      *api.PersistentVolume
   387  		expectedObj *api.PersistentVolume
   388  	}{
   389  		{
   390  			name: "feature enabled: pv is in pending phase and has a timestamp",
   391  			fg:   true,
   392  			newObj: &api.PersistentVolume{
   393  				ObjectMeta: metav1.ObjectMeta{
   394  					Name: "foo",
   395  				},
   396  			},
   397  			expectedObj: &api.PersistentVolume{
   398  				ObjectMeta: metav1.ObjectMeta{
   399  					Name: "foo",
   400  				},
   401  				Status: api.PersistentVolumeStatus{
   402  					Phase:                   api.VolumePending,
   403  					LastPhaseTransitionTime: &now,
   404  				},
   405  			},
   406  		},
   407  		{
   408  			name: "feature disabled: pv does not have phase and timestamp",
   409  			fg:   false,
   410  			newObj: &api.PersistentVolume{
   411  				ObjectMeta: metav1.ObjectMeta{
   412  					Name: "foo",
   413  				},
   414  			},
   415  			expectedObj: &api.PersistentVolume{
   416  				ObjectMeta: metav1.ObjectMeta{
   417  					Name: "foo",
   418  				},
   419  			},
   420  		},
   421  	}
   422  
   423  	for _, tc := range tests {
   424  		t.Run(tc.name, func(t *testing.T) {
   425  
   426  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PersistentVolumeLastPhaseTransitionTime, tc.fg)()
   427  			obj := tc.newObj.DeepCopy()
   428  			StatusStrategy.PrepareForCreate(context.TODO(), obj)
   429  			if !reflect.DeepEqual(obj, tc.expectedObj) {
   430  				t.Errorf("object diff: %s", cmp.Diff(obj, tc.expectedObj))
   431  			}
   432  		})
   433  	}
   434  }
   435  

View as plain text