github.com/verrazzano/verrazzano@v1.7.0/pkg/k8s/ready/statefulset_ready_test.go (about) 1 // Copyright (c) 2021, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package ready 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 11 appsv1 "k8s.io/api/apps/v1" 12 corev1 "k8s.io/api/core/v1" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 "k8s.io/apimachinery/pkg/types" 15 k8scheme "k8s.io/client-go/kubernetes/scheme" 16 "sigs.k8s.io/controller-runtime/pkg/client" 17 "sigs.k8s.io/controller-runtime/pkg/client/fake" 18 ) 19 20 func TestStatefulsetReady(t *testing.T) { 21 22 selector := &metav1.LabelSelector{ 23 MatchLabels: map[string]string{ 24 "app": "foo", 25 }, 26 } 27 enoughReplicas := &appsv1.StatefulSet{ 28 ObjectMeta: metav1.ObjectMeta{ 29 Name: "foo", 30 Namespace: "bar", 31 }, 32 Spec: appsv1.StatefulSetSpec{ 33 Selector: selector, 34 }, 35 Status: appsv1.StatefulSetStatus{ 36 ReadyReplicas: 1, 37 UpdatedReplicas: 1, 38 }, 39 } 40 enoughReplicasMultiple := &appsv1.StatefulSet{ 41 ObjectMeta: metav1.ObjectMeta{ 42 Name: "foo", 43 Namespace: "bar", 44 }, 45 Spec: appsv1.StatefulSetSpec{ 46 Selector: selector, 47 }, 48 Status: appsv1.StatefulSetStatus{ 49 ReadyReplicas: 2, 50 UpdatedReplicas: 2, 51 }, 52 } 53 notEnoughReadyReplicas := &appsv1.StatefulSet{ 54 ObjectMeta: metav1.ObjectMeta{ 55 Name: "foo", 56 Namespace: "bar", 57 }, 58 Spec: appsv1.StatefulSetSpec{ 59 Selector: selector, 60 }, 61 Status: appsv1.StatefulSetStatus{ 62 ReadyReplicas: 0, 63 UpdatedReplicas: 1, 64 }, 65 } 66 notEnoughUpdatedReplicas := &appsv1.StatefulSet{ 67 ObjectMeta: metav1.ObjectMeta{ 68 Name: "foo", 69 Namespace: "bar", 70 }, 71 Spec: appsv1.StatefulSetSpec{ 72 Selector: selector, 73 }, 74 Status: appsv1.StatefulSetStatus{ 75 ReadyReplicas: 1, 76 UpdatedReplicas: 0, 77 }, 78 } 79 80 readyPod := &corev1.Pod{ 81 ObjectMeta: metav1.ObjectMeta{ 82 Name: "foo-95d8c5d96-m6mbr", 83 Namespace: "bar", 84 Labels: map[string]string{ 85 controllerRevisionHashLabel: "foo-95d8c5d96", 86 "app": "foo", 87 }, 88 }, 89 Status: corev1.PodStatus{ 90 ContainerStatuses: []corev1.ContainerStatus{ 91 { 92 Ready: true, 93 }, 94 }, 95 }, 96 } 97 notReadyContainerPod := &corev1.Pod{ 98 ObjectMeta: metav1.ObjectMeta{ 99 Name: "foo-95d8c5d96-m6y76", 100 Namespace: "bar", 101 Labels: map[string]string{ 102 controllerRevisionHashLabel: "foo-95d8c5d96", 103 "app": "foo", 104 }, 105 }, 106 Status: corev1.PodStatus{ 107 ContainerStatuses: []corev1.ContainerStatus{ 108 { 109 Ready: false, 110 }, 111 }, 112 }, 113 } 114 notReadyInitContainerPod := &corev1.Pod{ 115 ObjectMeta: metav1.ObjectMeta{ 116 Name: "foo-95d8c5d96-m6mbr", 117 Namespace: "bar", 118 Labels: map[string]string{ 119 controllerRevisionHashLabel: "foo-95d8c5d96", 120 "app": "foo", 121 }, 122 }, 123 Status: corev1.PodStatus{ 124 InitContainerStatuses: []corev1.ContainerStatus{ 125 { 126 Ready: false, 127 }, 128 }, 129 }, 130 } 131 noPodHashLabel := &corev1.Pod{ 132 ObjectMeta: metav1.ObjectMeta{ 133 Name: "foo-95d8c5d96-m6mbr", 134 Namespace: "bar", 135 Labels: map[string]string{ 136 "app": "foo", 137 }, 138 }, 139 Status: corev1.PodStatus{ 140 ContainerStatuses: []corev1.ContainerStatus{ 141 { 142 Ready: true, 143 }, 144 }, 145 }, 146 } 147 148 controllerRevision := &appsv1.ControllerRevision{ 149 ObjectMeta: metav1.ObjectMeta{ 150 Name: "foo-95d8c5d96", 151 Namespace: "bar", 152 }, 153 Revision: 1, 154 } 155 156 namespacedName := []types.NamespacedName{ 157 { 158 Name: "foo", 159 Namespace: "bar", 160 }, 161 } 162 163 var tests = []struct { 164 name string 165 c client.Client 166 n []types.NamespacedName 167 ready bool 168 expected int32 169 }{ 170 { 171 "should be ready when statefulset has enough replicas and pod is ready", 172 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas, readyPod, controllerRevision).Build(), 173 namespacedName, 174 true, 175 1, 176 }, 177 { 178 "should be ready when statefulset has enough replicas and one pod of two pods is ready", 179 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicasMultiple, notReadyContainerPod, readyPod, controllerRevision).Build(), 180 namespacedName, 181 true, 182 1, 183 }, 184 { 185 "should be not ready when expected pods ready not reached", 186 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicasMultiple, readyPod, controllerRevision).Build(), 187 namespacedName, 188 false, 189 2, 190 }, 191 { 192 "should be not ready when statefulset has enough replicas but pod init container pods is not ready", 193 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas, notReadyInitContainerPod, controllerRevision).Build(), 194 namespacedName, 195 false, 196 1, 197 }, 198 { 199 "should be not ready when statefulset has enough replicas but pod container pods is not ready", 200 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas, notReadyContainerPod, controllerRevision).Build(), 201 namespacedName, 202 false, 203 1, 204 }, 205 { 206 "should be not ready when pod not found for statefulset", 207 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas).Build(), 208 namespacedName, 209 false, 210 1, 211 }, 212 { 213 "should be not ready when statefulset not found", 214 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build(), 215 namespacedName, 216 false, 217 1, 218 }, 219 { 220 "should be not ready when controller-revision-hash label not found", 221 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas, noPodHashLabel).Build(), 222 namespacedName, 223 false, 224 1, 225 }, 226 { 227 "should be not ready when controllerrevision resource not found", 228 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(enoughReplicas, readyPod).Build(), 229 namespacedName, 230 false, 231 1, 232 }, 233 { 234 "should be not ready when statefulset doesn't have enough ready replicas", 235 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(notEnoughReadyReplicas).Build(), 236 namespacedName, 237 false, 238 1, 239 }, 240 { 241 "should be not ready when statefulset doesn't have enough updated replicas", 242 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(notEnoughUpdatedReplicas).Build(), 243 namespacedName, 244 false, 245 1, 246 }, 247 { 248 "should be ready when no PodReadyCheck provided", 249 fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build(), 250 []types.NamespacedName{}, 251 true, 252 1, 253 }, 254 } 255 256 for _, tt := range tests { 257 t.Run(tt.name, func(t *testing.T) { 258 assert.Equal(t, tt.ready, StatefulSetsAreReady(vzlog.DefaultLogger(), tt.c, tt.n, tt.expected, "")) 259 }) 260 } 261 } 262 263 func TestDoStatefulsetsExist(t *testing.T) { 264 tests := []struct { 265 name string 266 stsNames []types.NamespacedName 267 want bool 268 }{ 269 {"no statefulset names provided", []types.NamespacedName{}, true}, 270 {"statefulset exists", []types.NamespacedName{{Name: "foo", Namespace: "bar"}}, true}, 271 {"all statefulsets exist", []types.NamespacedName{{Name: "foo", Namespace: "bar"}, {Name: "foo2", Namespace: "bar2"}}, true}, 272 {"only some statefulsets exist", []types.NamespacedName{{Name: "foo", Namespace: "bar"}, {Name: "nonexist", Namespace: "bar"}}, false}, 273 {"none of the statefulsets exist", []types.NamespacedName{{Name: "nofoo", Namespace: "nobar"}, {Name: "nofoo2", Namespace: "bar2"}}, false}, 274 {"statefulset in different namespace", []types.NamespacedName{{Name: "foo", Namespace: "bar2"}}, false}, 275 } 276 for _, tt := range tests { 277 t.Run(tt.name, func(t *testing.T) { 278 log := vzlog.DefaultLogger() 279 fakeClient := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects( 280 &appsv1.StatefulSet{ 281 ObjectMeta: metav1.ObjectMeta{ 282 Namespace: "bar", 283 Name: "foo", 284 }, 285 Spec: appsv1.StatefulSetSpec{ 286 Selector: &metav1.LabelSelector{ 287 MatchLabels: map[string]string{ 288 "app": "foo", 289 }, 290 }, 291 }, 292 }, 293 &appsv1.StatefulSet{ 294 ObjectMeta: metav1.ObjectMeta{ 295 Namespace: "bar2", 296 Name: "foo2", 297 }, 298 Spec: appsv1.StatefulSetSpec{ 299 Selector: &metav1.LabelSelector{ 300 MatchLabels: map[string]string{ 301 "app": "foo", 302 }, 303 }, 304 }, 305 }).Build() 306 assert.Equalf(t, tt.want, DoStatefulSetsExist(log, fakeClient, tt.stsNames, 1, tt.name), "Expected %v for %s", tt.want, tt.name) 307 }) 308 } 309 }