Tests: fail informatively instead of panicking the whole package - #27
Open
distronode-com wants to merge 1 commit into
Open
Tests: fail informatively instead of panicking the whole package#27distronode-com wants to merge 1 commit into
distronode-com wants to merge 1 commit into
Conversation
…ackage
`id := created["id"].(string)` on a response body that has no id panics, and a
panic aborts the WHOLE test binary: one bad request reported a nil-interface
stack trace and no other handler test result at all, with the status and error
message nowhere on screen.
Measured, not inferred. With a create that really fails (a loopback webhook URL,
rejected by the SSRF guard), the old pattern gives:
--- FAIL: TestZZOldPattern
panic: interface conversion: interface {} is nil, not string [recovered, repanicked]
FAIL github.com/calnode/calnode/internal/handler
and an unrelated passing test in the same package never reports at all. The same
failure through the new helpers gives:
zz_panic_demo_test.go:32: create webhook: status = 400; want 201 —
{"error":"webhook URL must not resolve to a private or loopback address:
\"127.0.0.1\" resolved to a private or loopback address"}
--- FAIL: TestZZNewPattern
--- PASS: TestZZSomeOtherUnrelatedTest
which is the actual diagnosis, on the first line, with every other test still
reporting. (That 400 is a real one: it cost real time to find behind the panic.)
Four helpers next to the existing ones in api_test.go, each taking a `what` so a
test making several requests still says which call failed: mustStatus, mustJSON,
mustCreated, mustString.
Of the 32 `].(string)` sites in internal/handler/*_test.go, 10 used the
single-value form and could panic — 6 of those decoded the body with no status
check at all (invites) and 2 checked the status without printing the body. All 10
now assert the status first, quoting the body, and read fields through mustString.
The remaining 22 already used the two-value form, so they could not panic, but 18
of them silently yielded "" for a missing field and deferred the failure to
something downstream that could not explain it (a 404 on an empty id). Those now
use mustString too. The last 4 are left alone deliberately, because there the
two-value form IS the assertion: test_email_test.go:49, public_eventtype_test.go:64,
claim_test.go:81, and the secret-length check in webhook_test.go.
No test's assertions changed. Where a status check was missing it was added, which
only makes an already-implicit dependency explicit; every test that passed before
passes now.
Verified: gofmt -l . empty, go vet ./... clean, go test ./... exit 0 (26 packages,
no failures). No non-test file is touched.
Contributor
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes in this run: full PR diff (test-only helpers + call-site migrations; 1 commit on test/fail-instead-of-panic).
- Informative response helpers —
mustStatus/mustJSON/mustCreated/mustStringinapi_test.gofail the single test with status + body instead of panicking the package or yielding empty ids that 404 later. - Call-site migration — panic-prone and silent two-value
.(string)extracts in availability, invites, MCP OAuth, overrides, webhooks, and a few booking/rule paths now go through those helpers; status is checked before field reads where it was missing. - Intentionally untouched sites — remaining two-value asserts that are the assertion (and out-of-scope leftovers like
calendar_test.go) match the PR description; no production code changed.
go test ./internal/handler/ passed on this head.
Grok | 𝕏
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

One failed request takes the whole handler package down
id := created["id"].(string)on a body that has noidpanics, and a panic aborts theentire test binary. So a single bad request reports a nil-interface stack trace and no
other handler test result at all, with the status and error message nowhere on screen.
Measured, not inferred. With a create that really fails (a loopback webhook URL, rejected
by the SSRF guard) plus one unrelated passing test in the same package:
Before
The unrelated test never reports.
After
The diagnosis is on the first line and every other test still reports. (Those two demo
tests were temporary and are not in the diff. That 400 is a real one — it cost real
diagnosis time hidden behind the panic.)
The change
Four helpers beside the existing ones in
api_test.go, each taking awhatthat names thecall so a test making several requests still says which one failed:
Of the 32
].(string)sites ininternal/handler/*_test.go:with no status check at all; 2 checked the status without printing the body. All 10 now
assert the status first and read fields through
mustString.""for a missing field,deferring the failure to something downstream that could not explain it — a 404 on an
empty id. Those use
mustStringtoo.test_email_test.go:49,public_eventtype_test.go:64,claim_test.go:81, and thesecret-length check in
webhook_test.go.No test's assertions changed. Where a status check was missing it was added, which only
makes an already-implicit dependency explicit. No non-test file is touched.
Testing
go test ./...green (26 packages);gofmt -l .empty;go vet ./...clean. Every testthat passed before passes now.