Files
HostKeeper/docs/TEST_PLAN.md
T
swanadiva 4a8b4a2bc4 test: Phase 3 comprehensive test coverage — 105 tests, zero race conditions
- Add test/crypto/ (19 tests): AES-256-GCM encrypt/decrypt, PBKDF2, IsEncrypted, HashPassword
- Add test/knownhosts/ (14 tests): TOFU verify, MITM detection, CRUD, persistence
- Add test/storage/ (20 tests): KeyPair/Snippet CRUD, encryption, MergeStrategy
- Add test/config/ (9 tests): config lifecycle, path getters
- Add test/tui/ (10 tests): WrapFooter, ClampWidth, TruncateStr
- Fix knownhosts deadlock: Add/Remove use saveInternal()
- Export responsive.go functions for testing
- Add docs/TEST_PLAN.md with full scenario documentation

Coverage: crypto 0%→100%, knownhosts 0%→100%, storage 40%→90%, config 22%→80%, tui 40%→70%
2026-06-29 12:05:02 +07:00

7.9 KiB

Hostkeeper Test Plan — Phase 3

Created: 2025-01-31 Purpose: Comprehensive test coverage for all packages Target Coverage: 90%+ for all packages


Current Coverage Summary

Package Current Target Gap
internal/errors 100% 100%
internal/models 91% 100% +9%
pkg/crypto 0% 100% +100%
pkg/knownhosts 0% 100% +100%
pkg/ssh 60% 90% +30%
pkg/storage 40% 90% +50%
pkg/config 22% 80% +58%
pkg/tui ~40% 70% +30%
cmd/hostkeeper ~40% 70% +30%

Test File Structure

test/
├── crypto/
│   └── crypto_test.go          (NEW — 17 scenarios)
├── knownhosts/
│   └── knownhosts_test.go      (NEW — 14 scenarios)
├── storage/
│   ├── export_import_test.go   (EXISTING)
│   └── json_storage_test.go    (NEW — 18 scenarios)
├── config/
│   └── config_test.go          (NEW — 10 scenarios)
├── ssh/
│   └── ssh_test.go             (EXISTING)
├── tui/
│   ├── theme_test.go           (EXISTING)
│   ├── error_banner_test.go    (EXISTING)
│   └── responsive_test.go      (NEW — 10 scenarios)
├── cmd/
│   └── root_test.go            (NEW — 8 scenarios)
├── errors_test.go              (EXISTING)
├── models_test.go              (EXISTING)
└── integration/
    └── integration_test.go     (EXISTING)

Total: 7 new test files, ~87 test scenarios


Scenario Details

1. test/crypto/crypto_test.go — CRITICAL

# Scenario Input Expected Priority
1.1 DeriveKey determinism same password + salt same key HIGH
1.2 DeriveKey password variation different password different key HIGH
1.3 DeriveKey salt variation different salt different key HIGH
1.4 DeriveKey empty password "" no panic, valid key MEDIUM
1.5 Encrypt/Decrypt round-trip "hello world" decrypt = original HIGH
1.6 Encrypt empty plaintext "" decrypt = "" MEDIUM
1.7 Encrypt large data 1MB random bytes round-trip OK MEDIUM
1.8 Encrypt unicode "こんにちは" round-trip OK MEDIUM
1.9 Encrypt with newlines "line1\nline2" round-trip OK MEDIUM
1.10 Wrong password decrypt with wrong pw ErrDecryptionFailed HIGH
1.11 Empty password decrypt with "" ErrDecryptionFailed HIGH
1.12 IsEncrypted valid ciphertext base64 ciphertext true HIGH
1.13 IsEncrypted plaintext "hello" false HIGH
1.14 IsEncrypted empty "" false MEDIUM
1.15 HashPassword determinism same pw same hash HIGH
1.16 HashPassword variation different pw different hash HIGH
1.17 Encrypt randomness same input, 2 calls different ciphertext MEDIUM

2. test/knownhosts/knownhosts_test.go — CRITICAL

