From f1e7419f480b9439d37284734fab6a8defd2c11e Mon Sep 17 00:00:00 2001 From: travisladuke Date: Thu, 11 Apr 2024 10:16:06 -0700 Subject: [PATCH] test: improve tests by using testcontainers Before, we assume that the host/dev env had a zerotier-one service running. Now we can start a container and use the zerotier-one in there, and then throw it away. --- test/integration.test.ts | 98 ++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index 4670281..48c965d 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -1,7 +1,8 @@ import { readFileSync } from "node:fs"; -import { describe, it } from "node:test"; +import { describe, it, before } from "node:test"; import assert from "node:assert"; +import { GenericContainer } from "testcontainers"; import createClient from "openapi-fetch"; import { PathsWithMethod } from "openapi-typescript-helpers"; import type { paths } from "/tmp/schema.ts"; // generated by openapi-typescript @@ -13,18 +14,16 @@ import { AnyValidateFunction } from "ajv/dist/core.js"; const Ajv = _Ajv.default; const addFormats = _addFormats.default; -if (!process.env.AUTH_TOKEN) { - console.error("No AUTH_TOKEN env var set. Exiting."); - process.exit(1); -} +const ZT_VERSION = process.env.ZT_VERSION || "1.12.2" -const isNextApiVersion = process.env.ENABLE_UNSTABLE; +function compareVersions(a: string, b: string) { + return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) +} -function createCreateClient() { - // AUTH_TOKEN=`cat ~/Library/Application\ Support/ZeroTier/One/authtoken.secret ` npm t - const authToken = process.env.AUTH_TOKEN; +function createCreateClient(token: string, port: number) { + const authToken = token; const client = createClient({ - baseUrl: "http://localhost:9993/", + baseUrl: `http://localhost:${port}/`, headers: { "X-ZT1-AUTH": authToken }, }); @@ -59,32 +58,51 @@ function assertValid( } } -describe("GET endpoints", async function () { - const map: { path: PathsWithMethod; id: string }[] = [ - { path: "/status", id: "NodeStatus" }, - { path: "/controller", id: "ControllerStatus" }, - { path: "/network", id: "JoinedNetworks" }, - { path: "/peer", id: "Peers" }, - ]; +const ZEROTIER_API_SECRET = "asdf"; - for (const { path, id } of map) { - it(id, async () => { - const validator = createValidator(id); +describe("API exercise", async function() { + let network_id: string; + const node_id = "1122334455"; + let container; + let client: ReturnType; + let apiPort: number; + + before(async () => { + container = await new GenericContainer(`zerotier/zerotier:${ZT_VERSION}`) + .withExposedPorts(9993) + .withPrivilegedMode() + .withAddedCapabilities("NET_ADMIN") + .withEnvironment({ ZEROTIER_API_SECRET }) + .withCopyContentToContainer([ + { + content: `{ "settings": { "allowManagementFrom": ["0.0.0.0/0"] } }`, + target: "/var/lib/zerotier-one/local.conf", + }, + ]) + .start(); + apiPort = container.getMappedPort(9993); + client = createCreateClient(ZEROTIER_API_SECRET, apiPort); + }); - const client = createCreateClient(); + describe("GET endpoints", async function() { + const map: { path: PathsWithMethod; id: string }[] = [ + { path: "/status", id: "NodeStatus" }, + { path: "/controller", id: "ControllerStatus" }, + { path: "/network", id: "JoinedNetworks" }, + { path: "/peer", id: "Peers" }, + ]; - const { data } = await client.GET(path, {}); - assert.ok(data); + for (const { path, id } of map) { + it(id, async () => { + const validator = createValidator(id); - assertValid(validator, data); - }); - } -}); + const { data } = await client.GET(path, {}); + assert.ok(data); -describe("API exercise", async function () { - const client = createCreateClient(); - let network_id: string; - const node_id = "1122334455"; + assertValid(validator, data); + }); + } + }); it("Creates a valid controller network", async () => { const { data: networkData } = await client.POST("/controller/network", { @@ -212,7 +230,7 @@ describe("API exercise", async function () { }); }); - describe("Unstable APIs", { skip: !isNextApiVersion }, async () => { + describe("Unstable APIs", { skip: compareVersions(ZT_VERSION, "1.12.2") !== 1 }, async () => { it("Sets the member name", async () => { const { data } = await client.POST( "/controller/network/{network_id}/member/{node_id}", @@ -265,12 +283,12 @@ describe("API exercise", async function () { }); }); - // it("Deletes the network by ID", async () => { - // const { data } = await client.DELETE( - // "/controller/network/{network_id}", - // { params: { path: { network_id } } }, - // ); - // const networkDelValidator = createValidator("ControllerNetwork"); - // assertValid(networkDelValidator, data); - // }); + it("Deletes the network by ID", async () => { + const { data } = await client.DELETE( + "/controller/network/{network_id}", + { params: { path: { network_id } } }, + ); + const networkDelValidator = createValidator("ControllerNetwork"); + assertValid(networkDelValidator, data); + }); });