Skip to content

Commit dd78eb5

Browse files
authored
skip next c3 tests on forks and cleanup r2 buckets from e2e tests (#12699)
1 parent 7a20f87 commit dd78eb5

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

packages/create-cloudflare/e2e/tests/frameworks/test-config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { detectPackageManager } from "../../../src/helpers/packageManagers";
22
import {
3+
CLOUDFLARE_API_TOKEN,
34
frameworkToTestFilter,
45
isExperimental,
56
keys,
@@ -985,6 +986,9 @@ function getExperimentalFrameworkTestConfig(
985986
testCommitMessage: true,
986987
unsupportedOSs: ["win32"],
987988
unsupportedPms: ["npm", "yarn"],
989+
// this test creates an R2 bucket, so it requires a Cloudflare API token
990+
// and needs to be skipped on forks
991+
quarantine: !CLOUDFLARE_API_TOKEN,
988992
verifyDeploy: {
989993
route: "/",
990994
expectedText: "Generated by create next app",

tools/e2e/__tests__/common.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import {
44
deleteDatabase,
55
deleteKVNamespace,
66
deleteProject,
7+
deleteR2Bucket,
78
deleteWorker,
89
listTmpDatabases,
910
listTmpE2EProjects,
1011
listTmpE2EWorkers,
1112
listTmpKVNamespaces,
13+
listTmpR2Buckets,
1214
} from "../common";
1315

1416
const originalAccountID = process.env.CLOUDFLARE_ACCOUNT_ID;
@@ -346,3 +348,59 @@ describe("deleteWorker()", () => {
346348
await deleteWorker(MOCK_WORKER);
347349
});
348350
});
351+
352+
describe("listTmpR2Buckets()", () => {
353+
it("makes a REST request and returns a filtered list of R2 buckets", async () => {
354+
agent
355+
.get("https://api.cloudflare.com")
356+
.intercept({
357+
path: `/client/v4/accounts/${MOCK_CLOUDFLARE_ACCOUNT_ID}/r2/buckets`,
358+
method: "GET",
359+
})
360+
.reply(
361+
200,
362+
JSON.stringify({
363+
result: {
364+
buckets: [
365+
{ name: "my-bucket-1", creation_date: nowStr },
366+
{ name: "my-bucket-2", creation_date: oldTimeStr },
367+
{
368+
name: "tmp-e2e-abc123-next--workers-opennext-cache",
369+
creation_date: nowStr,
370+
},
371+
{
372+
name: "tmp-e2e-def456-next--workers-opennext-cache",
373+
creation_date: oldTimeStr,
374+
},
375+
{ name: "tmp-e2e-project-1", creation_date: nowStr },
376+
{ name: "tmp-e2e-project-2", creation_date: oldTimeStr },
377+
],
378+
},
379+
success: true,
380+
})
381+
);
382+
383+
const result = await listTmpR2Buckets();
384+
385+
expect(result.map((b) => b.name)).toMatchInlineSnapshot(`
386+
[
387+
"tmp-e2e-def456-next--workers-opennext-cache",
388+
"tmp-e2e-project-2",
389+
]
390+
`);
391+
});
392+
});
393+
394+
describe("deleteR2Bucket()", () => {
395+
it("makes a REST request to delete the given R2 bucket", async () => {
396+
const MOCK_BUCKET = "tmp-e2e-abc123-next--workers-opennext-cache";
397+
agent
398+
.get("https://api.cloudflare.com")
399+
.intercept({
400+
path: `/client/v4/accounts/${MOCK_CLOUDFLARE_ACCOUNT_ID}/r2/buckets/${MOCK_BUCKET}`,
401+
method: "DELETE",
402+
})
403+
.reply(200, JSON.stringify({ result: [] }));
404+
await deleteR2Bucket(MOCK_BUCKET);
405+
});
406+
});

tools/e2e/common.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export type Project = {
1616
created_on: string;
1717
};
1818

19+
export type R2Bucket = {
20+
name: string;
21+
creation_date: string;
22+
};
23+
1924
export type ContainerApplication = {
2025
created_at: string;
2126
id: string;
@@ -266,6 +271,30 @@ export const deleteKVNamespace = async (id: string) => {
266271
);
267272
};
268273

274+
export const listTmpR2Buckets = async () => {
275+
const response = await apiFetchResponse(`/r2/buckets`, { method: "GET" });
276+
if (!response || !response.ok) {
277+
return [];
278+
}
279+
const json = (await response.json()) as {
280+
result: { buckets: R2Bucket[] };
281+
};
282+
return json.result.buckets.filter(
283+
(bucket) =>
284+
bucket.name.startsWith("tmp-e2e-") &&
285+
// Buckets are more than an hour old
286+
Date.now() - new Date(bucket.creation_date).valueOf() > 1000 * 60 * 60
287+
);
288+
};
289+
290+
export const deleteR2Bucket = async (name: string) => {
291+
return await apiFetch(
292+
`/r2/buckets/${name}`,
293+
"DELETE",
294+
/* failSilently */ true
295+
);
296+
};
297+
269298
export const listTmpDatabases = async () => {
270299
return (await apiFetchList<Database>(`/d1/database`)).filter(
271300
(db) =>

tools/e2e/e2eCleanup.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
deleteHyperdriveConfig,
77
deleteKVNamespace,
88
deleteProject,
9+
deleteR2Bucket,
910
deleteWorker,
1011
listCertificates,
1112
listE2eContainerImages,
@@ -15,6 +16,7 @@ import {
1516
listTmpE2EProjects,
1617
listTmpE2EWorkers,
1718
listTmpKVNamespaces,
19+
listTmpR2Buckets,
1820
} from "./common";
1921

2022
if (!process.env.CLOUDFLARE_API_TOKEN) {
@@ -38,6 +40,8 @@ async function run() {
3840
// so delete these first to avoid interrupting running e2e jobs (unless you are very very unlucky)
3941
await deleteKVNamespaces();
4042

43+
await deleteR2Buckets();
44+
4145
await deleteProjects();
4246

4347
await deleteWorkers();
@@ -174,3 +178,20 @@ async function deleteContainerApplications() {
174178
console.log(`Deleted ${container.name} (${container.id})`);
175179
}
176180
}
181+
182+
async function deleteR2Buckets() {
183+
const bucketsToDelete = await listTmpR2Buckets();
184+
185+
for (const bucket of bucketsToDelete) {
186+
console.log("Deleting R2 bucket: " + bucket.name);
187+
if (await deleteR2Bucket(bucket.name)) {
188+
console.log(`Successfully deleted R2 bucket ${bucket.name}`);
189+
} else {
190+
console.log(`Failed to delete R2 bucket ${bucket.name}`);
191+
}
192+
}
193+
194+
if (bucketsToDelete.length === 0) {
195+
console.log(`No R2 buckets to delete.`);
196+
}
197+
}

0 commit comments

Comments
 (0)