Skip to content

Commit 28883c0

Browse files
committed
Run integration tests as distro matrix in CI
1 parent 466766a commit 28883c0

3 files changed

Lines changed: 45 additions & 15 deletions

File tree

.github/workflows/ci.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,22 @@ jobs:
3333
integration-tests:
3434
runs-on: ubuntu-latest
3535
needs: build-and-test
36-
timeout-minutes: 40
36+
timeout-minutes: 50
37+
strategy:
38+
fail-fast: false
39+
matrix:
40+
include:
41+
- distro: alpine
42+
image: alpine:3.20
43+
- distro: debian
44+
image: debian:bookworm-slim
45+
- distro: ubuntu
46+
image: ubuntu:24.04
47+
- distro: fedora
48+
image: fedora:41
49+
- distro: archlinux
50+
image: archlinux:latest
51+
name: integration-tests (${{ matrix.distro }})
3752

3853
steps:
3954
- name: Checkout
@@ -55,7 +70,10 @@ jobs:
5570
- name: Run integration tests
5671
env:
5772
INTEGRATION_PLATFORM: linux/amd64
58-
INTEGRATION_IMAGE: busybox:latest
73+
INTEGRATION_IMAGE: ${{ matrix.image }}
74+
INTEGRATION_ROOTFS_CHECK_PATH: /bin/sh
75+
INTEGRATION_VM_CHECK_COMMAND: echo integration-vm-ok
76+
INTEGRATION_VM_CHECK_EXPECT: integration-vm-ok
5977
run: bun run test:integration
6078

6179
e2e-smoke:

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ bun run build
8080
bun run test:integration
8181
```
8282

83+
The CI integration matrix currently validates:
84+
85+
- `alpine:3.20`
86+
- `debian:bookworm-slim`
87+
- `ubuntu:24.04`
88+
- `fedora:41`
89+
- `archlinux:latest`
90+
8391
### Choosing the build platform (`--platform`)
8492

8593
`--platform` selects which OCI image variant to convert, and should match the architecture you plan to run in Gondolin.

test/integration/oci2gondolin.integration.test.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,21 @@ type CommandOptions = {
2222
const REPO_ROOT = process.cwd();
2323
const IMAGE = process.env.INTEGRATION_IMAGE ?? "busybox:latest";
2424
const PLATFORM = resolveIntegrationPlatform(process.env.INTEGRATION_PLATFORM ?? process.arch);
25+
const ROOTFS_CHECK_PATH = process.env.INTEGRATION_ROOTFS_CHECK_PATH ?? "/bin/sh";
26+
const VM_CHECK_COMMAND = process.env.INTEGRATION_VM_CHECK_COMMAND ?? "echo integration-vm-ok";
27+
const VM_CHECK_EXPECT = process.env.INTEGRATION_VM_CHECK_EXPECT ?? "integration-vm-ok";
2528

26-
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "docker2vm-integration-"));
27-
const rootfsOutDir = path.join(tempRoot, "busybox-rootfs");
28-
const assetsOutDir = path.join(tempRoot, "busybox-assets");
29+
const imageSlug = IMAGE.replace(/[^a-z0-9._-]+/gi, "-").toLowerCase();
30+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), `docker2vm-integration-${imageSlug}-`));
31+
const rootfsOutDir = path.join(tempRoot, `${imageSlug}-rootfs`);
32+
const assetsOutDir = path.join(tempRoot, `${imageSlug}-assets`);
2933

3034
afterAll(() => {
3135
fs.rmSync(tempRoot, { recursive: true, force: true });
3236
});
3337

3438
describe("oci2gondolin integration", () => {
35-
it("materializes a busybox rootfs image", async () => {
39+
it(`materializes a rootfs image for ${IMAGE}`, async () => {
3640
const debugfsBinary = requireBinary("debugfs", [
3741
"/opt/homebrew/opt/e2fsprogs/sbin/debugfs",
3842
"/usr/local/opt/e2fsprogs/sbin/debugfs",
@@ -52,7 +56,7 @@ describe("oci2gondolin integration", () => {
5256
"--out",
5357
rootfsOutDir,
5458
],
55-
{ cwd: REPO_ROOT, timeoutMs: 180_000 },
59+
{ cwd: REPO_ROOT, timeoutMs: 300_000 },
5660
);
5761

5862
assertSuccess(result, "oci2gondolin rootfs conversion");
@@ -76,16 +80,16 @@ describe("oci2gondolin integration", () => {
7680

7781
const debugfsResult = await runCommand(
7882
debugfsBinary,
79-
["-R", "stat /bin/busybox", rootfsPath],
83+
["-R", `stat ${ROOTFS_CHECK_PATH}`, rootfsPath],
8084
{ timeoutMs: 30_000 },
8185
);
8286

83-
assertSuccess(debugfsResult, "debugfs stat /bin/busybox");
87+
assertSuccess(debugfsResult, `debugfs stat ${ROOTFS_CHECK_PATH}`);
8488
const debugText = `${debugfsResult.stdout}\n${debugfsResult.stderr}`.toLowerCase();
8589
expect(debugText).not.toContain("file not found by ext2_lookup");
86-
}, 240_000);
90+
}, 420_000);
8791

88-
it("materializes busybox assets and executes inside a VM", async () => {
92+
it(`materializes assets for ${IMAGE} and executes inside a VM`, async () => {
8993
requireBinary(process.arch === "arm64" ? "qemu-system-aarch64" : "qemu-system-x86_64");
9094

9195
const result = await runCommand(
@@ -102,7 +106,7 @@ describe("oci2gondolin integration", () => {
102106
"--out",
103107
assetsOutDir,
104108
],
105-
{ cwd: REPO_ROOT, timeoutMs: 180_000 },
109+
{ cwd: REPO_ROOT, timeoutMs: 300_000 },
106110
);
107111

108112
assertSuccess(result, "oci2gondolin assets conversion");
@@ -141,9 +145,9 @@ describe("oci2gondolin integration", () => {
141145
process.env.GONDOLIN_GUEST_DIR = assetsOutDir;
142146
vm = await VM.create({ sandbox: vmSandbox });
143147

144-
const execResult = await vm.exec(["/bin/busybox", "echo", "integration-vm-ok"]);
148+
const execResult = await vm.exec(["/bin/sh", "-lc", VM_CHECK_COMMAND]);
145149
expect(execResult.exitCode).toBe(0);
146-
expect(execResult.stdout).toContain("integration-vm-ok");
150+
expect(execResult.stdout).toContain(VM_CHECK_EXPECT);
147151
} finally {
148152
await vm?.close().catch(() => {
149153
// ignore close errors in test teardown
@@ -155,7 +159,7 @@ describe("oci2gondolin integration", () => {
155159
process.env.GONDOLIN_GUEST_DIR = originalGuestDir;
156160
}
157161
}
158-
}, 300_000);
162+
}, 420_000);
159163
});
160164

161165
function resolveIntegrationPlatform(raw: string): "linux/amd64" | "linux/arm64" {

0 commit comments

Comments
 (0)