Skip to content

Commit cbc3b3c

Browse files
hc-github-team-consul-coretempshashankNandigama
authored
Backport of flaky tests fixes in peering, api-gateway, wan-federation, sameness packages into release/1.9.x (#4963)
* no-op commit due to failed cherry-picking * flaky tests fixes in peering, api-gateway, wan-federation, sameness packages (#4913) * update retry logic for gateway and httproute readiness * run only api-gateway tests * use custom retry * add retries in peering test * include sameness package test * add retries in other tests in peering * add wait before patching httproutes * update checks * update retries to recreate httproute * updated retry logic for httproute checks * update sameness tests * update httproute recreation logic in api_gateway jwt auth test * update cleanup in sameness tests * run all packages' tests * refactor code * refactor code * lint error fix * add retries while creating httproute * refactor functions * lint errors fixes * update comment --------- Co-authored-by: temp <[email protected]> Co-authored-by: shashankNandigama <[email protected]>
1 parent c86b785 commit cbc3b3c

File tree

10 files changed

+392
-77
lines changed

10 files changed

+392
-77
lines changed

acceptance/framework/helpers/helpers.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,104 @@ func WaitForInput(t *testing.T) {
397397
t.Fatal(err)
398398
}
399399
}
400+
401+
// WaitForHTTPRouteWithRetry waits for an HTTPRoute to exist with retry logic
402+
// and delete/recreate fallback to make the tests more robust against intermittent issues.
403+
// It checks for the HTTPRoute's existence multiple times per attempt, and if
404+
// not found, attempts to delete and recreate the resource by reapplying the kustomize manifest.
405+
func WaitForHTTPRouteWithRetry(t *testing.T, kubectlOptions *k8s.KubectlOptions, routeName, kustomizeDir string) {
406+
t.Helper()
407+
408+
logger.Log(t, "waiting for httproute to be created")
409+
found := false
410+
maxAttempts := 3
411+
checksPerAttempt := 5
412+
413+
for attempt := 1; attempt <= maxAttempts; attempt++ {
414+
logger.Logf(t, "httproute existence check attempt %d/%d", attempt, maxAttempts)
415+
416+
// Check for httproute existence using simple loop
417+
for i := range checksPerAttempt {
418+
_, err := k8s.RunKubectlAndGetOutputE(t, kubectlOptions, "get", "httproute", routeName)
419+
if err == nil {
420+
found = true
421+
logger.Logf(t, "httproute %s found successfully", routeName)
422+
break
423+
}
424+
logger.Logf(t, "httproute check %d/%d: %v", i+1, checksPerAttempt, err)
425+
time.Sleep(2 * time.Second)
426+
}
427+
428+
if found {
429+
break
430+
}
431+
432+
if attempt < maxAttempts {
433+
logger.Logf(t, "httproute not found after %d seconds, attempting delete/recreate (attempt %d/%d)", checksPerAttempt*2, attempt, maxAttempts)
434+
// Delete the httproute if it exists in a bad state
435+
_, err := k8s.RunKubectlAndGetOutputE(t, kubectlOptions, "delete", "httproute", routeName, "--ignore-not-found=true")
436+
if err != nil {
437+
logger.Logf(t, "warning: failed to delete httproute %s: %v", routeName, err)
438+
}
439+
// Recreate by reapplying the base resources
440+
out, err := k8s.RunKubectlAndGetOutputE(t, kubectlOptions, "apply", "-k", kustomizeDir)
441+
require.NoError(t, err, out)
442+
// Brief pause to let the recreation start
443+
time.Sleep(2 * time.Second)
444+
}
445+
}
446+
447+
if !found {
448+
require.Failf(t, "httproute %s was not found after %d attempts with delete/recreate", routeName, maxAttempts)
449+
}
450+
}
451+
452+
// EnsurePeeringAcceptorSecret ensures that a peering acceptor secret is created,
453+
// retrying by deleting and recreating the peering acceptor if the secret name is empty.
454+
// This is a helper function to handle flakiness in peering acceptor secret creation.
455+
func EnsurePeeringAcceptorSecret(t *testing.T, r *retry.R, kubectlOptions *k8s.KubectlOptions, peeringAcceptorPath string) string {
456+
t.Helper()
457+
458+
acceptorSecretName, err := k8s.RunKubectlAndGetOutputE(r, kubectlOptions, "get", "peeringacceptor", "server", "-o", "jsonpath={.status.secret.name}")
459+
require.NoError(r, err)
460+
461+
// If the secret name is empty, retry recreating the peering acceptor up to 5 times
462+
if acceptorSecretName == "" {
463+
const maxRetries = 5
464+
for attempt := 1; attempt <= maxRetries; attempt++ {
465+
logger.Logf(t, "peering acceptor secret name is empty, recreating peering acceptor (attempt %d/%d)", attempt, maxRetries)
466+
k8s.KubectlDelete(t, kubectlOptions, peeringAcceptorPath)
467+
468+
time.Sleep(5 * time.Second)
469+
470+
k8s.KubectlApply(t, kubectlOptions, peeringAcceptorPath)
471+
472+
time.Sleep(10 * time.Second)
473+
474+
acceptorSecretName, err = k8s.RunKubectlAndGetOutputE(r, kubectlOptions, "get", "peeringacceptor", "server", "-o", "jsonpath={.status.secret.name}")
475+
require.NoError(r, err)
476+
477+
if acceptorSecretName != "" {
478+
logger.Logf(t, "peering acceptor secret name successfully created after %d attempts", attempt)
479+
break
480+
}
481+
482+
if attempt == maxRetries {
483+
logger.Logf(t, "peering acceptor secret name still empty after %d attempts", maxRetries)
484+
}
485+
}
486+
}
487+
488+
require.NotEmpty(r, acceptorSecretName)
489+
return acceptorSecretName
490+
}
491+
492+
// HasStatusCondition checks if a condition exists with the expected status and reason.
493+
func HasStatusCondition(conditions []metav1.Condition, toCheck metav1.Condition) bool {
494+
for _, c := range conditions {
495+
if c.Type == toCheck.Type {
496+
return c.Reason == toCheck.Reason && c.Status == toCheck.Status
497+
}
498+
}
499+
return false
500+
}

acceptance/tests/api-gateway/api_gateway_external_servers_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,20 @@ func TestAPIGateway_ExternalServers(t *testing.T) {
9090
})
9191

9292
logger.Log(t, "creating api-gateway resources")
93-
out, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/api-gateway")
94-
require.NoError(t, err, out)
93+
// Apply api-gateway resources with retry logic to handle intermittent failures
94+
retry.Run(t, func(r *retry.R) {
95+
out, err := k8s.RunKubectlAndGetOutputE(r, ctx.KubectlOptions(r), "apply", "-k", "../fixtures/bases/api-gateway")
96+
require.NoError(r, err, out)
97+
})
9598
helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() {
9699
// Ignore errors here because if the test ran as expected
97100
// the custom resources will have been deleted.
98101
k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway")
99102
})
100103

104+
// Wait for the httproute to exist before patching, with delete/recreate fallback
105+
helpers.WaitForHTTPRouteWithRetry(t, ctx.KubectlOptions(t), "http-route", "../fixtures/bases/api-gateway")
106+
101107
logger.Log(t, "patching route to target server")
102108
k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "httproute", "http-route", "-p", `{"spec":{"rules":[{"backendRefs":[{"name":"static-server","port":80}]}]}}`, "--type=merge")
103109

0 commit comments

Comments
 (0)