Files
zerotier-one-api-spec/test/integration.test.ts
T
travisladuke c1863fd950 chore: improve test harness
`borp` lets node --test use typescript
with actual source-mapped stacktraces
and stuff
2024-02-29 09:08:47 -08:00

277 lines
7.5 KiB
TypeScript

import { readFileSync } from "node:fs";
import { describe, it } from "node:test";
import assert from "node:assert";
import createClient from "openapi-fetch";
import { PathsWithMethod } from "openapi-typescript-helpers";
import type { paths } from "/tmp/schema.ts"; // generated by openapi-typescript
import _Ajv from "ajv/dist/2020.js";
import _addFormats from "ajv-formats";
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 isNextApiVersion = process.env.ENABLE_UNSTABLE;
function createCreateClient() {
// AUTH_TOKEN=`cat ~/Library/Application\ Support/ZeroTier/One/authtoken.secret ` npm t
const authToken = process.env.AUTH_TOKEN;
const client = createClient<paths>({
baseUrl: "http://localhost:9993/",
headers: { "X-ZT1-AUTH": authToken },
});
return client;
}
function createValidator(schemaId: string) {
const specJson = readFileSync(
"./tsp-output/@typespec/json-schema/json-schema.json",
{ encoding: "utf8" },
);
const schema = JSON.parse(specJson);
const ajv = new Ajv({ allErrors: false });
addFormats(ajv);
ajv.addSchema(schema);
const validate = ajv.getSchema(schemaId);
assert(validate);
return { validate, schema };
}
function assertValid(
{ validate }: { validate: AnyValidateFunction },
data: object | undefined,
) {
const valid = validate(data);
if (!valid) {
console.error(JSON.stringify(data, null, 4));
assert.fail(JSON.stringify(validate.errors, null, 4));
}
}
describe("GET endpoints", async function () {
const map: { path: PathsWithMethod<paths, "get">; id: string }[] = [
{ path: "/status", id: "NodeStatus" },
{ path: "/controller", id: "ControllerStatus" },
{ path: "/network", id: "JoinedNetworks" },
{ path: "/peer", id: "Peers" },
];
for (const { path, id } of map) {
it(id, async () => {
const validator = createValidator(id);
const client = createCreateClient();
const { data } = await client.GET(path, {});
assert.ok(data);
assertValid(validator, data);
});
}
});
describe("API exercise", async function () {
const client = createCreateClient();
let network_id: string;
const node_id = "1122334455";
it("Creates a valid controller network", async () => {
const { data: networkData } = await client.POST("/controller/network", {
body: {},
});
assert(networkData);
const cnValidator = createValidator("ControllerNetwork");
assertValid(cnValidator, networkData);
network_id = networkData.id;
});
it("Gets the controller network by ID", async () => {
const { data } = await client.GET("/controller/network/{network_id}", {
params: { path: { network_id } },
});
assert(data);
const networkValidator = createValidator("ControllerNetwork");
assertValid(networkValidator, data);
});
it("Lists controller networks ", async () => {
const { data } = await client.GET("/controller/network");
assert(data);
const networkValidator = createValidator("ControllerNetworkIDList");
assertValid(networkValidator, data);
assert.ok(data.includes(network_id));
});
it("Creates a controller network member", async () => {
const { data } = await client.POST(
"/controller/network/{network_id}/member/{node_id}",
{
params: { path: { network_id, node_id } },
body: { authorized: true },
},
);
assert(data);
const validator = createValidator("ControllerNetworkMember");
assertValid(validator, data);
assert.equal(data.id, "1122334455");
});
it("Lists controller network members", async () => {
const { data } = await client.GET(
"/controller/network/{network_id}/member",
{ params: { path: { network_id } } },
);
assert(data);
const validator = createValidator("ControllerNetworkMemberList");
assertValid(validator, data);
assert.ok(Object.keys(data).includes("1122334455"));
});
it("Deletes a controller network member", async () => {
const { data } = await client.DELETE(
"/controller/network/{network_id}/member/{node_id}",
{
params: { path: { network_id, node_id } },
},
);
assert(data);
const validator = createValidator("ControllerNetworkMember");
assertValid(validator, data);
});
describe("Joining networks", async () => {
const network_id = "ff00160016000000";
it("Joins a network", async () => {
const { data } = await client.POST("/network/{network_id}", {
body: {},
params: { path: { network_id } },
});
assert(data);
const validator = createValidator("JoinedNetwork");
assertValid(validator, data);
});
it("Gets the joined networks", async () => {
const { data } = await client.GET("/network");
assert(data);
const validator = createValidator("JoinedNetworks");
assertValid(validator, data);
const ids = data.map((network) => network.id);
assert.ok(ids.includes(network_id));
});
it("Gets the joined network by ID", async () => {
const { data } = await client.GET("/network/{network_id}", {
params: { path: { network_id } },
});
assert(data);
const validator = createValidator("JoinedNetwork");
assertValid(validator, data);
assert.equal(network_id, data.id);
});
it("Leaves the joined network by ID", async () => {
const { data } = await client.DELETE("/network/{network_id}", {
params: { path: { network_id } },
});
assert(data);
const validator = createValidator("LeaveResult");
assertValid(validator, data);
});
});
describe("Unstable APIs", { skip: !isNextApiVersion }, async () => {
it("Sets the member name", async () => {
const { data } = await client.POST(
"/controller/network/{network_id}/member/{node_id}",
{
params: { path: { network_id, node_id } },
body: { authorized: true, name: "bob" },
},
);
assert(data);
const validator = createValidator("ControllerNetworkMember");
assertValid(validator, data);
});
it("Lists full networks", async () => {
const { data } = await client.GET("/unstable/controller/network");
assert(data);
const networksValidator = createValidator("ControllerNetworks");
assertValid(networksValidator, data);
});
it("Lists full network members", async () => {
const { data } = await client.GET(
"/unstable/controller/network/{network_id}/member",
{ params: { path: { network_id } } },
);
assert(data);
const networksValidator = createValidator(
"ControllerNetworkMemberListFull",
);
assertValid(networksValidator, data);
});
it("Gets the member name", async () => {
const { data } = await client.GET(
"/controller/network/{network_id}/member/{node_id}",
{
params: { path: { network_id, node_id } },
},
);
assert(data);
assert.equal("bob", data.name);
const validator = createValidator("ControllerNetworkMember");
assertValid(validator, 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);
// });
});