Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orchestrator tests #932

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
25 changes: 24 additions & 1 deletion javascript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions javascript/packages/orchestrator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"copy:podman": "cp -r src/providers/podman/resources/configs dist/providers/podman/resources",
"lint": "npx prettier --check ./src",
"lint:write": "npx prettier --write ./src",
"test": "echo \"Error: no test specified\""
"test": "mocha --require ts-node/register src/**/*.spec.ts"
},
"keywords": [
"testing",
Expand Down Expand Up @@ -56,10 +56,12 @@
},
"devDependencies": {
"@types/chai": "^4.3.5",
"@types/chai-as-promised": "^7.1.5",
"@types/fs-extra": "^11.0.1",
"@types/jsdom": "^21.1.1",
"@types/minimatch": "^5.1.2",
"@types/mocha": "^10.0.1"
"@types/mocha": "^10.0.1",
"chai-as-promised": "^7.1.1"
},
"homepage": "https://github.com/paritytech/zombienet#readme"
}
9 changes: 7 additions & 2 deletions javascript/packages/orchestrator/src/bootnode.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { hexAddPrefix, hexToU8a } from "@polkadot/util";
import { isMultiAddr } from "@zombienet/utils";
import { keys as libp2pKeys } from "libp2p-crypto";
import PeerId from "peer-id";
import { NodeMultiAddress } from "./types";

