github.com/spotahome/redis-operator@v1.2.4/service/k8s/statefulset_test.go (about)

     1  package k8s_test
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"k8s.io/apimachinery/pkg/api/resource"
     8  
     9  	v1 "k8s.io/api/core/v1"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	appsv1 "k8s.io/api/apps/v1"
    13  	kubeerrors "k8s.io/apimachinery/pkg/api/errors"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/runtime"
    16  	"k8s.io/apimachinery/pkg/runtime/schema"
    17  	kubernetes "k8s.io/client-go/kubernetes/fake"
    18  	kubetesting "k8s.io/client-go/testing"
    19  
    20  	"github.com/spotahome/redis-operator/log"
    21  	"github.com/spotahome/redis-operator/metrics"
    22  	"github.com/spotahome/redis-operator/service/k8s"
    23  )
    24  
    25  var (
    26  	statefulSetsGroup = schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "statefulsets"}
    27  )
    28  
    29  func newStatefulSetUpdateAction(ns string, statefulSet *appsv1.StatefulSet) kubetesting.UpdateActionImpl {
    30  	return kubetesting.NewUpdateAction(statefulSetsGroup, ns, statefulSet)
    31  }
    32  
    33  func newStatefulSetGetAction(ns, name string) kubetesting.GetActionImpl {
    34  	return kubetesting.NewGetAction(statefulSetsGroup, ns, name)
    35  }
    36  
    37  func newStatefulSetCreateAction(ns string, statefulSet *appsv1.StatefulSet) kubetesting.CreateActionImpl {
    38  	return kubetesting.NewCreateAction(statefulSetsGroup, ns, statefulSet)
    39  }
    40  
    41  func TestStatefulSetServiceGetCreateOrUpdate(t *testing.T) {
    42  	testStatefulSet := &appsv1.StatefulSet{
    43  		ObjectMeta: metav1.ObjectMeta{
    44  			Name:            "teststatefulSet1",
    45  			ResourceVersion: "10",
    46  		},
    47  	}
    48  
    49  	testns := "testns"
    50  
    51  	tests := []struct {
    52  		name                 string
    53  		statefulSet          *appsv1.StatefulSet
    54  		getStatefulSetResult *appsv1.StatefulSet
    55  		errorOnGet           error
    56  		errorOnCreation      error
    57  		expActions           []kubetesting.Action
    58  		expErr               bool
    59  	}{
    60  		{
    61  			name:                 "A new statefulSet should create a new statefulSet.",
    62  			statefulSet:          testStatefulSet,
    63  			getStatefulSetResult: nil,
    64  			errorOnGet:           kubeerrors.NewNotFound(schema.GroupResource{}, ""),
    65  			errorOnCreation:      nil,
    66  			expActions: []kubetesting.Action{
    67  				newStatefulSetGetAction(testns, testStatefulSet.ObjectMeta.Name),
    68  				newStatefulSetCreateAction(testns, testStatefulSet),
    69  			},
    70  			expErr: false,
    71  		},
    72  		{
    73  			name:                 "A new statefulSet should error when create a new statefulSet fails.",
    74  			statefulSet:          testStatefulSet,
    75  			getStatefulSetResult: nil,
    76  			errorOnGet:           kubeerrors.NewNotFound(schema.GroupResource{}, ""),
    77  			errorOnCreation:      errors.New("wanted error"),
    78  			expActions: []kubetesting.Action{
    79  				newStatefulSetGetAction(testns, testStatefulSet.ObjectMeta.Name),
    80  				newStatefulSetCreateAction(testns, testStatefulSet),
    81  			},
    82  			expErr: true,
    83  		},
    84  		{
    85  			name:                 "An existent statefulSet should update the statefulSet.",
    86  			statefulSet:          testStatefulSet,
    87  			getStatefulSetResult: testStatefulSet,
    88  			errorOnGet:           nil,
    89  			errorOnCreation:      nil,
    90  			expActions: []kubetesting.Action{
    91  				newStatefulSetGetAction(testns, testStatefulSet.ObjectMeta.Name),
    92  				newStatefulSetUpdateAction(testns, testStatefulSet),
    93  			},
    94  			expErr: false,
    95  		},
    96  	}
    97  
    98  	for _, test := range tests {
    99  		t.Run(test.name, func(t *testing.T) {
   100  			assert := assert.New(t)
   101  
   102  			// Mock.
   103  			mcli := &kubernetes.Clientset{}
   104  			mcli.AddReactor("get", "statefulsets", func(action kubetesting.Action) (bool, runtime.Object, error) {
   105  				return true, test.getStatefulSetResult, test.errorOnGet
   106  			})
   107  			mcli.AddReactor("create", "statefulsets", func(action kubetesting.Action) (bool, runtime.Object, error) {
   108  				return true, nil, test.errorOnCreation
   109  			})
   110  
   111  			service := k8s.NewStatefulSetService(mcli, log.Dummy, metrics.Dummy)
   112  			err := service.CreateOrUpdateStatefulSet(testns, test.statefulSet)
   113  
   114  			if test.expErr {
   115  				assert.Error(err)
   116  			} else {
   117  				assert.NoError(err)
   118  				// Check calls to kubernetes.
   119  				assert.Equal(test.expActions, mcli.Actions())
   120  			}
   121  		})
   122  	}
   123  	// test resize pvc
   124  	{
   125  		t.Run("test_Resize_Pvc", func(t *testing.T) {
   126  			assert := assert.New(t)
   127  			beforeSts := &appsv1.StatefulSet{
   128  				ObjectMeta: metav1.ObjectMeta{
   129  					Name:            "teststatefulSet1",
   130  					ResourceVersion: "10",
   131  				},
   132  				Spec: appsv1.StatefulSetSpec{
   133  					VolumeClaimTemplates: []v1.PersistentVolumeClaim{
   134  						{
   135  							Spec: v1.PersistentVolumeClaimSpec{
   136  								Resources: v1.ResourceRequirements{
   137  									Requests: v1.ResourceList{
   138  										v1.ResourceStorage: resource.MustParse("0.5Gi"),
   139  									},
   140  								},
   141  							},
   142  						},
   143  					},
   144  				},
   145  			}
   146  			afterSts := &appsv1.StatefulSet{
   147  				ObjectMeta: metav1.ObjectMeta{
   148  					Name:            "teststatefulSet1",
   149  					ResourceVersion: "10",
   150  				},
   151  				Spec: appsv1.StatefulSetSpec{
   152  					VolumeClaimTemplates: []v1.PersistentVolumeClaim{
   153  						{
   154  							Spec: v1.PersistentVolumeClaimSpec{
   155  								Resources: v1.ResourceRequirements{
   156  									Requests: v1.ResourceList{
   157  										v1.ResourceStorage: resource.MustParse("1Gi"),
   158  									},
   159  								},
   160  							},
   161  						},
   162  					},
   163  				},
   164  			}
   165  			pvcList := &v1.PersistentVolumeClaimList{
   166  				Items: []v1.PersistentVolumeClaim{
   167  					{
   168  						ObjectMeta: metav1.ObjectMeta{
   169  							Labels: map[string]string{
   170  								"app.kubernetes.io/component": "redis",
   171  								"app.kubernetes.io/name":      "teststatefulSet1",
   172  								"app.kubernetes.io/part-of":   "redis-failover",
   173  							},
   174  						},
   175  						Spec: v1.PersistentVolumeClaimSpec{
   176  							VolumeName: "vol-1",
   177  							Resources: v1.ResourceRequirements{
   178  								Requests: v1.ResourceList{
   179  									v1.ResourceStorage: resource.MustParse("0.5Gi"),
   180  								},
   181  							},
   182  						},
   183  					},
   184  					// resized already
   185  					{
   186  						Spec: v1.PersistentVolumeClaimSpec{
   187  							VolumeName: "vol-2",
   188  							Resources: v1.ResourceRequirements{
   189  								Requests: v1.ResourceList{
   190  									v1.ResourceStorage: resource.MustParse("1Gi"),
   191  								},
   192  							},
   193  						},
   194  					},
   195  				},
   196  			}
   197  			// Mock.
   198  			mcli := &kubernetes.Clientset{}
   199  			mcli.AddReactor("get", "statefulsets", func(action kubetesting.Action) (bool, runtime.Object, error) {
   200  				return true, beforeSts, nil
   201  			})
   202  			mcli.AddReactor("list", "persistentvolumeclaims", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
   203  				return true, pvcList, nil
   204  			})
   205  			mcli.AddReactor("update", "persistentvolumeclaims", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
   206  				// update pvc[0]
   207  				pvcList.Items[0] = *action.(kubetesting.UpdateActionImpl).Object.(*v1.PersistentVolumeClaim)
   208  				return true, action.(kubetesting.UpdateActionImpl).Object, nil
   209  			})
   210  			service := k8s.NewStatefulSetService(mcli, log.Dummy, metrics.Dummy)
   211  			err := service.CreateOrUpdateStatefulSet(testns, afterSts)
   212  			assert.NoError(err)
   213  			assert.Equal(pvcList.Items[0].Spec.Resources, pvcList.Items[1].Spec.Resources)
   214  			// should not call update
   215  			mcli.AddReactor("update", "persistentvolumeclaims", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
   216  				panic("shouldn't call update")
   217  			})
   218  			service = k8s.NewStatefulSetService(mcli, log.Dummy, metrics.Dummy)
   219  			err = service.CreateOrUpdateStatefulSet(testns, afterSts)
   220  			assert.NoError(err)
   221  		})
   222  	}
   223  }