Skip to content

Commit

Permalink
test: add CLI test to canary flow (#1918)
Browse files Browse the repository at this point in the history
Fixes #1903
  • Loading branch information
spypsy authored Sep 1, 2023
1 parent cc8bc8f commit cc68958
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 180 deletions.
20 changes: 18 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,18 @@ jobs:
- *setup_env
- run:
name: "Test"
command: spot_run_test_script ./scripts/run_tests canary aztec_js_browser.test.test.ts canary docker-compose.yml
command: spot_run_test_script ./scripts/run_tests canary aztec_js_browser.test.ts canary docker-compose.yml

run-deployment-canary-cli:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: spot_run_test_script ./scripts/run_tests canary cli.test.ts canary docker-compose.yml

# Repeatable config for defining the workflow below.
tag_regex: &tag_regex /^v.*/
Expand Down Expand Up @@ -1403,7 +1414,6 @@ workflows:
- deploy-dockerhub:
requires:
- e2e-end
- aztec-sandbox
<<: *deploy_defaults
- deploy-npm:
requires:
Expand Down Expand Up @@ -1431,3 +1441,9 @@ workflows:
- build-deployment-canary
<<: *deploy_defaults

- run-deployment-canary-cli:
requires:
- build-deployment-canary
<<: *deploy_defaults


2 changes: 2 additions & 0 deletions build_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@
],
"dependencies": [
"aztec.js",
"cli",
"foundation",
"l1-artifacts",
"noir-contracts"
]
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@types/node": "^18.7.23",
"jest": "^29.5.0",
"jest-mock-extended": "^3.0.5",
"string-argv": "^0.3.2",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/aztec-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import {
prepTx,
} from './utils.js';

export { cliTestSuite } from './test/cli_test_suite.js';

const accountCreationSalt = Fr.ZERO;

