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  }