| ... | ... | @@ -6,7 +6,6 @@ import * as Deferred from "effect/Deferred"; |
| 6 | 6 | import * as Effect from "effect/Effect"; |
| 7 | 7 | import * as Fiber from "effect/Fiber"; |
| 8 | 8 | import * as Hex from "effect/encoding/Hex"; |
| 9 | | import * as Fiber from "effect/Fiber"; |
| 10 | 9 | import * as FileSystem from "effect/FileSystem"; |
| 11 | 10 | import * as Layer from "effect/Layer"; |
| 12 | 11 | import * as PlatformError from "effect/PlatformError"; |
| ... | ... | @@ -57,6 +56,16 @@ const layerHttpClient = (bytes: Uint8Array) => |
| 57 | 56 | ), |
| 58 | 57 | ); |
| 59 | 58 | |
| 59 | // Records each request and never responds, simulating a wedged endpoint. |
| 60 | const layerStalledHttpClient = (requests: Array<unknown>) => |
| 61 | Layer.succeed( |
| 62 | HttpClient.HttpClient, |
| 63 | HttpClient.make((request) => { |
| 64 | requests.push(request); |
| 65 | return Effect.never; |
| 66 | }), |
| 67 | ); |
| 68 | |
| 60 | 69 | // Answers `cloudflared version` with the version recorded for that path, which |
| 61 | 70 | // defaults to the pinned release; tests change it to simulate other binaries. |
| 62 | 71 | const layerSpawner = (commands: Array<string>, versions: Record<string, string> = {}) => |
| ... | ... | @@ -767,4 +776,44 @@ describe("RelayClient", () => { |
| 767 | 776 | expect(renames.attempts).toBe(1); |
| 768 | 777 | }).pipe(Effect.scoped, Effect.provide(layerInstallRuntime(platform))), |
| 769 | 778 | ); |
| 779 | |
| 780 | it.effect("fails a stalled download after the download timeout", () => { |
| 781 | const requests: Array<unknown> = []; |
| 782 | return Effect.gen(function* () { |
| 783 | const fileSystem = yield* FileSystem.FileSystem; |
| 784 | const baseDir = yield* fileSystem.makeTempDirectoryScoped({ |
| 785 | prefix: "t3-cloudflared-test-", |
| 786 | }); |
| 787 | const manager = yield* RelayClient.makeCloudflaredRelayClient({ |
| 788 | baseDir, |
| 789 | releaseAsset: { |
| 790 | url: "https://example.test/cloudflared", |
| 791 | sha256: "00".repeat(32), |
| 792 | archive: "binary", |
| 793 | }, |
| 794 | }); |
| 795 | |
| 796 | const child = yield* Effect.forkChild(manager.install); |
| 797 | // Spin until the wedged download is in flight, so the clock |
| 798 | // adjustment below cannot run before the timeout is armed. |
| 799 | while (requests.length === 0) { |
| 800 | yield* Effect.yieldNow; |
| 801 | } |
| 802 | // The download timeout is 10 minutes; advance past it. |
| 803 | yield* TestClock.adjust("11 minutes"); |
| 804 | const error = yield* Fiber.join(child).pipe(Effect.flip); |
| 805 | expect(error).toBeInstanceOf(RelayClient.RelayClientInstallError); |
| 806 | expect(error.reason).toBe("download_failed"); |
| 807 | }).pipe( |
| 808 | Effect.scoped, |
| 809 | Effect.provide( |
| 810 | Layer.mergeAll( |
| 811 | NodeServices.layer, |
| 812 | layerStalledHttpClient(requests), |
| 813 | layerSpawner([]), |
| 814 | layerHostRuntime({ PATH: "" }), |
| 815 | ), |
| 816 | ), |
| 817 | ); |
| 818 | }); |
| 770 | 819 | }); |