Conversation
When a system test fails during setup — policy creation, agent enrollment and assignment, service container startup — it's usually a transient environment issue (dropped connection to Kibana, container killed by CI, slow response timeout), not a problem in the package under test. These failures are infrastructure noise that auto-file flaky issues and require manual triage. Implement setup-phase re-attempt: when prepareScenario fails (before any data validation), tear down the failed attempt and re-attempt the test from scratch, up to --setup-reattempts times (default 1, configurable, can be disabled with --setup-reattempts=0). Scope constraints, deliberately strict: 1. Setup-phase failures only. Data-validation failures (missing documents, field/mapping problems, unexpected hit counts) are real signal — they are reported as ErrTestCaseFailed and never re-attempted. The boundary is clean: prepareScenario wraps setup and endpoint auth, while validateTestScenario handles all data checks. 2. Per-test scope. Only the failing test config is re-attempted; siblings are untouched. Re-attempt cost is ~30-60s, paid only on failure. 3. Signal preserved. A test passing only after re-attempt gets FlakyMsg set with the earlier failures and is reported with <flakyFailure> in xUnit, so instability remains visible in aggregate even though the build no longer fails. Additionally: - Human reporter shows "PASS (flaky: …)" for re-attempted passes - Re-attempts stop on context cancellation or teardown failure (no retrying on a dirty environment) - --setup/--no-provision/--tear-down dev workflows unchanged - Added section to system testing HOWTO Fixes elastic#3888 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Context cancellation can be swallowed as a setup failure, causing the runner to continue into post-test steps even after the run has been cancelled.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds setup-phase re-attempts to the system test runner to reduce CI noise from transient infrastructure failures (e.g., Kibana timeouts, container termination) while preserving visibility of instability by marking tests as flaky when they only pass after a re-attempt.
Changes:
- Add a per-test setup re-attempt loop around scenario preparation, with teardown between attempts and a configurable
--setup-reattemptsflag (default: 1;0disables). - Introduce
FlakyMsgontestrunner.TestResultand surface it in human output (PASS (flaky: ...)) and xUnit output via<flakyFailure ...>. - Add unit tests for the re-attempt logic and xUnit flaky reporting, plus system testing HOWTO documentation.
File summaries
| File | Description |
|---|---|
| internal/testrunner/testrunner.go | Adds FlakyMsg to the shared TestResult model so reporters can surface flaky passes. |
| internal/testrunner/runners/system/tester.go | Implements setup-failure sentinel + re-attempt loop and annotates eventual passes as flaky. |
| internal/testrunner/runners/system/runner.go | Plumbs SetupReattempts runner option down into the system tester. |
| internal/testrunner/runners/system/reattempt_test.go | Adds unit tests for setup-phase re-attempt semantics and flaky annotation behavior. |
| internal/testrunner/reporters/formats/xunit.go | Emits <flakyFailure message="..."> for flaky passes in xUnit output. |
| internal/testrunner/reporters/formats/xunit_test.go | Tests xUnit flaky output and ensures flaky passes don’t count as failures/errors. |
| internal/testrunner/reporters/formats/human.go | Displays flaky passes as PASS (flaky: ...) in the human reporter. |
| internal/cobraext/flags.go | Defines the new --setup-reattempts CLI flag and description. |
| docs/howto/system_testing.md | Documents setup-phase re-attempt behavior and how flaky reporting is represented. |
| cmd/testrunner.go | Wires the new CLI flag into the system test runner options. |
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Were you able to run a setup re-attempt locally? Maybe some way of forcing errors in the setup?
I was trying to do so, but not able to find a scenario where it happens. I'd like to try it locally if possible.
EDIT: It would also be interesting to add a comment test integrations here in this Pull Request to force testing all the packages in the integrations repository with these elastic-package changes.
| Error string `xml:"error,omitempty"` | ||
| Failure string `xml:"failure,omitempty"` | ||
| Skipped *skipped `xml:"skipped,omitempty"` | ||
| FlakyFailure *flakyFailure `xml:"flakyFailure,omitempty"` |
There was a problem hiding this comment.
This new field is not added or taken into account in the json format.
Should it be added there for consistency ?
There was a problem hiding this comment.
Revisited after Teresa's request to keep result as a plain PASS. JSON now carries the previous-attempt failures in a separate flaky_details field (omitted when empty).
| Error string `xml:"error,omitempty"` | ||
| Failure string `xml:"failure,omitempty"` | ||
| Skipped *skipped `xml:"skipped,omitempty"` | ||
| FlakyFailure *flakyFailure `xml:"flakyFailure,omitempty"` |
There was a problem hiding this comment.
As a note, this new field will not be used by the Buildkite pipeline (IIRC it is not an standard field from xUnit) nor by the automation in the integrations repository to create new GitHub issues with label flaky-tests (no information about this flakiness will be added there).
| skipDeferCleanup := len(partial) > 0 && partial[0].Skipped != nil | ||
| return partial, err, r.tearDownTest(ctx, skipDeferCleanup) |
There was a problem hiding this comment.
If the parameter --defer-cleanup is set in the CLI, it will block every re-attempt.
skipDeferCleanup is derived from Skipped status rather than from whether this is a re-attempt. Each cleanup between retry attempts waits the full --defer-cleanup duration (e.g. 5 minutes), making retries painfully slow in practice.
Would it be ok to wait in each re-attempt if the user sets that flag in the CLI?
elastic-package test system -v --defer-cleanup 5mWDYT @teresaromero ? Keeping it as it is, it will let the developer to debug each re-attempt.
| var tcf testrunner.ErrTestCaseFailed | ||
| if errors.As(err, &tcf) { | ||
| return results, nil | ||
| } | ||
| return results, errSetupFailed{err: err} |
There was a problem hiding this comment.
Related to Copilot's message https://github.com/elastic/elastic-package/pull/3919/changes#r3928052171
I wonder if we should manage here if there is any context error to not wrap it with errSetupFailed
| var tcf testrunner.ErrTestCaseFailed | |
| if errors.As(err, &tcf) { | |
| return results, nil | |
| } | |
| return results, errSetupFailed{err: err} | |
| var tcf testrunner.ErrTestCaseFailed | |
| if errors.As(err, &tcf) { | |
| return results, nil | |
| } | |
| if ctx.Err() != nil { | |
| return results, ctx.Err() | |
| } | |
| return results, errSetupFailed{err: err} |
Or would it be better to do it where Copilot's message points out ?
There was a problem hiding this comment.
Reverted this because propagating ctx.Err() as hard error made runner discard the results
|
test integrations |
|
Created or updated PR in integrations repository to test this version. Check elastic/integrations#21166 |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved retry classification, log-scan, and cleanup issues can bypass retries, fail flaky passes, or retry a dirty environment.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 3
- Review effort level: Lite
| // Re-attempt the test from scratch, but only if the failure didn't | ||
| // come from a cancellation and the previous attempt could be torn | ||
| // down, so the new attempt starts from a clean environment. | ||
| if attemptNum < maxAttempts && ctx.Err() == nil && tdErr == nil { |
There was a problem hiding this comment.
🟡 Changes recommended
Critical result loss and moderate dirty-environment retry handling remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
internal/testrunner/runners/system/tester.go:2201
prepareScenariois not setup-only for data semantics:finalizeScenariocallsverifyDataStream, whosewaitForDocsevaluatesassert.hit_count,assert.min_count, andassert.fields_presentbefore returningErrTestCaseFailed. Wrapping every preparation error here makes missing-document/field/count validation failures retryable and can turn a real validation defect into a flaky pass, contrary to the strict no-retry contract. Distinguish setup/service errors from these assertion failures (or move the assertions out ofprepareScenario) before applyingerrSetupFailed.
return results, errSetupFailed{err: err}
internal/testrunner/runners/system/tester.go:802
- Checking only
tdErris not sufficient to enforce the no-dirty-environment rule. WhensetupServiceorsetupAgentfails inside deployerSetUp, their teardown handlers have not yet been registered here, and the deployers' setup-error cleanup logs and suppresses teardown failures. In that casetdErris nil even if partial resources could not be removed, so this branch retries on a dirty environment instead of stopping as required. Propagate those setup-cleanup errors or expose them to this retry gate.
if attemptNum < maxAttempts && ctx.Err() == nil && tdErr == nil {
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
teresaromero
left a comment
There was a problem hiding this comment.
I went through the code and left some comments. I am concern about having this activated by default; suggested to make it opt-in so we can be explicit about it.
Related to the formats/outputs; based on the comment of Mario https://github.com/elastic/elastic-package/pull/3919/changes#r3959485113 ; is it necesary to show it as a different "success" ? if the goal is to retry on setup (because is flaly) i think the output should be FAIL/PASS after all , regardless the setup retries it got. this way we keep output standard for buildkite. wdyt?
| cmd.Flags().Bool(cobraext.TearDownFlagName, false, cobraext.TearDownFlagDescription) | ||
| cmd.Flags().Bool(cobraext.NoProvisionFlagName, false, cobraext.NoProvisionFlagDescription) | ||
| cmd.Flags().String(cobraext.AgentVersionFlagName, "", cobraext.AgentVersionFlagDescription) | ||
| cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 1, cobraext.SetupReattemptsFlagDescription) |
There was a problem hiding this comment.
| cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 1, cobraext.SetupReattemptsFlagDescription) | |
| cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 0, cobraext.SetupReattemptsFlagDescription) |
Can we change the default to 0 and be explicit on this setting where ever we are using the command?
There was a problem hiding this comment.
If it is set to zero the default value to not change the current behavior, it will be good to support setting an environment variable too for this. That would help to update the CI in the integrations and elastic-package repository without having to update the CI scripts (adding new parameters). However this parameter is not global for the test command and it will be needed to split the commands in scripts.
So, I'd prefer if we do so, reading also an environment variable to allow setting the same value as the new parameter.
There was a problem hiding this comment.
Updated default as 0 and added env variable TEST_SETUP_REATTEMPTS that can be set inside integration pipeline to make re-attempts.
| return cobraext.FlagParsingError(err, cobraext.DeferCleanupFlagName) | ||
| } | ||
|
|
||
| setupReattempts, err := cmd.Flags().GetInt(cobraext.SetupReattemptsFlagName) |
There was a problem hiding this comment.
is there a max limit for reattempts?
There was a problem hiding this comment.
Added comments, my main concern is that these new re-attempts should not change the current behaviour for reporting failures and errors. And following that, it needs to be ensured that the cleaning (tearDownTest) runs between attempts and at the end of each test. Every re-attempt needs to be run after all the tearDown process is performed.
EDIT: If new changes are pushed, it would be interesting to run the tests with all the packages integrations via posting the test integrations comment. Not for all commits, but we would need to validate from time to time that this is not breaking anything and that it is working as expected.
| // All errors from prepareScenario are environment issues and should be | ||
| // re-attempted. Note: ErrTestCaseFailed can reach here from | ||
| // verifyDataStream (service exited non-zero) or waitForDocs (no hits | ||
| // within the timeout), both of which are setup-phase events. | ||
| // validateTestScenario failures are never returned as Go errors — they | ||
| // are captured in result.FailureMsg via result.WithError — so there is | ||
| // no validation signal to guard against here. |
There was a problem hiding this comment.
I'm not sure if this latest change would report the errors like service exited non-zero or waitForDocs with no hits as test cases failed.
They should appear in the xUnit file as failures or errors. I'm not sure how they are reported, but they are.
Could you check that this is still working in this way ?
There was a problem hiding this comment.
Moreover commit dba1cb7 removed the ErrTestCaseFailed guard, so waitForDocs failures, including assert.hit_count, assert.min_count and assert.fields_present, are re-attempted. A test whose input genuinely produces no data now waits the 10 minute default timeout twice, plus a second setup.
The PR description, the docs section, and the test comment at reattempt_test.go:86 all still claim these are never re-attempted. Could it be restored the guard for the waitForDocs error? In any case, it would be needed to update the description and docs independently of the solution chosen.
As it would happen in main, those waitForDocs errors should also be reported in the xUnit file.
It could be tested by changing some min_count or hit_count value in the test config of one package to force the failure.
There was a problem hiding this comment.
Restored the ErrTestCaseFailed guard, so waitForDocs failures (no hits, hit_count, min_count, fields_present, and undiscovered data streams) are not re-attempted and still surface as via FailureMsg, same as main.
There was a problem hiding this comment.
For the service-exit case, the first version turned it into a plain error, which made it retryable but also changed its xUnit report from <failure> to <error>. The docker_failing_test_service false-positive test caught that.
In 2d1eb0c, it is now wrapped in errServiceExited, which unwraps to ErrTestCaseFailed, so it is re-attempted but still reported as <failure> with the exact same message. TestServiceExitedReportedAsFailure guards this now.
Ran both locally against a 9.4.4 stack with --report-format xUnit --report-output file:
- docker_failing_test_service with defaults: one
<failure>, both CI assertions pass. - Same package with
--setup-reattempts 1: attempt 1 fails, teardown runs, attempt 2 starts in a fresh namespace, fails again, single reported, no leftover containers.
| return e.err | ||
| } | ||
|
|
||
| func (r *tester) runTestPerVariant(ctx context.Context, stackConfig stack.Config, result *testrunner.ResultComposer, cfgFile, variantName string) ([]testrunner.TestResult, error) { |
There was a problem hiding this comment.
Related to this comment #3919, the startingTime is obtained before this function.
That time is used to check the agent logs looking for any error or warning. If that startingTime is obtained before the retries, it could be checking other containres.
And this is also related to the other comment posted by Copilot #3919, it would be needed to assess if this is true. If there is a re-attempt, elastic-package needs to ensure that the scenario (kibana, elasticsearch) is not dirty. Previous Elastic Agents should be unenrolled and removed, policies should be deleted, data streams should be deleted too, and so on.
| if errors.As(err, &setupErr) { | ||
| // Setup failures are already reported as part of the test results, | ||
| // they are not returned as hard errors to the caller. | ||
| err = nil |
There was a problem hiding this comment.
If this error is overwritten with nil, and all the attempts finish with error.
The condition in line 809, will not be true. I'm thinking for instance in those cases that the service cannot start due to some error. We want to report that as before in the xUnit so it gets shown in Buildkite and in Github issues.
Related also to this other comment https://github.com/elastic/elastic-package/pull/3919/changes#r3980680995
There was a problem hiding this comment.
It could be tested forcing an error in some Dockerfile in any of the test packages, or any other error that could lead to a failure here.
Then it should be reported as part of the xUnit (as it is done currently).
IIRC this is the command to create the xUnit files in system tests:
elastic-package test system -v --report-output file --report-format xUnit
There was a problem hiding this comment.
Thanks for the thorough look. This downstream result-loss risk are pre-existing behaviour in upstream/main and not introduced by this PR.
On main, runTest already returns (results, nil) for all setup errors (line return results, nil in the original prepareScenario error handler). As a result, run() already continues into the stack dump.
Our re-attempt loop reproduces that same behaviour: when all attempts are exhausted, errSetupFailed is cleared and we return (partial, nil), so run() sees the same nil-error path it would have seen on main for a single failed attempt. Nothing is worse.
Agreed that fixing the result-loss in run() would be a good improvement, but it's a separate pre-existing issue. Happy to track it as a follow-up if that's useful.
| // are captured in result.FailureMsg via result.WithError — so there is | ||
| // no validation signal to guard against here. | ||
| if ctx.Err() != nil { | ||
| return results, ctx.Err() |
There was a problem hiding this comment.
IIRC on main a context cancellation during setup produced an <error> entry. Now runTest returns the context error as a hard error, and testrunner.run discards that tester's results
From main:
// report all other errors as error entries in the xUnit file
results, _ := result.WithError(err)
return results, nil
It would be needed to validate if those errors are still reported in the xUnit file as <error> too.
There was a problem hiding this comment.
Confirmed and fixed. runTest now handles the cancellation same way as main does. Also updated thread https://github.com/elastic/elastic-package/pull/3919/changes#r3989048115
There was a problem hiding this comment.
🟡 Changes recommended
Retry defaults, teardown safety, human flaky reporting, and prior-attempt log handling remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (4)
cmd/testrunner.go:21
- This added import is out of gofmt order;
internal/commonshould precedeinternal/environment. Running the repository formatter will rewrite this block and can make the format check fail.
"github.com/elastic/elastic-package/internal/environment"
"github.com/elastic/elastic-package/internal/common"
internal/testrunner/runners/system/tester.go:802
- Checking
tdErrhere is not sufficient to enforce the no-dirty-retry rule. WhenserviceDeployer.SetUporagentDeployer.SetUpfails, their deferred cleanup callsTearDownbut logs and suppresses cleanup errors, and the outer cleanup handlers are registered only after successful setup;tdErrtherefore remains nil and this branch retries despite a failed teardown. Propagate that cleanup failure or carry an explicit dirty-environment signal before retrying.
if attemptNum < maxAttempts && ctx.Err() == nil && tdErr == nil {
internal/testrunner/runners/system/tester.go:819
FlakyMsgis only consumed by the xUnit formatter. The human formatter still renders every result withoutErrorMsg,FailureMsg, orSkippedas plainPASS, so a recovered setup failure is not shown asPASS (flaky: …)as promised. Add the annotation to the human formatter and cover it in its tests.
partial[0].FlakyMsg = strings.Join(setupFailures, "; ")
internal/testrunner/runners/system/tester.go:780
- The retry loop now runs after
startTestingis captured inrun, butcheckAgentLogslater scans logs from that original timestamp. Any error-pattern entry emitted by a failed setup attempt is therefore reported again as an additionalFailureMsgafter a later setup retry passes, so the command can still fail instead of producing the advertised flaky pass. Scope the log check to the final attempt or otherwise exclude prior-attempt logs when the failure is recorded inFlakyMsg.
return runWithSetupReattempts(ctx, r.setupReattempts, attempt)
- Files reviewed: 9/9 changed files
- Comments generated: 2
- Review effort level: Lite
| cmd.Flags().Bool(cobraext.TearDownFlagName, false, cobraext.TearDownFlagDescription) | ||
| cmd.Flags().Bool(cobraext.NoProvisionFlagName, false, cobraext.NoProvisionFlagDescription) | ||
| cmd.Flags().String(cobraext.AgentVersionFlagName, "", cobraext.AgentVersionFlagDescription) | ||
| cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 0, cobraext.SetupReattemptsFlagDescription) |
| // If the test passed only after being re-attempted, description of the | ||
| // failures observed in previous attempts. The test is reported as | ||
| // passed, but flagged as flaky in reports that support it. | ||
| FlakyMsg string |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🟡 Changes recommended
Issues remain with the default retry behavior, setup cleanup handling, failure classification, and human-readable flaky reporting.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (7)
Previously missed (1) — in code that hasn't changed since the last review.
cmd/testrunner.go:21
- This import block is not gofmt-sorted:
internal/environmentis placed beforeinternal/common, so the format/lint step will rewrite it. Reorder these imports or run gofmt before merging.
cmd/testrunner.go:488
- The CLI default here is 0, so when neither the flag nor environment variable is set, system tests get no setup re-attempts. The PR contract specifies one re-attempt by default; use 1 here while preserving explicit
--setup-reattempts=0as the opt-out.
cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 0, cobraext.SetupReattemptsFlagDescription)
docs/howto/system_testing.md:1003
- This documents the opposite default from the requested behavior: one setup re-attempt should be enabled by default, with zero disabling it. Please update the sentence so users are not told that retries are off unless they explicitly enable them.
re-attempted from scratch. Setup re-attempts are disabled by default; enable
them with `--setup-reattempts=N` (maximum 5). For example:
internal/testrunner/runners/system/tester.go:2208
- This comment overstates the validation contract:
validateTestScenariocan return non-nil errors for expected-dataset resolution, repository/validator setup, and other runtime failures; only itsErrTestCaseFailedresults are captured inFailureMsg. Narrow the comment so future changes do not assume every validation error follows the same result path.
// validateTestScenario failures are never returned as Go errors — they
// are captured in result.FailureMsg via result.WithError — so there is
// no risk of retrying real validation failures here.
internal/testrunner/runners/system/tester.go:811
tdErronly reports errors fromtearDownTest. IfsetupServiceorsetupAgentfails inside its deployer'sSetUp, the deployer runs cleanup before returning but logs and suppresses cleanup errors, and the tester never registers a teardown handler. This condition can therefore be true even after setup cleanup failed, causing a retry against a potentially dirty environment despite the no-retry-on-teardown-failure guarantee. Propagate setup-time cleanup failures into this decision or otherwise make that failure non-retryable.
if attemptNum < maxAttempts && ctx.Err() == nil && tdErr == nil {
internal/testrunner/runners/system/tester.go:829
- When a later attempt passes, this only populates
FlakyMsg. The human reporter still renders every successful result as the literalPASSand never reads this field, so the requiredPASS (flaky: …)signal is absent from the default human output. Update the human formatter to include the flaky message for passed results.
if len(setupFailures) > 0 && len(partial) > 0 && testPassed(partial[0]) {
partial[0].FlakyMsg = strings.Join(setupFailures, "; ")
}
internal/testrunner/testrunner.go:123
FlakyMsgis not rendered by the human reporter, which still emits plainPASSfor results withoutFailureMsg. This hides the earlier setup failures in the default output and misses the requestedPASS (flaky: …)presentation; add aFlakyMsgbranch to the human formatter.
// If the test passed only after being re-attempted, description of the
// failures observed in previous attempts. The test is reported as
// passed, but flagged as flaky in reports that support it.
FlakyMsg string
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Retry defaults, teardown handling, error classification, and human flaky-pass reporting still have unresolved issues.
Review details
Suppressed comments (5)
cmd/testrunner.go:488
- The requested default is one re-attempt, but this flag is initialized to 0, so normal CLI runs never enter the retry loop unless the user opts in. This conflicts with the PR description; use 1 as the flag default while retaining an explicit 0 to disable retries.
cmd.Flags().Int(cobraext.SetupReattemptsFlagName, 0, cobraext.SetupReattemptsFlagDescription)
internal/testrunner/runners/system/tester.go:811
- This clean-retry check only observes tearDownTest's handlers. When a deployer SetUp fails, those handlers are registered only after SetUp succeeds, while the deployers' deferred cleanup logs and suppresses TearDown errors (internal/servicedeployer/compose.go:138-157 and internal/agentdeployer/agent.go:180-200). A failed cleanup can therefore leave tdErr nil and this code retries in a dirty environment, contrary to the stop-on-teardown-failure requirement; propagate those cleanup errors or mark the attempt non-retryable.
if attemptNum < maxAttempts && ctx.Err() == nil && tdErr == nil {
internal/testrunner/runners/system/tester.go:828
- This annotation is not consumed by the default human reporter:
reportHumanFormatonly checksErrorMsg,FailureMsg, andSkipped, then renders plainPASSwhen those are empty. A test that passes after a setup re-attempt therefore never shows the promisedPASS (flaky: …); update the human formatter (and its test) to renderFlakyMsg.
partial[0].FlakyMsg = strings.Join(setupFailures, "; ")
internal/testrunner/runners/system/tester.go:2213
- This catch-all classifies every
prepareScenarioerror other thanErrTestCaseFailedas retryable setup failure. For example,waitForDocsreturns plain errors for invalidassert.hit_count/assert.min_countvalues above the query limit, so a deterministic malformed test configuration is retried up to N times instead of being reported once; add a non-retryable classification for such config/data errors before wrapping environmental failures.
return results, errSetupFailed{err: err}
internal/testrunner/testrunner.go:123
- FlakyMsg is never consumed by the human formatter (internal/testrunner/reporters/formats/human.go:53-63), which still emits plain PASS. A pass after setup retries therefore misses the promised
PASS (flaky: …)signal; add the human-rendering branch and test it.
FlakyMsg string
- Files reviewed: 11/11 changed files
- Comments generated: 0 new
- Review effort level: Lite
⏳ Build in-progress, with failures
Failed CI StepsHistory
cc @kcreddy |
TL;DRBuildkite failed in Remediation
Investigation detailsRoot CauseThe PR changed the system test setup-path error classification:
So this is a test fixture drift caused by the PR’s intended behavior change, not infra flakiness. Evidence
Verification
Follow-up
What is this? | From workflow: PR Buildkite Detective Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not. |
There was a problem hiding this comment.
🟡 Changes recommended
Restrict retries to environment errors and report exhausted service exits as xUnit errors.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
internal/testrunner/runners/system/tester.go:798
- Only
ErrTestCaseFailedis excluded here, so every otherprepareScenarioerror becomes retryable. However,prepareScenarioalso emits deterministic package/config errors such as missing or ambiguous policy templates (tester.go:1351-1360) and invalid built package policy (1421-1423). With this flag enabled, those errors are repeated up to five times instead of restricting retries to environment failures, adding teardown/setup churn and delaying the real failure. Add an explicit retryable marker around only environment operations and leave package/config errors non-retryable.
return errSetupFailed{err: err}
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
| func (e errServiceExited) Unwrap() error { | ||
| return e.err | ||
| } |
Closes #3888