# Scenario Input Expected Priority
2.1 New creates file non-existent path file created HIGH
2.2 New loads existing existing file hosts loaded HIGH
2.3 Add new host hostname+port+key added HIGH
2.4 Add duplicate same host twice no error, no duplicate HIGH
2.5 Get existing hostname+port returns HostKey HIGH
2.6 Get non-existent unknown host nil MEDIUM
2.7 Remove existing hostname+port removed HIGH
2.8 Remove non-existent unknown host no error MEDIUM
2.9 Verify unknown new host (false, nil) TOFU HIGH
2.10 Verify known match correct key (true, hostKey) HIGH
2.11 Verify known mismatch wrong key (false, hostKey) MITM HIGH
2.12 HostKeyCallback autoAdd=true adds unknown hosts HIGH
2.13 Persistence Add → Save → New → Get found HIGH
2.14 Corrupted file invalid JSON error MEDIUM

3. test/storage/json_storage_test.go — HIGH

# Scenario Input Expected Priority
3.1 SaveKeyPair valid KeyPair success HIGH
3.2 ListKeyPairs after save returns saved HIGH
3.3 GetKeyPair found by ID returns KeyPair HIGH
3.4 GetKeyPair not found unknown ID error MEDIUM
3.5 DeleteKeyPair by ID removed HIGH
3.6 DeleteKeyPair not found unknown ID no error MEDIUM
3.7 SaveSnippet valid Snippet success HIGH
3.8 ListSnippets after save returns saved HIGH
3.9 GetSnippet found by ID returns Snippet HIGH
3.10 GetSnippet not found unknown ID error MEDIUM
3.11 DeleteSnippet by ID removed HIGH
3.12 DeleteSnippet not found unknown ID no error MEDIUM
3.13 SetPassword + SaveHost encrypted storage file encrypted HIGH
3.14 IsDataEncrypted encrypted file true HIGH
3.15 Wrong password load decrypt with wrong pw error HIGH
3.16 MergeStrategyMerge import with merge keeps existing + adds new HIGH
3.17 MergeStrategyReplace import with replace overwrites all HIGH
3.18 SaveHost empty ID host with "" ID generates UUID MEDIUM

4. test/config/config_test.go — MEDIUM

# Scenario Input Expected Priority
4.1 New first run no config file creates default HIGH
4.2 New existing valid config file loads config HIGH
4.3 Save modify + save persists HIGH
4.4 UpdateAppConfig change theme saved HIGH
4.5 GetConfigDir valid path MEDIUM
4.6 GetDataDir valid path MEDIUM
4.7 GetConfigFilePath ends with config.json MEDIUM
4.8 GetHostsFilePath ends with hosts.json MEDIUM
4.9 GetKeysFilePath ends with keys.json MEDIUM
4.10 GetSnippetsFilePath ends with snippets.json MEDIUM

5. test/tui/responsive_test.go — MEDIUM

# Scenario Input Expected Priority
5.1 WrapFooter short short string single line MEDIUM
5.2 WrapFooter long long string multi-line MEDIUM
5.3 WrapFooter empty "" "" LOW
5.4 ClampWidth over width > max clamped to max MEDIUM
5.5 ClampWidth under width < min clamped to min MEDIUM
5.6 ClampWidth in range min < width < max unchanged MEDIUM
5.7 TruncateStr short short string unchanged MEDIUM
5.8 TruncateStr long long string truncated + … MEDIUM
5.9 TruncateStr empty "" "" LOW
5.10 TruncateStr unicode "こんにちは世界" correct width MEDIUM

6. test/cmd/root_test.go — MEDIUM

# Scenario Input Expected Priority
6.1 RootCmd execute no args no error HIGH
6.2 Version flag --version shows version MEDIUM
6.3 FindHost by ID host ID returns host HIGH
6.4 FindHost by name host name returns host HIGH
6.5 FindHost by hostname IP/hostname returns host HIGH
6.6 FindHost not found unknown error MEDIUM
6.7 NewStorage no password --password="" unencrypted MEDIUM
6.8 NewStorage with password --password="x" encrypted HIGH

Execution Order

Phase 3, Sprint 1: Security-Critical (pkg/crypto, pkg/knownhosts)
Phase 3, Sprint 2: Core (pkg/storage, pkg/config)
Phase 3, Sprint 3: UI + CLI (pkg/tui, cmd/hostkeeper)
Phase 3, Sprint 4: Integration + Final

Success Criteria

  • All tests pass (go test ./test/...)
  • Coverage >= 90% for pkg/crypto
  • Coverage >= 90% for pkg/knownhosts
  • Coverage >= 80% for pkg/storage
  • Coverage >= 70% for pkg/config
  • Coverage >= 60% for pkg/tui
  • No race conditions (go test -race ./test/...)
  • Build clean (go build ./...)