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

feat: e2e tests #245

Open
wants to merge 24 commits into
base: feat/token-registry-v4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
- run:
name: test
command: npm run test -- --runInBand
- run:
name: e2e
command: npm run e2e
- run:
name: benchmark wrap functionality
command: npm run benchmark
Expand Down
417 changes: 414 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
},
"scripts": {
"dev": "ts-node src/index.ts",
"e2e": "concurrently -P -k -s first \"npm:e2e-test\" \"npm:blockchain\"",
"build": "npm run clean && npm run build:cjs && npm run build:type",
"build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json",
"build:type": "tsc -d --emitDeclarationOnly --outDir dist/types",
"clean": "rm -rf dist/",
"blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --logging.quiet=true",
"test": "jest --ci",
"test:coverage": "npm run test -- --coverage",
"test:watch": "npm run test -- --watch",
"e2e-test": "ts-node src/e2e/all.ts",
"lint": "eslint . --ext .ts --max-warnings 0",
"lint:fix": "eslint . --ext .ts --fix",
"benchmark:make-certs": "./scripts/makeCerts.sh 20000",
Expand Down Expand Up @@ -47,15 +50,18 @@
"@types/node": "^15.3.0",
"@types/node-fetch": "^2.5.10",
"@types/rimraf": "^3.0.0",
"@types/shelljs": "^0.8.11",
"@types/signale": "^1.4.1",
"@types/tmp": "^0.2.0",
"@typescript-eslint/eslint-plugin": "^4.24.0",
"@typescript-eslint/parser": "^4.24.0",
"commitizen": "^4.2.4",
"concurrently": "^6.2.0",
"eslint": "^7.26.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-jest": "^24.3.6",
"eslint-plugin-prettier": "^3.4.0",
"ganache": "^7.4.3",
"git-cz": "^4.7.6",
"jest": "^26.1.0",
"jest-watch-typeahead": "^0.6.3",
Expand All @@ -64,6 +70,7 @@
"proxyquire": "^2.1.3",
"rimraf": "^3.0.2",
"semantic-release": "^17.4.3",
"shelljs": "^0.8.5",
"tmp": "^0.2.1",
"ts-jest": "^26.5.6",
"ts-node": "^9.1.1",
Expand Down
80 changes: 80 additions & 0 deletions src/e2e/accept-surrender.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
checkFailure,
checkSurrenderAcceptSuccess,
deployTokenRegistry,
mintSurrenderToken,
mintTokenRegistry,
} from "./utils/helpers";
import { generateAcceptSurrenderCommand } from "./utils/commands";
import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from "./utils/constants";
import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks";
import { run } from "./utils/shell";

export const acceptSurrender = async (): Promise<void> => {
const tokenRegistryAddress = deployTokenRegistry(owner.privateKey);
// const errors: Error[] = [];
const defaultTitleEscrow = {
...defaultRunParameters,
beneficiary: owner.ethAddress,
holder: owner.ethAddress,
};

//"should be able to accept-surrender title-escrow on token-registry"
{
const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress);
const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey);
const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey);
let titleEscrowOwner: string = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId);
if (!(titleEscrowOwner === tokenRegistry)) throw new Error(`!(titleEscrowOwner === tokenRegistry)`);

const results = run(command);
titleEscrowOwner = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId);
if (!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD"))
throw new Error(`!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")`);
checkSurrenderAcceptSuccess(results);
}

//"should not be able to accept surrender invalid title-escrow on token-registry"
{
const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress);
const command = generateAcceptSurrenderCommand(
{ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow },
owner.privateKey
);
const results = run(command);
checkFailure(results, "Unminted Token");
}

//"should not be able to accept surrender title-escrow on invalid token-registry"
{
const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress);
const command = generateAcceptSurrenderCommand(
{ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow },
owner.privateKey
);
const results = run(command);
checkFailure(results, `Address ${BurnAddress} is not a valid Contract`);
}

//"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry"
{
const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress);
const command = generateAcceptSurrenderCommand(
{ tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow },
receiver.privateKey
);
const results = run(command);
checkFailure(results, "Wallet lack the rights for the transfer operation");
}

