| ... | ... | @@ -55,6 +55,8 @@ vi.mock("node:fs", async (importOriginal) => { |
| 55 | 55 | }; |
| 56 | 56 | }); |
| 57 | 57 | |
| 58 | const windowsHost = HostProcessPlatform.defaultValue() === "win32"; |
| 59 | const nullDevice = windowsHost ? "\\\\.\\NUL" : "/dev/null"; |
| 58 | 60 | const TestEnvelopeSchema = Schema.Struct({ mode: Schema.String }); |
| 59 | 61 | const encodeTestEnvelopeSchema = Schema.encodeEffect(Schema.fromJsonString(TestEnvelopeSchema)); |
| 60 | 62 | |
| ... | ... | @@ -146,7 +148,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { |
| 146 | 148 | |
| 147 | 149 | it.effect("returns none when the fd is unavailable", () => |
| 148 | 150 | Effect.gen(function* () { |
| 149 | | const fd = NodeFS.openSync("/dev/null", "r"); |
| 151 | const fd = NodeFS.openSync(nullDevice, "r"); |
| 150 | 152 | NodeFS.closeSync(fd); |
| 151 | 153 | |
| 152 | 154 | const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100 }); |
| ... | ... | @@ -157,7 +159,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { |
| 157 | 159 | it.effect("preserves fd and cause when stat fails for a non-availability reason", () => |
| 158 | 160 | Effect.gen(function* () { |
| 159 | 161 | const fd = yield* Effect.acquireRelease( |
| 160 | | Effect.sync(() => NodeFS.openSync("/dev/null", "r")), |
| 162 | Effect.sync(() => NodeFS.openSync(nullDevice, "r")), |
| 161 | 163 | (fd) => Effect.sync(() => NodeFS.closeSync(fd)), |
| 162 | 164 | ); |
| 163 | 165 | |
| ... | ... | @@ -201,40 +203,43 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { |
| 201 | 203 | }), |
| 202 | 204 | ); |
| 203 | 205 | |
| 204 | | it.effect("returns none when the bootstrap read times out before any value arrives", () => |
| 205 | | Effect.gen(function* () { |
| 206 | | const fs = yield* FileSystem.FileSystem; |
| 207 | | const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-bootstrap-" }); |
| 208 | | const fifoPath = NodePath.join(tempDir, "bootstrap.pipe"); |
| 209 | | |
| 210 | | yield* Effect.sync(() => NodeChildProcess.execFileSync("mkfifo", [fifoPath])); |
| 211 | | |
| 212 | | const _writer = yield* Effect.acquireRelease( |
| 213 | | Effect.sync(() => |
| 214 | | NodeChildProcess.spawn("sh", ["-c", 'exec 3>"$1"; sleep 60', "sh", fifoPath], { |
| 215 | | stdio: ["ignore", "ignore", "ignore"], |
| 216 | | }), |
| 217 | | ), |
| 218 | | (writer) => |
| 219 | | Effect.sync(() => { |
| 220 | | writer.kill("SIGKILL"); |
| 221 | | }), |
| 222 | | ); |
| 206 | // Needs a FIFO, which mkfifo creates; Windows has neither. |
| 207 | it.effect.skipIf(windowsHost)( |
| 208 | "returns none when the bootstrap read times out before any value arrives", |
| 209 | () => |
| 210 | Effect.gen(function* () { |
| 211 | const fs = yield* FileSystem.FileSystem; |
| 212 | const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-bootstrap-" }); |
| 213 | const fifoPath = NodePath.join(tempDir, "bootstrap.pipe"); |
| 214 | |
| 215 | yield* Effect.sync(() => NodeChildProcess.execFileSync("mkfifo", [fifoPath])); |
| 216 | |
| 217 | const _writer = yield* Effect.acquireRelease( |
| 218 | Effect.sync(() => |
| 219 | NodeChildProcess.spawn("sh", ["-c", 'exec 3>"$1"; sleep 60', "sh", fifoPath], { |
| 220 | stdio: ["ignore", "ignore", "ignore"], |
| 221 | }), |
| 222 | ), |
| 223 | (writer) => |
| 224 | Effect.sync(() => { |
| 225 | writer.kill("SIGKILL"); |
| 226 | }), |
| 227 | ); |
| 223 | 228 | |
| 224 | | const fd = yield* Effect.acquireRelease( |
| 225 | | Effect.sync(() => NodeFS.openSync(fifoPath, "r")), |
| 226 | | (fd) => Effect.sync(() => NodeFS.closeSync(fd)), |
| 227 | | ); |
| 229 | const fd = yield* Effect.acquireRelease( |
| 230 | Effect.sync(() => NodeFS.openSync(fifoPath, "r")), |
| 231 | (fd) => Effect.sync(() => NodeFS.closeSync(fd)), |
| 232 | ); |
| 228 | 233 | |
| 229 | | const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { |
| 230 | | timeoutMs: 100, |
| 231 | | }).pipe(Effect.forkScoped); |
| 234 | const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { |
| 235 | timeoutMs: 100, |
| 236 | }).pipe(Effect.forkScoped); |
| 232 | 237 | |
| 233 | | yield* Effect.yieldNow; |
| 234 | | yield* TestClock.adjust(Duration.millis(100)); |
| 238 | yield* Effect.yieldNow; |
| 239 | yield* TestClock.adjust(Duration.millis(100)); |
| 235 | 240 | |
| 236 | | const payload = yield* Fiber.join(fiber); |
| 237 | | assertNone(payload); |
| 238 | | }).pipe(Effect.provide(TestClock.layer())), |
| 241 | const payload = yield* Fiber.join(fiber); |
| 242 | assertNone(payload); |
| 243 | }).pipe(Effect.provide(TestClock.layer())), |
| 239 | 244 | ); |
| 240 | 245 | }); |