export async function generateNodeMultiAddress(
key: string,
args: string[],
Expand All @@ -21,11 +21,16 @@ export async function generateNodeMultiAddress(

const listenIndex = args.findIndex((arg) => arg === "--listen-addr");
if (listenIndex >= 0) {
if (!isMultiAddr(args[listenIndex + 1])) {
throw new Error("Provided address is not well formatted.");
}
const listenAddrParts = args[listenIndex + 1].split("/");
listenAddrParts[2] = ip;
listenAddrParts[4] = port.toString();
if (certhash) listenAddrParts.push("certhash", certhash);
multiaddress = `${listenAddrParts.join("/")}/p2p/${peerId.toB58String()}`;
multiaddress = `${listenAddrParts.join("/")}${
useWs ? "/ws/" : "/"
}p2p/${peerId.toB58String()}`;
} else {
multiaddress = `/ip4/${ip}/tcp/${port}/${
useWs ? "ws/" : "/"
Expand Down
14 changes: 5 additions & 9 deletions javascript/packages/orchestrator/src/chainSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,9 @@ export async function addAuthority(
) {
try {
const chainSpec = readAndParseChainSpec(specPath);

const { sr_stash } = node.accounts;

const keys = getAuthorityKeys(chainSpec);
if (!keys) return;

keys.push(key);

new CreateLogTable({
Expand Down Expand Up @@ -596,15 +593,14 @@ function findAndReplaceConfig(obj1: any, obj2: any) {
});
}

export function getRuntimeConfig(chainSpec: any) {
const runtimeConfig =
export function getRuntimeConfig(chainSpec: ChainSpec) {
return (
chainSpec.genesis.runtime?.runtime_genesis_config ||
chainSpec.genesis.runtime;

return runtimeConfig;
chainSpec.genesis.runtime
);
}

export function readAndParseChainSpec(specPath: string) {
export function readAndParseChainSpec(specPath: string): ChainSpec {
const rawdata = fs.readFileSync(specPath);
let chainSpec;
try {
Expand Down
63 changes: 63 additions & 0 deletions javascript/packages/orchestrator/src/specs/bootnode.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import chai, { assert } from "chai";
import chaiAsPromised from "chai-as-promised";
import { describe } from "mocha";
import { generateNodeMultiAddress } from "../bootnode";
chai.use(chaiAsPromised);

describe("Test bootnode.ts:", () => {
it("generateNodeMultiAddress without --listen-addr - success", async () => {
const check = await generateNodeMultiAddress(
"2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90",
["-lparachain=debug"],
"127.0.0.1",
38135,
);

assert.equal(
check,
"/ip4/127.0.0.1/tcp/38135/ws/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm",
);
});

it("generateNodeMultiAddress with --listen-addr - success", async () => {
const check = await generateNodeMultiAddress(
"2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90",
["-lparachain=debug", "--listen-addr", "/ip4/10.0.0.2/tcp/30333"],
"10.0.0.2",
30333,
);

assert.equal(
check,
"/ip4/10.0.0.2/tcp/30333/ws/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm",
);
});

it("generateNodeMultiAddress with ws=false - success", async () => {
const check = await generateNodeMultiAddress(
"2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90",
["-lparachain=debug", "--listen-addr", "/ip4/10.0.0.2/tcp/30333"],
"10.0.0.2",
30333,
false,
);

assert.equal(
check,
"/ip4/10.0.0.2/tcp/30333/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm",
);
});

it("generateNodeMultiAddress with wrong address in --listen-addr - throw Error", async () => {
return assert.isRejected(
generateNodeMultiAddress(
"2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90",
["-lparachain=debug", "--listen-addr", "/ip4/10.0.0.2/30333"],
"10.0.0.2",
30333,
),
Error,
"Provided address is not well formatted",
);
});
});
105 changes: 105 additions & 0 deletions javascript/packages/orchestrator/src/specs/chainSpec.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import chai, { assert, expect } from "chai";
import chaiAsPromised from "chai-as-promised";
import { describe } from "mocha";
import { copyFile, unlink } from "node:fs/promises";
import path from "path";

import {
fakeGenesisKey,
fakeNode,
fakeSession,
kusamaPath,
stringifyBigInt,
} from "./testHelper";

import {
clearAuthorities,
getNodeKey,
getRuntimeConfig,
readAndParseChainSpec,
} from "../chainSpec";
chai.use(chaiAsPromised);

describe("Test chainspec:", () => {
const kusamaCopiedPath = path.resolve(
path.join(__dirname, "./kusama-clear.json"),
);
const ksmSpec = readAndParseChainSpec(kusamaPath);

beforeEach(async () => {
await copyFile(kusamaPath, kusamaCopiedPath);
});

afterEach(async () => {
await unlink(kusamaCopiedPath);
});

it("readAndParseChainSpec - success", () => {
expect(ksmSpec).not.to.throw;
});

it("getRuntimeConfig - success", () => {
const result = getRuntimeConfig(ksmSpec);
const runtime = ksmSpec.genesis.runtime;
const a = stringifyBigInt(result);
const b = stringifyBigInt(runtime);

assert.equal(a, b);
});

it("specHaveSessionsKeys - success", () => {
const { session } = ksmSpec.genesis.runtime;
const a = stringifyBigInt(session);
const b = stringifyBigInt(fakeSession);
assert.equal(a, b);
});

it("clearAuthorities - success", async () => {
await clearAuthorities(kusamaCopiedPath);
const cleared = readAndParseChainSpec(kusamaCopiedPath);
assert.equal(cleared.genesis.runtime.session.keys.length, 0);
assert.equal(cleared.genesis.runtime.grandpa.authorities.length, 0);
assert.equal(cleared.genesis.runtime.session.keys.length, 0);

assert.notEqual(
ksmSpec.genesis.runtime.staking.stakers.length,
cleared.genesis.runtime.staking.stakers.length,
);
assert.notEqual(
ksmSpec.genesis.runtime.staking.invulnerables.length,
cleared.genesis.runtime.staking.invulnerables.length,
);
assert.notEqual(
ksmSpec.genesis.runtime.staking.validatorCount,
cleared.genesis.runtime.staking.validatorCount,
);
assert.equal(cleared.genesis.runtime.staking.stakers.length, 0);
assert.equal(cleared.genesis.runtime.staking.invulnerables.length, 0);
assert.equal(cleared.genesis.runtime.staking.validatorCount, 0);
});

it("getNodeKey - success", async () => {
const key = getNodeKey(JSON.parse(fakeNode));
assert.equal(key[0], fakeGenesisKey[0]);
assert.equal(key[1], fakeGenesisKey[1]);
assert.equal(key[2].grandpa, fakeGenesisKey[2].grandpa);
assert.equal(key[2].babe, fakeGenesisKey[2].babe);
assert.equal(key[2].im_online, fakeGenesisKey[2].im_online);
assert.equal(
key[2].parachain_validator,
fakeGenesisKey[2].parachain_validator,
);
assert.equal(
key[2].authority_discovery,
fakeGenesisKey[2].authority_discovery,
);
assert.equal(key[2].para_validator, fakeGenesisKey[2].para_validator);
assert.equal(key[2].para_assignment, fakeGenesisKey[2].para_assignment);
assert.equal(key[2].beefy, fakeGenesisKey[2].beefy);
assert.equal(key[2].aura, fakeGenesisKey[2].aura);
});

// it("addAuthority", () => {});
// it("...", () => {});
// it("...", () => {});
});
246 changes: 246 additions & 0 deletions javascript/packages/orchestrator/src/specs/kusama-local.json

Large diffs are not rendered by default.

224 changes: 224 additions & 0 deletions javascript/packages/orchestrator/src/specs/rococo-local.json

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions javascript/packages/orchestrator/src/specs/testHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import path from "path";
import { GenesisNodeKey } from "../chainSpec";

export function stringifyBigInt(obj: any) {
return JSON.stringify(obj, (_, v) =>
typeof v === "bigint" ? v.toString() : v,
);
}

export const kusamaPath = path.resolve(
path.join(__dirname, "./kusama-local.json"),
);
export const wrongKusamaPath = path.resolve(
path.join(__dirname, "./kusama.json"),
);
export const rococoPath = path.resolve(
path.join(__dirname, "./rococo-local.json"),
);

export const fakeNode = `{"name":"bob","key":"81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9","accounts":{"seed":"//Bob","mnemonic":"edit vote inhale clerk involve captain guard clever gain possible unit olympic","sr_account":{"address":"5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty","publicKey":"0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"},"sr_stash":{"address":"5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc","publicKey":"0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e"},"ed_account":{"address":"5GoNkf6WdbxCFnPdAnYYQyCjAKPJgLNxXwPjwTh6DGg6gN3E","publicKey":"0xd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69"},"ec_account":{"publicKey":"0x0390084fdbf27d2b79d26a4f13f0ccd982cb755a661969143c37cbc49ef5b91f27"}},"command":"polkadot","image":"docker.io/parity/polkadot:latest","chain":"rococo-local","validator":true,"args":["-lparachain=debug"],"env":[{"name":"COLORBT_SHOW_HIDDEN","value":"1"},{"name":"RUST_BACKTRACE","value":"FULL"}],"bootnodes":[],"telemetryUrl":"","telemetry":false,"prometheus":true,"overrides":[],"addToBootnodes":false,"zombieRole":"node","imagePullPolicy":"Always","p2pPort":43415,"wsPort":45163,"rpcPort":46529,"prometheusPort":35805,"externalPorts":{"p2pPort":43415,"wsPort":45163,"rpcPort":46529,"prometheusPort":35805},"group":"bob"}`;

export const fakeGenesisKey: GenesisNodeKey = [
"5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc",
"5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc",
{
grandpa: "5GoNkf6WdbxCFnPdAnYYQyCjAKPJgLNxXwPjwTh6DGg6gN3E",
babe: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
im_online: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
parachain_validator: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
authority_discovery: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
para_validator: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
para_assignment: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
beefy: "KWByAN7WfZABWS5AoWqxriRmF5f2jnDqy3rB5pfHLGkY93ibN",
aura: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
},
];
export const fakeSession = {
keys: [
[
"5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY",
"5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY",
{
grandpa: "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu",
babe: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
im_online: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
para_validator: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
para_assignment: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
authority_discovery: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
},
],
[
"5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc",
"5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc",
{
grandpa: "5GoNkf6WdbxCFnPdAnYYQyCjAKPJgLNxXwPjwTh6DGg6gN3E",
babe: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
im_online: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
para_validator: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
para_assignment: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
authority_discovery: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
},
],
],
};
13 changes: 13 additions & 0 deletions javascript/packages/utils/src/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,16 @@ export async function downloadFile(url: string, dest: string): Promise<void> {
);
}
}

export function isMultiAddr(addr: string) {
const ws =
/\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/[0-9]{0,5}\/(ws|wss|tls\/ws)\/p2p\/[a-zA-Z1-9^Il0O]+/i;

const webrtc =
/\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)\/p2p\/[a-zA-Z1-9^Il0O]+/i;

const multi = /\/(ip4|ip6)\/(.*?)\/tcp\/[0-9]{0,5}/i;

if (!multi.test(addr) && !ws.test(addr) && !webrtc.test(addr)) return false;
return true;
}
Loading