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
- Add tests for
internal/state — highest value per line. State corruption = data loss.
- Add
sanitizeHost table-driven tests — hostname edge cases are easy to get wrong.
- Add JSON roundtrip tests for
internal/model — catches tag typos early.
- Increase
internal/crypto coverage — only 33 test lines for 161 source lines with encryption logic.
- 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 — GLM 5.1
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 defaultsSave()— atomic write with tmp file, directory creationUpsertRecord()— update-or-append logic for lease recordsAppendAudit()— append-only audit log writerRecommended tests:
TestLoad_NoFile— returns empty state with defaultsTestLoad_InvalidJSON— returns parse errorTestSave_CreatesDir— creates parent directoriesTestSave_AtomicWrite— tmp file renamed on successTestUpsertRecord_Insert— appends new recordTestUpsertRecord_Update— replaces existing by LeaseIDTestAppendAudit— 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 pathsIsElevated()— checks root/admin statusRequireSupportedLinux()— validates distro supportRunner.Run()— command execution with dry-run supportRecommended tests:
TestSanitizeHost— various inputs: empty, special chars, unicode, dotsTestStatePath_Linux— returns/var/lib/tailstick/state.jsonTestRunner_DryRun— returns formatted dry-run stringTestRunner_EmptyArgs— returns error🟡 P2 — internal/model (133 lines, 0 test lines)
Risk: Domain types with JSON tags — serialization correctness.
Recommended tests:
TestLeaseRecordJSON_Roundtrip— marshal/unmarshal preserves fieldsTestLocalJSON_EmptyRecords— nil Records → empty arrayTestConfigJSON_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 dirsInfo()/Error()— formatted output to file and stdoutClose()— double-close safetyRecommended tests:
TestLogger_InfoWritesToFile— output appears in fileTestLogger_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
Priority Recommendations
internal/state— highest value per line. State corruption = data loss.sanitizeHosttable-driven tests — hostname edge cases are easy to get wrong.internal/model— catches tag typos early.internal/cryptocoverage — only 33 test lines for 161 source lines with encryption logic.go test -coverprofilein 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 — GLM 5.1