返回 DeepSeek-Reasonix
main_test.go
根目录 / desktop / main_test.go
1 package main
2
3 import (
4 "context"
5 "fmt"
6 "os"
7 "strings"
8 "testing"
9
10 "reasonix/internal/skill/skillwatch"
11 "reasonix/internal/testenv"
12 )
13
14 // TestLifecycleDiagnosticsUsePreShellOwnershipGate pins the ordering that keeps
15 // a superseded process from consuming lifecycle evidence: the host RPC service
16 // claims diagnostics ownership before it serves its first request.
17 func TestLifecycleDiagnosticsUsePreShellOwnershipGate(t *testing.T) {
18 source, err := os.ReadFile("host_rpc.go")
19 if err != nil {
20 t.Fatal(err)
21 }
22 beforeServe, _, ok := strings.Cut(string(source), "server.Serve(")
23 if !ok {
24 t.Fatal("host_rpc.go no longer contains the host RPC serve boundary")
25 }
26 if !strings.Contains(beforeServe, "prepareDesktopDiagnostics(app)") {
27 t.Fatal("host service must claim diagnostics ownership before serving")
28 }
29
30 appSource, err := os.ReadFile("app.go")
31 if err != nil {
32 t.Fatal(err)
33 }
34 _, afterStartup, ok := strings.Cut(string(appSource), "func (a *App) startup(ctx context.Context) {")
35 if !ok {
36 t.Fatal("app.go no longer contains App.startup")
37 }
38 startupBody, _, ok := strings.Cut(afterStartup, "\n}")
39 if !ok || !strings.Contains(startupBody, "initializeLifecycleDiagnostics(a)") {
40 t.Fatal("previous lifecycle consumption must remain owned by startup")
41 }
42 }
43
44 // TestMain isolates user config/state/cache dirs for the whole package. Without
45 // this, tests that persist desktop state, sessions, cache, or CLI-style config
46 // can leak into the developer's real Reasonix directories.
47 func TestMain(m *testing.M) {
48 // The watcher helper re-executes os.Executable(), which here is this test
49 // binary: serve the pipe instead of re-running the suite.
50 if skillwatch.MaybeRunHelper() {
51 return
52 }
53 dir, err := os.MkdirTemp("", "reasonix-desktop-test")
54 if err != nil {
55 os.Exit(1)
56 }
57 os.Setenv("HOME", dir)
58 os.Setenv("REASONIX_CREDENTIALS_STORE", "file")
59 os.Setenv("USERPROFILE", dir)
60 os.Setenv("XDG_CONFIG_HOME", dir+"/config")
61 os.Setenv("REASONIX_STATE_HOME", dir+"/state")
62 os.Setenv("REASONIX_CACHE_HOME", dir+"/cache")
63 os.Setenv("AppData", dir)
64 // Tests fail closed for telemetry. Any test that expects a request must
65 // replace the relevant endpoint with an httptest.Server explicitly.
66 crashEndpoint = "http://127.0.0.1:0/v1/report"
67 pingEndpoint = "http://127.0.0.1:0/v1/ping"
68 metricsEndpoint = "http://127.0.0.1:0/v1/metrics"
69 // Neutralize the host event bridge for the whole test binary: there is no
70 // shell to emit to here. Tests that assert on runtime events install their
71 // own capture through the per-instance runtimeEvents.emit hook, which takes
72 // precedence.
73 runtimeEventsEmitFallback = func(context.Context, string, ...any) {}
74 code := m.Run()
75 // Fixtures build an App without shutdownBody, which is what releases the
76 // cached session services. Their state lives under the scratch home removed
77 // below, not a per-test t.TempDir, so this is debt, not a cleanup failure.
78 if note := testenv.ReportLeakedFileLocks(); note != "" {
79 fmt.Fprintln(os.Stderr, note)
80 }
81 os.RemoveAll(dir)
82 os.Exit(code)
83 }
84
85 func TestDesktopTestTelemetryEndpointsAreFailClosed(t *testing.T) {
86 for name, endpoint := range map[string]string{
87 "crash": crashEndpoint,
88 "ping": pingEndpoint,
89 "metrics": metricsEndpoint,
90 } {
91 if strings.Contains(endpoint, "crash.reasonix.io") {
92 t.Fatalf("%s test endpoint targets production: %s", name, endpoint)
93 }
94 }
95 }
96
96 lines GO