Files
fleet/cmd
Rajendra kadam bf352c7208 Boot-test runServeCmd end to end (serve.go ~7% to ~64% coverage) (#48261)
Adds an end-to-end boot test for `runServeCmd`, the main server entry
point. This is the coverage milestone for #33370: `serve.go` goes from
~7% to ~64%, and `runServeCmd` itself from 0% to ~62%.

The earlier PRs on this issue (#44929, #45343, #45583, #46166, #46421,
#46517, #46742, #46830, #46893, #47151, #47562, #47891) extracted
testable pieces out of `runServeCmd`, but the function itself stayed at
0% — it blocks on an OS signal and wires the entire server together, so
the only way to cover it is to actually boot it. This PR does that.

`TestRunServeCmd` (gated behind `MYSQL_TEST` + `REDIS_TEST`) boots the
full server against a real migrated test MySQL and Redis, waits for
`/healthz`, then cancels the command context to trigger a graceful
shutdown. It covers two paths:

- **Full boot with Apple MDM enabled** — a 32-byte server private key
brings up the Apple MDM protocol services and the host-identity /
conditional-access SCEP setup, so the boot exercises the MDM startup
path as well as the core wiring, cron schedules, and HTTP server.
- **Fail-fast on bad config** — an invalid Redis host-cache
configuration (enabled with a non-positive TTL) aborts startup through
`initFatal` and returns rather than serving, covering the Redis-init
error path and the nil-pool guard.

Beyond coverage, this doubles as a regression net for the ongoing
`runServeCmd` slicing: a future change that breaks startup now fails
this test instead of reaching a release.

**One production change**, in `runServeCmd`'s shutdown `select`: it now
also watches `cmd.Context().Done()`. This is inert in production — the
root command runs via `Execute()` (not `ExecuteContext()`), so
`cmd.Context()` is `context.Background()` and never cancels. Only the
test runs the command with a cancelable context, which is how it shuts
the server down without sending a real signal (a `SIGTERM` would kill
the test binary).

A couple of notes for reviewers:
- The test uses `os.Setenv` (not `t.Setenv`) because the MySQL test
helper marks the test parallel; the boot scenarios run as serial
subtests so the process-global config env doesn't race.
- `runServeCmd` registers metrics with the process-global Prometheus
registry, which can only happen once per process, so there is a single
full boot here; the error-path scenario fails before that registration.
- The test DB is loaded from a schema dump that doesn't mark every data
migration as applied, so the boot runs with
`FLEET_UPGRADES_ALLOW_MISSING_MIGRATIONS=1`.

It adds ~2s to the `cmd/fleet` (`main`) test bundle, which is well off
the CI critical path.

**Related issue:** Refs #33370

# Checklist for submitter

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually (verified locally:
boots to /healthz, graceful shutdown, ~64% serve.go coverage)
- Changes file: not applicable — internal test coverage with no
user-visible behavior change

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved server shutdown handling to stop cleanly when the running
command’s context is canceled, not only on OS signals.
* Added stronger startup validation to fail fast for invalid Redis
host-cache configuration (e.g., non-positive TTL).
* **Tests**
* Added an end-to-end test that boots the server against real
MySQL/Redis, verifies graceful startup/shutdown, and confirms fast-fail
behavior for misconfiguration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 09:28:20 -04:00
..