const stripLeadingHex = (hex: string) => {
Expand Down
175 changes: 175 additions & 0 deletions yarn-project/aztec-cli/src/test/cli_test_suite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { AztecAddress } from '@aztec/aztec.js';
import { DebugLogger } from '@aztec/foundation/log';
import { AztecRPC, CompleteAddress } from '@aztec/types';

import stringArgv from 'string-argv';
import { format } from 'util';

import { getProgram } from '../index.js';

const INITIAL_BALANCE = 33000;
const TRANSFER_BALANCE = 3000;

export const cliTestSuite = (
testName: string,
aztecRpcSetup: () => Promise<AztecRPC>,
cleanup: () => Promise<void>,
rpcUrl: string,
debug: DebugLogger,
) => {
return describe(testName, () => {
let cli: ReturnType<typeof getProgram>;
let aztecRpcClient: AztecRPC;
let existingAccounts: CompleteAddress[];
let contractAddress: AztecAddress;
let log: (...args: any[]) => void;

// All logs emitted by the cli will be collected here, and reset between tests
const logs: string[] = [];

beforeAll(async () => {
aztecRpcClient = await aztecRpcSetup();
log = (...args: any[]) => {
logs.push(format(...args));
debug(...args);
};
});

afterAll(async () => {
await cleanup();
});

// in order to run the same command twice, we need to create a new CLI instance
const resetCli = () => {
cli = getProgram(log, debug);
};

beforeEach(() => {
logs.splice(0);
resetCli();
});

// Run a command on the CLI
const run = (cmd: string, addRpcUrl = true) => {
const args = stringArgv(cmd, 'node', 'dest/bin/index.js');
if (addRpcUrl) {
args.push('--rpc-url', rpcUrl);
}
return cli.parseAsync(args);
};

// Returns first match across all logs collected so far
const findInLogs = (regex: RegExp) => {
for (const log of logs) {
const match = regex.exec(log);
if (match) return match;
}
};

const findMultipleInLogs = (regex: RegExp) => {
const matches = [];
for (const log of logs) {
const match = regex.exec(log);
if (match) matches.push(match);
}
return matches;
};

const clearLogs = () => {
logs.splice(0);
};

it('creates & retrieves an account', async () => {
existingAccounts = await aztecRpcClient.getAccounts();
debug('Create an account');
await run(`create-account`);
const foundAddress = findInLogs(/Address:\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(foundAddress).toBeDefined();
const newAddress = AztecAddress.fromString(foundAddress!);

const accountsAfter = await aztecRpcClient.getAccounts();
const expectedAccounts = [...existingAccounts.map(a => a.address), newAddress];
expect(accountsAfter.map(a => a.address)).toEqual(expectedAccounts);
const newCompleteAddress = accountsAfter[accountsAfter.length - 1];

// Test get-accounts
debug('Check that account was added to the list of accs in RPC');
await run('get-accounts');
const fetchedAddresses = findMultipleInLogs(/Address:\s+(?<address>0x[a-fA-F0-9]+)/);
const foundFetchedAddress = fetchedAddresses.find(match => match.groups?.address === newAddress.toString());
expect(foundFetchedAddress).toBeDefined();

// Test get-account
debug('Check we can retrieve the specific account');
clearLogs();
await run(`get-account ${newAddress.toString()}`);
const fetchedAddress = findInLogs(/Public Key:\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(fetchedAddress).toEqual(newCompleteAddress.publicKey.toString());
});

it('deploys a contract & sends transactions', async () => {
// generate a private key
debug('Create an account using a private key');
await run('generate-private-key', false);
const privKey = findInLogs(/Private\sKey:\s+(?<privKey>[a-fA-F0-9]+)/)?.groups?.privKey;
expect(privKey).toHaveLength(64);
await run(`create-account --private-key ${privKey}`);
const foundAddress = findInLogs(/Address:\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(foundAddress).toBeDefined();
const ownerAddress = AztecAddress.fromString(foundAddress!);

debug('Deploy Private Token Contract using created account.');
await run(`deploy PrivateTokenContractAbi --args ${INITIAL_BALANCE} ${ownerAddress} --salt 0`);
const loggedAddress = findInLogs(/Contract\sdeployed\sat\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(loggedAddress).toBeDefined();
contractAddress = AztecAddress.fromString(loggedAddress!);

const deployedContract = await aztecRpcClient.getContractData(contractAddress);
expect(deployedContract?.contractAddress).toEqual(contractAddress);

debug('Check contract can be found in returned address');
await run(`check-deploy -ca ${loggedAddress}`);
const checkResult = findInLogs(/Contract\sfound\sat\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(checkResult).toEqual(deployedContract?.contractAddress.toString());

// clear logs
clearLogs();
await run(`get-contract-data ${loggedAddress}`);
const contractDataAddress = findInLogs(/Address:\s+(?<address>0x[a-fA-F0-9]+)/)?.groups?.address;
expect(contractDataAddress).toEqual(deployedContract?.contractAddress.toString());

debug("Check owner's balance");
await run(
`call getBalance --args ${ownerAddress} --contract-abi PrivateTokenContractAbi --contract-address ${contractAddress.toString()}`,
);
const balance = findInLogs(/View\sresult:\s+(?<data>\S+)/)?.groups?.data;
expect(balance!).toEqual(`${BigInt(INITIAL_BALANCE).toString()}n`);

debug('Transfer some tokens');
const existingAccounts = await aztecRpcClient.getAccounts();
// ensure we pick a different acc
const receiver = existingAccounts.find(acc => acc.address.toString() !== ownerAddress.toString());

await run(
`send transfer --args ${TRANSFER_BALANCE} ${receiver?.address.toString()} --contract-address ${contractAddress.toString()} --contract-abi PrivateTokenContractAbi --private-key ${privKey}`,
);
const txHash = findInLogs(/Transaction\shash:\s+(?<txHash>\S+)/)?.groups?.txHash;

debug('Check the transfer receipt');
await run(`get-tx-receipt ${txHash}`);
const txResult = findInLogs(/Transaction receipt:\s*(?<txHash>[\s\S]*?\})/)?.groups?.txHash;
const parsedResult = JSON.parse(txResult!);
expect(parsedResult.txHash).toEqual(txHash);
expect(parsedResult.status).toEqual('mined');
debug("Check Receiver's balance");
// Reset CLI as we're calling getBalance again
resetCli();
clearLogs();
await run(
`call getBalance --args ${receiver?.address.toString()} --contract-abi PrivateTokenContractAbi --contract-address ${contractAddress.toString()}`,
);
const receiverBalance = findInLogs(/View\sresult:\s+(?<data>\S+)/)?.groups?.data;
expect(receiverBalance).toEqual(`${BigInt(TRANSFER_BALANCE).toString()}n`);
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@aztec/types';

export const aztecRpcTestSuite = (testName: string, aztecRpcSetup: () => Promise<AztecRPC>) => {
describe(testName, function () {
describe(testName, () => {
let rpc: AztecRPC;

beforeAll(async () => {
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/canary/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
},
"dependencies": {
"@aztec/aztec.js": "workspace:^",
"@aztec/cli": "workspace:^",
"@aztec/foundation": "workspace:^",
"@aztec/l1-artifacts": "workspace:^",
"@aztec/noir-contracts": "workspace:^",
"@jest/globals": "^29.5.0",
Expand All @@ -32,6 +34,7 @@
"koa": "^2.14.2",
"koa-static": "^5.0.0",
"puppeteer": "^21.1.0",
"string-argv": "^0.3.2",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"tslib": "^2.4.0",
Expand Down
13 changes: 13 additions & 0 deletions yarn-project/canary/src/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createAztecRpcClient, createDebugLogger, makeFetch } from '@aztec/aztec.js';
import { cliTestSuite } from '@aztec/cli';

const { SANDBOX_URL = 'http://localhost:8080' } = process.env;

const debug = createDebugLogger('aztec:e2e_cli');

const setupRPC = () => {
const aztecRpcClient = createAztecRpcClient(SANDBOX_URL, makeFetch([1, 2, 3], true));
return Promise.resolve(aztecRpcClient);
};

cliTestSuite('CLI canary', setupRPC, () => Promise.resolve(), SANDBOX_URL, debug);
6 changes: 6 additions & 0 deletions yarn-project/canary/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
{
"path": "../aztec.js"
},
{
"path": "../aztec-cli"
},
{
"path": "../foundation"
},
{
"path": "../l1-artifacts"
},
Expand Down
Loading

0 comments on commit cc68958

Please sign in to comment.