Skip to content

Commit

Permalink
wip: nearly full test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
joewagner committed Jun 7, 2023
1 parent 1b28233 commit b8e18c9
Show file tree
Hide file tree
Showing 16 changed files with 481 additions and 127 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"format": "npm run prettier:fix && npm run lint:fix",
"prepublishOnly": "npm run build",
"test": "mocha",
"coverage": "c8 mocha",
"coverage": "TEST_TIMEOUT_FACTOR=3 c8 --100 --exclude test mocha --exit",
"clean": "rm -rf dist",
"build": "npx tsc && chmod +x dist/cli.js",
"tableland": "node --experimental-specifier-resolution=node ./dist/cli.js"
Expand Down
1 change: 1 addition & 0 deletions src/commands/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const handler = async (argv: Arguments<Options>): Promise<void> => {
chain: parseInt(chainId) as any,
});

/* c8 ignore next 3 */
if (argv.enableEnsExperiment && ens) {
name = await ens.resolveTable(name);
}
Expand Down
60 changes: 35 additions & 25 deletions src/commands/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,46 @@ async function getHandler(argv: yargs.ArgumentsCamelCase<Options>) {
}

async function setHandler(argv: yargs.ArgumentsCamelCase<Options>) {
const { domain, mappings } = argv;
const { ens } = await setupCommand(argv);
if (!ens) return;
try {
const { domain, mappings } = argv;
const { ens } = await setupCommand(argv);
if (!ens) {
logger.log(
"To use ENS, ensure you have set the enableEnsExperiment flag to true"
);
return;
}

const records = mappings.map((entry: any) => {
const [key, value] = entry.split("=");
const records = mappings.map((entry: any) => {
const [key, value] = entry.split("=");

const keyRegex = /^[a-zA-Z0-9_]*$/;
const valueRegex = /^[a-zA-Z_][a-zA-Z0-9_]*_[0-9]+_[0-9]+$/;
const keyRegex = /^[a-zA-Z0-9_]*$/;
const valueRegex = /^[a-zA-Z_][a-zA-Z0-9_]*_[0-9]+_[0-9]+$/;

if (keyRegex.exec(key) === null) {
throw new Error("Only letters or underscores in key name");
}
if (valueRegex.exec(value) === null) {
throw new Error("Tablename is invalid");
}
return {
key,
value,
};
});
if (keyRegex.exec(key) === null) {
throw new Error("Only letters or underscores in key name");
}
if (valueRegex.exec(value) === null) {
throw new Error("Tablename is invalid");
}
return {
key,
value,
};
});

if (await ens.addTableRecords(domain, records)) {
const response = {
domain,
records,
mappings,
};
if (await ens.addTableRecords(domain, records)) {
const response = {
domain,
records,
mappings,
};

logger.log(JSON.stringify(response));
logger.log(JSON.stringify(response));
}
/* c8 ignore next 3 */
} catch (err: any) {
logger.error(err?.cause?.message || err?.message);
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/commands/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ export const handler = async (argv: Arguments<Options>): Promise<void> => {
format: "objects",
unwrap: argv.unwrap,
});
} catch (e: any) {
if (e.message.includes("in JSON at position")) {
logger.log("Can't unwrap multiple rows. Use --unwrap=false");
} catch (err: any) {
if (err.message.includes("in JSON at position")) {
logger.error("Can't unwrap multiple rows. Use --unwrap=false");
/* c8 ignore next 3 */
} else {
throw e;
throw err;
}
}
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/commands/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export const desc =
export const aliases = ["s", "sh"];

process.on("SIGINT", function () {
/* c8 ignore next 2 */
logger.log("Caught interrupt signal");

process.exit();
});

Expand Down Expand Up @@ -108,6 +108,7 @@ async function shellYeah(
history = newHistory;
});
rl.on("SIGINT", () => {
/* c8 ignore next 1 */
process.exit();
});

Expand Down Expand Up @@ -141,6 +142,7 @@ async function shellYeah(
}

shellYeah(argv, tablelandConnection, history);
/* c8 ignore next 6 */
} catch (err: any) {
logger.error(err.message);
if (argv.verbose) {
Expand Down
4 changes: 4 additions & 0 deletions src/commands/write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ export const handler = async (argv: Arguments<Options>): Promise<void> => {
logger.error("the `write` command can only accept write queries");
return;
}
// Note: I can't figure out a write statement that updates 2 tables and makes
// it through the parser, but leaving this here because one might exist.
if (normalized.tables.length < 1) {
/* c8 ignore next 5 */
logger.error(
"after normalizing the statement there was no write query, hence nothing to do"
);
Expand All @@ -95,6 +98,7 @@ export const handler = async (argv: Arguments<Options>): Promise<void> => {
// re-normalize so we can be sure we've isolated each statement and it's tableId
const norm = await normalize(stmt);
if (norm.tables.length > 1) {
/* c8 ignore next 4 */
throw new Error(
"cannot normalize if single query affects more then one table"
);
Expand Down
6 changes: 5 additions & 1 deletion src/lib/EnsResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export default class EnsResolver {

constructor(options: EnsResolverOptions) {
const { signer, ensProviderUrl } = options;
if (!ensProviderUrl) throw new Error("No ensProviderUrl given");
/* c8 ignore next 3 */
if (!ensProviderUrl) {
throw new Error("No ensProviderUrl given");
}
this.signer = signer;
this.provider = new JsonRpcProvider(ensProviderUrl);

Expand All @@ -37,6 +40,7 @@ export default class EnsResolver {
const domain = domainArray.join(".");
const address = await this.provider.getResolver(domain);

// TODO: mock `this.provider.getResolver` so address is undefined and we get coverage on the or clause
return (await address?.getText(textRecord)) || tablename;
}

Expand Down
10 changes: 8 additions & 2 deletions src/lib/commandSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class Connections {

readyCheck() {
if (!this._readyResolved)
/* c8 ignore next 3 */
throw new Error(
"You must await the 'ready' method before using this class"
);
Expand All @@ -42,8 +43,10 @@ export class Connections {

get validator(): Validator {
this.readyCheck();
if (!this._validator)
/* c8 ignore next 3 */
if (!this._validator) {
throw new Error("No validator. Set a chain or a baseURL.");
}
return this._validator;
}

Expand All @@ -59,15 +62,18 @@ export class Connections {

get database(): Database {
this.readyCheck();
if (!this._database)
/* c8 ignore next 5 */
if (!this._database) {
throw new Error(
"No database defined. You must specify a providerUrl or chain."
);
}
return this._database;
}

get network(): helpers.ChainInfo {
this.readyCheck();
/* c8 ignore next 1 */
if (!this._network) throw new Error("No network");
return this._network;
}
Expand Down
56 changes: 40 additions & 16 deletions test/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@ import { equal, match } from "node:assert";
import { describe, test, afterEach, before } from "mocha";
import { spy, restore } from "sinon";
import yargs from "yargs/yargs";
import { getAccounts } from "@tableland/local";
import { getAccounts, getDatabase } from "@tableland/local";
import * as mod from "../src/commands/controller.js";
import { wait, logger } from "../src/utils.js";

describe("commands/controller", function () {
this.timeout("30s");

// account[0] is the Validator's wallet, try to avoid using that
const accounts = getAccounts();
const db = getDatabase(accounts[1]);

let tableName: string;
before(async function () {
await wait(500);
const { meta } = await db
.prepare("CREATE TABLE test_controller (a int);")
.all();
tableName = meta.txn?.name ?? "";
});

afterEach(function () {
Expand All @@ -26,8 +35,7 @@ describe("commands/controller", function () {
});

test("throws with invalid chain", async function () {
const [account] = getAccounts();
const privateKey = account.privateKey.slice(2);
const privateKey = accounts[1].privateKey.slice(2);
const consoleError = spy(logger, "error");
await yargs([
"controller",
Expand All @@ -45,8 +53,7 @@ describe("commands/controller", function () {
});

test("throws with invalid get argument", async function () {
const [account] = getAccounts();
const privateKey = account.privateKey.slice(2);
const privateKey = accounts[1].privateKey.slice(2);
const consoleError = spy(logger, "error");
await yargs([
"controller",
Expand All @@ -65,8 +72,7 @@ describe("commands/controller", function () {
});

test("throws with invalid set arguments", async function () {
const [account] = getAccounts();
const privateKey = account.privateKey.slice(2);
const privateKey = accounts[1].privateKey.slice(2);
const consoleError = spy(logger, "error");
await yargs([
"controller",
Expand All @@ -86,15 +92,14 @@ describe("commands/controller", function () {
});

test("passes when setting a controller", async function () {
const [account] = getAccounts();
const privateKey = account.privateKey.slice(2);
const privateKey = accounts[1].privateKey.slice(2);
const consoleLog = spy(logger, "log");

await yargs([
"controller",
"set",
"0x0000000000000000000000000000000000000000",
"healthbot_31337_1",
accounts[2].address,
tableName,
"--privateKey",
privateKey,
"--chain",
Expand All @@ -111,13 +116,12 @@ describe("commands/controller", function () {
});

test("passes when getting a controller", async function () {
const [account] = getAccounts();
const privateKey = account.privateKey.slice(2);
const privateKey = accounts[1].privateKey.slice(2);
const consoleLog = spy(logger, "log");
await yargs([
"controller",
"get",
"healthbot_31337_1",
tableName,
"--privateKey",
privateKey,
"--chain",
Expand All @@ -127,8 +131,28 @@ describe("commands/controller", function () {
.parse();

const value = consoleLog.getCall(0).firstArg;
equal(value, "0x0000000000000000000000000000000000000000");
equal(value, accounts[2].address);
});

// TODO: Create tests for locking a controller
test("passes when locking a controller", async function () {
const privateKey = accounts[1].privateKey.slice(2);
const consoleLog = spy(logger, "log");
await yargs([
"controller",
"lock",
tableName,
"--privateKey",
privateKey,
"--chain",
"local-tableland",
])
.command(mod)
.parse();

const res = consoleLog.getCall(0).firstArg;
const value = JSON.parse(res);

equal(value.hash.startsWith("0x"), true);
equal(value.from, accounts[1].address);
});
});
Loading

0 comments on commit b8e18c9

Please sign in to comment.