Skip to content

Commit cd902b9

Browse files
committed
test: verify that crossplane has flags set/unset and pod stays running
Signed-off-by: Jared Watts <[email protected]>
1 parent 6906a55 commit cd902b9

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

test/e2e/apiextensions_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,9 @@ func TestPropagateFieldsRemovalToXRAfterUpgrade(t *testing.T) {
304304
// explicitly disable them first before we create anything.
305305
WithSetup("DisableSSAClaims", funcs.AllOf(
306306
funcs.AsFeaturesFunc(environment.HelmUpgradeCrossplaneToSuite(config.TestSuiteDefault)), // Disable our feature flag.
307+
funcs.ArgUnsetWithin(1*time.Minute, "--enable-ssa-claims", namespace, "crossplane"),
307308
funcs.ReadyToTestWithin(1*time.Minute, namespace),
309+
funcs.DeploymentPodIsRunningMustNotChangeWithin(10*time.Second, namespace, "crossplane"),
308310
)).
309311
WithSetup("PrerequisitesAreCreated", funcs.AllOf(
310312
funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"),
@@ -323,7 +325,9 @@ func TestPropagateFieldsRemovalToXRAfterUpgrade(t *testing.T) {
323325
// would end up sharing ownership with the old CSA field manager.
324326
Assess("EnableSSAClaims", funcs.AllOf(
325327
funcs.AsFeaturesFunc(environment.HelmUpgradeCrossplaneToSuite(SuiteSSAClaims)),
328+
funcs.ArgSetWithin(1*time.Minute, "--enable-ssa-claims", namespace, "crossplane"),
326329
funcs.ReadyToTestWithin(1*time.Minute, namespace),
330+
funcs.DeploymentPodIsRunningMustNotChangeWithin(10*time.Second, namespace, "crossplane"),
327331
)).
328332
Assess("UpdateClaim", funcs.AllOf(
329333
funcs.ApplyClaim(FieldManager, manifests, "claim-update.yaml"),

test/e2e/funcs/feature.go

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,100 @@ func DeploymentBecomesAvailableWithin(d time.Duration, namespace, name string) f
133133
}
134134
}
135135

136+
// DeploymentPodIsRunningMustNotChangeWithin fails a test if the supplied Deployment does
137+
// not have a running Pod that stays running for the supplied duration.
138+
func DeploymentPodIsRunningMustNotChangeWithin(d time.Duration, namespace, name string) features.Func {
139+
return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
140+
t.Helper()
141+
142+
dp := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}}
143+
t.Logf("Ensuring deployment %s/%s has running pod that does not change within %s", dp.GetNamespace(), dp.GetName(), d.String())
144+
start := time.Now()
145+
146+
pod, err := podForDeployment(ctx, t, c, dp)
147+
if err != nil {
148+
t.Errorf("Failed to get pod for deployment %s/%s: %s", dp.GetNamespace(), dp.GetName(), err)
149+
return ctx
150+
}
151+
152+
// first wait for pod to be running
153+
if err := wait.For(conditions.New(c.Client().Resources()).PodConditionMatch(pod, corev1.PodReady, corev1.ConditionTrue), wait.WithTimeout(d), wait.WithInterval(DefaultPollInterval)); err != nil {
154+
t.Errorf("Deployment %s/%s never got a running pod after %s", dp.GetNamespace(), dp.GetName(), since(start))
155+
return ctx
156+
}
157+
158+
// now wait to make sure the pod stays running (does not change)
159+
start = time.Now()
160+
if err := wait.For(conditions.New(c.Client().Resources()).PodConditionMatch(pod, corev1.PodReady, corev1.ConditionFalse), wait.WithTimeout(d), wait.WithInterval(DefaultPollInterval)); err != nil {
161+
if deadlineExceed(err) {
162+
t.Logf("Deployment %s/%s had running pod that did not change after %s", dp.GetNamespace(), dp.GetName(), since(start))
163+
} else {
164+
t.Errorf("Error while observing pod for deployment %s/%s", dp.GetNamespace(), dp.GetName())
165+
}
166+
return ctx
167+
}
168+
t.Errorf("Deployment %s/%s had pod that changed within %s, but it should not have", dp.GetNamespace(), dp.GetName(), d.String())
169+
return ctx
170+
}
171+
}
172+
173+
// ArgSetWithin fails a test if the supplied Deployment does not have a Pod with
174+
// the given argument set within the supplied duration.
175+
func ArgSetWithin(d time.Duration, arg, namespace, name string) features.Func {
176+
return checkArgSetWithin(d, arg, true, namespace, name)
177+
}
178+
179+
// ArgUnsetWithin fails a test if the supplied Deployment does not have a Pod with
180+
// the given argument unset within the supplied duration.
181+
func ArgUnsetWithin(d time.Duration, arg, namespace, name string) features.Func {
182+
return checkArgSetWithin(d, arg, false, namespace, name)
183+
}
184+
185+
// checkArgSetWithin implements a check for the supplied Deployment having a Pod
186+
// with the given argument being either set or unset within the supplied
187+
// duration.
188+
func checkArgSetWithin(d time.Duration, arg string, wantSet bool, namespace, name string) features.Func {
189+
return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
190+
t.Helper()
191+
192+
dp := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}}
193+
t.Logf("Waiting %s for pod in deployment %s/%s to have arg %s set=%t...", d, dp.GetNamespace(), dp.GetName(), arg, wantSet)
194+
start := time.Now()
195+
196+
if err := wait.For(func(ctx context.Context) (done bool, err error) {
197+
pod, err := podForDeployment(ctx, t, c, dp)
198+
if err != nil {
199+
t.Logf("failed to get pod for deployment %s/%s: %s", dp.GetNamespace(), dp.GetName(), err)
200+
return false, nil
201+
}
202+
203+
found := false
204+
c := pod.Spec.Containers[0]
205+
for _, a := range c.Args {
206+
if a == arg {
207+
found = true
208+
}
209+
}
210+
211+
if wantSet && !found {
212+
t.Logf("did not find arg %s within %s", arg, c.Args)
213+
return false, nil
214+
} else if !wantSet && found {
215+
t.Logf("unexpectedly found arg %s within %s", arg, c.Args)
216+
return false, nil
217+
}
218+
219+
return true, nil
220+
}, wait.WithTimeout(d), wait.WithInterval(DefaultPollInterval)); err != nil {
221+
t.Fatal(err)
222+
return ctx
223+
}
224+
225+
t.Logf("Deployment %s/%s has pod with arg %s set=%t after %s", dp.GetNamespace(), dp.GetName(), arg, wantSet, since(start))
226+
return ctx
227+
}
228+
}
229+
136230
// ResourcesCreatedWithin fails a test if the supplied resources are not found
137231
// to exist within the supplied duration.
138232
func ResourcesCreatedWithin(d time.Duration, dir, pattern string, options ...decoder.DecodeOption) features.Func {
@@ -727,7 +821,7 @@ func CompositeResourceHasFieldValueWithin(d time.Duration, dir, claimFile, path
727821
return got != ""
728822
}
729823

730-
if err := wait.For(conditions.New(c.Client().Resources()).ResourceMatch(cm, hasResourceRef), wait.WithTimeout(d), wait.WithInterval(DefaultPollInterval)); err != nil {
824+
if err := wait.For(conditions.New(c.Client().Resources()).ResourceMatch(cm, hasResourceRef), wait.WithTimeout(d), wait.WithInterval(DefaultPollInterval), wait.WithImmediate()); err != nil {
731825
t.Errorf("Claim %q does not have a resourceRef to an XR: %v", cm.GetName(), err)
732826
return ctx
733827
}
@@ -1168,3 +1262,33 @@ func since(t time.Time) string {
11681262
func deadlineExceed(err error) bool {
11691263
return errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "would exceed context deadline")
11701264
}
1265+
1266+
// podForDeployment returns the pod for a given Deployment. If the number of
1267+
// pods found is not exactly one, or that one pod does not have exactly one
1268+
// container, then this function returns an error.
1269+
func podForDeployment(ctx context.Context, t *testing.T, c *envconf.Config, dp *appsv1.Deployment) (*corev1.Pod, error) {
1270+
t.Helper()
1271+
if err := c.Client().Resources().Get(ctx, dp.GetName(), dp.GetNamespace(), dp); err != nil {
1272+
t.Logf("failed to get deployment %s/%s: %s", dp.GetNamespace(), dp.GetName(), err)
1273+
return nil, err
1274+
}
1275+
1276+
// use the deployment's selector to list all pods belonging to the deployment
1277+
selector := metav1.FormatLabelSelector(dp.Spec.Selector)
1278+
pods := &corev1.PodList{}
1279+
if err := c.Client().Resources().List(ctx, pods, resources.WithLabelSelector(selector)); err != nil {
1280+
t.Logf("failed to list pods for deployment %s/%s: %s", dp.GetNamespace(), dp.GetName(), err)
1281+
return nil, err
1282+
}
1283+
1284+
if len(pods.Items) != 1 {
1285+
return nil, errors.Errorf("expected 1 pod, found %d", len(pods.Items))
1286+
}
1287+
1288+
pod := pods.Items[0]
1289+
if len(pod.Spec.Containers) != 1 {
1290+
return nil, errors.Errorf("expected 1 container, found %d", len(pod.Spec.Containers))
1291+
}
1292+
1293+
return &pod, nil
1294+
}

0 commit comments

Comments
 (0)