File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -92,6 +92,10 @@ func setupDemo() (cleanup func(), err error) {
9292 _ = os .Setenv ("DISPATCH_DB" , tmpDB )
9393 _ = os .Setenv ("DISPATCH_SESSION_STATE" , stateDir )
9494
95+ // Force workspace recovery on so interrupted session dots are visible
96+ // regardless of the user's config setting.
97+ _ = os .Setenv ("DISPATCH_WORKSPACE_RECOVERY" , "1" )
98+
9599 ok = true
96100 return func () { os .RemoveAll (tmpDir ) }, nil
97101}
@@ -193,9 +197,10 @@ func createDemoSessionState(stateDir string) error {
193197 now := time .Now ().UTC ()
194198 staleTime := now .Add (- 10 * time .Minute ) // old enough to exceed threshold
195199
196- // deadPID is a PID that is almost certainly not running, used to
197- // simulate interrupted sessions (stale lock with dead process).
198- const deadPID = 99999
200+ // deadPID is a PID near the maxPID ceiling (4194304) that is almost
201+ // certainly not running. Using 99999 collided with live Windows
202+ // processes (e.g. OpenConsole), so we match the test convention.
203+ const deadPID = 4194000
199204
200205 for _ , s := range demoAttentionSessions {
201206 sessDir := filepath .Join (stateDir , s .sessionID )
Original file line number Diff line number Diff line change @@ -294,6 +294,12 @@ func Load() (*Config, error) {
294294 cfg .MaxSessions = 0
295295 }
296296 cfg .sanitize ()
297+
298+ // Allow env var override for workspace recovery (used by --demo).
299+ if os .Getenv ("DISPATCH_WORKSPACE_RECOVERY" ) == "1" {
300+ cfg .WorkspaceRecovery = true
301+ }
302+
297303 return cfg , nil
298304}
299305
Original file line number Diff line number Diff line change @@ -181,6 +181,30 @@ func TestWorkspaceRecoveryJSONTrue(t *testing.T) {
181181 }
182182}
183183
184+ func TestWorkspaceRecoveryEnvOverride (t * testing.T ) {
185+ // Env var should force WorkspaceRecovery=true even when config says false.
186+ t .Setenv ("DISPATCH_WORKSPACE_RECOVERY" , "1" )
187+
188+ dir := t .TempDir ()
189+ cfgPath := filepath .Join (dir , configFileName )
190+ _ = os .WriteFile (cfgPath , []byte (`{"workspace_recovery": false}` ), 0o600 )
191+
192+ // Temporarily redirect configPath to our temp dir.
193+ t .Setenv ("DISPATCH_CONFIG_DIR_OVERRIDE" , dir )
194+
195+ // Since we can't easily redirect configPath in a test, verify the
196+ // env-var logic directly: Load() reads the file, then checks the env.
197+ cfg := Default ()
198+ _ = json .Unmarshal ([]byte (`{"workspace_recovery": false}` ), cfg )
199+ // Simulate what Load does after unmarshal:
200+ if os .Getenv ("DISPATCH_WORKSPACE_RECOVERY" ) == "1" {
201+ cfg .WorkspaceRecovery = true
202+ }
203+ if ! cfg .WorkspaceRecovery {
204+ t .Error ("DISPATCH_WORKSPACE_RECOVERY=1 should override config to true" )
205+ }
206+ }
207+
184208func TestDefaultValuesPreservedOnPartialJSON (t * testing.T ) {
185209 t .Parallel ()
186210 // When JSON has only some keys, defaults should fill the rest.
Original file line number Diff line number Diff line change @@ -74,10 +74,6 @@ func validateVersion(v string) error {
7474// RunUpdate downloads and installs the latest version of dispatch. It
7575// prints progress to stderr and returns an error on failure.
7676func RunUpdate (currentVersion string ) error {
77- if isDevVersion (currentVersion ) {
78- return errors .New ("cannot update a development build — install a release build first" )
79- }
80-
8177 configDir , err := platform .ConfigDir ()
8278 if err != nil {
8379 return fmt .Errorf ("resolving config directory: %w" , err )
Original file line number Diff line number Diff line change @@ -1808,13 +1808,21 @@ func TestCheckForUpdate_FetchError(t *testing.T) {
18081808// RunUpdate — configDir error path
18091809// ---------------------------------------------------------------------------
18101810
1811- func TestRunUpdate_MkdirAllError (t * testing.T ) {
1812- // Manually test with a path that won't exist.
1811+ func TestRunUpdate_DevVersionProceeds (t * testing.T ) {
1812+ tmpDir := t .TempDir ()
1813+ setConfigDir (t , tmpDir )
1814+ setMockTransport (t , func (req * http.Request ) (* http.Response , error ) {
1815+ w := httptest .NewRecorder ()
1816+ _ = json .NewEncoder (w ).Encode (githubRelease {TagName : "v1.0.0" })
1817+ return w .Result (), nil
1818+ })
1819+
1820+ // Dev builds should proceed past the version check. "dev" compares as
1821+ // 0.0.0 < 1.0.0, so the update flow continues into download/checksum
1822+ // stages, which fail because the mock serves JSON for all requests.
1823+ // The key assertion: the error is NOT about "development build".
18131824 err := RunUpdate ("dev" )
1814- if err == nil {
1815- t .Fatal ("expected error for dev version" )
1816- }
1817- if ! strings .Contains (err .Error (), "development build" ) {
1818- t .Errorf ("expected dev build error, got: %v" , err )
1825+ if err != nil && strings .Contains (err .Error (), "development build" ) {
1826+ t .Fatal ("RunUpdate should not reject dev builds" )
18191827 }
18201828}
Original file line number Diff line number Diff line change @@ -528,11 +528,14 @@ func TestReplaceWindows_RollbackOnFailure(t *testing.T) {
528528// RunUpdate edge cases
529529// ---------------------------------------------------------------------------
530530
531- func TestRunUpdate_DevVersion (t * testing.T ) {
531+ func TestRunUpdate_DevVersionNotBlocked (t * testing.T ) {
532532 t .Parallel ()
533533 err := RunUpdate ("dev" )
534- if err == nil {
535- t .Fatal ("expected error for dev version" )
534+ // Dev builds should no longer be rejected. The call may fail for other
535+ // reasons (network, lock contention, etc.) but never because of
536+ // the version string.
537+ if err != nil && strings .Contains (err .Error (), "development build" ) {
538+ t .Fatal ("RunUpdate should not reject dev builds" )
536539 }
537540}
538541
You can’t perform that action at this time.
0 commit comments