Skip to content

Commit 6923cf6

Browse files
authored
add sandbox testing & implement volume mounting for create (#42)
1 parent fd8bab5 commit 6923cf6

7 files changed

Lines changed: 283 additions & 31 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ jobs:
2929
- name: check
3030
run: deno check
3131

32+
- name: run tests
33+
env:
34+
DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }}
35+
DENO_DEPLOY_CLI_SPECIFIER: file://${{ github.workspace }}/main.ts
36+
run: deno test --allow-all
37+
3238
jsr:
3339
runs-on: ubuntu-latest
3440
permissions:

deno.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@cfa/gitignore-parser": "jsr:@cfa/gitignore-parser@^0.1.4",
1919
"@cliffy/command": "jsr:@cliffy/command@^1.0.0-rc.8",
2020
"@deno/sandbox": "jsr:@deno/sandbox@^0.5.0",
21+
"@std/assert": "jsr:@std/assert@^1.0.16",
2122
"@std/async": "jsr:@std/async@^1.0.15",
2223
"@std/cli": "jsr:@std/cli@1.0.22",
2324
"@std/dotenv": "jsr:@std/dotenv@^0.225.5",
@@ -37,7 +38,8 @@
3738
"superjson": "npm:superjson@^2.2.2",
3839
"@deno/framework-detect": "jsr:@deno/framework-detect@^0",
3940
"temporal-polyfill": "npm:temporal-polyfill@^0.3.0",
40-
"prompts": "npm:prompts@2.4.2"
41+
"prompts": "npm:prompts@2.4.2",
42+
"dax": "jsr:@david/dax@^0.44.2"
4143
},
4244
"exclude": [
4345
"astro-demo"

deno.lock

Lines changed: 68 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sandbox.test.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { $ } from "dax";
2+
import { assert, assertEquals } from "@std/assert";
3+
4+
if (!Deno.env.get("DENO_DEPLOY_TOKEN")) {
5+
console.error("DENO_DEPLOY_TOKEN environment variable is required.");
6+
Deno.exit(1);
7+
}
8+
9+
const sandbox = async (...args: string[]) => {
10+
console.log(`deno sandbox ${args.join(" ")}`);
11+
return (await $.raw`deno sandbox ${args.join(" ")}`.text()).trim();
12+
};
13+
14+
Deno.test("sandbox create", async () => {
15+
const sandboxId = await sandbox(
16+
"create",
17+
"--quiet",
18+
"--lifetime",
19+
"60s",
20+
"echo",
21+
"test",
22+
);
23+
await sandbox("kill", sandboxId);
24+
});
25+
26+
Deno.test("sandbox exec", async () => {
27+
const sandboxId = await sandbox("create", "--quiet", "--lifetime", "60s");
28+
29+
const res = await sandbox("exec", sandboxId, "echo", "'exec test'");
30+
assertEquals(res, "exec test");
31+
32+
await sandbox("kill", sandboxId);
33+
});
34+
35+
Deno.test("sandbox copy", async () => {
36+
const sandboxId = await sandbox("create", "--quiet", "--lifetime", "60s");
37+
38+
await Deno.writeTextFile("test.txt", "test content");
39+
40+
await sandbox("copy", "test.txt", `${sandboxId}:/tmp/test.txt`);
41+
42+
await sandbox("copy", `${sandboxId}:/tmp/test.txt`, "./downloaded.txt");
43+
const downloadedContent = await Deno.readTextFile("./downloaded.txt");
44+
assertEquals(downloadedContent, "test content");
45+
46+
await Deno.remove("test.txt");
47+
await Deno.remove("downloaded.txt");
48+
49+
await sandbox("kill", sandboxId);
50+
});
51+
52+
Deno.test("sandbox extend", async () => {
53+
const sandboxId = await sandbox(
54+
"create",
55+
"--quiet",
56+
"--lifetime",
57+
"60s",
58+
"sleep",
59+
"10",
60+
);
61+
62+
await sandbox("extend", sandboxId, "120s");
63+
64+
await sandbox("kill", sandboxId);
65+
});
66+
67+
Deno.test("sandbox exec with complex commands", async () => {
68+
const sandboxId = await sandbox("create", "--quiet", "--lifetime", "60s");
69+
70+
const result = await sandbox("exec", sandboxId, "'echo hello && echo world'");
71+
assert(result.includes("hello"));
72+
assert(result.includes("world"));
73+
74+
await sandbox("kill", sandboxId);
75+
});
76+
77+
Deno.test("sandbox copy directory structure", async () => {
78+
const sandboxId = await sandbox("create", "--quiet", "--lifetime", "60s");
79+
80+
await Deno.mkdir("testdir", { recursive: true });
81+
await Deno.writeTextFile("testdir/file1.txt", "content1");
82+
await Deno.writeTextFile("testdir/file2.txt", "content2");
83+
84+
await sandbox("exec", sandboxId, "'mkdir -p /tmp/testdir'");
85+
await sandbox(
86+
"copy",
87+
"testdir/file1.txt",
88+
`${sandboxId}:/tmp/testdir/file1.txt`,
89+
);
90+
await sandbox(
91+
"copy",
92+
"testdir/file2.txt",
93+
`${sandboxId}:/tmp/testdir/file2.txt`,
94+
);
95+
96+
const result = await sandbox("exec", sandboxId, "ls", "/tmp/testdir");
97+
assert(result.includes("file1.txt"));
98+
assert(result.includes("file2.txt"));
99+
100+
await Deno.remove("testdir", { recursive: true });
101+
await sandbox("kill", sandboxId);
102+
});
103+
104+
Deno.test("volumes create", async () => {
105+
const volumeName = `test-vol-${crypto.randomUUID()}`.slice(0, 32);
106+
107+
const volumeId = await sandbox(
108+
"volumes",
109+
"create",
110+
volumeName,
111+
"--capacity",
112+
"1gb",
113+
"--region",
114+
"ord",
115+
);
116+
117+
await sandbox("volumes", "delete", volumeId);
118+
});
119+
120+
Deno.test("sandbox with volume mount", async () => {
121+
const volumeName = `test-vol-${crypto.randomUUID()}`.slice(0, 32);
122+
123+
const volumeId = await sandbox(
124+
"volumes",
125+
"create",
126+
volumeName,
127+
"--capacity",
128+
"1gb",
129+
"--region",
130+
"ord",
131+
);
132+
133+
const sandboxId = await sandbox(
134+
"create",
135+
"--quiet",
136+
"--lifetime",
137+
"60s",
138+
"--volume",
139+
`${volumeId}:/data/dataset`,
140+
);
141+
142+
await sandbox(
143+
"exec",
144+
sandboxId,
145+
"\"echo 'volume test' > /data/dataset/test.txt\"",
146+
);
147+
const result = await sandbox(
148+
"exec",
149+
sandboxId,
150+
"cat",
151+
"/data/dataset/test.txt",
152+
);
153+
assertEquals(result, "volume test");
154+
155+
await sandbox("kill", sandboxId);
156+
await sandbox("volumes", "delete", volumeId);
157+
});

0 commit comments

Comments
 (0)