fix(cli): exorcise the DERP healthcheck demon from TestSupportBundle (#23337)

- Replace real healthcheck with mock `HealthcheckFunc` that returns a
canned report instantly
- Remove healthcheck cache-seeding goroutine/channel workaround
- Remove `HealthcheckTimeout: testutil.WaitSuperLong` (no longer needed)
- Reduce `setupCtx` from `WaitSuperLong` (60s) to `WaitLong` (25s)

The DERP healthcheck performs real network operations (portmapper
gateway probing, STUN) that hang for 60s+ on macOS CI runners. Since
`TestSupportBundle` validates bundle generation, not healthcheck
correctness, a canned report eliminates this entire class of flake.

Fixes coder/internal#272

> 🤖 This PR was created with the help of Coder Agents, and was reviewed
by my human. 🧑‍💻
This commit is contained in:
Cian Johnston
2026-03-20 09:46:13 +00:00
committed by GitHub
parent 484f637c6c
commit 06c50d13ad
+17 -19
View File
@@ -28,7 +28,9 @@ import (
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbfake"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/healthcheck"
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
"github.com/coder/coder/v2/coderd/healthcheck/health"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/agentsdk"
"github.com/coder/coder/v2/codersdk/healthsdk"
@@ -50,9 +52,21 @@ func TestSupportBundle(t *testing.T) {
dc.Values.Prometheus.Enable = true
secretValue := uuid.NewString()
seedSecretDeploymentOptions(t, &dc, secretValue)
// Use a mock healthcheck function to avoid flaky DERP health
// checks in CI. The DERP checker performs real network operations
// (portmapper gateway probing, STUN) that can hang for 60s+ on
// macOS CI runners. Since this test validates support bundle
// generation, not healthcheck correctness, a canned report is
// sufficient.
client, closer, api := coderdtest.NewWithAPI(t, &coderdtest.Options{
DeploymentValues: dc.Values,
HealthcheckTimeout: testutil.WaitSuperLong,
DeploymentValues: dc.Values,
HealthcheckFunc: func(_ context.Context, _ string, _ *healthcheck.Progress) *healthsdk.HealthcheckReport {
return &healthsdk.HealthcheckReport{
Time: time.Now(),
Healthy: true,
Severity: health.SeverityOK,
}
},
})
t.Cleanup(func() { closer.Close() })
@@ -60,7 +74,7 @@ func TestSupportBundle(t *testing.T) {
memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
// Set up test fixtures
setupCtx := testutil.Context(t, testutil.WaitSuperLong)
setupCtx := testutil.Context(t, testutil.WaitLong)
workspaceWithAgent := setupSupportBundleTestFixture(setupCtx, t, api.Database, owner.OrganizationID, owner.UserID, func(agents []*proto.Agent) []*proto.Agent {
// This should not show up in the bundle output
agents[0].Env["SECRET_VALUE"] = secretValue
@@ -69,22 +83,6 @@ func TestSupportBundle(t *testing.T) {
workspaceWithoutAgent := setupSupportBundleTestFixture(setupCtx, t, api.Database, owner.OrganizationID, owner.UserID, nil)
memberWorkspace := setupSupportBundleTestFixture(setupCtx, t, api.Database, owner.OrganizationID, member.ID, nil)
// Wait for healthcheck to complete successfully before continuing with sub-tests.
// The result is cached so subsequent requests will be fast.
healthcheckDone := make(chan *healthsdk.HealthcheckReport)
go func() {
defer close(healthcheckDone)
hc, err := healthsdk.New(client).DebugHealth(setupCtx)
if err != nil {
assert.NoError(t, err, "seed healthcheck cache")
return
}
healthcheckDone <- &hc
}()
if _, ok := testutil.AssertReceive(setupCtx, t, healthcheckDone); !ok {
t.Fatal("healthcheck did not complete in time -- this may be a transient issue")
}
t.Run("WorkspaceWithAgent", func(t *testing.T) {
t.Parallel()