//"should not be able to accept un-surrendered title-escrow on token-registry"
{
const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
const command = generateAcceptSurrenderCommand(
{ tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow },
owner.privateKey
);
const results = run(command);
checkFailure(results, "Title Escrow has not been surrendered");
}
};
28 changes: 28 additions & 0 deletions src/e2e/all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { acceptSurrender } from "./accept-surrender.e2e";
import { surrender } from "./surrender.e2e";
import { changeHolder } from "./change-holder.e2e";
import { deployDocumentStore, deployTokenRegistry } from "./deploy.e2e";
import { endorseTransfer } from "./endorse-transfer.e2e";
import { mint } from "./mint.e2e";
import { nominate } from "./nominate.e2e";
import { rejectSurrender } from "./reject-surrender.e2e";
import { endorseChangeOwner } from "./endorse-change-owner.e2e";

const awaitForDuration = async (runFunction: () => void): Promise<void> => {
await runFunction();
console.log(runFunction.name);
};

awaitForDuration(deployDocumentStore);
awaitForDuration(deployTokenRegistry);

awaitForDuration(mint);

awaitForDuration(surrender);
awaitForDuration(rejectSurrender);
awaitForDuration(acceptSurrender);

awaitForDuration(nominate);
awaitForDuration(changeHolder);
awaitForDuration(endorseChangeOwner);
awaitForDuration(endorseTransfer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name this file index better

150 changes: 150 additions & 0 deletions src/e2e/change-holder.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { TitleEscrowTransferHolderCommand } from "../commands/title-escrow/title-escrow-command.type";
import {
changeHolderToken,
checkChangeHolderSuccess,
checkFailure,
defaultTransferHolder,
deployTokenRegistry,
mintBurntToken,
mintSurrenderToken,
mintTokenRegistry,
} from "./utils/helpers";
import { generateChangeHolderCommand } from "./utils/commands";
import { BurnAddress, EmptyTokenID, owner, receiver } from "./utils/constants";
import { run } from "./utils/shell";
import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks";
import { BigNumber } from "ethers";

// "transfer holder title-escrow"
export const changeHolder = async (): Promise<void> => {
const tokenRegistryAddress = deployTokenRegistry(owner.privateKey);

//should be able to transfer holder title-escrow on token-registry"
{
const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
const transferHolder: TitleEscrowTransferHolderCommand = {
tokenId: tokenId,
tokenRegistry: tokenRegistry,
...defaultTransferHolder,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
const results = run(command);
checkChangeHolderSuccess(results);

const signer = await getSigner(transferHolder.network, receiver.privateKey);
const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId);
if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`);
if (!(titleEscrowInfo.holder === transferHolder.newHolder))
throw new Error(`titleEscrowInfo.holder === transferHolder.holder`);
if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`);
if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`);
if (!(titleEscrowInfo.registry === transferHolder.tokenRegistry))
throw new Error(`titleEscrowInfo.registry === transferHolder.address`);
const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(transferHolder.tokenId));
if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`);
}

//holder should be able to transfer holder of title-escrow"
{
const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
// Transfer Holder to Receiver
const initialHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: receiver.ethAddress,
};
changeHolderToken(owner.privateKey, initialHolder);
// Transfer Holder to Receiver
// Holder attempts to transfer Holder with permission
const transferHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: owner.ethAddress,
};
const command = generateChangeHolderCommand(transferHolder, receiver.privateKey);
// Holder attempts to transfer Holder with permission
const results = run(command);
checkChangeHolderSuccess(results);
}

//should not be able to transfer holder of invalid title-escrow on token-registry"
{
const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
const transferHolder: TitleEscrowTransferHolderCommand = {
tokenId: EmptyTokenID,
tokenRegistry: tokenRegistry,
...defaultTransferHolder,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
const results = run(command);
checkFailure(results, "Unminted Token");
}

//should not be able to transfer holder of title-escrow on invalid token-registry"
{
const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
const transferHolder: TitleEscrowTransferHolderCommand = {
tokenId: tokenId,
tokenRegistry: BurnAddress,
...defaultTransferHolder,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
const results = run(command);
checkFailure(results, `Address ${BurnAddress} is not a valid Contract`);
}

//beneficiary should not be able to transfer holder of title-escrow"
{
const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress);
// Transfer Holder to Receiver
const initialHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: receiver.ethAddress,
};
changeHolderToken(owner.privateKey, initialHolder);
// Transfer Holder to Receiver
// Beneficiary attempts to transfer Holder without permission
const transferHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: owner.ethAddress,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
// Beneficiary attempts to transfer Holder without permission
const results = run(command);
checkFailure(results, "Wallet lack the rights for the transfer operation");
}

