Skip to content

Commit bc4026e

Browse files
Add e2e tests for programmatic remote bindings api (#10244)
* add e2e tests for `startRemoteProxySession` * remove incorrect tsdoc comment for `maybeStartOrUpdateRemoteProxySession` * add e2e tests for `maybeStartOrUpdateRemoteProxySession`
1 parent 8287f46 commit bc4026e

File tree

2 files changed

+266
-3
lines changed

2 files changed

+266
-3
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import assert from "node:assert";
2+
import { resolve } from "node:path";
3+
import { afterAll, beforeAll, describe, expect, test } from "vitest";
4+
import { CLOUDFLARE_ACCOUNT_ID } from "../helpers/account-id";
5+
import { WranglerE2ETestHelper } from "../helpers/e2e-wrangler-test";
6+
import { generateResourceName } from "../helpers/generate-resource-name";
7+
import type {
8+
Miniflare,
9+
MiniflareOptions,
10+
RemoteProxyConnectionString,
11+
Response,
12+
} from "miniflare";
13+
14+
// Note: the tests in this file are simple ones that check basic functionalities of the remote bindings programmatic APIs
15+
// various other aspects of these APIs (e.g. different bindings, reloading capabilities) are indirectly tested when
16+
// generally testing remote bindings
17+
18+
describe.skipIf(!CLOUDFLARE_ACCOUNT_ID)(
19+
"wrangler dev - remote bindings - programmatic API",
20+
async () => {
21+
const remoteWorkerName = generateResourceName();
22+
const helper = new WranglerE2ETestHelper();
23+
24+
const { Miniflare } = await helper.importMiniflare();
25+
26+
const {
27+
experimental_startRemoteProxySession: startRemoteProxySession,
28+
experimental_maybeStartOrUpdateRemoteProxySession:
29+
maybeStartOrUpdateRemoteProxySession,
30+
} = await helper.importWrangler();
31+
32+
beforeAll(async () => {
33+
await helper.seed(resolve(__dirname, "./workers"));
34+
await helper.run(
35+
`wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-01-01`
36+
);
37+
}, 35_000);
38+
39+
afterAll(async () => {
40+
await helper.run(`wrangler delete --name ${remoteWorkerName}`);
41+
});
42+
43+
function getMfOptions(
44+
remoteProxyConnectionString: RemoteProxyConnectionString
45+
): MiniflareOptions {
46+
return {
47+
modules: true,
48+
script: `
49+
export default {
50+
async fetch(req, env) {
51+
const myServiceMsg = !env.MY_SERVICE ? null : await (await env.MY_SERVICE.fetch(req)).text();
52+
return new Response("worker response: " + (myServiceMsg ?? ""));
53+
}
54+
}`,
55+
serviceBindings: {
56+
MY_SERVICE: {
57+
name: remoteWorkerName,
58+
remoteProxyConnectionString,
59+
},
60+
},
61+
};
62+
}
63+
64+
describe("startRemoteProxySession", () => {
65+
test("base usage", async () => {
66+
const remoteProxySession = await startRemoteProxySession({
67+
MY_SERVICE: {
68+
type: "service",
69+
service: remoteWorkerName,
70+
},
71+
});
72+
await remoteProxySession.ready;
73+
74+
const mf = new Miniflare(
75+
getMfOptions(remoteProxySession.remoteProxyConnectionString)
76+
);
77+
78+
const response = await timedDispatchFetch(mf);
79+
const responseText = await response?.text();
80+
81+
expect(responseText).toEqual(
82+
"worker response: Hello from a remote worker"
83+
);
84+
85+
await mf.dispose();
86+
await remoteProxySession.dispose();
87+
});
88+
89+
test("user provided (incorrect but then corrected) auth data", async () => {
90+
const remoteProxySession = await startRemoteProxySession(
91+
{
92+
MY_SERVICE: {
93+
type: "service",
94+
service: remoteWorkerName,
95+
},
96+
},
97+
{
98+
auth: {
99+
accountId: CLOUDFLARE_ACCOUNT_ID,
100+
apiToken: {
101+
apiToken: "This is an incorrect API TOKEN!",
102+
},
103+
},
104+
}
105+
);
106+
await remoteProxySession.ready;
107+
108+
const mf = new Miniflare(
109+
getMfOptions(remoteProxySession.remoteProxyConnectionString)
110+
);
111+
112+
const noResponse = await timedDispatchFetch(mf);
113+
// We are unable to fetch from the worker since the remote connection is not correctly established
114+
expect(noResponse).toBe(null);
115+
116+
assert(process.env.CLOUDFLARE_API_TOKEN);
117+
118+
const amendedRemoteProxySession = await startRemoteProxySession(
119+
{
120+
MY_SERVICE: {
121+
type: "service",
122+
service: remoteWorkerName,
123+
},
124+
},
125+
{
126+
auth: {
127+
accountId: CLOUDFLARE_ACCOUNT_ID,
128+
apiToken: {
129+
apiToken: process.env.CLOUDFLARE_API_TOKEN,
130+
},
131+
},
132+
}
133+
);
134+
135+
await amendedRemoteProxySession.ready;
136+
137+
await mf.setOptions(
138+
getMfOptions(amendedRemoteProxySession.remoteProxyConnectionString)
139+
);
140+
141+
const response = await timedDispatchFetch(mf);
142+
const responseText = await response?.text();
143+
144+
expect(responseText).toEqual(
145+
"worker response: Hello from a remote worker"
146+
);
147+
148+
await mf.dispose();
149+
await remoteProxySession.dispose();
150+
await amendedRemoteProxySession.dispose();
151+
});
152+
});
153+
154+
describe("maybeStartOrUpdateRemoteProxySession", () => {
155+
test("base usage", async () => {
156+
const proxySessionData = await maybeStartOrUpdateRemoteProxySession({
157+
bindings: {
158+
MY_SERVICE: {
159+
type: "service",
160+
service: remoteWorkerName,
161+
experimental_remote: true,
162+
},
163+
},
164+
});
165+
166+
assert(proxySessionData);
167+
168+
await proxySessionData.session.ready;
169+
170+
const mf = new Miniflare(
171+
getMfOptions(proxySessionData.session.remoteProxyConnectionString)
172+
);
173+
174+
const response = await timedDispatchFetch(mf);
175+
const responseText = await response?.text();
176+
177+
expect(responseText).toEqual(
178+
"worker response: Hello from a remote worker"
179+
);
180+
181+
await mf.dispose();
182+
await proxySessionData.session.dispose();
183+
});
184+
185+
test("user provided (incorrect but then corrected) auth data", async () => {
186+
let proxySessionData = await maybeStartOrUpdateRemoteProxySession(
187+
{
188+
bindings: {
189+
MY_SERVICE: {
190+
type: "service",
191+
service: remoteWorkerName,
192+
experimental_remote: true,
193+
},
194+
},
195+
},
196+
undefined,
197+
{
198+
accountId: CLOUDFLARE_ACCOUNT_ID,
199+
apiToken: {
200+
apiToken: "This is an incorrect API TOKEN!",
201+
},
202+
}
203+
);
204+
205+
assert(proxySessionData);
206+
207+
await proxySessionData.session.ready;
208+
209+
const mf = new Miniflare(
210+
getMfOptions(proxySessionData.session.remoteProxyConnectionString)
211+
);
212+
213+
const noResponse = await timedDispatchFetch(mf);
214+
// We are unable to fetch from the worker since the remote connection is not correctly established
215+
expect(noResponse).toBe(null);
216+
217+
assert(process.env.CLOUDFLARE_API_TOKEN);
218+
219+
proxySessionData = await maybeStartOrUpdateRemoteProxySession(
220+
{
221+
bindings: {
222+
MY_SERVICE: {
223+
type: "service",
224+
service: remoteWorkerName,
225+
experimental_remote: true,
226+
},
227+
},
228+
},
229+
proxySessionData,
230+
{
231+
accountId: CLOUDFLARE_ACCOUNT_ID,
232+
apiToken: {
233+
apiToken: process.env.CLOUDFLARE_API_TOKEN,
234+
},
235+
}
236+
);
237+
238+
assert(proxySessionData);
239+
240+
await mf.setOptions(
241+
getMfOptions(proxySessionData.session.remoteProxyConnectionString)
242+
);
243+
244+
const response = await timedDispatchFetch(mf);
245+
const responseText = await response?.text();
246+
247+
expect(responseText).toEqual(
248+
"worker response: Hello from a remote worker"
249+
);
250+
251+
await mf.dispose();
252+
await proxySessionData.session.dispose();
253+
});
254+
});
255+
}
256+
);
257+
258+
async function timedDispatchFetch(mf: Miniflare): Promise<Response | null> {
259+
try {
260+
return await mf.dispatchFetch("http://localhost/", {
261+
signal: AbortSignal.timeout(5000),
262+
});
263+
} catch {
264+
return null;
265+
}
266+
}

packages/wrangler/src/api/remoteBindings/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ type WorkerConfigObject = {
121121
/**
122122
* Utility for potentially starting or updating a remote proxy session.
123123
*
124-
* It uses an internal map for storing existing remote proxy session indexed by worker names. If no worker name is provided
125-
* the remote proxy session won't be retrieved nor saved to/from the internal map.
126-
*
127124
* @param wranglerOrWorkerConfigObject either a file path to a wrangler configuration file or an object containing the name of
128125
* the target worker alongside its bindings.
129126
* @param preExistingRemoteProxySessionData the optional data of a pre-existing remote proxy session if there was one, this

0 commit comments

Comments
 (0)