Add integration tests for StatefulSetStartOrdinal feature (#115466)

* Add integration tests for StatefulSetStartOrdinal feature

* Move expensive test setup (apiserver and running controller) to be run once in StatefulSetStartOrdinal parameterized tests
This commit is contained in:
pwschuurman 2023-02-03 05:26:29 -08:00 committed by GitHub
parent 7a55b76f28
commit 7bf175d5a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 3 deletions

View File

@ -22,6 +22,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -479,3 +481,97 @@ func TestAutodeleteOwnerRefs(t *testing.T) {
}) })
} }
} }
func TestStatefulSetStartOrdinal(t *testing.T) {
tests := []struct {
ordinals *appsv1.StatefulSetOrdinals
name string
namespace string
replicas int
expectedPodNames []string
}{
{
name: "default start ordinal, no ordinals set",
namespace: "no-ordinals",
replicas: 3,
expectedPodNames: []string{"sts-0", "sts-1", "sts-2"},
},
{
name: "default start ordinal",
namespace: "no-start-ordinals",
ordinals: &appsv1.StatefulSetOrdinals{},
replicas: 3,
expectedPodNames: []string{"sts-0", "sts-1", "sts-2"},
},
{
name: "start ordinal 4",
namespace: "start-ordinal-4",
ordinals: &appsv1.StatefulSetOrdinals{
Start: 4,
},
replicas: 4,
expectedPodNames: []string{"sts-4", "sts-5", "sts-6", "sts-7"},
},
{
name: "start ordinal 5",
namespace: "start-ordinal-5",
ordinals: &appsv1.StatefulSetOrdinals{
Start: 2,
},
replicas: 7,
expectedPodNames: []string{"sts-2", "sts-3", "sts-4", "sts-5", "sts-6", "sts-7", "sts-8"},
},
}
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetStartOrdinal, true)()
closeFn, rm, informers, c := scSetup(t)
defer closeFn()
cancel := runControllerAndInformers(rm, informers)
defer cancel()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ns := framework.CreateNamespaceOrDie(c, test.namespace, t)
defer framework.DeleteNamespaceOrDie(c, ns, t)
// Label map is the map of pod labels used in newSTS()
labelMap := labelMap()
sts := newSTS("sts", ns.Name, test.replicas)
sts.Spec.Ordinals = test.ordinals
stss := createSTSs(t, c, []*appsv1.StatefulSet{sts})
sts = stss[0]
waitSTSStable(t, c, sts)
podClient := c.CoreV1().Pods(ns.Name)
pods := getPods(t, podClient, labelMap)
if len(pods.Items) != test.replicas {
t.Errorf("len(pods) = %v, want %v", len(pods.Items), test.replicas)
}
var podNames []string
for _, pod := range pods.Items {
podNames = append(podNames, pod.Name)
}
ignoreOrder := cmpopts.SortSlices(func(a, b string) bool {
return a < b
})
// Validate all the expected pods were created.
if diff := cmp.Diff(test.expectedPodNames, podNames, ignoreOrder); diff != "" {
t.Errorf("Unexpected pod names: (-want +got): %v", diff)
}
// Scale down to 1 pod and verify it matches the first pod.
scaleSTS(t, c, sts, 1)
waitSTSStable(t, c, sts)
pods = getPods(t, podClient, labelMap)
if len(pods.Items) != 1 {
t.Errorf("len(pods) = %v, want %v", len(pods.Items), 1)
}
if pods.Items[0].Name != test.expectedPodNames[0] {
t.Errorf("Unexpected singleton pod name: got = %v, want %v", pods.Items[0].Name, test.expectedPodNames[0])
}
})
}
}

View File

@ -199,9 +199,8 @@ func createHeadlessService(t *testing.T, clientSet clientset.Interface, headless
} }
} }
func createSTSsPods(t *testing.T, clientSet clientset.Interface, stss []*appsv1.StatefulSet, pods []*v1.Pod) ([]*appsv1.StatefulSet, []*v1.Pod) { func createSTSs(t *testing.T, clientSet clientset.Interface, stss []*appsv1.StatefulSet) []*appsv1.StatefulSet {
var createdSTSs []*appsv1.StatefulSet var createdSTSs []*appsv1.StatefulSet
var createdPods []*v1.Pod
for _, sts := range stss { for _, sts := range stss {
createdSTS, err := clientSet.AppsV1().StatefulSets(sts.Namespace).Create(context.TODO(), sts, metav1.CreateOptions{}) createdSTS, err := clientSet.AppsV1().StatefulSets(sts.Namespace).Create(context.TODO(), sts, metav1.CreateOptions{})
if err != nil { if err != nil {
@ -209,6 +208,11 @@ func createSTSsPods(t *testing.T, clientSet clientset.Interface, stss []*appsv1.
} }
createdSTSs = append(createdSTSs, createdSTS) createdSTSs = append(createdSTSs, createdSTS)
} }
return createdSTSs
}
func createPods(t *testing.T, clientSet clientset.Interface, pods []*v1.Pod) []*v1.Pod {
var createdPods []*v1.Pod
for _, pod := range pods { for _, pod := range pods {
createdPod, err := clientSet.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{}) createdPod, err := clientSet.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
if err != nil { if err != nil {
@ -217,7 +221,11 @@ func createSTSsPods(t *testing.T, clientSet clientset.Interface, stss []*appsv1.
createdPods = append(createdPods, createdPod) createdPods = append(createdPods, createdPod)
} }
return createdSTSs, createdPods return createdPods
}
func createSTSsPods(t *testing.T, clientSet clientset.Interface, stss []*appsv1.StatefulSet, pods []*v1.Pod) ([]*appsv1.StatefulSet, []*v1.Pod) {
return createSTSs(t, clientSet, stss), createPods(t, clientSet, pods)
} }
// Verify .Status.Replicas is equal to .Spec.Replicas // Verify .Status.Replicas is equal to .Spec.Replicas