// should not be able to transfer holder of surrendered title-escrow"
{
const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress);
const transferHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: owner.ethAddress,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
const results = run(command);
checkFailure(results, "Title Escrow has already been surrendered");
}

//should not be able to transfer holder of burnt title-escrow"
{
const { tokenRegistry, tokenId } = mintBurntToken(owner.privateKey, tokenRegistryAddress);
const transferHolder: TitleEscrowTransferHolderCommand = {
...defaultTransferHolder,
tokenId: tokenId,
tokenRegistry: tokenRegistry,
newHolder: owner.ethAddress,
};
const command = generateChangeHolderCommand(transferHolder, owner.privateKey);
const results = run(command);
checkFailure(results, "Title Escrow has already been shredded");
}
};
66 changes: 66 additions & 0 deletions src/e2e/deploy.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { run } from "./utils/shell";
import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../commands/deploy/deploy.types";
import { isAddress } from "web3-utils";
import { defaultRunParameters, EndStatus, owner } from "./utils/constants";
import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils/commands";
import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks";
import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/helpers";

export const deployTokenRegistry = async (): Promise<void> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can add a suffixes to indicate its a e2e test?
hard to discern whether its a method or e2e (this goes for all the e2e entry point functions)

//should be able to deploy token-registry"
{
const tokenRegistryParameter: DeployTokenRegistryCommand = {
registryName: "Test Token",
registrySymbol: "TKN",
...defaultTokenRegistry,
};

const command = generateDeployTokenRegistryCommand(tokenRegistryParameter, owner.privateKey);
const results = run(command);
const tokenRegistryAddress = checkTokenRegistrySuccess(results);
const signer = getSigner(defaultRunParameters.network, owner.privateKey);
const tokenInfo = await retrieveTokenInfo(signer, tokenRegistryAddress);
if (!(tokenInfo.name === tokenRegistryParameter.registryName)) {
throw new Error("tokenInfo.name === tokenRegistryParameter.registryName");
}
if (!(tokenInfo.symbol === tokenRegistryParameter.registrySymbol)) {
throw new Error("tokenInfo.symbol === tokenRegistryParameter.registrySymbol");
}
Comment on lines +22 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y do we need to check for the name and symbol, when those are the parameters you specified?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's checking the values on the deployed token-registry rather than within oa-cli, not necessary but is of some use in case something is seriously broken on the smart contract level

const rolesInfo = await rolesCheck(signer, tokenRegistryAddress);
if (!(rolesInfo.accepterRole === true)) {
throw new Error("rolesInfo.accepterRole === true");
}
if (!(rolesInfo.defaultRole === true)) {
throw new Error("rolesInfo.defaultRole === true");
}
if (!(rolesInfo.minterRole === true)) {
throw new Error("rolesInfo.minterRole === true");
}
if (!(rolesInfo.restorerRole === true)) {
throw new Error("rolesInfo.restorerRole === true");
}
}
};

export const deployDocumentStore = async (): Promise<void> => {
//should be able to deploy document-store
{
const documentStoreParameters: DeployDocumentStoreCommand = {
storeName: "Test Document Store",
...defaultRunParameters,
};

const command = generateDeployDocumentStoreCommand(documentStoreParameters, owner.privateKey);
const results = run(command);
const tokenRegistrySuccessFormat = `${EndStatus.success} Document store Test Document Store deployed at `;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mistake?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the document store is called Test Document Store
So it's Document store ${Test Document Store} deployed at 0x0
The results of this has no fixed length so it had to match the results directly

const checkSuccess = results.includes(tokenRegistrySuccessFormat);
if (!(checkSuccess === true)) throw new Error(`checkSuccess === true)`);
const splitResults = results.trim().split("\n");
const tokenRegistryAddressLine = splitResults[splitResults.length - 2];
const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length);
if (!(isAddress(tokenRegistryAddress) === true)) throw new Error(`isAddress(tokenRegistryAddress) === true)`);
if (!(isAddress(tokenRegistryAddress) === true)) {
throw new Error("isAddress(tokenRegistryAddress) === true");
}
}
};
Loading