Skip to content

fix(app): guard onPreRemove against a nil k8sd client - #141

Draft
bschimke95 wants to merge 1 commit into
mainfrom
fix/preremove-nil-client-test-flake
Draft

bschimke95 wants to merge 1 commit into
mainfrom
fix/preremove-nil-client-test-flake

Conversation

@bschimke95

@bschimke95 bschimke95 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

TestClusterAPIAuthTokens and a few other tests fail intermittently in CI with a nil-pointer panic in onPreRemove (https://github.com/canonical/k8sd/actions/runs/37477175533/job/112315519419). Microcluster calls PreRemove as a rollback step when bootstrap/join fails, but our test harness (testenv.WithState) never configured a K8sdClient on its mock snap, so the hook called a method on a nil interface and crashed. TestOnPreRemoveNodeAbsentFromCluster failed alongside it for a different reason: it asserted on elapsed wall-clock time, which isn't reliable under CI load.

Change

  • onPreRemove: skip the PENDING wait if the k8sd client is nil, instead of panicking.
  • testenv.WithState: give the mock snap a real GetClusterMember mock so the rollback path has something to call.
  • TestOnPreRemoveNodeAbsentFromCluster: assert on call count instead of ctx.Err().

microcluster invokes the PreRemove hook as rollback when bootstrap or
join fails, not only on explicit node removal. testenv.WithState's
snap mock never configured a K8sdClient, so snap.K8sdClient("")
returned (nil, nil) and onPreRemove panicked calling a method on a nil
interface, aborting the in-flight HTTP response and failing bootstrap
with an opaque EOF (TestClusterAPIAuthTokens and other WithState-based
tests across pkg/k8sd/app, pkg/k8sd/database, pkg/k8sd/api,
pkg/k8sd/features/cilium).

Skip the PENDING wait when the client is nil instead of crashing, and
wire a working GetClusterMember mock into the test harness so the
documented rollback path can complete.

Also replace TestOnPreRemoveNodeAbsentFromCluster's wall-clock
assertion (ctx.Err() against a 5s timeout) with a call-count check,
since elapsed time is not deterministic under CI scheduling load.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The core nil-client regression path lacks deterministic test coverage.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Prevents rollback-time nil-pointer panics in onPreRemove and stabilizes related tests.

Changes:

  • Skip membership polling when no k8sd client exists.
  • Configure the test state with a not-found client mock.
  • Replace timing-based verification with call-count verification.
File Description
pkg/​k8sd/​app/​hooks_remove.go Guards the pre-remove wait against a nil client.
pkg/​utils/​microcluster/​state.go Adds a rollback-safe client mock.
pkg/​k8sd/​app/​hooks_remove_test.go Makes the membership-loop assertion deterministic.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +47 to 49
g.Expect(mockK8sdClient.GetClusterMemberCalledWithNames).To(HaveLen(1))
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants