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 }