Skip to content
Source
Sign inSign up
Open History to see the last commit

presentation.test.ts

177 lines5.0 KB

1import { EnvironmentId } from "@t3tools/contracts";
2import { describe, expect, it } from "@effect/vitest";
3import * as Option from "effect/Option";
4​
5import {
6 BearerConnectionProfile,
7 type ConnectionCatalogEntry,
8 type ConnectionRoute,
9} from "./catalog.ts";
10import {
11 BearerConnectionTarget,
12 ConnectionTransientError,
13 RelayConnectionTarget,
14 type SupervisorConnectionState,
15} from "./model.ts";
16import { environmentMcpUrl, presentConnectionState } from "./presentation.ts";
17​
18const TARGET = new BearerConnectionTarget({
19 environmentId: EnvironmentId.make("environment-1"),
20 label: "Remote environment",
21 connectionId: "connection-1",
22});
23​
24const ENTRY: ConnectionCatalogEntry = {
25 target: TARGET,
26 profile: Option.some(
27 new BearerConnectionProfile({
28 connectionId: TARGET.connectionId,
29 environmentId: TARGET.environmentId,
30 label: TARGET.label,
31 httpBaseUrl: "https://environment.example.test",
32 wsBaseUrl: "wss://environment.example.test",
33 }),
34 ),
35 enabled: true,
36};
37​
38function supervisorState(overrides: Partial<SupervisorConnectionState>): SupervisorConnectionState {
39 return {
40 desired: true,
41 network: "online",
42 phase: "connecting",
43 stage: "preparing",
44 attempt: 1,
45 generation: 0,
46 lastFailure: null,
47 retryAt: null,
48 ...overrides,
49 };
51​
52describe("connection presentation", () => {
53 it("copies the T3 Connect MCP address first, then the route this device is connected over", () => {
54 const route = (connectionId: string, httpBaseUrl: string): ConnectionRoute => {
55 const target = new BearerConnectionTarget({ ...TARGET, connectionId });
56 return {
57 target,
58 profile: Option.some(
59 new BearerConnectionProfile({
60 connectionId,
61 environmentId: TARGET.environmentId,
62 label: TARGET.label,
63 httpBaseUrl,
64 wsBaseUrl: httpBaseUrl.replace(/^http/, "ws"),
65 }),
66 ),
67 };
68 };
69 const lan = route("lan", "http://192.168.4.53:3773/");
70 const tailnet = route("tailnet", "http://100.115.1.44:3773/");
71 const serve = route("serve", "https://machine.tailnet.ts.net/");
72 const entry: ConnectionCatalogEntry = {
73 ...ENTRY,
74 target: lan.target,
75 profile: lan.profile,
76 alternateRoutes: [tailnet, serve],
77 };
78​
79 expect(environmentMcpUrl({ entry, connectedTarget: tailnet.target })).toBe(
80 "http://100.115.1.44:3773/mcp",
81 );
82 expect(environmentMcpUrl({ entry })).toBe("http://192.168.4.53:3773/mcp");
83 expect(
84 environmentMcpUrl({
85 entry,
86 connectedTarget: lan.target,
87 relayHttpBaseUrl: "https://tunnel.example.test",
88 }),
89 ).toBe("https://tunnel.example.test/mcp");
90 });
91​
92 // regression: #16909 Copy MCP URL falls back to an alternate route when the relay route has no address
93 it("passes over routes without an address of their own", () => {
94 const relay = new RelayConnectionTarget({
95 environmentId: TARGET.environmentId,
96 label: TARGET.label,
97 });
98 const entry: ConnectionCatalogEntry = {
99 ...ENTRY,
100 target: relay,
101 profile: Option.none(),
102 alternateRoutes: [{ target: ENTRY.target, profile: ENTRY.profile }],
103 };
104​
105 expect(environmentMcpUrl({ entry, connectedTarget: relay })).toBe(
106 "https://environment.example.test/mcp",
107 );
108 expect(
109 environmentMcpUrl({
110 entry,
111 connectedTarget: relay,
112 relayHttpBaseUrl: "https://tunnel.example.test",
113 }),
114 ).toBe("https://tunnel.example.test/mcp");
115 });
116​
117 it("distinguishes initial connection, reconnect, and retry errors", () => {
118 expect(presentConnectionState(supervisorState({ phase: "connecting", attempt: 1 }))).toEqual({
119 phase: "connecting",
120 error: null,
121 traceId: null,
122 });
123 expect(
124 presentConnectionState(
125 supervisorState({
126 phase: "connecting",
127 attempt: 2,
128 lastFailure: new ConnectionTransientError({
129 reason: "transport",
130 detail: "Socket closed.",
131 traceId: "trace-previous",
132 }),
133 }),
134 ),
135 ).toEqual({
136 phase: "reconnecting",
137 error: "Socket closed.",
138 traceId: "trace-previous",
139 });
140 expect(
141 presentConnectionState(
142 supervisorState({
143 phase: "backoff",
144 attempt: 2,
145 retryAt: 1,
146 lastFailure: new ConnectionTransientError({
147 reason: "transport",
148 detail: "Disconnected.",
149 traceId: "trace-1",
150 }),
151 }),
152 ),
153 ).toEqual({
154 phase: "reconnecting",
155 error: "Disconnected.",
156 traceId: "trace-1",
157 });
158 });
159​
160 it("preserves an explicitly available environment while offline", () => {
161 expect(
162 presentConnectionState(
163 supervisorState({
164 desired: false,
165 network: "offline",
166 phase: "available",
167 stage: null,
168 attempt: 0,
169 }),
170 ),
171 ).toEqual({
172 phase: "available",
173 error: null,
174 traceId: null,
175 });
176 });
177});