fix: Windows command quoting, atomic JSON/log writes, restore dropped test

Implements items 1-3 of the whole-project review's suggested order
(docs/PROJECT_REVIEW_PLAN.md):

- Restore TestJobListViewIsCompact, accidentally dropped by 5b0e6fe;
  drop the redundant TestDefaultConfigUsesDetailedJobList row from
  TESTS.md and document the two other doc gaps the review found.
- Fix quoteLeadingWindowsProgramPath to find the earliest file-extension
  match at a word boundary instead of the first extension in list order,
  so a .bat/.cmd command whose argument ends in .exe no longer has its
  whole command line mistaken for the program path.
- Write gosentry.json, jobs.json, and run log files atomically (temp
  file + rename) so a crash or power loss mid-write can no longer leave
  a truncated file. Wire Service.Stop() into the app shutdown path so
  it actually runs, cancelling the run context for in-flight runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 16:53:59 +03:00
parent 89be009040
commit 1242b22e4f
9 changed files with 253 additions and 18 deletions
+41
View File
@@ -430,3 +430,44 @@ func TestJobsJSONDoesNotPersistRuntimeNoise(t *testing.T) {
}
}
}
// TestWriteJSONReplacesFileAtomically pins the durability fix: writeJSON must
// never truncate the destination in place. It writes through a temp file and
// renames over the target, so a reader can never observe a partially written
// file, and an existing file survives untouched if the marshal fails first.
func TestWriteJSONReplacesFileAtomically(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "gosentry.json")
original := domain.DefaultConfig()
original.LogsDir = "logs-original"
if err := writeJSON(path, original); err != nil {
t.Fatal(err)
}
updated := domain.DefaultConfig()
updated.LogsDir = "logs-updated"
if err := writeJSON(path, updated); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
var got domain.Config
if err := json.Unmarshal(data, &got); err != nil {
t.Fatal(err)
}
if got.LogsDir != "logs-updated" {
t.Fatalf("LogsDir = %q, want %q", got.LogsDir, "logs-updated")
}
entries, err := os.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
if len(entries) != 1 {
t.Fatalf("expected only the final file in %s, got %v", dir, entries)
}
}