From b26337501cbe2ea871fd3ccc130c866681fcd157 Mon Sep 17 00:00:00 2001 From: Mauro Date: Mon, 2 Mar 2026 01:59:26 +0100 Subject: [PATCH] fix: error check on state (#864) --- pkg/state/state.go | 12 +++++++++--- pkg/state/state_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/pkg/state/state.go b/pkg/state/state.go index 1663faa4c..57f371f12 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -40,7 +40,9 @@ func NewManager(workspace string) *Manager { oldStateFile := filepath.Join(workspace, "state.json") // Create state directory if it doesn't exist - os.MkdirAll(stateDir, 0o755) + if err := os.MkdirAll(stateDir, 0o755); err != nil { + log.Fatalf("[FATAL] state: failed to create state directory: %v", err) + } sm := &Manager{ workspace: workspace, @@ -54,13 +56,17 @@ func NewManager(workspace string) *Manager { if data, err := os.ReadFile(oldStateFile); err == nil { if err := json.Unmarshal(data, sm.state); err == nil { // Migrate to new location - sm.saveAtomic() + if err := sm.saveAtomic(); err != nil { + log.Printf("[WARN] state: failed to save state: %v", err) + } log.Printf("[INFO] state: migrated state from %s to %s", oldStateFile, stateFile) } } } else { // Load from new location - sm.load() + if err := sm.load(); err != nil { + log.Printf("[WARN] state: failed to load state: %v", err) + } } return sm diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 70117ad61..e5e116ef6 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -2,8 +2,10 @@ package state import ( "encoding/json" + "errors" "fmt" "os" + "os/exec" "path/filepath" "testing" ) @@ -214,3 +216,39 @@ func TestNewManager_EmptyWorkspace(t *testing.T) { t.Error("Expected zero timestamp for new state") } } + +func TestNewManager_MkdirFailureCrashes(t *testing.T) { + // Since log.Fatalf calls os.Exit(1), we cannot test it normally + // Otherwise, the test suite would stop altogether. + // We use the standard pattern of Go: rerun this test in a subprocess. + if os.Getenv("BE_CRASHER") == "1" { + tmpDir := os.Getenv("CRASH_DIR") + + statePath := filepath.Join(tmpDir, "state") + if err := os.WriteFile(statePath, []byte("I'm a file, not a folder"), 0o644); err != nil { + fmt.Printf("setup failed: %v", err) + os.Exit(0) + } + + NewManager(tmpDir) + os.Exit(0) + } + + tmpDir, err := os.MkdirTemp("", "state-crash-test-*") + if err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + cmd := exec.Command(os.Args[0], "-test.run=TestNewManager_MkdirFailureCrashes") + cmd.Env = append(os.Environ(), "BE_CRASHER=1", "CRASH_DIR="+tmpDir) + + err = cmd.Run() + + var e *exec.ExitError + if errors.As(err, &e) && !e.Success() { + return + } + + t.Fatalf("The process ended without error, a crash was expected via os.Exit(1). Err: %v", err) +}