| ... | @@ -45,6 +45,16 @@ const makeSuccessfulProcess = (stdout: string) => { | ... | @@ -45,6 +45,16 @@ const makeSuccessfulProcess = (stdout: string) => { |
| 45 | }); | 45 | }); |
| 46 | }; | 46 | }; |
| 47 | | 47 | |
| | 48 | const makeDelayedSuccessfulProcess = (stdout: string, delayMs: number) => { |
| | 49 | const process = makeSuccessfulProcess(stdout); |
| | 50 | return { |
| | 51 | ...process, |
| | 52 | exitCode: Effect.sleep(Duration.millis(delayMs)).pipe( |
| | 53 | Effect.as(ChildProcessSpawner.ExitCode(0)), |
| | 54 | ), |
| | 55 | }; |
| | 56 | }; |
| | 57 | |
| 48 | const makeRunningProcess = (onKill: () => void) => { | 58 | const makeRunningProcess = (onKill: () => void) => { |
| 49 | let finish: ((exitCode: ChildProcessSpawner.ExitCode) => void) | null = null; | 59 | let finish: ((exitCode: ChildProcessSpawner.ExitCode) => void) | null = null; |
| 50 | return ChildProcessSpawner.makeHandle({ | 60 | return ChildProcessSpawner.makeHandle({ |
| ... | @@ -174,6 +184,7 @@ describe("ssh tunnel scripts", () => { | ... | @@ -174,6 +184,7 @@ describe("ssh tunnel scripts", () => { |
| 174 | assert.include(buildRemoteLaunchScript(), '--base-dir "$DEFAULT_SERVER_HOME"'); | 184 | assert.include(buildRemoteLaunchScript(), '--base-dir "$DEFAULT_SERVER_HOME"'); |
| 175 | assert.notInclude(buildRemoteLaunchScript(), "server-home"); | 185 | assert.notInclude(buildRemoteLaunchScript(), "server-home"); |
| 176 | assert.include(buildRemoteLaunchScript(), "Remote T3 server did not become ready"); | 186 | assert.include(buildRemoteLaunchScript(), "Remote T3 server did not become ready"); |
| | 187 | assert.include(buildRemoteLaunchScript(), 'wait_ready "60000"'); |
| 177 | assert.include(buildRemoteLaunchScript({ packageSpec: "t3@nightly" }), "t3@nightly"); | 188 | assert.include(buildRemoteLaunchScript({ packageSpec: "t3@nightly" }), "t3@nightly"); |
| 178 | assert.include( | 189 | assert.include( |
| 179 | buildRemotePairingScript(target), | 190 | buildRemotePairingScript(target), |
| ... | @@ -235,6 +246,29 @@ describe("ssh tunnel scripts", () => { | ... | @@ -235,6 +246,29 @@ describe("ssh tunnel scripts", () => { |
| 235 | }).pipe(Effect.provide(processLayer)); | 246 | }).pipe(Effect.provide(processLayer)); |
| 236 | }); | 247 | }); |
| 237 | | 248 | |
| | 249 | it.effect("allows cold remote launches to exceed the default SSH command timeout", () => { |
| | 250 | const target = { |
| | 251 | alias: "devbox", |
| | 252 | hostname: "devbox.example.com", |
| | 253 | username: "julius", |
| | 254 | port: 2222, |
| | 255 | } as const; |
| | 256 | const spawner = ChildProcessSpawner.make(() => |
| | 257 | Effect.succeed(makeDelayedSuccessfulProcess('{"remotePort":3774}\n', 75_000)), |
| | 258 | ); |
| | 259 | const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner); |
| | 260 | const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer, TestClock.layer()); |
| | 261 | |
| | 262 | return Effect.gen(function* () { |
| | 263 | const fiber = yield* Effect.forkChild(launchOrReuseRemoteServer(target)); |
| | 264 | yield* Effect.yieldNow; |
| | 265 | yield* TestClock.adjust(Duration.seconds(75)); |
| | 266 | |
| | 267 | const result = yield* Fiber.join(fiber); |
| | 268 | assert.equal(result.remotePort, 3774); |
| | 269 | }).pipe(Effect.provide(processLayer)); |
| | 270 | }); |
| | 271 | |
| 238 | it("allows the remote port picker to run without a state file path", () => { | 272 | it("allows the remote port picker to run without a state file path", () => { |
| 239 | assert.include(REMOTE_PICK_PORT_SCRIPT, 'const filePath = process.argv[2] ?? "";'); | 273 | assert.include(REMOTE_PICK_PORT_SCRIPT, 'const filePath = process.argv[2] ?? "";'); |
| 240 | }); | 274 | }); |