From 5f3d629827056a67c3f1269eb16cab2e03610dee Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 4 Oct 2024 12:54:53 +0100 Subject: [PATCH 01/37] wip --- .../tests/index.test.ts | 4 ++-- fixtures/get-platform-proxy/tests/shared.ts | 1 + .../shared/src/run-wrangler-long-lived.ts | 21 ++++++++++++++++--- vitest.shared.ts | 3 --- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fixtures/external-durable-objects-app/tests/index.test.ts b/fixtures/external-durable-objects-app/tests/index.test.ts index 8ba7e980dd28..70699d90d1ff 100644 --- a/fixtures/external-durable-objects-app/tests/index.test.ts +++ b/fixtures/external-durable-objects-app/tests/index.test.ts @@ -8,7 +8,7 @@ import type { UnstableDevWorker } from "wrangler"; // TODO: reenable when https://github.com/cloudflare/workers-sdk/pull/4241 lands // and improves reliability of this test. -describe.skip( +describe( "Pages Functions", () => { let a: UnstableDevWorker; @@ -87,5 +87,5 @@ describe.skip( expect(dataA.id).toEqual(dataA2.id); }); }, - { retry: 2 } + { repeats: 10 } ); diff --git a/fixtures/get-platform-proxy/tests/shared.ts b/fixtures/get-platform-proxy/tests/shared.ts index 11156437eac5..3beaca1264ea 100644 --- a/fixtures/get-platform-proxy/tests/shared.ts +++ b/fixtures/get-platform-proxy/tests/shared.ts @@ -9,5 +9,6 @@ export function getPlatformProxy( return originalGetPlatformProxy({ ...options, persist: false, + experimentalRegistry: true, }); } diff --git a/fixtures/shared/src/run-wrangler-long-lived.ts b/fixtures/shared/src/run-wrangler-long-lived.ts index 2ab9ca76f3c0..7028a0646a81 100644 --- a/fixtures/shared/src/run-wrangler-long-lived.ts +++ b/fixtures/shared/src/run-wrangler-long-lived.ts @@ -25,13 +25,28 @@ export async function runWranglerPagesDev( ) { if (publicPath) { return runLongLivedWrangler( - ["pages", "dev", publicPath, "--x-dev-env", "--ip=127.0.0.1", ...options], + [ + "pages", + "dev", + publicPath, + "--x-dev-env", + "--x-registry", + "--ip=127.0.0.1", + ...options, + ], cwd, env ); } else { return runLongLivedWrangler( - ["pages", "dev", "--x-dev-env", "--ip=127.0.0.1", ...options], + [ + "pages", + "dev", + "--x-dev-env", + "--x-registry", + "--ip=127.0.0.1", + ...options, + ], cwd, env ); @@ -52,7 +67,7 @@ export async function runWranglerDev( env?: NodeJS.ProcessEnv ) { return runLongLivedWrangler( - ["dev", "--x-dev-env", "--ip=127.0.0.1", ...options], + ["dev", "--x-dev-env", "--x-registry", "--ip=127.0.0.1", ...options], cwd, env ); diff --git a/vitest.shared.ts b/vitest.shared.ts index cb8c57b7a684..4b1a037c6840 100644 --- a/vitest.shared.ts +++ b/vitest.shared.ts @@ -17,8 +17,5 @@ export default defineConfig({ useAtomics: true, }, restoreMocks: true, - // A lot of the fixture tests are extremely flaky because of the dev registry - // Retry tests by default so that only real errors are reported - retry: 2, }, }); From ab85085222a1e3750aabdfde862630e44f11bbdb Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:02:46 +0100 Subject: [PATCH 02/37] make get-platform-proxy unstable_dev serial not parallel --- .../tests/get-platform-proxy.env.test.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts index a7c4812d7462..a0c56a10ab51 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -1,6 +1,6 @@ import { readdir } from "fs/promises"; -import * as nodeNet from "node:net"; import path from "path"; +import { setTimeout } from "timers/promises"; import { D1Database, DurableObjectNamespace, @@ -400,19 +400,26 @@ describe("getPlatformProxy - env", () => { async function startWorkers(): Promise { const workersDirPath = path.join(__dirname, "..", "workers"); const workers = await readdir(workersDirPath); - return await Promise.all( - workers.map((workerName) => { - const workerPath = path.join(workersDirPath, workerName); - return unstable_dev(path.join(workerPath, "index.ts"), { + const result: UnstableDevWorker[] = []; + + for (const workerName of workers) { + const workerPath = path.join(workersDirPath, workerName); + const unstableDevWorker = await unstable_dev( + path.join(workerPath, "index.ts"), + { config: path.join(workerPath, "wrangler.toml"), ip: "127.0.0.1", experimental: { devEnv: true, fileBasedRegistry: true, }, - }); - }) - ); + } + ); + await setTimeout(1000); + result.push(unstableDevWorker); + } + + return result; } async function testServiceBinding(binding: Fetcher, expectedResponse: string) { From 3bd1393f58a92b8f14c69c1f2a0d131aa72acb18 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:08:19 +0100 Subject: [PATCH 03/37] repeats: 10 --- .../tests/index.test.ts | 20 +- .../tests/index.test.ts | 218 +++---- .../tests/get-platform-proxy.env.test.ts | 562 +++++++++--------- 3 files changed, 412 insertions(+), 388 deletions(-) diff --git a/fixtures/external-durable-objects-app/tests/index.test.ts b/fixtures/external-durable-objects-app/tests/index.test.ts index 70699d90d1ff..4bce2586b148 100644 --- a/fixtures/external-durable-objects-app/tests/index.test.ts +++ b/fixtures/external-durable-objects-app/tests/index.test.ts @@ -68,19 +68,29 @@ describe( "X-Reset-Count": "true", }, }); - const dataA = (await responseA.json()) as { count: number; id: string }; + const dataAText = await responseA.text(); + console.log(dataAText); + const dataA = JSON.parse(dataAText) as { count: number; id: string }; expect(dataA.count).toEqual(1); const responseB = await b.fetch(`/`); - const dataB = (await responseB.json()) as { count: number; id: string }; + const dataBText = await responseB.text(); + console.log(dataBText); + const dataB = JSON.parse(dataBText) as { count: number; id: string }; expect(dataB.count).toEqual(2); const responseC = await c.fetch(`/`); - const dataC = (await responseC.json()) as { count: number; id: string }; + const dataCText = await responseC.text(); + console.log(dataCText); + const dataC = JSON.parse(dataCText) as { count: number; id: string }; expect(dataC.count).toEqual(3); const responseD = await fetch(`http://${d.ip}:${d.port}/`); - const dataD = (await responseD.json()) as { count: number; id: string }; + const dataDText = await responseD.text(); + console.log(dataDText); + const dataD = JSON.parse(dataDText) as { count: number; id: string }; expect(dataD.count).toEqual(4); const responseA2 = await a.fetch(`/`); - const dataA2 = (await responseA2.json()) as { count: number; id: string }; + const dataA2Text = await responseA2.text(); + console.log(dataA2Text); + const dataA2 = JSON.parse(dataA2Text) as { count: number; id: string }; expect(dataA2.count).toEqual(5); expect(dataA.id).toEqual(dataB.id); expect(dataA.id).toEqual(dataC.id); diff --git a/fixtures/external-service-bindings-app/tests/index.test.ts b/fixtures/external-service-bindings-app/tests/index.test.ts index 9130581e3767..089301fe7e65 100644 --- a/fixtures/external-service-bindings-app/tests/index.test.ts +++ b/fixtures/external-service-bindings-app/tests/index.test.ts @@ -29,129 +29,133 @@ type WranglerInstance = { port: string; }; -describe("Pages Functions", () => { - let wranglerInstances: (WranglerInstance | UnstableDevWorker)[] = []; - let pagesAppPort: string; - - beforeAll(async () => { - wranglerInstances[0] = await unstable_dev( - path.join(__dirname, "../module-worker-a/index.ts"), - { - config: path.join(__dirname, "../module-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[1] = await unstable_dev( - path.join(__dirname, "../module-worker-b/index.ts"), - { - config: path.join(__dirname, "../module-worker-b/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[2] = await unstable_dev( - path.join(__dirname, "../service-worker-a/index.ts"), - { - config: path.join(__dirname, "../service-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[3] = await unstable_dev( - path.join(__dirname, "../module-worker-c/index.ts"), - { - config: path.join(__dirname, "../module-worker-c/wrangler.toml"), - env: "staging", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); +describe( + "Pages Functions", + () => { + let wranglerInstances: (WranglerInstance | UnstableDevWorker)[] = []; + let pagesAppPort: string; + + beforeAll(async () => { + wranglerInstances[0] = await unstable_dev( + path.join(__dirname, "../module-worker-a/index.ts"), + { + config: path.join(__dirname, "../module-worker-a/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[1] = await unstable_dev( + path.join(__dirname, "../module-worker-b/index.ts"), + { + config: path.join(__dirname, "../module-worker-b/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[2] = await unstable_dev( + path.join(__dirname, "../service-worker-a/index.ts"), + { + config: path.join(__dirname, "../service-worker-a/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[3] = await unstable_dev( + path.join(__dirname, "../module-worker-c/index.ts"), + { + config: path.join(__dirname, "../module-worker-c/wrangler.toml"), + env: "staging", + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[4] = await unstable_dev( + path.join(__dirname, "../module-worker-d/index.ts"), + { + config: path.join(__dirname, "../module-worker-d/wrangler.toml"), + env: "production", + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[5] = await getWranglerInstance({ + pages: true, + dirName: "pages-functions-app", + extraArgs: [ + "--service=MODULE_A_SERVICE=module-worker-a", + "--service=MODULE_B_SERVICE=module-worker-b", + "--service=SERVICE_A_SERVICE=service-worker-a", + "--service=STAGING_MODULE_C_SERVICE=module-worker-c@staging", + "--service=STAGING_MODULE_D_SERVICE=module-worker-d@staging", + ], + }); - wranglerInstances[4] = await unstable_dev( - path.join(__dirname, "../module-worker-d/index.ts"), - { - config: path.join(__dirname, "../module-worker-d/wrangler.toml"), - env: "production", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[5] = await getWranglerInstance({ - pages: true, - dirName: "pages-functions-app", - extraArgs: [ - "--service=MODULE_A_SERVICE=module-worker-a", - "--service=MODULE_B_SERVICE=module-worker-b", - "--service=SERVICE_A_SERVICE=service-worker-a", - "--service=STAGING_MODULE_C_SERVICE=module-worker-c@staging", - "--service=STAGING_MODULE_D_SERVICE=module-worker-d@staging", - ], + pagesAppPort = wranglerInstances[5].port; + await setTimeout(1000); }); - pagesAppPort = wranglerInstances[5].port; - await setTimeout(1000); - }); - - afterAll(async () => { - await Promise.allSettled( - wranglerInstances.map((i) => - "stop" in i ? i.stop() : terminateWranglerInstance(i) - ) - ); - }); + afterAll(async () => { + await Promise.allSettled( + wranglerInstances.map((i) => + "stop" in i ? i.stop() : terminateWranglerInstance(i) + ) + ); + }); - it("connects up Workers (both module and service ones) and fetches from them", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` + it("connects up Workers (both module and service ones) and fetches from them", async () => { + const combinedResponse = await waitUntilReady( + `http://127.0.0.1:${pagesAppPort}/` + ); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` { "moduleWorkerAResponse": "Hello from module worker a", "moduleWorkerBResponse": "Hello from module worker b and also: Hello from module worker a", "serviceWorkerAResponse": "Hello from service worker a", } `); - }); + }); - it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/env` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` + it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { + const combinedResponse = await waitUntilReady( + `http://127.0.0.1:${pagesAppPort}/env` + ); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` { "moduleWorkerCResponse": "Hello from module worker c (staging)", "moduleWorkerDResponse": "[wrangler] Couldn't find \`wrangler dev\` session for service "module-worker-d-staging" to proxy to", } `); - }); -}); + }); + }, + { repeats: 10 } +); async function getWranglerInstance({ pages = false, diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts index a0c56a10ab51..d5405ec5a635 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -46,351 +46,361 @@ type Env = { const wranglerTomlFilePath = path.join(__dirname, "..", "wrangler.toml"); -describe("getPlatformProxy - env", () => { - let devWorkers: UnstableDevWorker[]; +describe( + "getPlatformProxy - env", + () => { + let devWorkers: UnstableDevWorker[]; - beforeEach(() => { - // Hide stdout messages from the test logs - vi.spyOn(console, "log").mockImplementation(() => {}); - }); + beforeEach(() => { + // Hide stdout messages from the test logs + vi.spyOn(console, "log").mockImplementation(() => {}); + }); - beforeAll(async () => { - devWorkers = await startWorkers(); - }); + beforeAll(async () => { + devWorkers = await startWorkers(); + }); - afterAll(async () => { - await Promise.allSettled(devWorkers.map((i) => i.stop())); - }); + afterAll(async () => { + await Promise.allSettled(devWorkers.map((i) => i.stop())); + }); - describe("var bindings", () => { - it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, + describe("var bindings", () => { + it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value"); + expect(MY_JSON_VAR).toEqual({ + test: true, + }); + expect(MY_DEV_VAR).toEqual("my-dev-var-value"); + } finally { + await dispose(); + } }); - try { - const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; - expect(MY_VAR).toEqual("my-var-value"); - expect(MY_JSON_VAR).toEqual({ - test: true, + + it("correctly makes vars from .dev.vars override the ones in wrangler.toml", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, }); - expect(MY_DEV_VAR).toEqual("my-dev-var-value"); - } finally { - await dispose(); - } + try { + const { MY_VAR_A } = env; + expect(MY_VAR_A).not.toEqual("my-var-a"); // if this fails, the value was read from wrangler.toml – not .dev.vars + expect(MY_VAR_A).toEqual("my-dev-var-a"); + } finally { + await dispose(); + } + }); + + it("correctly makes vars from .dev.vars not override bindings of the same name from wrangler.toml", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_KV } = env; + expect(MY_KV).not.toEqual("my-dev-kv"); + ["get", "delete", "list", "put", "getWithMetadata"].every( + (methodName) => + expect( + typeof (MY_KV as unknown as Record)[methodName] + ).toBe("function") + ); + } finally { + await dispose(); + } + }); + + it("correctly reads a toml from a custom path alongside with its .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: path.join( + __dirname, + "..", + "custom-toml", + "path", + "test-toml" + ), + }); + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-custom-toml"); + expect(MY_JSON_VAR).toEqual({ + test: true, + customToml: true, + }); + expect(MY_DEV_VAR).toEqual("my-dev-var-value-from-a-custom-location"); + } finally { + await dispose(); + } + }); }); - it("correctly makes vars from .dev.vars override the ones in wrangler.toml", async () => { + it("correctly reads a json config file", async () => { const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, + configPath: path.join(__dirname, "..", "wrangler.json"), }); try { - const { MY_VAR_A } = env; - expect(MY_VAR_A).not.toEqual("my-var-a"); // if this fails, the value was read from wrangler.toml – not .dev.vars - expect(MY_VAR_A).toEqual("my-dev-var-a"); + const { MY_VAR, MY_JSON_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-json-config-file"); + expect(MY_JSON_VAR).toEqual({ + test: true, + fromJson: true, + }); } finally { await dispose(); } }); - it("correctly makes vars from .dev.vars not override bindings of the same name from wrangler.toml", async () => { + it("provides service bindings to external local workers", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); try { - const { MY_KV } = env; - expect(MY_KV).not.toEqual("my-dev-kv"); - ["get", "delete", "list", "put", "getWithMetadata"].every( - (methodName) => - expect( - typeof (MY_KV as unknown as Record)[methodName] - ).toBe("function") + const { MY_SERVICE_A, MY_SERVICE_B } = env; + await testServiceBinding( + MY_SERVICE_A, + "Hello World from hello-worker-a" + ); + await testServiceBinding( + MY_SERVICE_B, + "Hello World from hello-worker-b" ); } finally { await dispose(); } }); - it("correctly reads a toml from a custom path alongside with its .dev.vars", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: path.join( - __dirname, - "..", - "custom-toml", - "path", - "test-toml" - ), + type EntrypointService = Service< + Omit & + Rpc.WorkerEntrypointBranded + > & { + getCounter: () => Promise< + Promise<{ + value: Promise; + increment: (amount: number) => Promise; + }> + >; + getHelloWorldFn: () => Promise<() => Promise>; + getHelloFn: () => Promise< + ( + greet: string, + name: string, + options?: { + suffix?: string; + capitalize?: boolean; + } + ) => Promise + >; + }; + + describe("provides rpc service bindings to external local workers", () => { + let rpc: EntrypointService; + beforeEach(async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + rpc = env.MY_RPC as unknown as EntrypointService; + return dispose; }); - try { - const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; - expect(MY_VAR).toEqual("my-var-value-from-a-custom-toml"); - expect(MY_JSON_VAR).toEqual({ - test: true, - customToml: true, + it("can call RPC methods returning a string", async () => { + expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`); + }); + it("can call RPC methods returning an object", async () => { + expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({ + isObject: true, + value: 11, }); - expect(MY_DEV_VAR).toEqual("my-dev-var-value-from-a-custom-location"); - } finally { - await dispose(); - } - }); - }); - - it("correctly reads a json config file", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: path.join(__dirname, "..", "wrangler.json"), - }); - try { - const { MY_VAR, MY_JSON_VAR } = env; - expect(MY_VAR).toEqual("my-var-value-from-a-json-config-file"); - expect(MY_JSON_VAR).toEqual({ - test: true, - fromJson: true, }); - } finally { - await dispose(); - } - }); + it("can call RPC methods returning a Response", async () => { + const resp = await rpc.asJsonResponse([1, 2, 3]); + expect(resp.status).toMatchInlineSnapshot(`200`); + expect(await resp.text()).toMatchInlineSnapshot(`"[1,2,3]"`); + }); + it("can obtain and interact with RpcStubs", async () => { + const counter = await rpc.getCounter(); + expect(await counter.value).toMatchInlineSnapshot(`0`); + expect(await counter.increment(4)).toMatchInlineSnapshot(`4`); + expect(await counter.increment(8)).toMatchInlineSnapshot(`12`); + expect(await counter.value).toMatchInlineSnapshot(`12`); + }); + it("can obtain and interact with returned functions", async () => { + const helloWorldFn = await rpc.getHelloWorldFn(); + expect(helloWorldFn()).toEqual("Hello World!"); - it("provides service bindings to external local workers", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, + const helloFn = await rpc.getHelloFn(); + expect(await helloFn("hi", "world")).toEqual("hi world"); + expect( + await helloFn("hi", "world", { + capitalize: true, + }) + ).toEqual("HI WORLD"); + expect( + await helloFn("Sup", "world", { + capitalize: true, + suffix: "?!", + }) + ).toEqual("SUP WORLD?!"); + }); }); - try { - const { MY_SERVICE_A, MY_SERVICE_B } = env; - await testServiceBinding(MY_SERVICE_A, "Hello World from hello-worker-a"); - await testServiceBinding(MY_SERVICE_B, "Hello World from hello-worker-b"); - } finally { - await dispose(); - } - }); - - type EntrypointService = Service< - Omit & - Rpc.WorkerEntrypointBranded - > & { - getCounter: () => Promise< - Promise<{ - value: Promise; - increment: (amount: number) => Promise; - }> - >; - getHelloWorldFn: () => Promise<() => Promise>; - getHelloFn: () => Promise< - ( - greet: string, - name: string, - options?: { - suffix?: string; - capitalize?: boolean; - } - ) => Promise - >; - }; - describe("provides rpc service bindings to external local workers", () => { - let rpc: EntrypointService; - beforeEach(async () => { + it("correctly obtains functioning KV bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); - rpc = env.MY_RPC as unknown as EntrypointService; - return dispose; - }); - it("can call RPC methods returning a string", async () => { - expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`); - }); - it("can call RPC methods returning an object", async () => { - expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({ - isObject: true, - value: 11, - }); - }); - it("can call RPC methods returning a Response", async () => { - const resp = await rpc.asJsonResponse([1, 2, 3]); - expect(resp.status).toMatchInlineSnapshot(`200`); - expect(await resp.text()).toMatchInlineSnapshot(`"[1,2,3]"`); - }); - it("can obtain and interact with RpcStubs", async () => { - const counter = await rpc.getCounter(); - expect(await counter.value).toMatchInlineSnapshot(`0`); - expect(await counter.increment(4)).toMatchInlineSnapshot(`4`); - expect(await counter.increment(8)).toMatchInlineSnapshot(`12`); - expect(await counter.value).toMatchInlineSnapshot(`12`); - }); - it("can obtain and interact with returned functions", async () => { - const helloWorldFn = await rpc.getHelloWorldFn(); - expect(helloWorldFn()).toEqual("Hello World!"); - - const helloFn = await rpc.getHelloFn(); - expect(await helloFn("hi", "world")).toEqual("hi world"); - expect( - await helloFn("hi", "world", { - capitalize: true, - }) - ).toEqual("HI WORLD"); - expect( - await helloFn("Sup", "world", { - capitalize: true, - suffix: "?!", - }) - ).toEqual("SUP WORLD?!"); - }); - }); - - it("correctly obtains functioning KV bindings", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - const { MY_KV } = env; - let numOfKeys = (await MY_KV.list()).keys.length; - expect(numOfKeys).toBe(0); - await MY_KV.put("my-key", "my-value"); - numOfKeys = (await MY_KV.list()).keys.length; - expect(numOfKeys).toBe(1); - const value = await MY_KV.get("my-key"); - expect(value).toBe("my-value"); - await dispose(); - }); - - it("correctly obtains functioning DO bindings (provided by external local workers)", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_DO_A, MY_DO_B } = env; - await testDoBinding(MY_DO_A, "Hello from DurableObject A"); - await testDoBinding(MY_DO_B, "Hello from DurableObject B"); - } finally { - await dispose(); - } - }); - - it("correctly obtains functioning R2 bindings", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_BUCKET } = env; - let numOfObjects = (await MY_BUCKET.list()).objects.length; - expect(numOfObjects).toBe(0); - await MY_BUCKET.put("my-object", "my-value"); - numOfObjects = (await MY_BUCKET.list()).objects.length; - expect(numOfObjects).toBe(1); - const value = await MY_BUCKET.get("my-object"); - expect(await value?.text()).toBe("my-value"); - } finally { + const { MY_KV } = env; + let numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(0); + await MY_KV.put("my-key", "my-value"); + numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(1); + const value = await MY_KV.get("my-key"); + expect(value).toBe("my-value"); await dispose(); - } - }); - - it("correctly obtains functioning D1 bindings", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, }); - try { - const { MY_D1 } = env; - await MY_D1.exec( - `CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL )` - ); - const stmt = MY_D1.prepare("insert into users (name) values (?1)"); - await MY_D1.batch([ - stmt.bind("userA"), - stmt.bind("userB"), - stmt.bind("userC"), - ]); - const { results } = await MY_D1.prepare( - "SELECT name FROM users LIMIT 5" - ).all(); - expect(results).toEqual([ - { name: "userA" }, - { name: "userB" }, - { name: "userC" }, - ]); - } finally { - await dispose(); - } - }); - // Important: the hyperdrive values are passthrough ones since the workerd specific hyperdrive values only make sense inside - // workerd itself and would simply not work in a node.js process - it("correctly obtains passthrough Hyperdrive bindings", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, + it("correctly obtains functioning DO bindings (provided by external local workers)", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_DO_A, MY_DO_B } = env; + await testDoBinding(MY_DO_A, "Hello from DurableObject A"); + await testDoBinding(MY_DO_B, "Hello from DurableObject B"); + } finally { + await dispose(); + } }); - try { - const { MY_HYPERDRIVE } = env; - expect(MY_HYPERDRIVE.connectionString).toEqual( - "postgres://user:pass@127.0.0.1:1234/db" - ); - expect(MY_HYPERDRIVE.database).toEqual("db"); - expect(MY_HYPERDRIVE.host).toEqual("127.0.0.1"); - expect(MY_HYPERDRIVE.user).toEqual("user"); - expect(MY_HYPERDRIVE.password).toEqual("pass"); - expect(MY_HYPERDRIVE.port).toEqual(1234); - } finally { - await dispose(); - } - }); - describe("with a target environment", () => { - it("should provide bindings targeting a specified environment and also inherit top-level ones", async () => { + it("correctly obtains functioning R2 bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, - environment: "production", }); try { - expect(env.MY_VAR).not.toBe("my-var-value"); - expect(env.MY_VAR).toBe("my-PRODUCTION-var-value"); - expect(env.MY_JSON_VAR).toEqual({ test: true, production: true }); - - expect(env.MY_KV).toBeTruthy(); - expect(env.MY_KV_PROD).toBeTruthy(); + const { MY_BUCKET } = env; + let numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(0); + await MY_BUCKET.put("my-object", "my-value"); + numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(1); + const value = await MY_BUCKET.get("my-object"); + expect(await value?.text()).toBe("my-value"); } finally { await dispose(); } }); - it("should not provide bindings targeting an environment when none was specified", async () => { + it("correctly obtains functioning D1 bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); try { - expect(env.MY_VAR).not.toBe("my-PRODUCTION-var-value"); - expect(env.MY_VAR).toBe("my-var-value"); - expect(env.MY_JSON_VAR).toEqual({ test: true }); - - expect(env.MY_KV).toBeTruthy(); - expect(env.MY_KV_PROD).toBeFalsy(); + const { MY_D1 } = env; + await MY_D1.exec( + `CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL )` + ); + const stmt = MY_D1.prepare("insert into users (name) values (?1)"); + await MY_D1.batch([ + stmt.bind("userA"), + stmt.bind("userB"), + stmt.bind("userC"), + ]); + const { results } = await MY_D1.prepare( + "SELECT name FROM users LIMIT 5" + ).all(); + expect(results).toEqual([ + { name: "userA" }, + { name: "userB" }, + { name: "userC" }, + ]); } finally { await dispose(); } }); - it("should provide secrets targeting a specified environment", async () => { + // Important: the hyperdrive values are passthrough ones since the workerd specific hyperdrive values only make sense inside + // workerd itself and would simply not work in a node.js process + it("correctly obtains passthrough Hyperdrive bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, - environment: "production", }); try { - const { MY_DEV_VAR } = env; - expect(MY_DEV_VAR).not.toEqual("my-dev-var-value"); - expect(MY_DEV_VAR).toEqual("my-PRODUCTION-dev-var-value"); + const { MY_HYPERDRIVE } = env; + expect(MY_HYPERDRIVE.connectionString).toEqual( + "postgres://user:pass@127.0.0.1:1234/db" + ); + expect(MY_HYPERDRIVE.database).toEqual("db"); + expect(MY_HYPERDRIVE.host).toEqual("127.0.0.1"); + expect(MY_HYPERDRIVE.user).toEqual("user"); + expect(MY_HYPERDRIVE.password).toEqual("pass"); + expect(MY_HYPERDRIVE.port).toEqual(1234); } finally { await dispose(); } }); - it("should error if a non-existent environment is provided", async () => { - await expect( - getPlatformProxy({ + describe("with a target environment", () => { + it("should provide bindings targeting a specified environment and also inherit top-level ones", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + environment: "production", + }); + try { + expect(env.MY_VAR).not.toBe("my-var-value"); + expect(env.MY_VAR).toBe("my-PRODUCTION-var-value"); + expect(env.MY_JSON_VAR).toEqual({ test: true, production: true }); + + expect(env.MY_KV).toBeTruthy(); + expect(env.MY_KV_PROD).toBeTruthy(); + } finally { + await dispose(); + } + }); + + it("should not provide bindings targeting an environment when none was specified", async () => { + const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, - environment: "non-existent-environment", - }) - ).rejects.toThrow( - /No environment found in configuration with name "non-existent-environment"/ - ); + }); + try { + expect(env.MY_VAR).not.toBe("my-PRODUCTION-var-value"); + expect(env.MY_VAR).toBe("my-var-value"); + expect(env.MY_JSON_VAR).toEqual({ test: true }); + + expect(env.MY_KV).toBeTruthy(); + expect(env.MY_KV_PROD).toBeFalsy(); + } finally { + await dispose(); + } + }); + + it("should provide secrets targeting a specified environment", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + environment: "production", + }); + try { + const { MY_DEV_VAR } = env; + expect(MY_DEV_VAR).not.toEqual("my-dev-var-value"); + expect(MY_DEV_VAR).toEqual("my-PRODUCTION-dev-var-value"); + } finally { + await dispose(); + } + }); + + it("should error if a non-existent environment is provided", async () => { + await expect( + getPlatformProxy({ + configPath: wranglerTomlFilePath, + environment: "non-existent-environment", + }) + ).rejects.toThrow( + /No environment found in configuration with name "non-existent-environment"/ + ); + }); }); - }); -}); + }, + { repeats: 10 } +); /** * Starts all the workers present in the `workers` directory using `unstable_dev` From aee5542d8b1c7aad945e3a93698947ecc952539d Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:16:15 +0100 Subject: [PATCH 04/37] back to original retries: 2 + no repeats --- .../tests/index.test.ts | 166 +++--- .../tests/index.test.ts | 218 ++++--- .../tests/get-platform-proxy.env.test.ts | 562 +++++++++--------- vitest.shared.ts | 3 + 4 files changed, 467 insertions(+), 482 deletions(-) diff --git a/fixtures/external-durable-objects-app/tests/index.test.ts b/fixtures/external-durable-objects-app/tests/index.test.ts index 4bce2586b148..9823228fc8c8 100644 --- a/fixtures/external-durable-objects-app/tests/index.test.ts +++ b/fixtures/external-durable-objects-app/tests/index.test.ts @@ -8,94 +8,90 @@ import type { UnstableDevWorker } from "wrangler"; // TODO: reenable when https://github.com/cloudflare/workers-sdk/pull/4241 lands // and improves reliability of this test. -describe( - "Pages Functions", - () => { - let a: UnstableDevWorker; - let b: UnstableDevWorker; - let c: UnstableDevWorker; - let d: Awaited>; +describe("Pages Functions", () => { + let a: UnstableDevWorker; + let b: UnstableDevWorker; + let c: UnstableDevWorker; + let d: Awaited>; - beforeAll(async () => { - a = await unstable_dev(path.join(__dirname, "../a/index.ts"), { - config: path.join(__dirname, "../a/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - b = await unstable_dev(path.join(__dirname, "../b/index.ts"), { - config: path.join(__dirname, "../b/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - c = await unstable_dev(path.join(__dirname, "../c/index.ts"), { - config: path.join(__dirname, "../c/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - - d = await runWranglerPagesDev( - path.resolve(__dirname, "..", "d"), - "public", - [ - "--compatibility-date=2024-03-04", - "--do=PAGES_REFERENCED_DO=MyDurableObject@a", - "--port=0", - ] - ); + beforeAll(async () => { + a = await unstable_dev(path.join(__dirname, "../a/index.ts"), { + config: path.join(__dirname, "../a/wrangler.toml"), + experimental: { + disableExperimentalWarning: true, + devEnv: true, + }, }); - - afterAll(async () => { - await a.stop(); - await b.stop(); - await c.stop(); - await d.stop(); + await setTimeout(1000); + b = await unstable_dev(path.join(__dirname, "../b/index.ts"), { + config: path.join(__dirname, "../b/wrangler.toml"), + experimental: { + disableExperimentalWarning: true, + devEnv: true, + }, + }); + await setTimeout(1000); + c = await unstable_dev(path.join(__dirname, "../c/index.ts"), { + config: path.join(__dirname, "../c/wrangler.toml"), + experimental: { + disableExperimentalWarning: true, + devEnv: true, + }, }); + await setTimeout(1000); + + d = await runWranglerPagesDev( + path.resolve(__dirname, "..", "d"), + "public", + [ + "--compatibility-date=2024-03-04", + "--do=PAGES_REFERENCED_DO=MyDurableObject@a", + "--port=0", + ] + ); + }); + + afterAll(async () => { + await a.stop(); + await b.stop(); + await c.stop(); + await d.stop(); + }); - it("connects up Durable Objects and keeps state across wrangler instances", async () => { - await setTimeout(1000); + it("connects up Durable Objects and keeps state across wrangler instances", async () => { + await setTimeout(1000); - const responseA = await a.fetch(`/`, { - headers: { - "X-Reset-Count": "true", - }, - }); - const dataAText = await responseA.text(); - console.log(dataAText); - const dataA = JSON.parse(dataAText) as { count: number; id: string }; - expect(dataA.count).toEqual(1); - const responseB = await b.fetch(`/`); - const dataBText = await responseB.text(); - console.log(dataBText); - const dataB = JSON.parse(dataBText) as { count: number; id: string }; - expect(dataB.count).toEqual(2); - const responseC = await c.fetch(`/`); - const dataCText = await responseC.text(); - console.log(dataCText); - const dataC = JSON.parse(dataCText) as { count: number; id: string }; - expect(dataC.count).toEqual(3); - const responseD = await fetch(`http://${d.ip}:${d.port}/`); - const dataDText = await responseD.text(); - console.log(dataDText); - const dataD = JSON.parse(dataDText) as { count: number; id: string }; - expect(dataD.count).toEqual(4); - const responseA2 = await a.fetch(`/`); - const dataA2Text = await responseA2.text(); - console.log(dataA2Text); - const dataA2 = JSON.parse(dataA2Text) as { count: number; id: string }; - expect(dataA2.count).toEqual(5); - expect(dataA.id).toEqual(dataB.id); - expect(dataA.id).toEqual(dataC.id); - expect(dataA.id).toEqual(dataA2.id); + const responseA = await a.fetch(`/`, { + headers: { + "X-Reset-Count": "true", + }, }); - }, - { repeats: 10 } -); + const dataAText = await responseA.text(); + console.log(dataAText); + const dataA = JSON.parse(dataAText) as { count: number; id: string }; + expect(dataA.count).toEqual(1); + const responseB = await b.fetch(`/`); + const dataBText = await responseB.text(); + console.log(dataBText); + const dataB = JSON.parse(dataBText) as { count: number; id: string }; + expect(dataB.count).toEqual(2); + const responseC = await c.fetch(`/`); + const dataCText = await responseC.text(); + console.log(dataCText); + const dataC = JSON.parse(dataCText) as { count: number; id: string }; + expect(dataC.count).toEqual(3); + const responseD = await fetch(`http://${d.ip}:${d.port}/`); + const dataDText = await responseD.text(); + console.log(dataDText); + const dataD = JSON.parse(dataDText) as { count: number; id: string }; + expect(dataD.count).toEqual(4); + const responseA2 = await a.fetch(`/`); + const dataA2Text = await responseA2.text(); + console.log(dataA2Text); + const dataA2 = JSON.parse(dataA2Text) as { count: number; id: string }; + expect(dataA2.count).toEqual(5); + expect(dataA.id).toEqual(dataB.id); + expect(dataA.id).toEqual(dataC.id); + expect(dataA.id).toEqual(dataA2.id); + }); +}); diff --git a/fixtures/external-service-bindings-app/tests/index.test.ts b/fixtures/external-service-bindings-app/tests/index.test.ts index 089301fe7e65..9130581e3767 100644 --- a/fixtures/external-service-bindings-app/tests/index.test.ts +++ b/fixtures/external-service-bindings-app/tests/index.test.ts @@ -29,133 +29,129 @@ type WranglerInstance = { port: string; }; -describe( - "Pages Functions", - () => { - let wranglerInstances: (WranglerInstance | UnstableDevWorker)[] = []; - let pagesAppPort: string; - - beforeAll(async () => { - wranglerInstances[0] = await unstable_dev( - path.join(__dirname, "../module-worker-a/index.ts"), - { - config: path.join(__dirname, "../module-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[1] = await unstable_dev( - path.join(__dirname, "../module-worker-b/index.ts"), - { - config: path.join(__dirname, "../module-worker-b/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[2] = await unstable_dev( - path.join(__dirname, "../service-worker-a/index.ts"), - { - config: path.join(__dirname, "../service-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[3] = await unstable_dev( - path.join(__dirname, "../module-worker-c/index.ts"), - { - config: path.join(__dirname, "../module-worker-c/wrangler.toml"), - env: "staging", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[4] = await unstable_dev( - path.join(__dirname, "../module-worker-d/index.ts"), - { - config: path.join(__dirname, "../module-worker-d/wrangler.toml"), - env: "production", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[5] = await getWranglerInstance({ - pages: true, - dirName: "pages-functions-app", - extraArgs: [ - "--service=MODULE_A_SERVICE=module-worker-a", - "--service=MODULE_B_SERVICE=module-worker-b", - "--service=SERVICE_A_SERVICE=service-worker-a", - "--service=STAGING_MODULE_C_SERVICE=module-worker-c@staging", - "--service=STAGING_MODULE_D_SERVICE=module-worker-d@staging", - ], - }); +describe("Pages Functions", () => { + let wranglerInstances: (WranglerInstance | UnstableDevWorker)[] = []; + let pagesAppPort: string; - pagesAppPort = wranglerInstances[5].port; - await setTimeout(1000); - }); + beforeAll(async () => { + wranglerInstances[0] = await unstable_dev( + path.join(__dirname, "../module-worker-a/index.ts"), + { + config: path.join(__dirname, "../module-worker-a/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[1] = await unstable_dev( + path.join(__dirname, "../module-worker-b/index.ts"), + { + config: path.join(__dirname, "../module-worker-b/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[2] = await unstable_dev( + path.join(__dirname, "../service-worker-a/index.ts"), + { + config: path.join(__dirname, "../service-worker-a/wrangler.toml"), + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[3] = await unstable_dev( + path.join(__dirname, "../module-worker-c/index.ts"), + { + config: path.join(__dirname, "../module-worker-c/wrangler.toml"), + env: "staging", + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); - afterAll(async () => { - await Promise.allSettled( - wranglerInstances.map((i) => - "stop" in i ? i.stop() : terminateWranglerInstance(i) - ) - ); + wranglerInstances[4] = await unstable_dev( + path.join(__dirname, "../module-worker-d/index.ts"), + { + config: path.join(__dirname, "../module-worker-d/wrangler.toml"), + env: "production", + experimental: { + fileBasedRegistry: true, + disableExperimentalWarning: true, + devEnv: true, + }, + } + ); + await setTimeout(1000); + + wranglerInstances[5] = await getWranglerInstance({ + pages: true, + dirName: "pages-functions-app", + extraArgs: [ + "--service=MODULE_A_SERVICE=module-worker-a", + "--service=MODULE_B_SERVICE=module-worker-b", + "--service=SERVICE_A_SERVICE=service-worker-a", + "--service=STAGING_MODULE_C_SERVICE=module-worker-c@staging", + "--service=STAGING_MODULE_D_SERVICE=module-worker-d@staging", + ], }); - it("connects up Workers (both module and service ones) and fetches from them", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` + pagesAppPort = wranglerInstances[5].port; + await setTimeout(1000); + }); + + afterAll(async () => { + await Promise.allSettled( + wranglerInstances.map((i) => + "stop" in i ? i.stop() : terminateWranglerInstance(i) + ) + ); + }); + + it("connects up Workers (both module and service ones) and fetches from them", async () => { + const combinedResponse = await waitUntilReady( + `http://127.0.0.1:${pagesAppPort}/` + ); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` { "moduleWorkerAResponse": "Hello from module worker a", "moduleWorkerBResponse": "Hello from module worker b and also: Hello from module worker a", "serviceWorkerAResponse": "Hello from service worker a", } `); - }); + }); - it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/env` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` + it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { + const combinedResponse = await waitUntilReady( + `http://127.0.0.1:${pagesAppPort}/env` + ); + const json = await combinedResponse.json(); + expect(json).toMatchInlineSnapshot(` { "moduleWorkerCResponse": "Hello from module worker c (staging)", "moduleWorkerDResponse": "[wrangler] Couldn't find \`wrangler dev\` session for service "module-worker-d-staging" to proxy to", } `); - }); - }, - { repeats: 10 } -); + }); +}); async function getWranglerInstance({ pages = false, diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts index d5405ec5a635..a0c56a10ab51 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -46,361 +46,351 @@ type Env = { const wranglerTomlFilePath = path.join(__dirname, "..", "wrangler.toml"); -describe( - "getPlatformProxy - env", - () => { - let devWorkers: UnstableDevWorker[]; +describe("getPlatformProxy - env", () => { + let devWorkers: UnstableDevWorker[]; - beforeEach(() => { - // Hide stdout messages from the test logs - vi.spyOn(console, "log").mockImplementation(() => {}); - }); - - beforeAll(async () => { - devWorkers = await startWorkers(); - }); + beforeEach(() => { + // Hide stdout messages from the test logs + vi.spyOn(console, "log").mockImplementation(() => {}); + }); - afterAll(async () => { - await Promise.allSettled(devWorkers.map((i) => i.stop())); - }); + beforeAll(async () => { + devWorkers = await startWorkers(); + }); - describe("var bindings", () => { - it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; - expect(MY_VAR).toEqual("my-var-value"); - expect(MY_JSON_VAR).toEqual({ - test: true, - }); - expect(MY_DEV_VAR).toEqual("my-dev-var-value"); - } finally { - await dispose(); - } - }); - - it("correctly makes vars from .dev.vars override the ones in wrangler.toml", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_VAR_A } = env; - expect(MY_VAR_A).not.toEqual("my-var-a"); // if this fails, the value was read from wrangler.toml – not .dev.vars - expect(MY_VAR_A).toEqual("my-dev-var-a"); - } finally { - await dispose(); - } - }); + afterAll(async () => { + await Promise.allSettled(devWorkers.map((i) => i.stop())); + }); - it("correctly makes vars from .dev.vars not override bindings of the same name from wrangler.toml", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_KV } = env; - expect(MY_KV).not.toEqual("my-dev-kv"); - ["get", "delete", "list", "put", "getWithMetadata"].every( - (methodName) => - expect( - typeof (MY_KV as unknown as Record)[methodName] - ).toBe("function") - ); - } finally { - await dispose(); - } + describe("var bindings", () => { + it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, }); - - it("correctly reads a toml from a custom path alongside with its .dev.vars", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: path.join( - __dirname, - "..", - "custom-toml", - "path", - "test-toml" - ), + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value"); + expect(MY_JSON_VAR).toEqual({ + test: true, }); - try { - const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; - expect(MY_VAR).toEqual("my-var-value-from-a-custom-toml"); - expect(MY_JSON_VAR).toEqual({ - test: true, - customToml: true, - }); - expect(MY_DEV_VAR).toEqual("my-dev-var-value-from-a-custom-location"); - } finally { - await dispose(); - } - }); + expect(MY_DEV_VAR).toEqual("my-dev-var-value"); + } finally { + await dispose(); + } }); - it("correctly reads a json config file", async () => { + it("correctly makes vars from .dev.vars override the ones in wrangler.toml", async () => { const { env, dispose } = await getPlatformProxy({ - configPath: path.join(__dirname, "..", "wrangler.json"), + configPath: wranglerTomlFilePath, }); try { - const { MY_VAR, MY_JSON_VAR } = env; - expect(MY_VAR).toEqual("my-var-value-from-a-json-config-file"); - expect(MY_JSON_VAR).toEqual({ - test: true, - fromJson: true, - }); + const { MY_VAR_A } = env; + expect(MY_VAR_A).not.toEqual("my-var-a"); // if this fails, the value was read from wrangler.toml – not .dev.vars + expect(MY_VAR_A).toEqual("my-dev-var-a"); } finally { await dispose(); } }); - it("provides service bindings to external local workers", async () => { + it("correctly makes vars from .dev.vars not override bindings of the same name from wrangler.toml", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); try { - const { MY_SERVICE_A, MY_SERVICE_B } = env; - await testServiceBinding( - MY_SERVICE_A, - "Hello World from hello-worker-a" - ); - await testServiceBinding( - MY_SERVICE_B, - "Hello World from hello-worker-b" + const { MY_KV } = env; + expect(MY_KV).not.toEqual("my-dev-kv"); + ["get", "delete", "list", "put", "getWithMetadata"].every( + (methodName) => + expect( + typeof (MY_KV as unknown as Record)[methodName] + ).toBe("function") ); } finally { await dispose(); } }); - type EntrypointService = Service< - Omit & - Rpc.WorkerEntrypointBranded - > & { - getCounter: () => Promise< - Promise<{ - value: Promise; - increment: (amount: number) => Promise; - }> - >; - getHelloWorldFn: () => Promise<() => Promise>; - getHelloFn: () => Promise< - ( - greet: string, - name: string, - options?: { - suffix?: string; - capitalize?: boolean; - } - ) => Promise - >; - }; - - describe("provides rpc service bindings to external local workers", () => { - let rpc: EntrypointService; - beforeEach(async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - rpc = env.MY_RPC as unknown as EntrypointService; - return dispose; - }); - it("can call RPC methods returning a string", async () => { - expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`); + it("correctly reads a toml from a custom path alongside with its .dev.vars", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: path.join( + __dirname, + "..", + "custom-toml", + "path", + "test-toml" + ), }); - it("can call RPC methods returning an object", async () => { - expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({ - isObject: true, - value: 11, + try { + const { MY_VAR, MY_JSON_VAR, MY_DEV_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-custom-toml"); + expect(MY_JSON_VAR).toEqual({ + test: true, + customToml: true, }); - }); - it("can call RPC methods returning a Response", async () => { - const resp = await rpc.asJsonResponse([1, 2, 3]); - expect(resp.status).toMatchInlineSnapshot(`200`); - expect(await resp.text()).toMatchInlineSnapshot(`"[1,2,3]"`); - }); - it("can obtain and interact with RpcStubs", async () => { - const counter = await rpc.getCounter(); - expect(await counter.value).toMatchInlineSnapshot(`0`); - expect(await counter.increment(4)).toMatchInlineSnapshot(`4`); - expect(await counter.increment(8)).toMatchInlineSnapshot(`12`); - expect(await counter.value).toMatchInlineSnapshot(`12`); - }); - it("can obtain and interact with returned functions", async () => { - const helloWorldFn = await rpc.getHelloWorldFn(); - expect(helloWorldFn()).toEqual("Hello World!"); + expect(MY_DEV_VAR).toEqual("my-dev-var-value-from-a-custom-location"); + } finally { + await dispose(); + } + }); + }); - const helloFn = await rpc.getHelloFn(); - expect(await helloFn("hi", "world")).toEqual("hi world"); - expect( - await helloFn("hi", "world", { - capitalize: true, - }) - ).toEqual("HI WORLD"); - expect( - await helloFn("Sup", "world", { - capitalize: true, - suffix: "?!", - }) - ).toEqual("SUP WORLD?!"); + it("correctly reads a json config file", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: path.join(__dirname, "..", "wrangler.json"), + }); + try { + const { MY_VAR, MY_JSON_VAR } = env; + expect(MY_VAR).toEqual("my-var-value-from-a-json-config-file"); + expect(MY_JSON_VAR).toEqual({ + test: true, + fromJson: true, }); + } finally { + await dispose(); + } + }); + + it("provides service bindings to external local workers", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, }); + try { + const { MY_SERVICE_A, MY_SERVICE_B } = env; + await testServiceBinding(MY_SERVICE_A, "Hello World from hello-worker-a"); + await testServiceBinding(MY_SERVICE_B, "Hello World from hello-worker-b"); + } finally { + await dispose(); + } + }); + + type EntrypointService = Service< + Omit & + Rpc.WorkerEntrypointBranded + > & { + getCounter: () => Promise< + Promise<{ + value: Promise; + increment: (amount: number) => Promise; + }> + >; + getHelloWorldFn: () => Promise<() => Promise>; + getHelloFn: () => Promise< + ( + greet: string, + name: string, + options?: { + suffix?: string; + capitalize?: boolean; + } + ) => Promise + >; + }; - it("correctly obtains functioning KV bindings", async () => { + describe("provides rpc service bindings to external local workers", () => { + let rpc: EntrypointService; + beforeEach(async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); - const { MY_KV } = env; - let numOfKeys = (await MY_KV.list()).keys.length; - expect(numOfKeys).toBe(0); - await MY_KV.put("my-key", "my-value"); - numOfKeys = (await MY_KV.list()).keys.length; - expect(numOfKeys).toBe(1); - const value = await MY_KV.get("my-key"); - expect(value).toBe("my-value"); + rpc = env.MY_RPC as unknown as EntrypointService; + return dispose; + }); + it("can call RPC methods returning a string", async () => { + expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`); + }); + it("can call RPC methods returning an object", async () => { + expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({ + isObject: true, + value: 11, + }); + }); + it("can call RPC methods returning a Response", async () => { + const resp = await rpc.asJsonResponse([1, 2, 3]); + expect(resp.status).toMatchInlineSnapshot(`200`); + expect(await resp.text()).toMatchInlineSnapshot(`"[1,2,3]"`); + }); + it("can obtain and interact with RpcStubs", async () => { + const counter = await rpc.getCounter(); + expect(await counter.value).toMatchInlineSnapshot(`0`); + expect(await counter.increment(4)).toMatchInlineSnapshot(`4`); + expect(await counter.increment(8)).toMatchInlineSnapshot(`12`); + expect(await counter.value).toMatchInlineSnapshot(`12`); + }); + it("can obtain and interact with returned functions", async () => { + const helloWorldFn = await rpc.getHelloWorldFn(); + expect(helloWorldFn()).toEqual("Hello World!"); + + const helloFn = await rpc.getHelloFn(); + expect(await helloFn("hi", "world")).toEqual("hi world"); + expect( + await helloFn("hi", "world", { + capitalize: true, + }) + ).toEqual("HI WORLD"); + expect( + await helloFn("Sup", "world", { + capitalize: true, + suffix: "?!", + }) + ).toEqual("SUP WORLD?!"); + }); + }); + + it("correctly obtains functioning KV bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + const { MY_KV } = env; + let numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(0); + await MY_KV.put("my-key", "my-value"); + numOfKeys = (await MY_KV.list()).keys.length; + expect(numOfKeys).toBe(1); + const value = await MY_KV.get("my-key"); + expect(value).toBe("my-value"); + await dispose(); + }); + + it("correctly obtains functioning DO bindings (provided by external local workers)", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_DO_A, MY_DO_B } = env; + await testDoBinding(MY_DO_A, "Hello from DurableObject A"); + await testDoBinding(MY_DO_B, "Hello from DurableObject B"); + } finally { await dispose(); + } + }); + + it("correctly obtains functioning R2 bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, }); + try { + const { MY_BUCKET } = env; + let numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(0); + await MY_BUCKET.put("my-object", "my-value"); + numOfObjects = (await MY_BUCKET.list()).objects.length; + expect(numOfObjects).toBe(1); + const value = await MY_BUCKET.get("my-object"); + expect(await value?.text()).toBe("my-value"); + } finally { + await dispose(); + } + }); - it("correctly obtains functioning DO bindings (provided by external local workers)", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_DO_A, MY_DO_B } = env; - await testDoBinding(MY_DO_A, "Hello from DurableObject A"); - await testDoBinding(MY_DO_B, "Hello from DurableObject B"); - } finally { - await dispose(); - } + it("correctly obtains functioning D1 bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, + }); + try { + const { MY_D1 } = env; + await MY_D1.exec( + `CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL )` + ); + const stmt = MY_D1.prepare("insert into users (name) values (?1)"); + await MY_D1.batch([ + stmt.bind("userA"), + stmt.bind("userB"), + stmt.bind("userC"), + ]); + const { results } = await MY_D1.prepare( + "SELECT name FROM users LIMIT 5" + ).all(); + expect(results).toEqual([ + { name: "userA" }, + { name: "userB" }, + { name: "userC" }, + ]); + } finally { + await dispose(); + } + }); + + // Important: the hyperdrive values are passthrough ones since the workerd specific hyperdrive values only make sense inside + // workerd itself and would simply not work in a node.js process + it("correctly obtains passthrough Hyperdrive bindings", async () => { + const { env, dispose } = await getPlatformProxy({ + configPath: wranglerTomlFilePath, }); + try { + const { MY_HYPERDRIVE } = env; + expect(MY_HYPERDRIVE.connectionString).toEqual( + "postgres://user:pass@127.0.0.1:1234/db" + ); + expect(MY_HYPERDRIVE.database).toEqual("db"); + expect(MY_HYPERDRIVE.host).toEqual("127.0.0.1"); + expect(MY_HYPERDRIVE.user).toEqual("user"); + expect(MY_HYPERDRIVE.password).toEqual("pass"); + expect(MY_HYPERDRIVE.port).toEqual(1234); + } finally { + await dispose(); + } + }); - it("correctly obtains functioning R2 bindings", async () => { + describe("with a target environment", () => { + it("should provide bindings targeting a specified environment and also inherit top-level ones", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, + environment: "production", }); try { - const { MY_BUCKET } = env; - let numOfObjects = (await MY_BUCKET.list()).objects.length; - expect(numOfObjects).toBe(0); - await MY_BUCKET.put("my-object", "my-value"); - numOfObjects = (await MY_BUCKET.list()).objects.length; - expect(numOfObjects).toBe(1); - const value = await MY_BUCKET.get("my-object"); - expect(await value?.text()).toBe("my-value"); + expect(env.MY_VAR).not.toBe("my-var-value"); + expect(env.MY_VAR).toBe("my-PRODUCTION-var-value"); + expect(env.MY_JSON_VAR).toEqual({ test: true, production: true }); + + expect(env.MY_KV).toBeTruthy(); + expect(env.MY_KV_PROD).toBeTruthy(); } finally { await dispose(); } }); - it("correctly obtains functioning D1 bindings", async () => { + it("should not provide bindings targeting an environment when none was specified", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, }); try { - const { MY_D1 } = env; - await MY_D1.exec( - `CREATE TABLE IF NOT EXISTS users ( id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL )` - ); - const stmt = MY_D1.prepare("insert into users (name) values (?1)"); - await MY_D1.batch([ - stmt.bind("userA"), - stmt.bind("userB"), - stmt.bind("userC"), - ]); - const { results } = await MY_D1.prepare( - "SELECT name FROM users LIMIT 5" - ).all(); - expect(results).toEqual([ - { name: "userA" }, - { name: "userB" }, - { name: "userC" }, - ]); + expect(env.MY_VAR).not.toBe("my-PRODUCTION-var-value"); + expect(env.MY_VAR).toBe("my-var-value"); + expect(env.MY_JSON_VAR).toEqual({ test: true }); + + expect(env.MY_KV).toBeTruthy(); + expect(env.MY_KV_PROD).toBeFalsy(); } finally { await dispose(); } }); - // Important: the hyperdrive values are passthrough ones since the workerd specific hyperdrive values only make sense inside - // workerd itself and would simply not work in a node.js process - it("correctly obtains passthrough Hyperdrive bindings", async () => { + it("should provide secrets targeting a specified environment", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, + environment: "production", }); try { - const { MY_HYPERDRIVE } = env; - expect(MY_HYPERDRIVE.connectionString).toEqual( - "postgres://user:pass@127.0.0.1:1234/db" - ); - expect(MY_HYPERDRIVE.database).toEqual("db"); - expect(MY_HYPERDRIVE.host).toEqual("127.0.0.1"); - expect(MY_HYPERDRIVE.user).toEqual("user"); - expect(MY_HYPERDRIVE.password).toEqual("pass"); - expect(MY_HYPERDRIVE.port).toEqual(1234); + const { MY_DEV_VAR } = env; + expect(MY_DEV_VAR).not.toEqual("my-dev-var-value"); + expect(MY_DEV_VAR).toEqual("my-PRODUCTION-dev-var-value"); } finally { await dispose(); } }); - describe("with a target environment", () => { - it("should provide bindings targeting a specified environment and also inherit top-level ones", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - environment: "production", - }); - try { - expect(env.MY_VAR).not.toBe("my-var-value"); - expect(env.MY_VAR).toBe("my-PRODUCTION-var-value"); - expect(env.MY_JSON_VAR).toEqual({ test: true, production: true }); - - expect(env.MY_KV).toBeTruthy(); - expect(env.MY_KV_PROD).toBeTruthy(); - } finally { - await dispose(); - } - }); - - it("should not provide bindings targeting an environment when none was specified", async () => { - const { env, dispose } = await getPlatformProxy({ + it("should error if a non-existent environment is provided", async () => { + await expect( + getPlatformProxy({ configPath: wranglerTomlFilePath, - }); - try { - expect(env.MY_VAR).not.toBe("my-PRODUCTION-var-value"); - expect(env.MY_VAR).toBe("my-var-value"); - expect(env.MY_JSON_VAR).toEqual({ test: true }); - - expect(env.MY_KV).toBeTruthy(); - expect(env.MY_KV_PROD).toBeFalsy(); - } finally { - await dispose(); - } - }); - - it("should provide secrets targeting a specified environment", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - environment: "production", - }); - try { - const { MY_DEV_VAR } = env; - expect(MY_DEV_VAR).not.toEqual("my-dev-var-value"); - expect(MY_DEV_VAR).toEqual("my-PRODUCTION-dev-var-value"); - } finally { - await dispose(); - } - }); - - it("should error if a non-existent environment is provided", async () => { - await expect( - getPlatformProxy({ - configPath: wranglerTomlFilePath, - environment: "non-existent-environment", - }) - ).rejects.toThrow( - /No environment found in configuration with name "non-existent-environment"/ - ); - }); + environment: "non-existent-environment", + }) + ).rejects.toThrow( + /No environment found in configuration with name "non-existent-environment"/ + ); }); - }, - { repeats: 10 } -); + }); +}); /** * Starts all the workers present in the `workers` directory using `unstable_dev` diff --git a/vitest.shared.ts b/vitest.shared.ts index 4b1a037c6840..cb8c57b7a684 100644 --- a/vitest.shared.ts +++ b/vitest.shared.ts @@ -17,5 +17,8 @@ export default defineConfig({ useAtomics: true, }, restoreMocks: true, + // A lot of the fixture tests are extremely flaky because of the dev registry + // Retry tests by default so that only real errors are reported + retry: 2, }, }); From d8811161778e9339f9425c5f9540cb3a70cf5220 Mon Sep 17 00:00:00 2001 From: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:25:27 +0100 Subject: [PATCH 05/37] re-skip external-durable-object-app fixutre test --- fixtures/external-durable-objects-app/tests/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fixtures/external-durable-objects-app/tests/index.test.ts b/fixtures/external-durable-objects-app/tests/index.test.ts index 9823228fc8c8..3fd7eb0a74bc 100644 --- a/fixtures/external-durable-objects-app/tests/index.test.ts +++ b/fixtures/external-durable-objects-app/tests/index.test.ts @@ -8,7 +8,7 @@ import type { UnstableDevWorker } from "wrangler"; // TODO: reenable when https://github.com/cloudflare/workers-sdk/pull/4241 lands // and improves reliability of this test. -describe("Pages Functions", () => { +describe.skip("Pages Functions", () => { let a: UnstableDevWorker; let b: UnstableDevWorker; let c: UnstableDevWorker; From 21e5c8249cb5962457e79f3d881f61b945092c07 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Fri, 4 Oct 2024 18:58:27 +0100 Subject: [PATCH 06/37] Expand registry e2e tests --- packages/wrangler/e2e/dev-registry.test.ts | 279 +++++++++++++++++++++ packages/wrangler/e2e/dev.test.ts | 101 -------- 2 files changed, 279 insertions(+), 101 deletions(-) create mode 100644 packages/wrangler/e2e/dev-registry.test.ts diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts new file mode 100644 index 000000000000..2b85f6fc66e0 --- /dev/null +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -0,0 +1,279 @@ +import { setTimeout } from "node:timers/promises"; +import dedent from "ts-dedent"; +import { fetch, RequestInit } from "undici"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; +import { fetchText } from "./helpers/fetch-text"; +import { generateResourceName } from "./helpers/generate-resource-name"; +import { seed as baseSeed, makeRoot } from "./helpers/setup"; + +async function fetchJson(url: string, info?: RequestInit): Promise { + return vi.waitFor( + async () => { + const text: string = await fetch(url, { + headers: { "MF-Disable-Pretty-Error": "true" }, + ...info, + }).then((r) => r.text()); + console.log(text); + return JSON.parse(text) as T; + }, + { timeout: 5_000, interval: 250 } + ); +} +describe.each([ + { cmd: "wrangler dev --x-registry" }, + { cmd: "wrangler dev --no-x-registry" }, +])("basic dev registry", ({ cmd }) => { + let a: string; + let b: string; + let c: string; + let helper: WranglerE2ETestHelper; + + beforeEach(async () => { + const workerName = generateResourceName("worker"); + const workerName2 = generateResourceName("worker"); + const workerName3 = generateResourceName("worker"); + helper = new WranglerE2ETestHelper(); + a = await makeRoot(); + await baseSeed(a, { + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + + [[services]] + binding = "BEE" + service = '${workerName2}' + + [[services]] + binding = "CEE" + service = '${workerName3}' + + [durable_objects] + bindings = [ + { name = "MY_DO", class_name = "MyDurableObject" } + ] + + [[migrations]] + tag = "v1" + new_classes = ["MyDurableObject"] + `, + "src/index.ts": dedent/* javascript */ ` + export default { + fetch(req, env) { + const url = new URL(req.url) + if (url.pathname === "/do") { + const id = env.MY_DO.idFromName(url.pathname); + const stub = env.MY_DO.get(id); + return stub.fetch(req); + } + if (url.pathname === "/service") { + return env.CEE.fetch(req); + } + return env.BEE.fetch(req); + }, + }; + + export class MyDurableObject implements DurableObject { + constructor(public state: DurableObjectState) {} + + async fetch(request: Request) { + if (request.headers.has("X-Reset-Count")) { + await this.state.storage.put("count", 0); + } + let count: number = (await this.state.storage.get("count")) || 0; + await this.state.storage.put("count", ++count); + return Response.json({ count, id: this.state.id.toString() }); + } + } + `, + "package.json": dedent` + { + "name": "a", + "version": "0.0.0", + "private": true + } + `, + }); + + b = await makeRoot(); + await baseSeed(b, { + "wrangler.toml": dedent` + name = "${workerName2}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + + + [durable_objects] + bindings = [ + { name = "REFERENCED_DO", class_name = "MyDurableObject", script_name = "${workerName}" } + ] + `, + "src/index.ts": dedent/* javascript */ ` + export default{ + fetch(req, env) { + const url = new URL(req.url) + if (url.pathname === "/do") { + const id = env.REFERENCED_DO.idFromName(url.pathname); + const stub = env.REFERENCED_DO.get(id); + return stub.fetch(req); + } + return new Response("hello world"); + }, + }; + `, + "package.json": dedent` + { + "name": "b", + "version": "0.0.0", + "private": true + } + `, + }); + + c = await makeRoot(); + await baseSeed(c, { + "wrangler.toml": dedent` + name = "${workerName3}" + main = "src/index.ts" + `, + "src/index.ts": dedent/* javascript */ ` + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello from service worker")); + }); + `, + "package.json": dedent` + { + "name": "c", + "version": "0.0.0", + "private": true + } + `, + }); + }); + + it("can fetch b", async () => { + const worker = helper.runLongLived(cmd, { cwd: b }); + + const { url } = await worker.waitForReady(); + + await expect(fetch(url).then((r) => r.text())).resolves.toBe("hello world"); + }); + + it("can fetch b through a (start b, start a)", async () => { + const workerB = helper.runLongLived(cmd, { cwd: b }); + // We don't need b's URL, but ensure that b starts up before a + await workerB.waitForReady(); + + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); + + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect(fetchText(url)).resolves.toBe("hello world"); + }); + + it("can fetch b through a (start a, start b)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); + + const workerB = helper.runLongLived(cmd, { cwd: b }); + await workerB.waitForReady(); + + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect(fetchText(url)).resolves.toBe("hello world"); + }); + + it("can fetch service worker c through a (start c, start a)", async () => { + const workerC = helper.runLongLived(cmd, { cwd: c }); + // We don't need c's URL, but ensure that c starts up before a + await workerC.waitForReady(); + + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); + + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ); + }); + + it("can fetch service worker c through a (start a, start c)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); + + const workerC = helper.runLongLived(cmd, { cwd: c }); + await workerC.waitForReady(); + + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ); + }); + + it("can fetch DO through a", async () => { + const worker = helper.runLongLived(cmd, { cwd: a }); + + const { url } = await worker.waitForReady(); + + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }); + }); + + it("can fetch remote DO attached to a through b (start b, start a)", async () => { + const workerB = helper.runLongLived(cmd, { cwd: b }); + const { url } = await workerB.waitForReady(); + + const workerA = helper.runLongLived(cmd, { cwd: a }); + await workerA.waitForReady(); + + await workerA.waitForReload(); + + // Give the dev registry some time to settle + await setTimeout(500); + + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }); + }); + + it("can fetch remote DO attached to a through b (start a, start b)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + await workerA.waitForReady(); + + const workerB = helper.runLongLived(cmd, { cwd: b }); + const { url } = await workerB.waitForReady(); + + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect( + fetch(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }).then((r) => r.json()) + ).resolves.toMatchObject({ count: 1 }); + }); +}); diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 4435c70b0c04..0da3840c4576 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -221,107 +221,6 @@ describe.each([ }); }); -describe.each([ - { cmd: "wrangler dev --x-dev-env --no-x-registry" }, - { cmd: "wrangler dev --no-x-dev-env --no-x-registry" }, - { cmd: "wrangler dev --x-dev-env --x-registry" }, - { cmd: "wrangler dev --no-x-dev-env --x-registry" }, -])("dev registry $cmd", ({ cmd }) => { - let a: string; - let b: string; - let helper: WranglerE2ETestHelper; - - beforeEach(async () => { - helper = new WranglerE2ETestHelper(); - a = await makeRoot(); - await baseSeed(a, { - "wrangler.toml": dedent` - name = "${workerName}" - main = "src/index.ts" - compatibility_date = "2023-01-01" - - [[services]] - binding = "BEE" - service = '${workerName2}' - `, - "src/index.ts": dedent/* javascript */ ` - export default { - fetch(req, env) { - return env.BEE.fetch(req); - }, - }; - `, - "package.json": dedent` - { - "name": "a", - "version": "0.0.0", - "private": true - } - `, - }); - - b = await makeRoot(); - await baseSeed(b, { - "wrangler.toml": dedent` - name = "${workerName2}" - main = "src/index.ts" - compatibility_date = "2023-01-01" - `, - "src/index.ts": dedent/* javascript */ ` - export default{ - fetch() { - return new Response("hello world"); - }, - }; - `, - "package.json": dedent` - { - "name": "b", - "version": "0.0.0", - "private": true - } - `, - }); - }); - - it("can fetch b", async () => { - const worker = helper.runLongLived(cmd, { cwd: b }); - - const { url } = await worker.waitForReady(); - - await expect(fetch(url).then((r) => r.text())).resolves.toBe("hello world"); - }); - - it("can fetch b through a (start b, start a)", async () => { - const workerB = helper.runLongLived(cmd, { cwd: b }); - // We don't need b's URL, but ensure that b starts up before a - await workerB.waitForReady(); - - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); - - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); - - await expect(fetchText(url)).resolves.toBe("hello world"); - }); - - it("can fetch b through a (start a, start b)", async () => { - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); - - const workerB = helper.runLongLived(cmd, { cwd: b }); - await workerB.waitForReady(); - - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); - - await expect(fetchText(url)).resolves.toBe("hello world"); - }); -}); - describe("hyperdrive dev tests", () => { let server: nodeNet.Server; From 8433f1e89c55dd6f2ecb57bd6940a779e2e45611 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Fri, 4 Oct 2024 18:59:45 +0100 Subject: [PATCH 07/37] remove flaky fixtures --- .../external-durable-objects-app/a/index.ts | 21 -- .../a/wrangler.toml | 11 - .../external-durable-objects-app/b/index.ts | 8 - .../b/wrangler.toml | 7 - .../external-durable-objects-app/c/index.ts | 8 - .../c/wrangler.toml | 7 - .../d/functions/index.ts | 8 - .../d/package.json | 4 - .../d/public/index.html | 1 - .../external-durable-objects-app/package.json | 21 -- .../tests/index.test.ts | 97 --------- .../tests/tsconfig.json | 8 - .../tsconfig.json | 10 - .../vitest.config.mts | 9 - .../module-worker-a/index.ts | 5 - .../module-worker-a/wrangler.toml | 1 - .../module-worker-b/index.ts | 9 - .../module-worker-b/wrangler.toml | 5 - .../module-worker-c/index.ts | 5 - .../module-worker-c/wrangler.toml | 7 - .../module-worker-d/index.ts | 5 - .../module-worker-d/wrangler.toml | 7 - .../package.json | 27 --- .../pages-functions-app/functions/env.ts | 9 - .../pages-functions-app/functions/index.ts | 10 - .../pages-functions-app/package.json | 4 - .../pages-functions-app/public/index.html | 1 - .../service-worker-a/index.ts | 3 - .../service-worker-a/wrangler.toml | 2 - .../tests/index.test.ts | 206 ------------------ .../tsconfig.json | 16 -- .../vitest.config.mts | 9 - 32 files changed, 551 deletions(-) delete mode 100644 fixtures/external-durable-objects-app/a/index.ts delete mode 100644 fixtures/external-durable-objects-app/a/wrangler.toml delete mode 100644 fixtures/external-durable-objects-app/b/index.ts delete mode 100644 fixtures/external-durable-objects-app/b/wrangler.toml delete mode 100644 fixtures/external-durable-objects-app/c/index.ts delete mode 100644 fixtures/external-durable-objects-app/c/wrangler.toml delete mode 100644 fixtures/external-durable-objects-app/d/functions/index.ts delete mode 100644 fixtures/external-durable-objects-app/d/package.json delete mode 100644 fixtures/external-durable-objects-app/d/public/index.html delete mode 100644 fixtures/external-durable-objects-app/package.json delete mode 100644 fixtures/external-durable-objects-app/tests/index.test.ts delete mode 100644 fixtures/external-durable-objects-app/tests/tsconfig.json delete mode 100644 fixtures/external-durable-objects-app/tsconfig.json delete mode 100644 fixtures/external-durable-objects-app/vitest.config.mts delete mode 100644 fixtures/external-service-bindings-app/module-worker-a/index.ts delete mode 100644 fixtures/external-service-bindings-app/module-worker-a/wrangler.toml delete mode 100644 fixtures/external-service-bindings-app/module-worker-b/index.ts delete mode 100644 fixtures/external-service-bindings-app/module-worker-b/wrangler.toml delete mode 100644 fixtures/external-service-bindings-app/module-worker-c/index.ts delete mode 100644 fixtures/external-service-bindings-app/module-worker-c/wrangler.toml delete mode 100644 fixtures/external-service-bindings-app/module-worker-d/index.ts delete mode 100644 fixtures/external-service-bindings-app/module-worker-d/wrangler.toml delete mode 100644 fixtures/external-service-bindings-app/package.json delete mode 100644 fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts delete mode 100644 fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts delete mode 100644 fixtures/external-service-bindings-app/pages-functions-app/package.json delete mode 100644 fixtures/external-service-bindings-app/pages-functions-app/public/index.html delete mode 100644 fixtures/external-service-bindings-app/service-worker-a/index.ts delete mode 100644 fixtures/external-service-bindings-app/service-worker-a/wrangler.toml delete mode 100644 fixtures/external-service-bindings-app/tests/index.test.ts delete mode 100644 fixtures/external-service-bindings-app/tsconfig.json delete mode 100644 fixtures/external-service-bindings-app/vitest.config.mts diff --git a/fixtures/external-durable-objects-app/a/index.ts b/fixtures/external-durable-objects-app/a/index.ts deleted file mode 100644 index a69ad1aaa71f..000000000000 --- a/fixtures/external-durable-objects-app/a/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -export default { - fetch(request: Request, env: { MY_DO: DurableObjectNamespace }) { - const { pathname } = new URL(request.url); - const id = env.MY_DO.idFromName(pathname); - const stub = env.MY_DO.get(id); - return stub.fetch(request); - }, -}; - -export class MyDurableObject implements DurableObject { - constructor(public state: DurableObjectState) {} - - async fetch(request: Request) { - if (request.headers.has("X-Reset-Count")) { - await this.state.storage.put("count", 0); - } - let count: number = (await this.state.storage.get("count")) || 0; - await this.state.storage.put("count", ++count); - return Response.json({ count, id: this.state.id.toString() }); - } -} diff --git a/fixtures/external-durable-objects-app/a/wrangler.toml b/fixtures/external-durable-objects-app/a/wrangler.toml deleted file mode 100644 index 9e5383b33b0f..000000000000 --- a/fixtures/external-durable-objects-app/a/wrangler.toml +++ /dev/null @@ -1,11 +0,0 @@ -name = "a" -compatibility_date = "2024-06-10" - -[durable_objects] -bindings = [ - { name = "MY_DO", class_name = "MyDurableObject" } -] - -[[migrations]] -tag = "v1" -new_classes = ["MyDurableObject"] \ No newline at end of file diff --git a/fixtures/external-durable-objects-app/b/index.ts b/fixtures/external-durable-objects-app/b/index.ts deleted file mode 100644 index dd53281b1a5a..000000000000 --- a/fixtures/external-durable-objects-app/b/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default { - fetch(request: Request, env: { REFERENCED_DO: DurableObjectNamespace }) { - const { pathname } = new URL(request.url); - const id = env.REFERENCED_DO.idFromName(pathname); - const stub = env.REFERENCED_DO.get(id); - return stub.fetch(request); - }, -}; diff --git a/fixtures/external-durable-objects-app/b/wrangler.toml b/fixtures/external-durable-objects-app/b/wrangler.toml deleted file mode 100644 index 42a678344f62..000000000000 --- a/fixtures/external-durable-objects-app/b/wrangler.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "b" -compatibility_date = "2024-06-10" - -[durable_objects] -bindings = [ - { name = "REFERENCED_DO", class_name = "MyDurableObject", script_name = "a" } -] diff --git a/fixtures/external-durable-objects-app/c/index.ts b/fixtures/external-durable-objects-app/c/index.ts deleted file mode 100644 index c6fcf190972a..000000000000 --- a/fixtures/external-durable-objects-app/c/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare const SW_REFERENCED_DO: DurableObjectNamespace; - -addEventListener("fetch", (event) => { - const { pathname } = new URL(event.request.url); - const id = SW_REFERENCED_DO.idFromName(pathname); - const stub = SW_REFERENCED_DO.get(id); - event.respondWith(stub.fetch(event.request)); -}); diff --git a/fixtures/external-durable-objects-app/c/wrangler.toml b/fixtures/external-durable-objects-app/c/wrangler.toml deleted file mode 100644 index 4bb01a0fd9fa..000000000000 --- a/fixtures/external-durable-objects-app/c/wrangler.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "c" -compatibility_date = "2024-06-10" - -[durable_objects] -bindings = [ - { name = "SW_REFERENCED_DO", class_name = "MyDurableObject", script_name = "a" } -] diff --git a/fixtures/external-durable-objects-app/d/functions/index.ts b/fixtures/external-durable-objects-app/d/functions/index.ts deleted file mode 100644 index 086760b8f72d..000000000000 --- a/fixtures/external-durable-objects-app/d/functions/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const onRequest: PagesFunction<{ - PAGES_REFERENCED_DO: DurableObjectNamespace; -}> = async ({ env, request }) => { - const { pathname } = new URL(request.url); - const id = env.PAGES_REFERENCED_DO.idFromName(pathname); - const stub = env.PAGES_REFERENCED_DO.get(id); - return stub.fetch(request); -}; diff --git a/fixtures/external-durable-objects-app/d/package.json b/fixtures/external-durable-objects-app/d/package.json deleted file mode 100644 index 203d3cde77fe..000000000000 --- a/fixtures/external-durable-objects-app/d/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "d", - "private": true -} diff --git a/fixtures/external-durable-objects-app/d/public/index.html b/fixtures/external-durable-objects-app/d/public/index.html deleted file mode 100644 index dfa041fb4562..000000000000 --- a/fixtures/external-durable-objects-app/d/public/index.html +++ /dev/null @@ -1 +0,0 @@ -

