返回 DeepSeek-Reasonix
instance_handoff_windows_test.go
根目录 / desktop / cmd / update-helper / instance_handoff_windows_test.go
1 //go:build windows
2
3 package main
4
5 import (
6 "errors"
7 "io"
8 "log"
9 "os"
10 "path/filepath"
11 "testing"
12 "time"
13
14 "reasonix/desktop/internal/instanceidentity"
15 )
16
17 func stubDesktopHandoff(t *testing.T) {
18 t.Helper()
19 verify, notify := verifyDesktopHandoffFn, notifyHandoffBlockedFn
20 t.Cleanup(func() { verifyDesktopHandoffFn = verify; notifyHandoffBlockedFn = notify })
21 verifyDesktopHandoffFn = func(string, bool) error { return nil }
22 notifyHandoffBlockedFn = func(bool) {}
23 }
24 func TestDesktopHandoffConfirmsOnlyTargetInstance(t *testing.T) {
25 root, home := t.TempDir(), t.TempDir()
26 target := filepath.Join(root, "reasonix-desktop.exe")
27 old := filepath.Join(t.TempDir(), "reasonix-desktop.exe")
28 for _, p := range []string{target, old} {
29 if err := os.WriteFile(p, []byte("fixture"), 0600); err != nil {
30 t.Fatal(err)
31 }
32 }
33 id := instanceidentity.ForHome(home)
34 t.Setenv("REASONIX_HOME", home)
35 t.Setenv(instanceidentity.UpdateEnvironmentKey, id)
36 original, now, sleep := desktopEndpointImageFn, handoffNowFn, handoffSleepFn
37 t.Cleanup(func() { desktopEndpointImageFn = original; handoffNowFn = now; handoffSleepFn = sleep })
38 for _, tc := range []struct {
39 name string
40 started bool
41 paths []string
42 probeErr error
43 wantErr bool
44 }{
45 {name: "no owner before launch", paths: []string{""}},
46 {name: "active target", started: true, paths: []string{target}},
47 {name: "new owner ready", started: true, paths: []string{"", target}},
48 {name: "old owner preserved", paths: []string{old}, wantErr: true},
49 {name: "old owner wins race", started: true, paths: []string{"", old}, wantErr: true},
50 {name: "access denied", probeErr: errors.New("access denied"), wantErr: true},
51 {name: "timeout", started: true, paths: []string{""}, wantErr: true},
52 } {
53 t.Run(tc.name, func(t *testing.T) {
54 clock := time.Unix(0, 0)
55 handoffNowFn = func() time.Time { return clock }
56 handoffSleepFn = func(d time.Duration) { clock = clock.Add(d) }
57 n := 0
58 desktopEndpointImageFn = func(got string) (string, error) {
59 if got != id {
60 t.Fatalf("probed another home %q", got)
61 }
62 if tc.probeErr != nil {
63 return "", tc.probeErr
64 }
65 i := n
66 if i >= len(tc.paths) {
67 i = len(tc.paths) - 1
68 }
69 n++
70 return tc.paths[i], nil
71 }
72 err := verifyDesktopHandoff(root, tc.started)
73 if (err != nil) != tc.wantErr {
74 t.Fatalf("error=%v wantError=%v", err, tc.wantErr)
75 }
76 })
77 }
78 }
79 func TestDesktopHandoffRejectsUnboundIdentity(t *testing.T) {
80 home := t.TempDir()
81 t.Setenv("REASONIX_HOME", home)
82 for _, id := range []string{"", instanceidentity.ForHome(t.TempDir())} {
83 t.Setenv(instanceidentity.UpdateEnvironmentKey, id)
84 if err := verifyDesktopHandoff(t.TempDir(), false); err == nil {
85 t.Fatal("unbound helper accepted")
86 }
87 }
88 }
89
90 func TestPublishedRelaunchDoesNotReportSuccessWhenOldOwnerWins(t *testing.T) {
91 stubDesktopHandoff(t)
92 originalStart := startRelaunchFn
93 t.Cleanup(func() { startRelaunchFn = originalStart })
94 root := t.TempDir()
95 target := filepath.Join(root, "reasonix-desktop.exe")
96 if err := os.WriteFile(target, []byte("target"), 0700); err != nil {
97 t.Fatal(err)
98 }
99 started, notified := false, false
100 startRelaunchFn = func(string, string) error { started = true; return nil }
101 verifyDesktopHandoffFn = func(_ string, after bool) error {
102 if after {
103 return errors.New("old owner acquired endpoint")
104 }
105 return nil
106 }
107 notifyHandoffBlockedFn = func(installed bool) {
108 if !installed {
109 t.Fatal("lost installed outcome")
110 }
111 notified = true
112 }
113 if code := relaunchPublishedInstall(log.New(io.Discard, "", 0), target, root, "restart"); code != 1 || !started || !notified {
114 t.Fatalf("code=%d started=%v notified=%v", code, started, notified)
115 }
116 }
117
117 lines GO