# Test Gap Analysis — Microck/tailstick **Task:** test-gap | **Category:** analysis | **Severity:** P2 (Medium) ## Summary tailstick has 3,156 lines of Go across 12 packages. 5 packages have test files covering ~610 test lines. 7 packages have **zero tests**. Overall estimated test coverage: ~35-40% of source code. ## Untested Packages (Critical Gaps) ### 🔴 P1 — internal/state (82 lines, 0 test lines) **Risk:** State persistence is the canonical source of truth for lease data. - `Load()` — handles file-not-found, JSON parse errors, schema defaults - `Save()` — atomic write with tmp file, directory creation - `UpsertRecord()` — update-or-append logic for lease records - `AppendAudit()` — append-only audit log writer **Recommended tests:** - `TestLoad_NoFile` — returns empty state with defaults - `TestLoad_InvalidJSON` — returns parse error - `TestSave_CreatesDir` — creates parent directories - `TestSave_AtomicWrite` — tmp file renamed on success - `TestUpsertRecord_Insert` — appends new record - `TestUpsertRecord_Update` — replaces existing by LeaseID - `TestAppendAudit` — appends JSON line to file ### 🟡 P2 — internal/platform (216 lines, 0 test lines) **Risk:** OS detection, path resolution, privilege checking. - `Detect()` — gathers host context (OS, arch, boot ID, exe path) - `sanitizeHost()` — hostname sanitization (special chars, empties) - `StatePath()/LogPath()/LocalSecretPath()` — platform-specific paths - `IsElevated()` — checks root/admin status - `RequireSupportedLinux()` — validates distro support - `Runner.Run()` — command execution with dry-run support **Recommended tests:** - `TestSanitizeHost` — various inputs: empty, special chars, unicode, dots - `TestStatePath_Linux` — returns `/var/lib/tailstick/state.json` - `TestRunner_DryRun` — returns formatted dry-run string - `TestRunner_EmptyArgs` — returns error ### 🟡 P2 — internal/model (133 lines, 0 test lines) **Risk:** Domain types with JSON tags — serialization correctness. - All types use JSON tags; invalid serialization could corrupt state files. **Recommended tests:** - `TestLeaseRecordJSON_Roundtrip` — marshal/unmarshal preserves fields - `TestLocalJSON_EmptyRecords` — nil Records → empty array - `TestConfigJSON_RequiredFields` — verify required fields present ### 🟢 P3 — internal/logging (63 lines, 0 test lines) **Risk:** Low. Simple file logger with mutex. - `New()` — creates log file with parent dirs - `Info()/Error()` — formatted output to file and stdout - `Close()` — double-close safety **Recommended tests:** - `TestLogger_InfoWritesToFile` — output appears in file - `TestLogger_CloseTwice` — no panic on double close ### ⚪ P4 — cmd/* (4 entry points, 11 lines each) Tiny main() wrappers — not worth testing directly. ## Existing Test Coverage Assessment | Package | Source Lines | Test Lines | Ratio | |---------|-------------|------------|-------| | internal/app | 1,532 | 533 | 35% | | internal/gui | 356 | 132 | 37% | | internal/tailscale | 415 | 145 | 35% | | internal/crypto | 161 | 33 | 20% | | internal/config | 154 | 38 | 25% | | **internal/state** | **82** | **0** | **0%** | | **internal/platform** | **216** | **0** | **0%** | | **internal/model** | **133** | **0** | **0%** | | **internal/logging** | **63** | **0** | **0%** | ## Priority Recommendations 1. **Add tests for `internal/state`** — highest value per line. State corruption = data loss. 2. **Add `sanitizeHost` table-driven tests** — hostname edge cases are easy to get wrong. 3. **Add JSON roundtrip tests for `internal/model`** — catches tag typos early. 4. **Increase `internal/crypto` coverage** — only 33 test lines for 161 source lines with encryption logic. 5. **Consider `go test -coverprofile` in CI** — add to `.github/workflows/ci.yml`. ## Files Referenced - `internal/state/store.go` (82 lines, 0 tests) - `internal/platform/platform.go` (175 lines, 0 tests) - `internal/platform/exec.go` (41 lines, 0 tests) - `internal/model/types.go` (133 lines, 0 tests) - `internal/logging/logger.go` (63 lines, 0 tests) - `internal/crypto/secret.go` (128 lines, 33 test lines — low coverage) - `.github/workflows/ci.yml` (no coverage step) --- *Generated by [Nightshift v3](https://github.com/marcus/nightshift) — GLM 5.1*