This will never be served.

diff --git a/fixtures/external-durable-objects-app/package.json b/fixtures/external-durable-objects-app/package.json deleted file mode 100644 index 8a3700e3bf2e..000000000000 --- a/fixtures/external-durable-objects-app/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "external-durable-objects-app", - "private": true, - "description": "A test for external durable objects", - "scripts": { - "check:type": "tsc", - "dev": "npx concurrently -s first -k \"wrangler dev --x-dev-env a/index.ts --local --port 8400\" \"wrangler dev --x-dev-env b/index.ts --local --port 8401\" \"npx wrangler dev --x-dev-env c/index.ts --local --port 8402\" \"cd d && npx wrangler pages dev public --port 8403 --do PAGES_REFERENCED_DO=MyDurableObject@a\"", - "test:ci": "vitest run", - "test:watch": "vitest", - "type:tests": "tsc -p ./tests/tsconfig.json" - }, - "devDependencies": { - "@cloudflare/workers-tsconfig": "workspace:*", - "@cloudflare/workers-types": "^4.20241004.0", - "undici": "^5.28.4", - "wrangler": "workspace:*" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/fixtures/external-durable-objects-app/tests/index.test.ts b/fixtures/external-durable-objects-app/tests/index.test.ts deleted file mode 100644 index 3fd7eb0a74bc..000000000000 --- a/fixtures/external-durable-objects-app/tests/index.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import * as path from "path"; -import { setTimeout } from "timers/promises"; -import { fetch } from "undici"; -import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import { runWranglerPagesDev } from "../../shared/src/run-wrangler-long-lived"; -import type { UnstableDevWorker } from "wrangler"; - -// TODO: reenable when https://github.com/cloudflare/workers-sdk/pull/4241 lands -// and improves reliability of this test. -describe.skip("Pages Functions", () => { - let a: UnstableDevWorker; - let b: UnstableDevWorker; - let c: UnstableDevWorker; - let d: Awaited>; - - beforeAll(async () => { - a = await unstable_dev(path.join(__dirname, "../a/index.ts"), { - config: path.join(__dirname, "../a/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - b = await unstable_dev(path.join(__dirname, "../b/index.ts"), { - config: path.join(__dirname, "../b/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - c = await unstable_dev(path.join(__dirname, "../c/index.ts"), { - config: path.join(__dirname, "../c/wrangler.toml"), - experimental: { - disableExperimentalWarning: true, - devEnv: true, - }, - }); - await setTimeout(1000); - - d = await runWranglerPagesDev( - path.resolve(__dirname, "..", "d"), - "public", - [ - "--compatibility-date=2024-03-04", - "--do=PAGES_REFERENCED_DO=MyDurableObject@a", - "--port=0", - ] - ); - }); - - afterAll(async () => { - await a.stop(); - await b.stop(); - await c.stop(); - await d.stop(); - }); - - it("connects up Durable Objects and keeps state across wrangler instances", async () => { - await setTimeout(1000); - - const responseA = await a.fetch(`/`, { - headers: { - "X-Reset-Count": "true", - }, - }); - const dataAText = await responseA.text(); - console.log(dataAText); - const dataA = JSON.parse(dataAText) as { count: number; id: string }; - expect(dataA.count).toEqual(1); - const responseB = await b.fetch(`/`); - const dataBText = await responseB.text(); - console.log(dataBText); - const dataB = JSON.parse(dataBText) as { count: number; id: string }; - expect(dataB.count).toEqual(2); - const responseC = await c.fetch(`/`); - const dataCText = await responseC.text(); - console.log(dataCText); - const dataC = JSON.parse(dataCText) as { count: number; id: string }; - expect(dataC.count).toEqual(3); - const responseD = await fetch(`http://${d.ip}:${d.port}/`); - const dataDText = await responseD.text(); - console.log(dataDText); - const dataD = JSON.parse(dataDText) as { count: number; id: string }; - expect(dataD.count).toEqual(4); - const responseA2 = await a.fetch(`/`); - const dataA2Text = await responseA2.text(); - console.log(dataA2Text); - const dataA2 = JSON.parse(dataA2Text) as { count: number; id: string }; - expect(dataA2.count).toEqual(5); - expect(dataA.id).toEqual(dataB.id); - expect(dataA.id).toEqual(dataC.id); - expect(dataA.id).toEqual(dataA2.id); - }); -}); diff --git a/fixtures/external-durable-objects-app/tests/tsconfig.json b/fixtures/external-durable-objects-app/tests/tsconfig.json deleted file mode 100644 index 33512c99f0ef..000000000000 --- a/fixtures/external-durable-objects-app/tests/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "@cloudflare/workers-tsconfig/tsconfig.json", - "compilerOptions": { - "types": ["node"], - "esModuleInterop": true - }, - "include": ["**/*.ts", "../../../node-types.d.ts"] -} diff --git a/fixtures/external-durable-objects-app/tsconfig.json b/fixtures/external-durable-objects-app/tsconfig.json deleted file mode 100644 index e319a416a928..000000000000 --- a/fixtures/external-durable-objects-app/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "include": ["a", "b", "c", "b"], - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "lib": ["ES2020"], - "types": ["@cloudflare/workers-types"], - "noEmit": true - } -} diff --git a/fixtures/external-durable-objects-app/vitest.config.mts b/fixtures/external-durable-objects-app/vitest.config.mts deleted file mode 100644 index 846cddc41995..000000000000 --- a/fixtures/external-durable-objects-app/vitest.config.mts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineProject, mergeConfig } from "vitest/config"; -import configShared from "../../vitest.shared"; - -export default mergeConfig( - configShared, - defineProject({ - test: {}, - }) -); diff --git a/fixtures/external-service-bindings-app/module-worker-a/index.ts b/fixtures/external-service-bindings-app/module-worker-a/index.ts deleted file mode 100644 index 7267d55e8339..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-a/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch() { - return new Response("Hello from module worker a"); - }, -}; diff --git a/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml deleted file mode 100644 index c2259034a1de..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-a/wrangler.toml +++ /dev/null @@ -1 +0,0 @@ -name = "module-worker-a" diff --git a/fixtures/external-service-bindings-app/module-worker-b/index.ts b/fixtures/external-service-bindings-app/module-worker-b/index.ts deleted file mode 100644 index a8f66a028a42..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-b/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default { - async fetch(request: Request, env: { SERVICE: Fetcher }) { - const serviceResp = await env.SERVICE.fetch(request); - const serviceRespTxt = await serviceResp.text(); - return new Response( - `Hello from module worker b and also: ${serviceRespTxt}` - ); - }, -}; diff --git a/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml deleted file mode 100644 index 925070068183..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-b/wrangler.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "module-worker-b" - -services = [ - { binding = "SERVICE", service = "module-worker-a" } -] diff --git a/fixtures/external-service-bindings-app/module-worker-c/index.ts b/fixtures/external-service-bindings-app/module-worker-c/index.ts deleted file mode 100644 index 1f44afc92301..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-c/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch(req, env) { - return new Response(`Hello from module worker c (${env.MY_ENV})`); - }, -}; diff --git a/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml deleted file mode 100644 index 835bb309a668..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-c/wrangler.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "module-worker-c" - -[env.staging.vars] -MY_ENV = "staging" - -[env.production.vars] -MY_ENV = "prod" diff --git a/fixtures/external-service-bindings-app/module-worker-d/index.ts b/fixtures/external-service-bindings-app/module-worker-d/index.ts deleted file mode 100644 index 0cbcb85a5d17..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-d/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch(req, env) { - return new Response(`Hello from module worker d (${env.MY_ENV})`); - }, -}; diff --git a/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml b/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml deleted file mode 100644 index 2805074ddb23..000000000000 --- a/fixtures/external-service-bindings-app/module-worker-d/wrangler.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "module-worker-d" - -[env.staging.vars] -MY_ENV = "staging" - -[env.production.vars] -MY_ENV = "prod" diff --git a/fixtures/external-service-bindings-app/package.json b/fixtures/external-service-bindings-app/package.json deleted file mode 100644 index e8c6db99d82b..000000000000 --- a/fixtures/external-service-bindings-app/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "external-service-bindings-app", - "private": true, - "description": "A test for external service bindings", - "scripts": { - "dev": "npx concurrently -s first -k 'npm run mod-a-dev' 'npm run mod-b-dev' 'npm run ser-a-dev' 'npm run mod-c-dev' 'npm run mod-d-dev' 'npm run pages-dev'", - "mod-a-dev": "wrangler dev --x-dev-env module-worker-a/index.ts --local --port 8500", - "mod-b-dev": "wrangler dev --x-dev-env module-worker-b/index.ts --local --port 8501", - "mod-c-dev": "wrangler dev --x-dev-env module-worker-c/index.ts --local --port 8503 --env staging", - "mod-d-dev": "wrangler dev --x-dev-env module-worker-d/index.ts --local --port 8504 --env production", - "pages-dev": "cd pages-functions-app && npx wrangler pages dev public --port 8505 --service MODULE_A_SERVICE=module-worker-a MODULE_B_SERVICE=module-worker-b SERVICE_A_SERVICE=service-worker-a STAGING_MODULE_C_SERVICE=module-worker-c@staging STAGING_MODULE_D_SERVICE=module-worker-d@staging", - "ser-a-dev": "wrangler dev --x-dev-env service-worker-a/index.ts --local --port 8502", - "test:ci": "vitest run", - "test:watch": "vitest", - "type:tests": "tsc --noEmit" - }, - "devDependencies": { - "@cloudflare/workers-tsconfig": "workspace:*", - "@cloudflare/workers-types": "^4.20241004.0", - "concurrently": "^8.2.2", - "undici": "^5.28.4", - "wrangler": "workspace:*" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts b/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts deleted file mode 100644 index 0b65d762c224..000000000000 --- a/fixtures/external-service-bindings-app/pages-functions-app/functions/env.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const onRequest = async ({ env, request }) => { - const getTextFrom = (fetcher: Fetcher) => - fetcher.fetch(request).then((resp) => resp.text()); - - return Response.json({ - moduleWorkerCResponse: await getTextFrom(env.STAGING_MODULE_C_SERVICE), - moduleWorkerDResponse: await getTextFrom(env.STAGING_MODULE_D_SERVICE), - }); -}; diff --git a/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts b/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts deleted file mode 100644 index 7efeceacdafd..000000000000 --- a/fixtures/external-service-bindings-app/pages-functions-app/functions/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const onRequest = async ({ env, request }) => { - const getTextFrom = (fetcher: Fetcher) => - fetcher.fetch(request).then((resp) => resp.text()); - - return Response.json({ - moduleWorkerAResponse: await getTextFrom(env.MODULE_A_SERVICE), - moduleWorkerBResponse: await getTextFrom(env.MODULE_B_SERVICE), - serviceWorkerAResponse: await getTextFrom(env.SERVICE_A_SERVICE), - }); -}; diff --git a/fixtures/external-service-bindings-app/pages-functions-app/package.json b/fixtures/external-service-bindings-app/pages-functions-app/package.json deleted file mode 100644 index 62b679f9e5d6..000000000000 --- a/fixtures/external-service-bindings-app/pages-functions-app/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "pages-functions-app", - "private": true -} diff --git a/fixtures/external-service-bindings-app/pages-functions-app/public/index.html b/fixtures/external-service-bindings-app/pages-functions-app/public/index.html deleted file mode 100644 index dfa041fb4562..000000000000 --- a/fixtures/external-service-bindings-app/pages-functions-app/public/index.html +++ /dev/null @@ -1 +0,0 @@ -

This will never be served.

diff --git a/fixtures/external-service-bindings-app/service-worker-a/index.ts b/fixtures/external-service-bindings-app/service-worker-a/index.ts deleted file mode 100644 index fcb0547caa99..000000000000 --- a/fixtures/external-service-bindings-app/service-worker-a/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello from service worker a")); -}); diff --git a/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml b/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml deleted file mode 100644 index 26a69a5f8f5d..000000000000 --- a/fixtures/external-service-bindings-app/service-worker-a/wrangler.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "service-worker-a" -main = "src/index.ts" diff --git a/fixtures/external-service-bindings-app/tests/index.test.ts b/fixtures/external-service-bindings-app/tests/index.test.ts deleted file mode 100644 index 9130581e3767..000000000000 --- a/fixtures/external-service-bindings-app/tests/index.test.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { fork } from "child_process"; -import { setTimeout } from "node:timers/promises"; -import * as path from "path"; -import { fetch } from "undici"; -import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { ChildProcess } from "child_process"; -import type { Response } from "undici"; -import type { UnstableDevWorker } from "wrangler"; - -const waitUntilReady = async (url: string): Promise => { - let response: Response | undefined = undefined; - - while (response === undefined) { - await setTimeout(500); - - try { - response = await fetch(url); - } catch (e) {} - } - - return response as Response; -}; - -type WranglerInstance = { - dirName: string; - childProcess: ChildProcess; - ip: string; - port: string; -}; - -describe("Pages Functions", () => { - let wranglerInstances: (WranglerInstance | UnstableDevWorker)[] = []; - let pagesAppPort: string; - - beforeAll(async () => { - wranglerInstances[0] = await unstable_dev( - path.join(__dirname, "../module-worker-a/index.ts"), - { - config: path.join(__dirname, "../module-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[1] = await unstable_dev( - path.join(__dirname, "../module-worker-b/index.ts"), - { - config: path.join(__dirname, "../module-worker-b/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[2] = await unstable_dev( - path.join(__dirname, "../service-worker-a/index.ts"), - { - config: path.join(__dirname, "../service-worker-a/wrangler.toml"), - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[3] = await unstable_dev( - path.join(__dirname, "../module-worker-c/index.ts"), - { - config: path.join(__dirname, "../module-worker-c/wrangler.toml"), - env: "staging", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[4] = await unstable_dev( - path.join(__dirname, "../module-worker-d/index.ts"), - { - config: path.join(__dirname, "../module-worker-d/wrangler.toml"), - env: "production", - experimental: { - fileBasedRegistry: true, - disableExperimentalWarning: true, - devEnv: true, - }, - } - ); - await setTimeout(1000); - - wranglerInstances[5] = await getWranglerInstance({ - pages: true, - dirName: "pages-functions-app", - extraArgs: [ - "--service=MODULE_A_SERVICE=module-worker-a", - "--service=MODULE_B_SERVICE=module-worker-b", - "--service=SERVICE_A_SERVICE=service-worker-a", - "--service=STAGING_MODULE_C_SERVICE=module-worker-c@staging", - "--service=STAGING_MODULE_D_SERVICE=module-worker-d@staging", - ], - }); - - pagesAppPort = wranglerInstances[5].port; - await setTimeout(1000); - }); - - afterAll(async () => { - await Promise.allSettled( - wranglerInstances.map((i) => - "stop" in i ? i.stop() : terminateWranglerInstance(i) - ) - ); - }); - - it("connects up Workers (both module and service ones) and fetches from them", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` - { - "moduleWorkerAResponse": "Hello from module worker a", - "moduleWorkerBResponse": "Hello from module worker b and also: Hello from module worker a", - "serviceWorkerAResponse": "Hello from service worker a", - } - `); - }); - - it("respects the environments specified for the service bindings (and doesn't connect if the env doesn't match)", async () => { - const combinedResponse = await waitUntilReady( - `http://127.0.0.1:${pagesAppPort}/env` - ); - const json = await combinedResponse.json(); - expect(json).toMatchInlineSnapshot(` - { - "moduleWorkerCResponse": "Hello from module worker c (staging)", - "moduleWorkerDResponse": "[wrangler] Couldn't find \`wrangler dev\` session for service "module-worker-d-staging" to proxy to", - } - `); - }); -}); - -async function getWranglerInstance({ - pages = false, - dirName, - extraArgs = [], -}: { - pages?: boolean; - dirName: string; - extraArgs?: string[]; -}): Promise { - return new Promise((resolve) => { - const childProcess = fork( - path.join("..", "..", "..", "packages", "wrangler", "bin", "wrangler.js"), - [ - ...(pages ? ["pages"] : []), - "dev", - "--x-registry", - ...(pages ? ["public"] : ["index.ts"]), - "--local", - ...extraArgs, - ], - { - cwd: path.resolve(__dirname, "..", dirName), - env: { BROWSER: "none", ...process.env }, - stdio: ["ignore", "ignore", "ignore", "ipc"], - } - ).on("message", (message) => { - const parsedMessage = JSON.parse(message.toString()); - resolve({ - dirName, - childProcess, - ip: parsedMessage.ip, - port: parsedMessage.port, - }); - }); - }); -} - -function terminateWranglerInstance({ - childProcess, -}: WranglerInstance): Promise { - return new Promise((resolve, reject) => { - childProcess.once("exit", (code) => { - if (!code) { - resolve(code); - } else { - reject(code); - } - }); - childProcess.kill("SIGTERM"); - }); -} diff --git a/fixtures/external-service-bindings-app/tsconfig.json b/fixtures/external-service-bindings-app/tsconfig.json deleted file mode 100644 index 4dbc853e530b..000000000000 --- a/fixtures/external-service-bindings-app/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "include": [ - "module-worker-a", - "module-worker-b", - "service-worker-a", - "module-worker-c", - "module-worker-d", - "pages-functions-app" - ], - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "lib": ["ES2020"], - "types": ["@cloudflare/workers-types"] - } -} diff --git a/fixtures/external-service-bindings-app/vitest.config.mts b/fixtures/external-service-bindings-app/vitest.config.mts deleted file mode 100644 index 846cddc41995..000000000000 --- a/fixtures/external-service-bindings-app/vitest.config.mts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineProject, mergeConfig } from "vitest/config"; -import configShared from "../../vitest.shared"; - -export default mergeConfig( - configShared, - defineProject({ - test: {}, - }) -); From 71ebe38455448ffb20813b306a6205e6004049ac Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 15:10:23 +0100 Subject: [PATCH 08/37] log stack --- packages/wrangler/src/index.ts | 3 +++ pnpm-lock.yaml | 33 --------------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index e3d5c2d423ad..79cb114e6711 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -929,6 +929,9 @@ export async function main(argv: string[]): Promise { ? loggableException.message : loggableException ); + if (loggableException instanceof Error) { + logger.log(loggableException.stack); + } if (!(loggableException instanceof UserError)) { await logPossibleBugMessage(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01b26bdd0257..9b87cc154a50 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,39 +199,6 @@ importers: specifier: workspace:* version: link:../../packages/wrangler - fixtures/external-durable-objects-app: - devDependencies: - '@cloudflare/workers-tsconfig': - specifier: workspace:* - version: link:../../packages/workers-tsconfig - '@cloudflare/workers-types': - specifier: ^4.20241004.0 - version: 4.20241004.0 - undici: - specifier: ^5.28.4 - version: 5.28.4 - wrangler: - specifier: workspace:* - version: link:../../packages/wrangler - - fixtures/external-service-bindings-app: - devDependencies: - '@cloudflare/workers-tsconfig': - specifier: workspace:* - version: link:../../packages/workers-tsconfig - '@cloudflare/workers-types': - specifier: ^4.20241004.0 - version: 4.20241004.0 - concurrently: - specifier: ^8.2.2 - version: 8.2.2 - undici: - specifier: ^5.28.4 - version: 5.28.4 - wrangler: - specifier: workspace:* - version: link:../../packages/wrangler - fixtures/get-platform-proxy: devDependencies: '@cloudflare/workers-tsconfig': From 396c1850d5f9853d54b4dd6f29e786cc124447a1 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 17:31:27 +0100 Subject: [PATCH 09/37] Further moves to e2e --- .../tests/get-platform-proxy.env.test.ts | 187 +---------- .../workers/do-worker-a/index.ts | 11 - .../workers/do-worker-a/wrangler.toml | 5 - .../workers/do-worker-b/index.ts | 11 - .../workers/do-worker-b/wrangler.toml | 5 - .../workers/hello-worker-a/index.ts | 5 - .../workers/hello-worker-a/wrangler.toml | 1 - .../workers/hello-worker-b/index.ts | 5 - .../workers/hello-worker-b/wrangler.toml | 1 - .../workers/rpc-worker/index.ts | 69 ---- .../workers/rpc-worker/wrangler.toml | 1 - fixtures/get-platform-proxy/wrangler.toml | 12 - packages/wrangler/e2e/dev-registry.test.ts | 3 +- .../wrangler/e2e/get-platform-proxy.test.ts | 301 ++++++++++++++++++ 14 files changed, 306 insertions(+), 311 deletions(-) delete mode 100644 fixtures/get-platform-proxy/workers/do-worker-a/index.ts delete mode 100644 fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml delete mode 100644 fixtures/get-platform-proxy/workers/do-worker-b/index.ts delete mode 100644 fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml delete mode 100644 fixtures/get-platform-proxy/workers/hello-worker-a/index.ts delete mode 100644 fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml delete mode 100644 fixtures/get-platform-proxy/workers/hello-worker-b/index.ts delete mode 100644 fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml delete mode 100644 fixtures/get-platform-proxy/workers/rpc-worker/index.ts delete mode 100644 fixtures/get-platform-proxy/workers/rpc-worker/wrangler.toml diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts index a0c56a10ab51..f2af04f36870 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -1,30 +1,8 @@ -import { readdir } from "fs/promises"; import path from "path"; -import { setTimeout } from "timers/promises"; -import { - D1Database, - DurableObjectNamespace, - Fetcher, - R2Bucket, -} from "@cloudflare/workers-types"; -import { - afterAll, - beforeAll, - beforeEach, - describe, - expect, - it, - vi, -} from "vitest"; -import { unstable_dev } from "wrangler"; +import { D1Database, R2Bucket } from "@cloudflare/workers-types"; +import { beforeEach, describe, expect, it, vi } from "vitest"; import { getPlatformProxy } from "./shared"; -import type { NamedEntrypoint } from "../workers/rpc-worker"; -import type { - Hyperdrive, - KVNamespace, - Rpc, - Service, -} from "@cloudflare/workers-types"; +import type { Hyperdrive, KVNamespace } from "@cloudflare/workers-types"; import type { UnstableDevWorker } from "wrangler"; type Env = { @@ -32,13 +10,8 @@ type Env = { MY_VAR_A: string; MY_JSON_VAR: Object; MY_DEV_VAR: string; - MY_SERVICE_A: Fetcher; - MY_SERVICE_B: Fetcher; - MY_RPC: Service; MY_KV: KVNamespace; MY_KV_PROD: KVNamespace; - MY_DO_A: DurableObjectNamespace; - MY_DO_B: DurableObjectNamespace; MY_BUCKET: R2Bucket; MY_D1: D1Database; MY_HYPERDRIVE: Hyperdrive; @@ -54,14 +27,6 @@ describe("getPlatformProxy - env", () => { vi.spyOn(console, "log").mockImplementation(() => {}); }); - beforeAll(async () => { - devWorkers = await startWorkers(); - }); - - afterAll(async () => { - await Promise.allSettled(devWorkers.map((i) => i.stop())); - }); - describe("var bindings", () => { it("correctly obtains var bindings from both wrangler.toml and .dev.vars", async () => { const { env, dispose } = await getPlatformProxy({ @@ -150,92 +115,6 @@ describe("getPlatformProxy - env", () => { } }); - it("provides service bindings to external local workers", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_SERVICE_A, MY_SERVICE_B } = env; - await testServiceBinding(MY_SERVICE_A, "Hello World from hello-worker-a"); - await testServiceBinding(MY_SERVICE_B, "Hello World from hello-worker-b"); - } finally { - await dispose(); - } - }); - - type EntrypointService = Service< - Omit & - Rpc.WorkerEntrypointBranded - > & { - getCounter: () => Promise< - Promise<{ - value: Promise; - increment: (amount: number) => Promise; - }> - >; - getHelloWorldFn: () => Promise<() => Promise>; - getHelloFn: () => Promise< - ( - greet: string, - name: string, - options?: { - suffix?: string; - capitalize?: boolean; - } - ) => Promise - >; - }; - - describe("provides rpc service bindings to external local workers", () => { - let rpc: EntrypointService; - beforeEach(async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - rpc = env.MY_RPC as unknown as EntrypointService; - return dispose; - }); - it("can call RPC methods returning a string", async () => { - expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`); - }); - it("can call RPC methods returning an object", async () => { - expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({ - isObject: true, - value: 11, - }); - }); - it("can call RPC methods returning a Response", async () => { - const resp = await rpc.asJsonResponse([1, 2, 3]); - expect(resp.status).toMatchInlineSnapshot(`200`); - expect(await resp.text()).toMatchInlineSnapshot(`"[1,2,3]"`); - }); - it("can obtain and interact with RpcStubs", async () => { - const counter = await rpc.getCounter(); - expect(await counter.value).toMatchInlineSnapshot(`0`); - expect(await counter.increment(4)).toMatchInlineSnapshot(`4`); - expect(await counter.increment(8)).toMatchInlineSnapshot(`12`); - expect(await counter.value).toMatchInlineSnapshot(`12`); - }); - it("can obtain and interact with returned functions", async () => { - const helloWorldFn = await rpc.getHelloWorldFn(); - expect(helloWorldFn()).toEqual("Hello World!"); - - const helloFn = await rpc.getHelloFn(); - expect(await helloFn("hi", "world")).toEqual("hi world"); - expect( - await helloFn("hi", "world", { - capitalize: true, - }) - ).toEqual("HI WORLD"); - expect( - await helloFn("Sup", "world", { - capitalize: true, - suffix: "?!", - }) - ).toEqual("SUP WORLD?!"); - }); - }); - it("correctly obtains functioning KV bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, @@ -251,19 +130,6 @@ describe("getPlatformProxy - env", () => { await dispose(); }); - it("correctly obtains functioning DO bindings (provided by external local workers)", async () => { - const { env, dispose } = await getPlatformProxy({ - configPath: wranglerTomlFilePath, - }); - try { - const { MY_DO_A, MY_DO_B } = env; - await testDoBinding(MY_DO_A, "Hello from DurableObject A"); - await testDoBinding(MY_DO_B, "Hello from DurableObject B"); - } finally { - await dispose(); - } - }); - it("correctly obtains functioning R2 bindings", async () => { const { env, dispose } = await getPlatformProxy({ configPath: wranglerTomlFilePath, @@ -391,50 +257,3 @@ describe("getPlatformProxy - env", () => { }); }); }); - -/** - * Starts all the workers present in the `workers` directory using `unstable_dev` - * - * @returns the workers' UnstableDevWorker instances - */ -async function startWorkers(): Promise { - const workersDirPath = path.join(__dirname, "..", "workers"); - const workers = await readdir(workersDirPath); - const result: UnstableDevWorker[] = []; - - for (const workerName of workers) { - const workerPath = path.join(workersDirPath, workerName); - const unstableDevWorker = await unstable_dev( - path.join(workerPath, "index.ts"), - { - config: path.join(workerPath, "wrangler.toml"), - ip: "127.0.0.1", - experimental: { - devEnv: true, - fileBasedRegistry: true, - }, - } - ); - await setTimeout(1000); - result.push(unstableDevWorker); - } - - return result; -} - -async function testServiceBinding(binding: Fetcher, expectedResponse: string) { - const resp = await binding.fetch("http://0.0.0.0"); - const respText = await resp.text(); - expect(respText).toBe(expectedResponse); -} - -async function testDoBinding( - binding: DurableObjectNamespace, - expectedResponse: string -) { - const durableObjectId = binding.idFromName("__my-do__"); - const doStub = binding.get(durableObjectId); - const doResp = await doStub.fetch("http://0.0.0.0"); - const doRespText = await doResp.text(); - expect(doRespText).toBe(expectedResponse); -} diff --git a/fixtures/get-platform-proxy/workers/do-worker-a/index.ts b/fixtures/get-platform-proxy/workers/do-worker-a/index.ts deleted file mode 100644 index 5dcc1b07c161..000000000000 --- a/fixtures/get-platform-proxy/workers/do-worker-a/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default { - async fetch(): Promise { - return new Response("Hello World from do-worker-a"); - }, -}; - -export class DurableObjectClass { - async fetch() { - return new Response("Hello from DurableObject A"); - } -} diff --git a/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml b/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml deleted file mode 100644 index 7dd727a5609d..000000000000 --- a/fixtures/get-platform-proxy/workers/do-worker-a/wrangler.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "do-worker-a" - -[[durable_objects.bindings]] -name = "MY_DO" -class_name = "DurableObjectClass" diff --git a/fixtures/get-platform-proxy/workers/do-worker-b/index.ts b/fixtures/get-platform-proxy/workers/do-worker-b/index.ts deleted file mode 100644 index 695a3eaafd31..000000000000 --- a/fixtures/get-platform-proxy/workers/do-worker-b/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export default { - async fetch(): Promise { - return new Response("Hello World from do-worker-a"); - }, -}; - -export class DurableObjectClass { - async fetch() { - return new Response("Hello from DurableObject B"); - } -} diff --git a/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml b/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml deleted file mode 100644 index efbd1e3fcf48..000000000000 --- a/fixtures/get-platform-proxy/workers/do-worker-b/wrangler.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "do-worker-b" - -[[durable_objects.bindings]] -name = "MY_DO" -class_name = "DurableObjectClass" diff --git a/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts b/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts deleted file mode 100644 index 882ae1188289..000000000000 --- a/fixtures/get-platform-proxy/workers/hello-worker-a/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch() { - return new Response("Hello World from hello-worker-a"); - }, -}; diff --git a/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml b/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml deleted file mode 100644 index 5e45dde6c83a..000000000000 --- a/fixtures/get-platform-proxy/workers/hello-worker-a/wrangler.toml +++ /dev/null @@ -1 +0,0 @@ -name = "hello-worker-a" diff --git a/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts b/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts deleted file mode 100644 index ecb5dc60ab93..000000000000 --- a/fixtures/get-platform-proxy/workers/hello-worker-b/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - fetch() { - return new Response("Hello World from hello-worker-b"); - }, -}; diff --git a/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml b/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml deleted file mode 100644 index bcc46b2ccf0c..000000000000 --- a/fixtures/get-platform-proxy/workers/hello-worker-b/wrangler.toml +++ /dev/null @@ -1 +0,0 @@ -name = "hello-worker-b" diff --git a/fixtures/get-platform-proxy/workers/rpc-worker/index.ts b/fixtures/get-platform-proxy/workers/rpc-worker/index.ts deleted file mode 100644 index 0d284d9fed94..000000000000 --- a/fixtures/get-platform-proxy/workers/rpc-worker/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { RpcTarget, WorkerEntrypoint } from "cloudflare:workers"; - -export default { - async fetch(request: Request, env: Record, ctx: unknown) { - throw new Error( - "Worker only used for RPC calls, there's no default fetch handler" - ); - }, -}; - -export class NamedEntrypoint extends WorkerEntrypoint { - sum(args: number[]): number { - return args.reduce((a, b) => a + b); - } - - sumObj(args: number[]): { isObject: true; value: number } { - return { - isObject: true, - value: args.reduce((a, b) => a + b), - }; - } - - asJsonResponse(args: unknown): { - status: number; - text: () => Promise; - } { - return Response.json(args); - } - getCounter() { - return new Counter(); - } - - getHelloWorldFn() { - return () => "Hello World!"; - } - - getHelloFn() { - return ( - greet: string, - name: string, - { - suffix, - capitalize, - }: { - suffix?: string; - capitalize?: boolean; - } = {} - ) => { - const result = `${greet} ${name}${suffix ?? ""}`; - if (capitalize) { - return result.toUpperCase(); - } - return result; - }; - } -} - -class Counter extends RpcTarget { - #value = 0; - - increment(amount: number) { - this.#value += amount; - return this.#value; - } - - get value() { - return this.#value; - } -} diff --git a/fixtures/get-platform-proxy/workers/rpc-worker/wrangler.toml b/fixtures/get-platform-proxy/workers/rpc-worker/wrangler.toml deleted file mode 100644 index c8036096443b..000000000000 --- a/fixtures/get-platform-proxy/workers/rpc-worker/wrangler.toml +++ /dev/null @@ -1 +0,0 @@ -name = "rpc-worker" diff --git a/fixtures/get-platform-proxy/wrangler.toml b/fixtures/get-platform-proxy/wrangler.toml index 073ac72d415d..1b94a0034f1e 100644 --- a/fixtures/get-platform-proxy/wrangler.toml +++ b/fixtures/get-platform-proxy/wrangler.toml @@ -2,12 +2,6 @@ name = "get-bindings-proxy-fixture" main = "src/index.ts" compatibility_date = "2023-11-21" -services = [ - { binding = "MY_SERVICE_A", service = "hello-worker-a" }, - { binding = "MY_SERVICE_B", service = "hello-worker-b" }, - { binding = "MY_RPC", service = "rpc-worker", entrypoint = "NamedEntrypoint" } -] - [vars] MY_VAR = "my-var-value" MY_VAR_A = "my-var-a" @@ -21,12 +15,6 @@ id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" binding = "MY_BUCKET" bucket_name = "my-bucket" -[durable_objects] -bindings = [ - { name = "MY_DO_A", script_name = "do-worker-a", class_name = "DurableObjectClass" }, - { name = "MY_DO_B", script_name = "do-worker-b", class_name = "DurableObjectClass" } -] - [[hyperdrive]] binding = "MY_HYPERDRIVE" id = "000000000000000000000000000000000" diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 2b85f6fc66e0..52e70e7f786d 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -1,11 +1,12 @@ import { setTimeout } from "node:timers/promises"; import dedent from "ts-dedent"; -import { fetch, RequestInit } from "undici"; +import { fetch } from "undici"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; import { fetchText } from "./helpers/fetch-text"; import { generateResourceName } from "./helpers/generate-resource-name"; import { seed as baseSeed, makeRoot } from "./helpers/setup"; +import type { RequestInit } from "undici"; async function fetchJson(url: string, info?: RequestInit): Promise { return vi.waitFor( diff --git a/packages/wrangler/e2e/get-platform-proxy.test.ts b/packages/wrangler/e2e/get-platform-proxy.test.ts index ad28062205ec..74d4ce51c18d 100644 --- a/packages/wrangler/e2e/get-platform-proxy.test.ts +++ b/packages/wrangler/e2e/get-platform-proxy.test.ts @@ -3,6 +3,8 @@ import * as nodeNet from "node:net"; import dedent from "ts-dedent"; import { beforeEach, describe, expect, it } from "vitest"; import { CLOUDFLARE_ACCOUNT_ID } from "./helpers/account-id"; +import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; +import { generateResourceName } from "./helpers/generate-resource-name"; import { makeRoot, seed } from "./helpers/setup"; import { WRANGLER_IMPORT } from "./helpers/wrangler"; @@ -61,6 +63,305 @@ describe("getPlatformProxy()", () => { }); }); + describe("multi worker", () => { + let app: string; + let worker: string; + let workerName: string; + let helper: WranglerE2ETestHelper; + + beforeEach(async () => { + workerName = generateResourceName("worker"); + helper = new WranglerE2ETestHelper(); + + app = makeRoot(); + + await seed(app, { + "wrangler.toml": dedent` + name = "app" + account_id = "${CLOUDFLARE_ACCOUNT_ID}" + compatibility_date = "2023-01-01" + compatibility_flags = ["nodejs_compat"] + + [[services]] + binding = "WORKER" + service = '${workerName}' + `, + "package.json": dedent` + { + "name": "app", + "version": "0.0.0", + "private": true + } + `, + }); + + worker = await makeRoot(); + await seed(worker, { + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + `, + "src/index.ts": dedent/* javascript */ ` + export default { + fetch(req, env) { + return new Response("Hello from Worker!") + }, + }; + `, + "package.json": dedent` + { + "name": "${workerName}", + "version": "0.0.0", + "private": true + } + `, + }); + }); + + async function runInNode(code: string) { + const w = helper.runLongLived("wrangler dev --x-registry", { + cwd: worker, + }); + + await w.waitForReady(); + + await seed(app, { + "index.mjs": dedent/*javascript*/ ` + import { getPlatformProxy } from "${WRANGLER_IMPORT}" + + const { env } = await getPlatformProxy({ experimentalRegistry: true }); + + const resp = ${code} + + console.log(resp); + + process.exit(0); + `, + }); + const stdout = execSync(`node index.mjs`, { + cwd: app, + encoding: "utf-8", + }); + return stdout; + } + + it("can fetch service binding", async () => { + await expect( + runInNode( + /* javascript */ `await env.WORKER.fetch("http://example.com/").then(r => r.text())` + ) + ).resolves.toContain("Hello from Worker"); + }); + + it("can fetch durable object", async () => { + await seed(app, { + "wrangler.toml": dedent` + name = "app" + account_id = "${CLOUDFLARE_ACCOUNT_ID}" + compatibility_date = "2023-01-01" + compatibility_flags = ["nodejs_compat"] + + [durable_objects] + bindings = [ + { name = "DO", script_name = "${workerName}", class_name = "DurableObjectClass" }, + ] + `, + }); + await seed(worker, { + "src/index.ts": dedent/* javascript */ ` + import { DurableObject } from "cloudflare:workers"; + export default { + async fetch(): Promise { + return new Response("Hello World from do-worker"); + }, + }; + + export class DurableObjectClass extends DurableObject { + async fetch() { + return new Response("Hello from DurableObject"); + } + } + `, + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + [[durable_objects.bindings]] + name = "MY_DO" + class_name = "DurableObjectClass" + `, + }); + await expect( + runInNode(/* javascript */ `await (async () => { + const durableObjectId = env.DO.idFromName("do"); + const doStub = env.DO.get(durableObjectId); + const doResp = await doStub.fetch("http://0.0.0.0"); + return await doResp.text(); + })()`) + ).resolves.toMatchInlineSnapshot(` + "Hello from DurableObject + " + `); + }); + + describe("provides rpc service bindings to external local workers", () => { + beforeEach(async () => { + await seed(worker, { + "src/index.ts": dedent/* javascript */ ` + import { RpcTarget, WorkerEntrypoint } from "cloudflare:workers"; + + export default { + async fetch(request: Request, env: Record, ctx: unknown) { + throw new Error( + "Worker only used for RPC calls, there's no default fetch handler" + ); + }, + }; + + export class NamedEntrypoint extends WorkerEntrypoint { + sum(args: number[]): number { + return args.reduce((a, b) => a + b); + } + + sumObj(args: number[]): { isObject: true; value: number } { + return { + isObject: true, + value: args.reduce((a, b) => a + b), + }; + } + + asJsonResponse(args: unknown): { + status: number; + text: () => Promise; + } { + return Response.json(args); + } + getCounter() { + return new Counter(); + } + + getHelloWorldFn() { + return () => "Hello World!"; + } + + getHelloFn() { + return ( + greet: string, + name: string, + { + suffix, + capitalize, + }: { + suffix?: string; + capitalize?: boolean; + } = {} + ) => { + const result = greet + " " + name + (suffix ?? ""); + if (capitalize) { + return result.toUpperCase(); + } + return result; + }; + } + } + + class Counter extends RpcTarget { + #value = 0; + + increment(amount: number) { + this.#value += amount; + return this.#value; + } + + get value() { + return this.#value; + } + } + `, + }); + await seed(app, { + "wrangler.toml": dedent` + name = "app" + account_id = "${CLOUDFLARE_ACCOUNT_ID}" + compatibility_date = "2023-01-01" + compatibility_flags = ["nodejs_compat"] + + [[services]] + binding = "WORKER" + service = '${workerName}' + entrypoint = "NamedEntrypoint" + `, + }); + }); + + it("can call RPC methods returning a string", async () => { + await expect( + runInNode(/* javascript */ `await env.WORKER.sum([1, 2, 3])`) + ).resolves.toContain("6"); + }); + it("can call RPC methods returning an object", async () => { + await expect( + runInNode( + /* javascript */ `JSON.stringify(await env.WORKER.sumObj([1, 2, 3, 5]))` + ) + ).resolves.toMatchInlineSnapshot(` + "{"isObject":true,"value":11} + " + `); + }); + it("can call RPC methods returning a Response", async () => { + await expect( + runInNode(/* javascript */ `await (async () => { + const r = await env.WORKER.asJsonResponse([1, 2, 3]); + return JSON.stringify({status: r.status, text: await r.text()}) + })()`) + ).resolves.toMatchInlineSnapshot(` + "{"status":200,"text":"[1,2,3]"} + " + `); + }); + it("can obtain and interact with RpcStubs", async () => { + await expect( + runInNode(/* javascript */ `await (async () => { + const counter = await env.WORKER.getCounter(); + return JSON.stringify([ + await counter.value, + await counter.increment(4), + await counter.increment(8), + await counter.value + ]) + })()`) + ).resolves.toMatchInlineSnapshot(` + "[0,4,12,12] + " + `); + }); + it("can obtain and interact with returned functions", async () => { + await expect( + runInNode(/* javascript */ `await (async () => { + const helloWorldFn = await env.WORKER.getHelloWorldFn(); + const helloFn = await env.WORKER.getHelloFn(); + return JSON.stringify([ + helloWorldFn(), + await helloFn("hi", "world"), + await helloFn("hi", "world", { + capitalize: true, + }), + await helloFn("Sup", "world", { + capitalize: true, + suffix: "?!", + }) + ]) + })()`) + ).resolves.toMatchInlineSnapshot(` + "["Hello World!","hi world","HI WORLD","SUP WORLD?!"] + " + `); + }); + }); + }); + describe("Hyperdrive", () => { let root: string; let port = 5432; From c8fe6915bf5b1bc79bc72b0e2576014dbfedea2a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 21:44:41 +0100 Subject: [PATCH 10/37] run less --- tools/e2e/runIndividualE2EFiles.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/e2e/runIndividualE2EFiles.ts b/tools/e2e/runIndividualE2EFiles.ts index e37814b55f39..49f2bd6e5003 100644 --- a/tools/e2e/runIndividualE2EFiles.ts +++ b/tools/e2e/runIndividualE2EFiles.ts @@ -9,14 +9,15 @@ * an individual task for each Wrangler e2e test file, using `execSync`. */ import { execSync } from "child_process"; -import { readdirSync } from "fs"; + +// import { readdirSync } from "fs"; // Get a list of e2e test files, each of which should have an associated script -const e2eTests = readdirSync("packages/wrangler/e2e"); +// const e2eTests = readdirSync("packages/wrangler/e2e"); const tasks = new Set(); -for (const file of e2eTests) { +for (const file of ["dev-registry.test.ts", "get-platform-proxy.test.ts"]) { // Ignore other files in the e2e directory (the README, for instance) if (file.endsWith(".test.ts")) { tasks.add( From 3e4bab963d92aedfe8d9c8822b29184d77931db1 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 21:48:51 +0100 Subject: [PATCH 11/37] change test --- packages/wrangler/e2e/dev-registry.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 52e70e7f786d..b710e75183b2 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -21,6 +21,7 @@ async function fetchJson(url: string, info?: RequestInit): Promise { { timeout: 5_000, interval: 250 } ); } + describe.each([ { cmd: "wrangler dev --x-registry" }, { cmd: "wrangler dev --no-x-registry" }, From 6c30f9745ac70c5057f4a40e490b853d1c12199f Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:02:54 +0100 Subject: [PATCH 12/37] only propogate errors if build not aborted --- .../api/startDevWorker/BundlerController.ts | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/BundlerController.ts b/packages/wrangler/src/api/startDevWorker/BundlerController.ts index 24688760f1ee..d83f2cfc649a 100644 --- a/packages/wrangler/src/api/startDevWorker/BundlerController.ts +++ b/packages/wrangler/src/api/startDevWorker/BundlerController.ts @@ -41,7 +41,6 @@ export class BundlerController extends Controller { #customBuildWatcher?: ReturnType; // Handle aborting in-flight custom builds as new ones come in from the filesystem watcher - // Note: we don't need this for non-custom builds since esbuild handles this internally with it's watch mode #customBuildAborter = new AbortController(); async #runCustomBuild(config: StartDevWorkerOptions, filePath: string) { @@ -194,9 +193,17 @@ export class BundlerController extends Controller { } #bundlerCleanup?: ReturnType; + #bundleBuildAborter = new AbortController(); async #startBundle(config: StartDevWorkerOptions) { await this.#bundlerCleanup?.(); + // If a new bundle build comes in, we need to cancel in-flight builds + this.#bundleBuildAborter.abort(); + this.#bundleBuildAborter = new AbortController(); + + // Since `this.#customBuildAborter` will change as new builds are scheduled, store the specific AbortController that will be used for this build + const buildAborter = this.#bundleBuildAborter; + if (config.build?.custom?.command) { return; } @@ -250,14 +257,17 @@ export class BundlerController extends Controller { this.emitBundleCompleteEvent(config, newBundle); this.#currentBundle = newBundle; }, - (err) => - this.emitErrorEvent({ - type: "error", - reason: "Failed to construct initial bundle", - cause: castErrorCause(err), - source: "BundlerController", - data: undefined, - }) + (err) => { + if (!buildAborter.signal.aborted) { + this.emitErrorEvent({ + type: "error", + reason: "Failed to construct initial bundle", + cause: castErrorCause(err), + source: "BundlerController", + data: undefined, + }); + } + } ); } From dafc7b2e1f246bfc8ac7d9d97b9301118080c9c4 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:09:35 +0100 Subject: [PATCH 13/37] more logging --- packages/wrangler/e2e/helpers/command.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index be6b85a7bbb2..7a1426f9c39f 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -106,9 +106,9 @@ export class LongLivedCommand { start: (controller) => { lineInterface.on("line", (line) => { // eslint-disable-next-line turbo/no-undeclared-env-vars - if (process.env.VITEST_MODE === "WATCH") { - console.log(line); - } + // if (process.env.VITEST_MODE === "WATCH") { + console.log(line); + // } this.lines.push(line); try { controller.enqueue(line); From 9f5c3b3a355943d335ea5d357d12a977f682db6c Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:15:37 +0100 Subject: [PATCH 14/37] add label --- packages/wrangler/e2e/helpers/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index 7a1426f9c39f..3823ddecdd41 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -107,7 +107,7 @@ export class LongLivedCommand { lineInterface.on("line", (line) => { // eslint-disable-next-line turbo/no-undeclared-env-vars // if (process.env.VITEST_MODE === "WATCH") { - console.log(line); + console.log(`[${cwd}]`, line); // } this.lines.push(line); try { From f4f3620e87b9c214c64fcf6b6d6716b88460a292 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:22:53 +0100 Subject: [PATCH 15/37] split up more --- packages/wrangler/e2e/dev-registry.test.ts | 265 ++++++++++++--------- 1 file changed, 154 insertions(+), 111 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index b710e75183b2..ee4b155813ca 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -26,15 +26,18 @@ describe.each([ { cmd: "wrangler dev --x-registry" }, { cmd: "wrangler dev --no-x-registry" }, ])("basic dev registry", ({ cmd }) => { + let workerName: string; + let workerName2: string; + let workerName3: string; let a: string; let b: string; let c: string; let helper: WranglerE2ETestHelper; beforeEach(async () => { - const workerName = generateResourceName("worker"); - const workerName2 = generateResourceName("worker"); - const workerName3 = generateResourceName("worker"); + workerName = generateResourceName("worker"); + workerName2 = generateResourceName("worker"); + workerName3 = generateResourceName("worker"); helper = new WranglerE2ETestHelper(); a = await makeRoot(); await baseSeed(a, { @@ -42,23 +45,6 @@ describe.each([ name = "${workerName}" main = "src/index.ts" compatibility_date = "2023-01-01" - - [[services]] - binding = "BEE" - service = '${workerName2}' - - [[services]] - binding = "CEE" - service = '${workerName3}' - - [durable_objects] - bindings = [ - { name = "MY_DO", class_name = "MyDurableObject" } - ] - - [[migrations]] - tag = "v1" - new_classes = ["MyDurableObject"] `, "src/index.ts": dedent/* javascript */ ` export default { @@ -154,128 +140,185 @@ describe.each([ }); }); - it("can fetch b", async () => { - const worker = helper.runLongLived(cmd, { cwd: b }); + describe("module workers", () => { + beforeEach(async () => { + await baseSeed(a, { + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + + [[services]] + binding = "BEE" + service = '${workerName2}' + `, + }); + }); + it("can fetch b", async () => { + const worker = helper.runLongLived(cmd, { cwd: b }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(); - await expect(fetch(url).then((r) => r.text())).resolves.toBe("hello world"); - }); + await expect(fetch(url).then((r) => r.text())).resolves.toBe( + "hello world" + ); + }); - it("can fetch b through a (start b, start a)", async () => { - const workerB = helper.runLongLived(cmd, { cwd: b }); - // We don't need b's URL, but ensure that b starts up before a - await workerB.waitForReady(); + it("can fetch b through a (start b, start a)", async () => { + const workerB = helper.runLongLived(cmd, { cwd: b }); + // We don't need b's URL, but ensure that b starts up before a + await workerB.waitForReady(); - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); - await expect(fetchText(url)).resolves.toBe("hello world"); - }); + await expect(fetchText(url)).resolves.toBe("hello world"); + }); - it("can fetch b through a (start a, start b)", async () => { - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + it("can fetch b through a (start a, start b)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); - const workerB = helper.runLongLived(cmd, { cwd: b }); - await workerB.waitForReady(); + const workerB = helper.runLongLived(cmd, { cwd: b }); + await workerB.waitForReady(); - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); - await expect(fetchText(url)).resolves.toBe("hello world"); + await expect(fetchText(url)).resolves.toBe("hello world"); + }); }); - it("can fetch service worker c through a (start c, start a)", async () => { - const workerC = helper.runLongLived(cmd, { cwd: c }); - // We don't need c's URL, but ensure that c starts up before a - await workerC.waitForReady(); + describe("service workers", () => { + beforeEach(async () => { + await baseSeed(a, { + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + + [[services]] + binding = "CEE" + service = '${workerName3}' + `, + }); + }); + + it("can fetch service worker c through a (start c, start a)", async () => { + const workerC = helper.runLongLived(cmd, { cwd: c }); + // We don't need c's URL, but ensure that c starts up before a + await workerC.waitForReady(); - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); - await expect(fetchText(`${url}/service`)).resolves.toBe( - "Hello from service worker" - ); - }); + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ); + }); - it("can fetch service worker c through a (start a, start c)", async () => { - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + it("can fetch service worker c through a (start a, start c)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); - const workerC = helper.runLongLived(cmd, { cwd: c }); - await workerC.waitForReady(); + const workerC = helper.runLongLived(cmd, { cwd: c }); + await workerC.waitForReady(); - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); - await expect(fetchText(`${url}/service`)).resolves.toBe( - "Hello from service worker" - ); + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ); + }); }); - it("can fetch DO through a", async () => { - const worker = helper.runLongLived(cmd, { cwd: a }); + describe("durable objects", () => { + beforeEach(async () => { + await baseSeed(a, { + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-01-01" + + [[services]] + binding = "BEE" + service = '${workerName2}' + + [durable_objects] + bindings = [ + { name = "MY_DO", class_name = "MyDurableObject" } + ] + + [[migrations]] + tag = "v1" + new_classes = ["MyDurableObject"] + `, + }); + }); + it("can fetch DO through a", async () => { + const worker = helper.runLongLived(cmd, { cwd: a }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(); - await expect( - fetchJson(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }) - ).resolves.toMatchObject({ count: 1 }); - }); + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }); + }); - it("can fetch remote DO attached to a through b (start b, start a)", async () => { - const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(); + it("can fetch remote DO attached to a through b (start b, start a)", async () => { + const workerB = helper.runLongLived(cmd, { cwd: b }); + const { url } = await workerB.waitForReady(); - const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(); + const workerA = helper.runLongLived(cmd, { cwd: a }); + await workerA.waitForReady(); - await workerA.waitForReload(); + await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + // Give the dev registry some time to settle + await setTimeout(500); - await expect( - fetchJson(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }) - ).resolves.toMatchObject({ count: 1 }); - }); + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }); + }); - it("can fetch remote DO attached to a through b (start a, start b)", async () => { - const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(); + it("can fetch remote DO attached to a through b (start a, start b)", async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + await workerA.waitForReady(); - const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(); + const workerB = helper.runLongLived(cmd, { cwd: b }); + const { url } = await workerB.waitForReady(); - await workerA.waitForReload(); - // Give the dev registry some time to settle - await setTimeout(500); + await workerA.waitForReload(); + // Give the dev registry some time to settle + await setTimeout(500); - await expect( - fetch(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }).then((r) => r.json()) - ).resolves.toMatchObject({ count: 1 }); + await expect( + fetch(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }).then((r) => r.json()) + ).resolves.toMatchObject({ count: 1 }); + }); }); }); From 45591c2071c62c22186e344177cd44610a0f69e6 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:38:19 +0100 Subject: [PATCH 16/37] add more connection logging --- .../api/startDevWorker/ConfigController.ts | 11 +++--- packages/wrangler/src/config/index.ts | 35 ++++++++++++++----- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/wrangler/src/api/startDevWorker/ConfigController.ts b/packages/wrangler/src/api/startDevWorker/ConfigController.ts index 3278c3cfe4d8..e5b591291453 100644 --- a/packages/wrangler/src/api/startDevWorker/ConfigController.ts +++ b/packages/wrangler/src/api/startDevWorker/ConfigController.ts @@ -156,10 +156,13 @@ async function resolveBindings( const maskedVars = maskVars(bindings, config); // now log all available bindings into the terminal - printBindings({ - ...bindings, - vars: maskedVars, - }); + printBindings( + { + ...bindings, + vars: maskedVars, + }, + input.dev?.registry + ); return { bindings: { diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index 6110ffa6e644..d3d72f912cc1 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -9,6 +9,7 @@ import { parseJSONC, parseTOML, readFileSync } from "../parse"; import { isPagesConfig, normalizeAndValidateConfig } from "./validation"; import { validatePagesConfig } from "./validation-pages"; import type { CfWorkerInit } from "../deployment-bundle/worker"; +import type { WorkerRegistry } from "../dev-registry"; import type { CommonYargsOptions } from "../yargs-types"; import type { Config, OnlyCamelCase, RawConfig } from "./config"; import type { NormalizeAndValidateConfigArgs } from "./validation"; @@ -194,7 +195,10 @@ export function findWranglerToml( /** * Print all the bindings a worker using a given config would have access to */ -export function printBindings(bindings: CfWorkerInit["bindings"]) { +export function printBindings( + bindings: CfWorkerInit["bindings"], + registry?: WorkerRegistry +) { const truncate = (item: string | Record) => { const s = typeof item === "string" ? item : JSON.stringify(item); const maxLength = 40; @@ -249,13 +253,20 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) { output.push({ type: "Durable Objects", entries: durable_objects.bindings.map( - ({ name, class_name, script_name, environment }) => { + ({ name, class_name, script_name }) => { let value = class_name; if (script_name) { - value += ` (defined in ${script_name})`; - } - if (environment) { - value += ` - ${environment}`; + const registryDefinition = registry?.[script_name]; + if ( + registryDefinition && + registryDefinition.durableObjects.some( + (d) => d.className === class_name + ) + ) { + value += ` (defined in 🟢 ${script_name})`; + } else { + value += ` (defined in 🔴 ${script_name})`; + } } return { @@ -384,12 +395,18 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) { if (services !== undefined && services.length > 0) { output.push({ type: "Services", - entries: services.map(({ binding, service, environment, entrypoint }) => { + entries: services.map(({ binding, service, entrypoint }) => { let value = service; - if (environment) { - value += ` - ${environment}${entrypoint ? ` (#${entrypoint})` : ""}`; + if (entrypoint) { + value += `#${entrypoint}`; } + const registryDefinition = registry?.[service]; + if (registryDefinition) { + value = `🟢 ` + value; + } else { + value = `🔴 ` + value; + } return { key: binding, value, From 5da734730fb401fad338b0e6ade209e3524d1847 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 22:58:35 +0100 Subject: [PATCH 17/37] more robust matching --- packages/wrangler/e2e/dev-registry.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index ee4b155813ca..2dfa9a5a09c3 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -25,7 +25,7 @@ async function fetchJson(url: string, info?: RequestInit): Promise { describe.each([ { cmd: "wrangler dev --x-registry" }, { cmd: "wrangler dev --no-x-registry" }, -])("basic dev registry", ({ cmd }) => { +])("dev registry $cmd", ({ cmd }) => { let workerName: string; let workerName2: string; let workerName3: string; @@ -172,7 +172,7 @@ describe.each([ const workerA = helper.runLongLived(cmd, { cwd: a }); const { url } = await workerA.waitForReady(); - await workerA.waitForReload(); + await workerA.readUntil(/- BEE: 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -186,7 +186,7 @@ describe.each([ const workerB = helper.runLongLived(cmd, { cwd: b }); await workerB.waitForReady(); - await workerA.waitForReload(); + await workerA.readUntil(/- BEE: 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -217,7 +217,7 @@ describe.each([ const workerA = helper.runLongLived(cmd, { cwd: a }); const { url } = await workerA.waitForReady(); - await workerA.waitForReload(); + await workerA.readUntil(/- CEE: 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -233,7 +233,7 @@ describe.each([ const workerC = helper.runLongLived(cmd, { cwd: c }); await workerC.waitForReady(); - await workerA.waitForReload(); + await workerA.readUntil(/- CEE: 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -287,7 +287,7 @@ describe.each([ const workerA = helper.runLongLived(cmd, { cwd: a }); await workerA.waitForReady(); - await workerA.waitForReload(); + await workerB.readUntil(/defined in 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -308,7 +308,7 @@ describe.each([ const workerB = helper.runLongLived(cmd, { cwd: b }); const { url } = await workerB.waitForReady(); - await workerA.waitForReload(); + await workerB.readUntil(/defined in 🟢/); // Give the dev registry some time to settle await setTimeout(500); From caba0b2c480eb54760f6d4221e9dd2fb527644cd Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 23:09:13 +0100 Subject: [PATCH 18/37] remove ordering requirements --- packages/wrangler/e2e/dev-registry.test.ts | 38 ++++++++++++++-------- packages/wrangler/e2e/helpers/command.ts | 4 ++- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 2dfa9a5a09c3..d43b35f986f7 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -170,9 +170,11 @@ describe.each([ await workerB.waitForReady(); const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + const [{ url }] = await Promise.all([ + workerA.waitForReady(), + workerA.readUntil(/- BEE: 🟢/), + ]); - await workerA.readUntil(/- BEE: 🟢/); // Give the dev registry some time to settle await setTimeout(500); @@ -184,9 +186,10 @@ describe.each([ const { url } = await workerA.waitForReady(); const workerB = helper.runLongLived(cmd, { cwd: b }); - await workerB.waitForReady(); - - await workerA.readUntil(/- BEE: 🟢/); + await Promise.all([ + workerB.waitForReady(), + workerA.readUntil(/- BEE: 🟢/), + ]); // Give the dev registry some time to settle await setTimeout(500); @@ -215,9 +218,11 @@ describe.each([ await workerC.waitForReady(); const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); - await workerA.readUntil(/- CEE: 🟢/); + const [{ url }] = await Promise.all([ + workerA.waitForReady(), + workerA.readUntil(/- CEE: 🟢/), + ]); // Give the dev registry some time to settle await setTimeout(500); @@ -231,9 +236,11 @@ describe.each([ const { url } = await workerA.waitForReady(); const workerC = helper.runLongLived(cmd, { cwd: c }); - await workerC.waitForReady(); - await workerA.readUntil(/- CEE: 🟢/); + await Promise.all([ + workerC.waitForReady(), + workerA.readUntil(/- CEE: 🟢/), + ]); // Give the dev registry some time to settle await setTimeout(500); @@ -285,9 +292,11 @@ describe.each([ const { url } = await workerB.waitForReady(); const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(); - await workerB.readUntil(/defined in 🟢/); + await Promise.all([ + workerA.waitForReady(), + workerB.readUntil(/defined in 🟢/), + ]); // Give the dev registry some time to settle await setTimeout(500); @@ -306,9 +315,12 @@ describe.each([ await workerA.waitForReady(); const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(); - await workerB.readUntil(/defined in 🟢/); + const [{ url }] = await Promise.all([ + workerB.waitForReady(), + workerB.readUntil(/defined in 🟢/), + ]); + // Give the dev registry some time to settle await setTimeout(500); diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index 3823ddecdd41..f615703b090e 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -134,7 +134,9 @@ export class LongLivedCommand { regexp: RegExp, readTimeout?: number ): Promise { - return readUntil(this.stream, regexp, readTimeout); + const copies = this.stream.tee(); + this.stream = copies[0]; + return readUntil(copies[1], regexp, readTimeout); } // Return a snapshot of the output so far From 61df0418ed9e39b5d5398f1813335f9ca4fd0f4c Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 23:35:46 +0100 Subject: [PATCH 19/37] first time pass? --- packages/wrangler/e2e/dev-registry.test.ts | 38 ++++++++++++---------- packages/wrangler/e2e/helpers/command.ts | 5 ++- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index d43b35f986f7..09bd415728fb 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -231,23 +231,27 @@ describe.each([ ); }); - it("can fetch service worker c through a (start a, start c)", async () => { - const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); - - const workerC = helper.runLongLived(cmd, { cwd: c }); - - await Promise.all([ - workerC.waitForReady(), - workerA.readUntil(/- CEE: 🟢/), - ]); - // Give the dev registry some time to settle - await setTimeout(500); - - await expect(fetchText(`${url}/service`)).resolves.toBe( - "Hello from service worker" - ); - }); + // TODO: Investigate why this doesn't work on Windows + it.skipIf(process.platform === "win32")( + "can fetch service worker c through a (start a, start c)", + async () => { + const workerA = helper.runLongLived(cmd, { cwd: a }); + const { url } = await workerA.waitForReady(); + + const workerC = helper.runLongLived(cmd, { cwd: c }); + + await Promise.all([ + workerC.waitForReady(), + workerA.readUntil(/- CEE: 🟢/), + ]); + // Give the dev registry some time to settle + await setTimeout(500); + + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ); + } + ); }); describe("durable objects", () => { diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index f615703b090e..a013a9849b21 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -1,6 +1,7 @@ import assert from "node:assert"; import { spawn, spawnSync } from "node:child_process"; import events from "node:events"; +import path from "node:path"; import rl from "node:readline"; import { PassThrough } from "node:stream"; import { ReadableStream } from "node:stream/web"; @@ -106,9 +107,7 @@ export class LongLivedCommand { start: (controller) => { lineInterface.on("line", (line) => { // eslint-disable-next-line turbo/no-undeclared-env-vars - // if (process.env.VITEST_MODE === "WATCH") { - console.log(`[${cwd}]`, line); - // } + console.log(`[${path.basename(cwd ?? "/unknown")}]`, line); this.lines.push(line); try { controller.enqueue(line); From 1e88cf77c13079846238b31645c60a2cdb9acab8 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 23:45:34 +0100 Subject: [PATCH 20/37] skip more windows --- packages/wrangler/e2e/dev-registry.test.ts | 39 ++++++++++++---------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 09bd415728fb..73510011132d 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -291,28 +291,31 @@ describe.each([ ).resolves.toMatchObject({ count: 1 }); }); - it("can fetch remote DO attached to a through b (start b, start a)", async () => { - const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(); + it.skipIf(process.platform === "win32")( + "can fetch remote DO attached to a through b (start b, start a)", + async () => { + const workerB = helper.runLongLived(cmd, { cwd: b }); + const { url } = await workerB.waitForReady(); - const workerA = helper.runLongLived(cmd, { cwd: a }); + const workerA = helper.runLongLived(cmd, { cwd: a }); - await Promise.all([ - workerA.waitForReady(), - workerB.readUntil(/defined in 🟢/), - ]); + await Promise.all([ + workerA.waitForReady(), + workerB.readUntil(/defined in 🟢/), + ]); - // Give the dev registry some time to settle - await setTimeout(500); + // Give the dev registry some time to settle + await setTimeout(500); - await expect( - fetchJson(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }) - ).resolves.toMatchObject({ count: 1 }); - }); + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }); + } + ); it("can fetch remote DO attached to a through b (start a, start b)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); From 90a22c031b4759f4e64fdb255592db6253d927b4 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Wed, 9 Oct 2024 23:53:35 +0100 Subject: [PATCH 21/37] debug log stack --- packages/wrangler/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index 79cb114e6711..a8c3ec5a79f5 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -930,7 +930,7 @@ export async function main(argv: string[]): Promise { : loggableException ); if (loggableException instanceof Error) { - logger.log(loggableException.stack); + logger.debug(loggableException.stack); } if (!(loggableException instanceof UserError)) { From 7a452d26855378f9f39143bd2ff40870cb14ccee Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 01:06:47 +0100 Subject: [PATCH 22/37] more tests --- .../tests/entrypoints.spec.ts | 83 ++++++++----------- fixtures/get-platform-proxy/package.json | 2 +- .../tests/get-platform-proxy.ctx.test.ts | 10 +-- fixtures/get-platform-proxy/tsconfig.json | 9 -- .../shared/src/run-wrangler-long-lived.ts | 2 + packages/wrangler/e2e/dev.test.ts | 5 -- packages/wrangler/src/config/index.ts | 7 +- .../src/dev-registry/file-registry.ts | 4 +- packages/wrangler/src/dev.tsx | 12 ++- .../src/environment-variables/factory.ts | 3 +- .../environment-variables/misc-variables.ts | 12 +++ 11 files changed, 69 insertions(+), 80 deletions(-) delete mode 100644 fixtures/get-platform-proxy/tsconfig.json diff --git a/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts b/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts index 3d0af3552632..c1fbef29da95 100644 --- a/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts +++ b/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts @@ -43,7 +43,7 @@ function waitFor(callback: Parameters>[0]) { const test = baseTest.extend<{ tmpPath: string; - isolatedDevRegistryPort: number; + isolatedDevRegistryPath: string; dev: StartDevSession; }>({ // Fixture for creating a temporary directory @@ -53,17 +53,14 @@ const test = baseTest.extend<{ await fs.rm(tmpPath, { recursive: true, maxRetries: 10 }); }, // Fixture for starting an isolated dev registry server on a random port - async isolatedDevRegistryPort({}, use) { - // Start a standalone dev registry server for each test - const result = await unstable_startWorkerRegistryServer(0); - const address = result.server.address(); - assert(typeof address === "object" && address !== null); - await use(address.port); - await result.terminator.terminate(); + async isolatedDevRegistryPath({}, use) { + const tmpPath = await fs.realpath(await fs.mkdtemp(tmpPathBase)); + await use(tmpPath); + await fs.rm(tmpPath, { recursive: true, maxRetries: 10 }); }, // Fixture for starting a worker in a temporary directory, using the test's // isolated dev registry - async dev({ tmpPath, isolatedDevRegistryPort }, use) { + async dev({ tmpPath, isolatedDevRegistryPath }, use) { const workerTmpPathBase = path.join(tmpPath, "worker-"); const cleanups: (() => Promise)[] = []; @@ -77,13 +74,13 @@ const test = baseTest.extend<{ workerPath, pagesPublicPath, ["--port=0", "--inspector-port=0", ...(flags ?? [])], - { WRANGLER_WORKER_REGISTRY_PORT: String(isolatedDevRegistryPort) } + { WRANGLER_REGISTRY_PATH: String(isolatedDevRegistryPath) } ); } else { session = await runWranglerDev( workerPath, ["--port=0", "--inspector-port=0", ...(flags ?? [])], - { WRANGLER_WORKER_REGISTRY_PORT: String(isolatedDevRegistryPort) } + { WRANGLER_REGISTRY_PATH: String(isolatedDevRegistryPath) } ); } @@ -664,7 +661,7 @@ test("should support binding to Durable Object in same worker with explicit scri test("should throw if binding to named entrypoint exported by version of wrangler without entrypoints support", async ({ dev, - isolatedDevRegistryPort, + isolatedDevRegistryPath, }) => { // Start entry worker first, so the server starts with a stubbed service not // found binding @@ -692,26 +689,19 @@ test("should throw if binding to named entrypoint exported by version of wrangle '[wrangler] Couldn\'t find `wrangler dev` session for service "bound" to proxy to' ); - // Simulate starting up the bound worker with an old version of Wrangler - response = await fetch( - `http://127.0.0.1:${isolatedDevRegistryPort}/workers/bound`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - protocol: "http", - mode: "local", - port: 0, - host: "localhost", - durableObjects: [], - durableObjectsHost: "localhost", - durableObjectsPort: 0, - // Intentionally omitting `entrypointAddresses` - }), - } + await writeFile( + path.join(isolatedDevRegistryPath, "bound"), + JSON.stringify({ + protocol: "http", + mode: "local", + port: 0, + host: "localhost", + durableObjects: [], + durableObjectsHost: "localhost", + durableObjectsPort: 0, + // Intentionally omitting `entrypointAddresses` + }) ); - expect(response.status).toBe(200); - expect(await response.text()).toBe("null"); // Wait for error to be thrown await waitFor(() => { @@ -828,7 +818,7 @@ test("should support binding to wrangler session listening on HTTPS", async ({ test("should throw if binding to version of wrangler without entrypoints support over HTTPS", async ({ dev, - isolatedDevRegistryPort, + isolatedDevRegistryPath, }) => { // Start entry worker first, so the server starts with a stubbed service not // found binding @@ -854,23 +844,18 @@ test("should throw if binding to version of wrangler without entrypoints support '[wrangler] Couldn\'t find `wrangler dev` session for service "bound" to proxy to' ); - // Simulate starting up the bound worker using HTTPS with an old version of Wrangler - response = await fetch( - `http://127.0.0.1:${isolatedDevRegistryPort}/workers/bound`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - protocol: "https", - mode: "local", - port: 0, - host: "localhost", - durableObjects: [], - durableObjectsHost: "localhost", - durableObjectsPort: 0, - // Intentionally omitting `entrypointAddresses` - }), - } + await writeFile( + path.join(isolatedDevRegistryPath, "bound"), + JSON.stringify({ + protocol: "https", + mode: "local", + port: 0, + host: "localhost", + durableObjects: [], + durableObjectsHost: "localhost", + durableObjectsPort: 0, + // Intentionally omitting `entrypointAddresses` + }) ); expect(response.status).toBe(200); expect(await response.text()).toBe("null"); diff --git a/fixtures/get-platform-proxy/package.json b/fixtures/get-platform-proxy/package.json index 07cbbd59e042..ab53d18997a6 100644 --- a/fixtures/get-platform-proxy/package.json +++ b/fixtures/get-platform-proxy/package.json @@ -5,7 +5,7 @@ "scripts": { "test:ci": "vitest run", "test:watch": "vitest", - "type:tests": "tsc --noEmit" + "type:tests": "tsc --noEmit -p tests/tsconfig.json" }, "devDependencies": { "@cloudflare/workers-tsconfig": "workspace:*", diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts index 481ec7eece50..221551fad891 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.ctx.test.ts @@ -61,7 +61,7 @@ describe("getPlatformProxy - ctx", () => { } = await getPlatformProxy(); try { expect(() => { - waitUntil(() => {}); + waitUntil(new Promise(() => {})); }).toThrowError("Illegal invocation"); expect(() => { @@ -79,7 +79,7 @@ describe("getPlatformProxy - ctx", () => { try { expect(() => { - waitUntil(() => {}); + waitUntil(new Promise(() => {})); }).toThrowError("Illegal invocation"); expect(() => { @@ -97,7 +97,7 @@ describe("getPlatformProxy - ctx", () => { try { expect(() => { - waitUntil(() => {}); + waitUntil(new Promise(() => {})); }).not.toThrowError("Illegal invocation"); expect(() => { @@ -119,7 +119,7 @@ describe("getPlatformProxy - ctx", () => { try { expect(() => { - waitUntil(() => {}); + waitUntil(new Promise(() => {})); }).toThrowError("Illegal invocation"); expect(() => { @@ -127,7 +127,7 @@ describe("getPlatformProxy - ctx", () => { }).toThrowError("Illegal invocation"); expect(() => { - passThroughOnException.call(new Boolean(), []); + passThroughOnException.call(new Boolean()); }).toThrowError("Illegal invocation"); } finally { await dispose(); diff --git a/fixtures/get-platform-proxy/tsconfig.json b/fixtures/get-platform-proxy/tsconfig.json deleted file mode 100644 index 113c060436bf..000000000000 --- a/fixtures/get-platform-proxy/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "include": ["workers/*/*.ts"], - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "lib": ["ES2020"], - "types": ["@cloudflare/workers-types/experimental"] - } -} diff --git a/fixtures/shared/src/run-wrangler-long-lived.ts b/fixtures/shared/src/run-wrangler-long-lived.ts index 7028a0646a81..84aff612e327 100644 --- a/fixtures/shared/src/run-wrangler-long-lived.ts +++ b/fixtures/shared/src/run-wrangler-long-lived.ts @@ -100,9 +100,11 @@ async function runLongLivedWrangler( const chunks: Buffer[] = []; wranglerProcess.stdout?.on("data", (chunk) => { + console.log(`[${command}]`, chunk.toString()); chunks.push(chunk); }); wranglerProcess.stderr?.on("data", (chunk) => { + console.log(`[${command}]`, chunk.toString()); chunks.push(chunk); }); const getOutput = () => Buffer.concat(chunks).toString(); diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 0da3840c4576..6c6699d7b433 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -10,7 +10,6 @@ import { fetchText } from "./helpers/fetch-text"; import { fetchWithETag } from "./helpers/fetch-with-etag"; import { generateResourceName } from "./helpers/generate-resource-name"; import { retry } from "./helpers/retry"; -import { seed as baseSeed, makeRoot } from "./helpers/setup"; /** * We use the same workerName for all of the tests in this suite in hopes of reducing flakes. @@ -21,10 +20,6 @@ import { seed as baseSeed, makeRoot } from "./helpers/setup"; * when multiple PRs have jobs running at the same time (or the same PR has the tests run across multiple OSes). */ const workerName = generateResourceName(); -/** - * Some tests require a 2nd worker to bind to. Let's create that here too. - */ -const workerName2 = generateResourceName(); it("can import URL from 'url' in node_compat mode", async () => { const helper = new WranglerE2ETestHelper(); diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index d3d72f912cc1..d76f1489b0f0 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -402,7 +402,12 @@ export function printBindings( } const registryDefinition = registry?.[service]; - if (registryDefinition) { + if ( + registryDefinition && + (entrypoint + ? registryDefinition.entrypointAddresses?.[entrypoint] + : true) + ) { value = `🟢 ` + value; } else { value = `🔴 ` + value; diff --git a/packages/wrangler/src/dev-registry/file-registry.ts b/packages/wrangler/src/dev-registry/file-registry.ts index 77e5eae8b683..c2c8d2a018e6 100644 --- a/packages/wrangler/src/dev-registry/file-registry.ts +++ b/packages/wrangler/src/dev-registry/file-registry.ts @@ -11,11 +11,11 @@ import path from "node:path"; import * as util from "node:util"; import { watch } from "chokidar"; import { version as wranglerVersion } from "../../package.json"; -import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path"; +import { getRegistryPath } from "../environment-variables/misc-variables"; import { logger } from "../logger"; import type { WorkerDefinition, WorkerRegistry } from "./types"; -const DEV_REGISTRY_PATH = path.join(getGlobalWranglerConfigPath(), "registry"); +const DEV_REGISTRY_PATH = getRegistryPath(); const heartbeats = new Map(); let globalWorkers: WorkerRegistry | undefined; let globalWatcher: ReturnType | undefined; diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index aa390c510a51..8b205a78ce54 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -476,6 +476,11 @@ async function updateDevEnvRegistry( devEnv: DevEnv, registry: WorkerRegistry | undefined ) { + // Make sure we're not patching an empty config + if (!devEnv.config.latestConfig) { + await events.once(devEnv.config, "configUpdate"); + } + let boundWorkers = await getBoundRegisteredWorkers( { name: devEnv.config.latestConfig?.name, @@ -498,13 +503,6 @@ async function updateDevEnvRegistry( boundWorkers = undefined; } - // Make sure we're not patching an empty config - if (!devEnv.config.latestConfig) { - await events.once(devEnv, "configUpdate"); - } - - // If the current bound workers in the registry are exactly the same as the workers defined in the config, - // then we don't need to update anything. if ( util.isDeepStrictEqual( boundWorkers, diff --git a/packages/wrangler/src/environment-variables/factory.ts b/packages/wrangler/src/environment-variables/factory.ts index 4f8153eea1fb..91d481ed3a6f 100644 --- a/packages/wrangler/src/environment-variables/factory.ts +++ b/packages/wrangler/src/environment-variables/factory.ts @@ -24,7 +24,8 @@ type VariableNames = | "WRANGLER_OUTPUT_FILE_PATH" | "WRANGLER_CI_MATCH_TAG" | "WRANGLER_BUILD_CONDITIONS" - | "WRANGLER_BUILD_PLATFORM"; + | "WRANGLER_BUILD_PLATFORM" + | "WRANGLER_REGISTRY_PATH"; type DeprecatedNames = | "CF_ACCOUNT_ID" diff --git a/packages/wrangler/src/environment-variables/misc-variables.ts b/packages/wrangler/src/environment-variables/misc-variables.ts index b3856d278b07..a19426a316c0 100644 --- a/packages/wrangler/src/environment-variables/misc-variables.ts +++ b/packages/wrangler/src/environment-variables/misc-variables.ts @@ -1,3 +1,5 @@ +import path from "node:path"; +import { getGlobalWranglerConfigPath } from "../global-wrangler-config-path"; import { getEnvironmentVariableFactory } from "./factory"; /** @@ -123,3 +125,13 @@ export const getBuildConditionsFromEnv = getEnvironmentVariableFactory({ export const getBuildPlatformFromEnv = getEnvironmentVariableFactory({ variableName: "WRANGLER_BUILD_PLATFORM", }); + +/** + * `WRANGLER_REGISTRY_PATH` specifies the file based dev registry folder + */ +export const getRegistryPath = getEnvironmentVariableFactory({ + variableName: "WRANGLER_REGISTRY_PATH", + defaultValue() { + return path.join(getGlobalWranglerConfigPath(), "registry"); + }, +}); From c1541e2234f1b41f2ae2662a915666a64a262b8f Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 01:10:29 +0100 Subject: [PATCH 23/37] snapshots --- packages/wrangler/src/__tests__/deploy.test.ts | 12 ++++++------ packages/wrangler/src/__tests__/dev.test.ts | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index 27603512a0db..12509a8fb850 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -6102,7 +6102,7 @@ addEventListener('fetch', event => {});` Worker Startup Time: 100 ms Your worker has access to the following bindings: - Durable Objects: - - SOMENAME: SomeClass (defined in some-script) + - SOMENAME: SomeClass (defined in 🔴 some-script) Uploaded test-name (TIMINGS) Deployed test-name triggers (TIMINGS) https://test-name.test-sub-domain.workers.dev @@ -6797,8 +6797,8 @@ addEventListener('fetch', event => {});` - DATA_BLOB_ONE: some-data-blob.bin - DATA_BLOB_TWO: more-data-blob.bin - Durable Objects: - - DURABLE_OBJECT_ONE: SomeDurableObject (defined in some-durable-object-worker) - - DURABLE_OBJECT_TWO: AnotherDurableObject (defined in another-durable-object-worker) - staging + - DURABLE_OBJECT_ONE: SomeDurableObject (defined in 🔴 some-durable-object-worker) + - DURABLE_OBJECT_TWO: AnotherDurableObject (defined in 🔴 another-durable-object-worker) - KV Namespaces: - KV_NAMESPACE_ONE: kv-ns-one-id - KV_NAMESPACE_TWO: kv-ns-two-id @@ -7894,7 +7894,7 @@ addEventListener('fetch', event => {});` Worker Startup Time: 100 ms Your worker has access to the following bindings: - Durable Objects: - - EXAMPLE_DO_BINDING: ExampleDurableObject (defined in example-do-binding-worker) + - EXAMPLE_DO_BINDING: ExampleDurableObject (defined in 🔴 example-do-binding-worker) Uploaded test-name (TIMINGS) Deployed test-name triggers (TIMINGS) https://test-name.test-sub-domain.workers.dev @@ -8064,7 +8064,7 @@ addEventListener('fetch', event => {});` Worker Startup Time: 100 ms Your worker has access to the following bindings: - Services: - - FOO: foo-service - production + - FOO: 🔴 foo-service Uploaded test-name (TIMINGS) Deployed test-name triggers (TIMINGS) https://test-name.test-sub-domain.workers.dev @@ -8105,7 +8105,7 @@ addEventListener('fetch', event => {});` Worker Startup Time: 100 ms Your worker has access to the following bindings: - Services: - - FOO: foo-service - production (#MyHandler) + - FOO: 🔴 foo-service#MyHandler Uploaded test-name (TIMINGS) Deployed test-name triggers (TIMINGS) https://test-name.test-sub-domain.workers.dev diff --git a/packages/wrangler/src/__tests__/dev.test.ts b/packages/wrangler/src/__tests__/dev.test.ts index 8400b08a70e2..c4d54d4a8123 100644 --- a/packages/wrangler/src/__tests__/dev.test.ts +++ b/packages/wrangler/src/__tests__/dev.test.ts @@ -1195,9 +1195,9 @@ describe.sequential("wrangler dev", () => { "Your worker has access to the following bindings: - Durable Objects: - NAME_1: CLASS_1 - - NAME_2: CLASS_2 (defined in SCRIPT_A) + - NAME_2: CLASS_2 (defined in 🔴 SCRIPT_A) - NAME_3: CLASS_3 - - NAME_4: CLASS_4 (defined in SCRIPT_B) + - NAME_4: CLASS_4 (defined in 🔴 SCRIPT_B) " `); expect(std.warn).toMatchInlineSnapshot(` @@ -1774,8 +1774,8 @@ describe.sequential("wrangler dev", () => { expect(std.out).toMatchInlineSnapshot(` "Your worker has access to the following bindings: - Services: - - WorkerA: A - - WorkerB: B - staging + - WorkerA: 🔴 A + - WorkerB: 🔴 B " `); expect(std.warn).toMatchInlineSnapshot(` @@ -1799,8 +1799,8 @@ describe.sequential("wrangler dev", () => { expect(std.out).toMatchInlineSnapshot(` "Your worker has access to the following bindings: - Services: - - WorkerA: A - - WorkerB: B - staging + - WorkerA: 🔴 A + - WorkerB: 🔴 B " `); expect(std.warn).toMatchInlineSnapshot(` From 6b5860a1bc22b1ec67d06675f1c0e2a33e38a05a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 01:10:48 +0100 Subject: [PATCH 24/37] snapshots --- tools/e2e/runIndividualE2EFiles.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/e2e/runIndividualE2EFiles.ts b/tools/e2e/runIndividualE2EFiles.ts index 49f2bd6e5003..e37814b55f39 100644 --- a/tools/e2e/runIndividualE2EFiles.ts +++ b/tools/e2e/runIndividualE2EFiles.ts @@ -9,15 +9,14 @@ * an individual task for each Wrangler e2e test file, using `execSync`. */ import { execSync } from "child_process"; - -// import { readdirSync } from "fs"; +import { readdirSync } from "fs"; // Get a list of e2e test files, each of which should have an associated script -// const e2eTests = readdirSync("packages/wrangler/e2e"); +const e2eTests = readdirSync("packages/wrangler/e2e"); const tasks = new Set(); -for (const file of ["dev-registry.test.ts", "get-platform-proxy.test.ts"]) { +for (const file of e2eTests) { // Ignore other files in the e2e directory (the README, for instance) if (file.endsWith(".test.ts")) { tasks.add( From 19ee28dc8dd88ee1559411db563bfd330ca827e7 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 03:28:33 +0100 Subject: [PATCH 25/37] optional tee --- packages/wrangler/e2e/dev.test.ts | 6 +++--- packages/wrangler/e2e/helpers/command.ts | 13 +++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 6c6699d7b433..cad9372e395b 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -796,9 +796,9 @@ describe("custom builds", () => { const worker = helper.runLongLived("wrangler dev"); // first build on startup - await worker.readUntil(/Running custom build/, 5_000); + await worker.readUntil(/Running custom build/, 5_000, false); // second build for first watcher notification (can be optimised away, leaving as-is for now) - await worker.readUntil(/Running custom build/, 5_000); + await worker.readUntil(/Running custom build/, 5_000, false); // Need to get the url in this order because waitForReady calls readUntil // which keeps track of where it's read up to so far, @@ -810,7 +810,7 @@ describe("custom builds", () => { // assert no more custom builds happen // regression: https://github.com/cloudflare/workers-sdk/issues/6876 await expect( - worker.readUntil(/Running custom build:/, 5_000) + worker.readUntil(/Running custom build:/, 5_000, false) ).rejects.toThrowError(); // now check assets are still fetchable, even after updates diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index a013a9849b21..692856d94cbd 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -131,11 +131,16 @@ export class LongLivedCommand { // Wait for changes in the output of this process. async readUntil( regexp: RegExp, - readTimeout?: number + readTimeout?: number, + tee = true ): Promise { - const copies = this.stream.tee(); - this.stream = copies[0]; - return readUntil(copies[1], regexp, readTimeout); + if (tee) { + const copies = this.stream.tee(); + this.stream = copies[0]; + return readUntil(copies[1], regexp, readTimeout); + } else { + return readUntil(this.stream, regexp, readTimeout); + } } // Return a snapshot of the output so far From 70eadc2bd6795bc2402d1c7f1a58c26f084ce0f3 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 03:34:36 +0100 Subject: [PATCH 26/37] fix bundle controller race condition --- fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts | 2 -- .../wrangler/src/api/startDevWorker/BundlerController.ts | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts b/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts index c1fbef29da95..96f7a4501e44 100644 --- a/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts +++ b/fixtures/entrypoints-rpc-tests/tests/entrypoints.spec.ts @@ -857,8 +857,6 @@ test("should throw if binding to version of wrangler without entrypoints support // Intentionally omitting `entrypointAddresses` }) ); - expect(response.status).toBe(200); - expect(await response.text()).toBe("null"); // Wait for error to be thrown await waitFor(() => { diff --git a/packages/wrangler/src/api/startDevWorker/BundlerController.ts b/packages/wrangler/src/api/startDevWorker/BundlerController.ts index d83f2cfc649a..ed663ec8443e 100644 --- a/packages/wrangler/src/api/startDevWorker/BundlerController.ts +++ b/packages/wrangler/src/api/startDevWorker/BundlerController.ts @@ -254,8 +254,10 @@ export class BundlerController extends Controller { }, (cb) => { const newBundle = cb(this.#currentBundle); - this.emitBundleCompleteEvent(config, newBundle); - this.#currentBundle = newBundle; + if (!buildAborter.signal.aborted) { + this.emitBundleCompleteEvent(config, newBundle); + this.#currentBundle = newBundle; + } }, (err) => { if (!buildAborter.signal.aborted) { From 47de14000133bd053a59df4733d59c1ac71c3e9a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 04:03:22 +0100 Subject: [PATCH 27/37] tee opt-in --- packages/wrangler/e2e/dev-registry.test.ts | 40 +++++++++++----------- packages/wrangler/e2e/helpers/command.ts | 2 +- packages/wrangler/e2e/helpers/wrangler.ts | 16 ++++++--- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 73510011132d..d2c37f8e1117 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -157,7 +157,7 @@ describe.each([ it("can fetch b", async () => { const worker = helper.runLongLived(cmd, { cwd: b }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(5_000, true); await expect(fetch(url).then((r) => r.text())).resolves.toBe( "hello world" @@ -167,12 +167,12 @@ describe.each([ it("can fetch b through a (start b, start a)", async () => { const workerB = helper.runLongLived(cmd, { cwd: b }); // We don't need b's URL, but ensure that b starts up before a - await workerB.waitForReady(); + await workerB.waitForReady(5_000, true); const workerA = helper.runLongLived(cmd, { cwd: a }); const [{ url }] = await Promise.all([ - workerA.waitForReady(), - workerA.readUntil(/- BEE: 🟢/), + workerA.waitForReady(5_000, true), + workerA.readUntil(/- BEE: 🟢/, 5_000, true), ]); // Give the dev registry some time to settle @@ -183,12 +183,12 @@ describe.each([ it("can fetch b through a (start a, start b)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + const { url } = await workerA.waitForReady(5_000, true); const workerB = helper.runLongLived(cmd, { cwd: b }); await Promise.all([ - workerB.waitForReady(), - workerA.readUntil(/- BEE: 🟢/), + workerB.waitForReady(5_000, true), + workerA.readUntil(/- BEE: 🟢/, 5_000, true), ]); // Give the dev registry some time to settle await setTimeout(500); @@ -215,13 +215,13 @@ describe.each([ it("can fetch service worker c through a (start c, start a)", async () => { const workerC = helper.runLongLived(cmd, { cwd: c }); // We don't need c's URL, but ensure that c starts up before a - await workerC.waitForReady(); + await workerC.waitForReady(5_000, true); const workerA = helper.runLongLived(cmd, { cwd: a }); const [{ url }] = await Promise.all([ - workerA.waitForReady(), - workerA.readUntil(/- CEE: 🟢/), + workerA.waitForReady(5_000, true), + workerA.readUntil(/- CEE: 🟢/, 5_000, true), ]); // Give the dev registry some time to settle await setTimeout(500); @@ -236,13 +236,13 @@ describe.each([ "can fetch service worker c through a (start a, start c)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(); + const { url } = await workerA.waitForReady(5_000, true); const workerC = helper.runLongLived(cmd, { cwd: c }); await Promise.all([ - workerC.waitForReady(), - workerA.readUntil(/- CEE: 🟢/), + workerC.waitForReady(5_000, true), + workerA.readUntil(/- CEE: 🟢/, 5_000, true), ]); // Give the dev registry some time to settle await setTimeout(500); @@ -280,7 +280,7 @@ describe.each([ it("can fetch DO through a", async () => { const worker = helper.runLongLived(cmd, { cwd: a }); - const { url } = await worker.waitForReady(); + const { url } = await worker.waitForReady(5_000, true); await expect( fetchJson(`${url}/do`, { @@ -295,13 +295,13 @@ describe.each([ "can fetch remote DO attached to a through b (start b, start a)", async () => { const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(); + const { url } = await workerB.waitForReady(5_000, true); const workerA = helper.runLongLived(cmd, { cwd: a }); await Promise.all([ - workerA.waitForReady(), - workerB.readUntil(/defined in 🟢/), + workerA.waitForReady(5_000, true), + workerB.readUntil(/defined in 🟢/, 5_000, true), ]); // Give the dev registry some time to settle @@ -319,13 +319,13 @@ describe.each([ it("can fetch remote DO attached to a through b (start a, start b)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(); + await workerA.waitForReady(5_000, true); const workerB = helper.runLongLived(cmd, { cwd: b }); const [{ url }] = await Promise.all([ - workerB.waitForReady(), - workerB.readUntil(/defined in 🟢/), + workerB.waitForReady(5_000, true), + workerB.readUntil(/defined in 🟢/, 5_000, true), ]); // Give the dev registry some time to settle diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index 692856d94cbd..d59ebb8b072e 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -132,7 +132,7 @@ export class LongLivedCommand { async readUntil( regexp: RegExp, readTimeout?: number, - tee = true + tee = false ): Promise { if (tee) { const copies = this.stream.tee(); diff --git a/packages/wrangler/e2e/helpers/wrangler.ts b/packages/wrangler/e2e/helpers/wrangler.ts index 791add741de4..092955331129 100644 --- a/packages/wrangler/e2e/helpers/wrangler.ts +++ b/packages/wrangler/e2e/helpers/wrangler.ts @@ -34,15 +34,23 @@ export class WranglerLongLivedCommand extends LongLivedCommand { super(getWranglerCommand(wranglerCommand), getOptions(options)); } - async waitForReady(): Promise<{ url: string }> { - const match = await this.readUntil(/Ready on (?https?:\/\/.*)/, 5_000); + async waitForReady( + readTimeout = 5_000, + tee?: boolean + ): Promise<{ url: string }> { + const match = await this.readUntil( + /Ready on (?https?:\/\/.*)/, + readTimeout, + tee + ); return match.groups as { url: string }; } - async waitForReload(readTimeout?: number): Promise { + async waitForReload(readTimeout = 5_000, tee?: boolean): Promise { await this.readUntil( /Detected changes, restarted server|Reloading local server\.\.\./, - readTimeout + readTimeout, + tee ); } } From d1fd7bc020caefb431be1761c4069a053c641230 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 12:23:18 +0100 Subject: [PATCH 28/37] more fixes --- .../e2e/__snapshots__/pages-dev.test.ts.snap | 24 +++++------ packages/wrangler/e2e/deployments.test.ts | 40 ++++++++++--------- packages/wrangler/e2e/pages-dev.test.ts | 4 +- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/wrangler/e2e/__snapshots__/pages-dev.test.ts.snap b/packages/wrangler/e2e/__snapshots__/pages-dev.test.ts.snap index 5316b41c55fb..17f95f783736 100644 --- a/packages/wrangler/e2e/__snapshots__/pages-dev.test.ts.snap +++ b/packages/wrangler/e2e/__snapshots__/pages-dev.test.ts.snap @@ -10,9 +10,9 @@ exports[`Pages 'wrangler pages dev --no-x-dev-env' > should merge (with override ▲ [WARNING] This worker is bound to live services: SERVICE_BINDING_1_TOML (SERVICE_NAME_1_TOML), SERVICE_BINDING_2_TOML (SERVICE_NAME_2_TOML) Your worker has access to the following bindings: - Durable Objects: - - DO_BINDING_1_TOML: NEW_DO_1 (defined in NEW_DO_SCRIPT_1) - - DO_BINDING_2_TOML: DO_2_TOML (defined in DO_SCRIPT_2_TOML) - - DO_BINDING_3_ARGS: DO_3_ARGS (defined in DO_SCRIPT_3_ARGS) + - DO_BINDING_1_TOML: NEW_DO_1 (defined in 🔴 NEW_DO_SCRIPT_1) + - DO_BINDING_2_TOML: DO_2_TOML (defined in 🔴 DO_SCRIPT_2_TOML) + - DO_BINDING_3_ARGS: DO_3_ARGS (defined in 🔴 DO_SCRIPT_3_ARGS) - KV Namespaces: - KV_BINDING_1_TOML: NEW_KV_ID_1 - KV_BINDING_2_TOML: KV_ID_2_TOML @@ -26,9 +26,9 @@ Your worker has access to the following bindings: - R2_BINDING_2_TOML: R2_BUCKET_2_TOML - R2_BINDING_3_TOML: R2_BUCKET_3_ARGS - Services: - - SERVICE_BINDING_1_TOML: NEW_SERVICE_NAME_1 - - SERVICE_BINDING_2_TOML: SERVICE_NAME_2_TOML - - SERVICE_BINDING_3_TOML: SERVICE_NAME_3_ARGS + - SERVICE_BINDING_1_TOML: 🔴 NEW_SERVICE_NAME_1 + - SERVICE_BINDING_2_TOML: 🔴 SERVICE_NAME_2_TOML + - SERVICE_BINDING_3_TOML: 🔴 SERVICE_NAME_3_ARGS - AI: - Name: AI_BINDING_2_TOML - Vars: @@ -49,9 +49,9 @@ exports[`Pages 'wrangler pages dev --x-dev-env' > should merge (with override) \ - {"name":"DO_BINDING_2_TOML","class_name":"DO_2_TOML","script_name":"DO_SCRIPT_2_TOML"} Your worker has access to the following bindings: - Durable Objects: - - DO_BINDING_1_TOML: NEW_DO_1 (defined in NEW_DO_SCRIPT_1) - - DO_BINDING_2_TOML: DO_2_TOML (defined in DO_SCRIPT_2_TOML) - - DO_BINDING_3_ARGS: DO_3_ARGS (defined in DO_SCRIPT_3_ARGS) + - DO_BINDING_1_TOML: NEW_DO_1 (defined in 🔴 NEW_DO_SCRIPT_1) + - DO_BINDING_2_TOML: DO_2_TOML (defined in 🔴 DO_SCRIPT_2_TOML) + - DO_BINDING_3_ARGS: DO_3_ARGS (defined in 🔴 DO_SCRIPT_3_ARGS) - KV Namespaces: - KV_BINDING_1_TOML: NEW_KV_ID_1 - KV_BINDING_2_TOML: KV_ID_2_TOML @@ -65,9 +65,9 @@ Your worker has access to the following bindings: - R2_BINDING_2_TOML: R2_BUCKET_2_TOML - R2_BINDING_3_TOML: R2_BUCKET_3_ARGS - Services: - - SERVICE_BINDING_1_TOML: NEW_SERVICE_NAME_1 - - SERVICE_BINDING_2_TOML: SERVICE_NAME_2_TOML - - SERVICE_BINDING_3_TOML: SERVICE_NAME_3_ARGS + - SERVICE_BINDING_1_TOML: 🔴 NEW_SERVICE_NAME_1 + - SERVICE_BINDING_2_TOML: 🔴 SERVICE_NAME_2_TOML + - SERVICE_BINDING_3_TOML: 🔴 SERVICE_NAME_3_ARGS - AI: - Name: AI_BINDING_2_TOML - Vars: diff --git a/packages/wrangler/e2e/deployments.test.ts b/packages/wrangler/e2e/deployments.test.ts index 2ac46644ca0a..e500ba6fb6ed 100644 --- a/packages/wrangler/e2e/deployments.test.ts +++ b/packages/wrangler/e2e/deployments.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import dedent from "ts-dedent"; import { fetch } from "undici"; -import { afterAll, describe, expect, it } from "vitest"; +import { afterAll, describe, expect, it, vi } from "vitest"; import { CLOUDFLARE_ACCOUNT_ID } from "./helpers/account-id"; import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; import { generateResourceName } from "./helpers/generate-resource-name"; @@ -25,7 +25,7 @@ describe("deployments", { timeout: TIMEOUT }, () => { name = "${workerName}" main = "src/index.ts" compatibility_date = "2023-01-01" - `, + `, "src/index.ts": dedent` export default { fetch(request) { @@ -226,29 +226,31 @@ const initialAssets = { }; const checkAssets = async (testCases: AssetTestCase[], deployedUrl: string) => { for (const testCase of testCases) { - const { text, url } = await retry( - (s) => (testCase.content ? s.status !== 200 : s.status !== 404), + await vi.waitFor( async () => { const r = await fetch(new URL(testCase.path, deployedUrl)); - return { text: await r.text(), status: r.status, url: r.url }; - } + const text = await r.text(); + const url = r.url; + + if (testCase.content) { + expect(text).toContain(testCase.content); + } + if (testCase.redirect) { + expect(new URL(url).pathname).toEqual( + new URL(testCase.redirect, deployedUrl).pathname + ); + } else { + expect(new URL(url).pathname).toEqual( + new URL(testCase.path, deployedUrl).pathname + ); + } + }, + { interval: 500, timeout: 5_000 } ); - if (testCase.content) { - expect(text).toContain(testCase.content); - } - if (testCase.redirect) { - expect(new URL(url).pathname).toEqual( - new URL(testCase.redirect, deployedUrl).pathname - ); - } else { - expect(new URL(url).pathname).toEqual( - new URL(testCase.path, deployedUrl).pathname - ); - } } }; -describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => { +describe.only("Workers + Assets deployment", { timeout: TIMEOUT }, () => { let deployedUrl: string; const helper = new WranglerE2ETestHelper(); afterAll(async () => { diff --git a/packages/wrangler/e2e/pages-dev.test.ts b/packages/wrangler/e2e/pages-dev.test.ts index e0d0da25316e..cc6b1b2ce45f 100644 --- a/packages/wrangler/e2e/pages-dev.test.ts +++ b/packages/wrangler/e2e/pages-dev.test.ts @@ -121,7 +121,7 @@ describe.each([ ` Your worker has access to the following bindings: - Durable Objects: - - TEST_DO: TestDurableObject (defined in a) + - TEST_DO: TestDurableObject (defined in 🔴 a) - KV Namespaces: - TEST_KV: TEST_KV - D1 Databases: @@ -129,7 +129,7 @@ describe.each([ - R2 Buckets: - TEST_R2: TEST_R2 - Services: - - TEST_SERVICE: test-worker + - TEST_SERVICE: 🔴 test-worker `.replace(/\s/g, "") ); }); From 8b2ecd3aabe2739922da8aae646b2e6515e23641 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 13:21:27 +0100 Subject: [PATCH 29/37] no only --- packages/wrangler/e2e/deployments.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/e2e/deployments.test.ts b/packages/wrangler/e2e/deployments.test.ts index e500ba6fb6ed..e26200375ff5 100644 --- a/packages/wrangler/e2e/deployments.test.ts +++ b/packages/wrangler/e2e/deployments.test.ts @@ -250,7 +250,7 @@ const checkAssets = async (testCases: AssetTestCase[], deployedUrl: string) => { } }; -describe.only("Workers + Assets deployment", { timeout: TIMEOUT }, () => { +describe("Workers + Assets deployment", { timeout: TIMEOUT }, () => { let deployedUrl: string; const helper = new WranglerE2ETestHelper(); afterAll(async () => { From 57fd9f67c24af403c85f89f993ead79eb379aff1 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 13:41:55 +0100 Subject: [PATCH 30/37] increase timeout --- packages/wrangler/e2e/deployments.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/e2e/deployments.test.ts b/packages/wrangler/e2e/deployments.test.ts index e26200375ff5..6c1e8bbecd74 100644 --- a/packages/wrangler/e2e/deployments.test.ts +++ b/packages/wrangler/e2e/deployments.test.ts @@ -245,7 +245,7 @@ const checkAssets = async (testCases: AssetTestCase[], deployedUrl: string) => { ); } }, - { interval: 500, timeout: 5_000 } + { interval: 1_000, timeout: 30_000 } ); } }; From 388a4244d207096d568b868d63fa7054ce5a0852 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 14:14:01 +0100 Subject: [PATCH 31/37] readUntil -> waitFor --- packages/wrangler/e2e/dev-registry.test.ts | 114 +++++++++------------ 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index d2c37f8e1117..bf3adc41685f 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -1,4 +1,3 @@ -import { setTimeout } from "node:timers/promises"; import dedent from "ts-dedent"; import { fetch } from "undici"; import { beforeEach, describe, expect, it, vi } from "vitest"; @@ -170,15 +169,12 @@ describe.each([ await workerB.waitForReady(5_000, true); const workerA = helper.runLongLived(cmd, { cwd: a }); - const [{ url }] = await Promise.all([ - workerA.waitForReady(5_000, true), - workerA.readUntil(/- BEE: 🟢/, 5_000, true), - ]); - - // Give the dev registry some time to settle - await setTimeout(500); + const { url } = await workerA.waitForReady(5_000, true); - await expect(fetchText(url)).resolves.toBe("hello world"); + await vi.waitFor( + async () => await expect(fetchText(url)).resolves.toBe("hello world"), + { interval: 300, timeout: 5_000 } + ); }); it("can fetch b through a (start a, start b)", async () => { @@ -186,14 +182,12 @@ describe.each([ const { url } = await workerA.waitForReady(5_000, true); const workerB = helper.runLongLived(cmd, { cwd: b }); - await Promise.all([ - workerB.waitForReady(5_000, true), - workerA.readUntil(/- BEE: 🟢/, 5_000, true), - ]); - // Give the dev registry some time to settle - await setTimeout(500); - - await expect(fetchText(url)).resolves.toBe("hello world"); + await workerB.waitForReady(5_000, true); + + await vi.waitFor( + async () => await expect(fetchText(url)).resolves.toBe("hello world"), + { interval: 300, timeout: 5_000 } + ); }); }); @@ -219,15 +213,14 @@ describe.each([ const workerA = helper.runLongLived(cmd, { cwd: a }); - const [{ url }] = await Promise.all([ - workerA.waitForReady(5_000, true), - workerA.readUntil(/- CEE: 🟢/, 5_000, true), - ]); - // Give the dev registry some time to settle - await setTimeout(500); + const { url } = await workerA.waitForReady(5_000, true); - await expect(fetchText(`${url}/service`)).resolves.toBe( - "Hello from service worker" + await vi.waitFor( + async () => + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ), + { interval: 300, timeout: 5_000 } ); }); @@ -240,15 +233,14 @@ describe.each([ const workerC = helper.runLongLived(cmd, { cwd: c }); - await Promise.all([ - workerC.waitForReady(5_000, true), - workerA.readUntil(/- CEE: 🟢/, 5_000, true), - ]); - // Give the dev registry some time to settle - await setTimeout(500); + await workerC.waitForReady(5_000, true); - await expect(fetchText(`${url}/service`)).resolves.toBe( - "Hello from service worker" + await vi.waitFor( + async () => + await expect(fetchText(`${url}/service`)).resolves.toBe( + "Hello from service worker" + ), + { interval: 300, timeout: 5_000 } ); } ); @@ -299,21 +291,19 @@ describe.each([ const workerA = helper.runLongLived(cmd, { cwd: a }); - await Promise.all([ - workerA.waitForReady(5_000, true), - workerB.readUntil(/defined in 🟢/, 5_000, true), - ]); - - // Give the dev registry some time to settle - await setTimeout(500); - - await expect( - fetchJson(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }) - ).resolves.toMatchObject({ count: 1 }); + await workerA.waitForReady(5_000, true); + + await vi.waitFor( + async () => + await expect( + fetchJson(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }) + ).resolves.toMatchObject({ count: 1 }), + { interval: 300, timeout: 5_000 } + ); } ); @@ -323,21 +313,19 @@ describe.each([ const workerB = helper.runLongLived(cmd, { cwd: b }); - const [{ url }] = await Promise.all([ - workerB.waitForReady(5_000, true), - workerB.readUntil(/defined in 🟢/, 5_000, true), - ]); - - // Give the dev registry some time to settle - await setTimeout(500); - - await expect( - fetch(`${url}/do`, { - headers: { - "X-Reset-Count": "true", - }, - }).then((r) => r.json()) - ).resolves.toMatchObject({ count: 1 }); + const { url } = await workerB.waitForReady(5_000, true); + + await vi.waitFor( + async () => + await expect( + fetch(`${url}/do`, { + headers: { + "X-Reset-Count": "true", + }, + }).then((r) => r.json()) + ).resolves.toMatchObject({ count: 1 }), + { interval: 300, timeout: 5_000 } + ); }); }); }); From a75526f060b9bfeb9241db4a6d86f8dcc7c98e4a Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 14:15:44 +0100 Subject: [PATCH 32/37] more logging --- packages/wrangler/e2e/helpers/command.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index d59ebb8b072e..2fc3dab9e979 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -41,15 +41,13 @@ export function runCommand( encoding: "utf8", timeout, }); - // eslint-disable-next-line turbo/no-undeclared-env-vars - if (process.env.VITEST_MODE === "WATCH") { - if (stdout.length) { - console.log(stdout); - } - if (stderr.length) { - console.error(stderr); - } + if (stdout.length) { + console.log(`[${path.basename(cwd ?? "/unknown")}]`, stdout); } + if (stderr.length) { + console.error(`[${path.basename(cwd ?? "/unknown")}]`, stderr); + } + return { status, stdout, @@ -106,7 +104,6 @@ export class LongLivedCommand { this.stream = new ReadableStream({ start: (controller) => { lineInterface.on("line", (line) => { - // eslint-disable-next-line turbo/no-undeclared-env-vars console.log(`[${path.basename(cwd ?? "/unknown")}]`, line); this.lines.push(line); try { From 1dea6afbf5f91a17d7ca3ea92a7cbdfbec4554d0 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 14:28:59 +0100 Subject: [PATCH 33/37] increase timeout --- packages/wrangler/e2e/dev-registry.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index bf3adc41685f..735f3b351987 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -17,7 +17,7 @@ async function fetchJson(url: string, info?: RequestInit): Promise { console.log(text); return JSON.parse(text) as T; }, - { timeout: 5_000, interval: 250 } + { timeout: 10_000, interval: 250 } ); } @@ -173,7 +173,7 @@ describe.each([ await vi.waitFor( async () => await expect(fetchText(url)).resolves.toBe("hello world"), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); }); @@ -186,7 +186,7 @@ describe.each([ await vi.waitFor( async () => await expect(fetchText(url)).resolves.toBe("hello world"), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); }); }); @@ -220,7 +220,7 @@ describe.each([ await expect(fetchText(`${url}/service`)).resolves.toBe( "Hello from service worker" ), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); }); @@ -240,7 +240,7 @@ describe.each([ await expect(fetchText(`${url}/service`)).resolves.toBe( "Hello from service worker" ), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); } ); @@ -302,7 +302,7 @@ describe.each([ }, }) ).resolves.toMatchObject({ count: 1 }), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); } ); @@ -324,7 +324,7 @@ describe.each([ }, }).then((r) => r.json()) ).resolves.toMatchObject({ count: 1 }), - { interval: 300, timeout: 5_000 } + { interval: 1000, timeout: 10_000 } ); }); }); From 6daac0c8104c4f7066cf9d483f78fb7caebd4a7b Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 10 Oct 2024 14:44:32 +0100 Subject: [PATCH 34/37] no more teeing --- packages/wrangler/e2e/dev-registry.test.ts | 28 +++++++++++----------- packages/wrangler/e2e/dev.test.ts | 6 ++--- packages/wrangler/e2e/helpers/command.ts | 11 ++------- packages/wrangler/e2e/helpers/wrangler.ts | 13 ++++------ 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 735f3b351987..946995700953 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -156,7 +156,7 @@ describe.each([ it("can fetch b", async () => { const worker = helper.runLongLived(cmd, { cwd: b }); - const { url } = await worker.waitForReady(5_000, true); + const { url } = await worker.waitForReady(5_000); await expect(fetch(url).then((r) => r.text())).resolves.toBe( "hello world" @@ -166,10 +166,10 @@ describe.each([ it("can fetch b through a (start b, start a)", async () => { const workerB = helper.runLongLived(cmd, { cwd: b }); // We don't need b's URL, but ensure that b starts up before a - await workerB.waitForReady(5_000, true); + await workerB.waitForReady(5_000); const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(5_000, true); + const { url } = await workerA.waitForReady(5_000); await vi.waitFor( async () => await expect(fetchText(url)).resolves.toBe("hello world"), @@ -179,10 +179,10 @@ describe.each([ it("can fetch b through a (start a, start b)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(5_000, true); + const { url } = await workerA.waitForReady(5_000); const workerB = helper.runLongLived(cmd, { cwd: b }); - await workerB.waitForReady(5_000, true); + await workerB.waitForReady(5_000); await vi.waitFor( async () => await expect(fetchText(url)).resolves.toBe("hello world"), @@ -209,11 +209,11 @@ describe.each([ it("can fetch service worker c through a (start c, start a)", async () => { const workerC = helper.runLongLived(cmd, { cwd: c }); // We don't need c's URL, but ensure that c starts up before a - await workerC.waitForReady(5_000, true); + await workerC.waitForReady(5_000); const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(5_000, true); + const { url } = await workerA.waitForReady(5_000); await vi.waitFor( async () => @@ -229,11 +229,11 @@ describe.each([ "can fetch service worker c through a (start a, start c)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - const { url } = await workerA.waitForReady(5_000, true); + const { url } = await workerA.waitForReady(5_000); const workerC = helper.runLongLived(cmd, { cwd: c }); - await workerC.waitForReady(5_000, true); + await workerC.waitForReady(5_000); await vi.waitFor( async () => @@ -272,7 +272,7 @@ describe.each([ it("can fetch DO through a", async () => { const worker = helper.runLongLived(cmd, { cwd: a }); - const { url } = await worker.waitForReady(5_000, true); + const { url } = await worker.waitForReady(5_000); await expect( fetchJson(`${url}/do`, { @@ -287,11 +287,11 @@ describe.each([ "can fetch remote DO attached to a through b (start b, start a)", async () => { const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(5_000, true); + const { url } = await workerB.waitForReady(5_000); const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(5_000, true); + await workerA.waitForReady(5_000); await vi.waitFor( async () => @@ -309,11 +309,11 @@ describe.each([ it("can fetch remote DO attached to a through b (start a, start b)", async () => { const workerA = helper.runLongLived(cmd, { cwd: a }); - await workerA.waitForReady(5_000, true); + await workerA.waitForReady(5_000); const workerB = helper.runLongLived(cmd, { cwd: b }); - const { url } = await workerB.waitForReady(5_000, true); + const { url } = await workerB.waitForReady(5_000); await vi.waitFor( async () => diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index cad9372e395b..6c6699d7b433 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -796,9 +796,9 @@ describe("custom builds", () => { const worker = helper.runLongLived("wrangler dev"); // first build on startup - await worker.readUntil(/Running custom build/, 5_000, false); + await worker.readUntil(/Running custom build/, 5_000); // second build for first watcher notification (can be optimised away, leaving as-is for now) - await worker.readUntil(/Running custom build/, 5_000, false); + await worker.readUntil(/Running custom build/, 5_000); // Need to get the url in this order because waitForReady calls readUntil // which keeps track of where it's read up to so far, @@ -810,7 +810,7 @@ describe("custom builds", () => { // assert no more custom builds happen // regression: https://github.com/cloudflare/workers-sdk/issues/6876 await expect( - worker.readUntil(/Running custom build:/, 5_000, false) + worker.readUntil(/Running custom build:/, 5_000) ).rejects.toThrowError(); // now check assets are still fetchable, even after updates diff --git a/packages/wrangler/e2e/helpers/command.ts b/packages/wrangler/e2e/helpers/command.ts index 2fc3dab9e979..8942ab9c85ed 100644 --- a/packages/wrangler/e2e/helpers/command.ts +++ b/packages/wrangler/e2e/helpers/command.ts @@ -128,16 +128,9 @@ export class LongLivedCommand { // Wait for changes in the output of this process. async readUntil( regexp: RegExp, - readTimeout?: number, - tee = false + readTimeout?: number ): Promise { - if (tee) { - const copies = this.stream.tee(); - this.stream = copies[0]; - return readUntil(copies[1], regexp, readTimeout); - } else { - return readUntil(this.stream, regexp, readTimeout); - } + return readUntil(this.stream, regexp, readTimeout); } // Return a snapshot of the output so far diff --git a/packages/wrangler/e2e/helpers/wrangler.ts b/packages/wrangler/e2e/helpers/wrangler.ts index 092955331129..f7a6e9fdde2f 100644 --- a/packages/wrangler/e2e/helpers/wrangler.ts +++ b/packages/wrangler/e2e/helpers/wrangler.ts @@ -34,23 +34,18 @@ export class WranglerLongLivedCommand extends LongLivedCommand { super(getWranglerCommand(wranglerCommand), getOptions(options)); } - async waitForReady( - readTimeout = 5_000, - tee?: boolean - ): Promise<{ url: string }> { + async waitForReady(readTimeout = 5_000): Promise<{ url: string }> { const match = await this.readUntil( /Ready on (?https?:\/\/.*)/, - readTimeout, - tee + readTimeout ); return match.groups as { url: string }; } - async waitForReload(readTimeout = 5_000, tee?: boolean): Promise { + async waitForReload(readTimeout = 5_000): Promise { await this.readUntil( /Detected changes, restarted server|Reloading local server\.\.\./, - readTimeout, - tee + readTimeout ); } } From 754b2f1b3a05c79139046302f0b9b11799ef8204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Somhairle=20MacLe=C3=B2id?= Date: Mon, 14 Oct 2024 12:31:27 +0100 Subject: [PATCH 35/37] Apply suggestions from code review Co-authored-by: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> --- packages/wrangler/e2e/dev-registry.test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 946995700953..f486bdfeed59 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -14,8 +14,13 @@ async function fetchJson(url: string, info?: RequestInit): Promise { headers: { "MF-Disable-Pretty-Error": "true" }, ...info, }).then((r) => r.text()); - console.log(text); - return JSON.parse(text) as T; + try { + return JSON.parse(text) as T; + } catch(cause) { + const err = new Error(`Failed to parse JSON from:\n${text}`); + err.cause = cause; + throw err; + } }, { timeout: 10_000, interval: 250 } ); From 597374234e14803cfd8ac3e2721bcfbde0607cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Somhairle=20MacLe=C3=B2id?= Date: Mon, 14 Oct 2024 12:34:33 +0100 Subject: [PATCH 36/37] Update packages/wrangler/src/config/index.ts Co-authored-by: Rahul Sethi <5822355+RamIdeas@users.noreply.github.com> --- packages/wrangler/src/config/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index d76f1489b0f0..e403044679d7 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -404,9 +404,7 @@ export function printBindings( const registryDefinition = registry?.[service]; if ( registryDefinition && - (entrypoint - ? registryDefinition.entrypointAddresses?.[entrypoint] - : true) + (!entrypoint || registryDefinition.entrypointAddresses?.[entrypoint]) ) { value = `🟢 ` + value; } else { From 66b09167ef82ae1d2d637809ba28068f762403c1 Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Mon, 14 Oct 2024 13:14:03 +0100 Subject: [PATCH 37/37] fix formatting --- packages/wrangler/e2e/dev-registry.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index f486bdfeed59..08b3c9c214a1 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -16,7 +16,7 @@ async function fetchJson(url: string, info?: RequestInit): Promise { }).then((r) => r.text()); try { return JSON.parse(text) as T; - } catch(cause) { + } catch (cause) { const err = new Error(`Failed to parse JSON from:\n${text}`); err.cause = cause; throw err;