Add CLI tests and setup CI #53
190
test/cli.test.ts
190
test/cli.test.ts
@ -1,9 +1,21 @@
|
||||
import fs from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import assert from 'assert';
|
||||
import { SpawnSyncReturns, spawnSync } from 'child_process';
|
||||
import { spawnSync } from 'child_process';
|
||||
|
||||
const TOKEN_TYPE = 'aphoton';
|
||||
import {
|
||||
CHAIN_ID,
|
||||
TOKEN_TYPE,
|
||||
COMMIT_DURATION,
|
||||
delay,
|
||||
checkResultAndRetrieveOutput,
|
||||
createBond,
|
||||
getBondObj,
|
||||
getAccountObj,
|
||||
getRecordObj,
|
||||
getAuthorityObj,
|
||||
getAuctionObj,
|
||||
getBidObject
|
||||
} from './helpers';
|
||||
|
||||
describe('Test laconic CLI commands', () => {
|
||||
test('laconic', async () => {
|
||||
@ -40,6 +52,9 @@ describe('Test laconic CLI commands', () => {
|
||||
const testAccount2 = 'ethm1vc62ysqu504at932jjq8pwrqgjt67rx6ggn5yu';
|
||||
assert(testAccount, 'TEST_ACCOUNT not set in env');
|
||||
|
||||
const testAuthorityName = 'laconic';
|
||||
let testAuctionId: string;
|
||||
|
||||
test('laconic cns status', async () => {
|
||||
const result = spawnSync('laconic', ['cns', 'status']);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
@ -47,7 +62,7 @@ describe('Test laconic CLI commands', () => {
|
||||
// Expect output object to have CNS status props
|
||||
expect(outputObj).toHaveProperty('version');
|
||||
expect(outputObj).toHaveProperty('node');
|
||||
expect(outputObj).toHaveProperty('node.network', 'laconic_9000-1');
|
||||
expect(outputObj).toHaveProperty('node.network', CHAIN_ID);
|
||||
expect(outputObj).toHaveProperty('sync');
|
||||
expect(Number(outputObj.sync.latest_block_height)).toBeGreaterThan(0);
|
||||
expect(outputObj).toHaveProperty('validator');
|
||||
@ -67,7 +82,7 @@ describe('Test laconic CLI commands', () => {
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expect output object to have resultant bond id
|
||||
expect(outputObj).toHaveProperty('bondId');
|
||||
expect(outputObj.bondId).toBeDefined();
|
||||
|
||||
bondId = outputObj.bondId;
|
||||
});
|
||||
@ -130,8 +145,8 @@ describe('Test laconic CLI commands', () => {
|
||||
|
||||
expect(outputObj.length).toEqual(1);
|
||||
expect(outputObj[0]).toMatchObject(expectedAccount);
|
||||
expect(outputObj[0]).toHaveProperty('number');
|
||||
expect(outputObj[0]).toHaveProperty('sequence');
|
||||
expect(outputObj[0].number).toBeDefined();
|
||||
expect(outputObj[0].sequence).toBeDefined();
|
||||
|
||||
balanceBeforeSend = Number(outputObj[0].balance[0].quantity);
|
||||
expect(balanceBeforeSend).toBeGreaterThan(0);
|
||||
@ -171,7 +186,7 @@ describe('Test laconic CLI commands', () => {
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expect output object to resultant bond id
|
||||
expect(outputObj).toHaveProperty('id');
|
||||
expect(outputObj.id).toBeDefined();
|
||||
|
||||
recordId = outputObj.id;
|
||||
});
|
||||
@ -185,9 +200,9 @@ describe('Test laconic CLI commands', () => {
|
||||
|
||||
expect(outputObj.length).toEqual(1);
|
||||
expect(outputObj[0]).toMatchObject(expectedRecord);
|
||||
expect(outputObj[0]).toHaveProperty('createTime');
|
||||
expect(outputObj[0]).toHaveProperty('expiryTime');
|
||||
expect(outputObj[0]).toHaveProperty('owners');
|
||||
expect(outputObj[0].createTime).toBeDefined();
|
||||
expect(outputObj[0].expiryTime).toBeDefined();
|
||||
expect(outputObj[0].owners).toBeDefined();
|
||||
expect(outputObj[0].owners.length).toEqual(1);
|
||||
});
|
||||
|
||||
@ -218,10 +233,8 @@ describe('Test laconic CLI commands', () => {
|
||||
});
|
||||
|
||||
describe('Name authority operations (pre auction)', () => {
|
||||
const authorityName = 'laconic';
|
||||
|
||||
test('laconic cns authority reserve <authority_name>', async () => {
|
||||
const result = spawnSync('laconic', ['cns', 'authority', 'reserve', authorityName]);
|
||||
const result = spawnSync('laconic', ['cns', 'authority', 'reserve', testAuthorityName]);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expect result
|
||||
@ -229,7 +242,7 @@ describe('Test laconic CLI commands', () => {
|
||||
});
|
||||
|
||||
test('laconic cns authority whois <authority_name>', async () => {
|
||||
const result = spawnSync('laconic', ['cns', 'authority', 'whois', authorityName]);
|
||||
const result = spawnSync('laconic', ['cns', 'authority', 'whois', testAuthorityName]);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expected authority (still in auction)
|
||||
@ -237,23 +250,66 @@ describe('Test laconic CLI commands', () => {
|
||||
|
||||
expect(outputObj.length).toEqual(1);
|
||||
expect(outputObj[0]).toMatchObject(expectedAuthority);
|
||||
expect(outputObj[0]).toHaveProperty('expiryTime');
|
||||
expect(outputObj[0].expiryTime).toBeDefined();
|
||||
expect(outputObj[0].height).toBeGreaterThan(0);
|
||||
|
||||
testAuctionId = outputObj[0].auction.id;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Auction operations', () => {
|
||||
const bidAmount = 25000000;
|
||||
let bidRevealFilePath: string;
|
||||
|
||||
test('laconic cns auction get <auction_id>', async () => {
|
||||
// TODO
|
||||
const result = spawnSync('laconic', ['cns', 'auction', 'get', testAuctionId]);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expected auction (still in commit stage)
|
||||
const expectedAuction = getAuctionObj({ owner: testAccount, status: 'commit' });
|
||||
|
||||
expect(outputObj.length).toEqual(1);
|
||||
expect(outputObj[0]).toMatchObject(expectedAuction);
|
||||
});
|
||||
|
||||
test('laconic cns auction bid commit <auction_id> <quantity> <type>', async () => {
|
||||
// TODO
|
||||
const result = spawnSync('laconic', ['cns', 'auction', 'bid', 'commit', testAuctionId, bidAmount.toString(), TOKEN_TYPE]);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expected output
|
||||
expect(outputObj.reveal_file).toBeDefined();
|
||||
|
||||
bidRevealFilePath = outputObj.reveal_file;
|
||||
});
|
||||
|
||||
test('laconic cns auction bid reveal <auction_id> <file-path>', async () => {
|
||||
// TODO
|
||||
test('laconic cns auction bid reveal <auction_id> <file_path>', async () => {
|
||||
// Wait for commits duration (60s)
|
||||
await delay(COMMIT_DURATION * 1000);
|
||||
|
||||
const auctionResult = spawnSync('laconic', ['cns', 'auction', 'get', testAuctionId]);
|
||||
const auctionOutputObj = checkResultAndRetrieveOutput(auctionResult);
|
||||
|
||||
const expectedAuction = getAuctionObj({ owner: testAccount, status: 'reveal' });
|
||||
const expectedBid = getBidObject({ bidder: testAccount });
|
||||
|
||||
expect(auctionOutputObj[0]).toMatchObject(expectedAuction);
|
||||
expect(auctionOutputObj[0].bids[0]).toMatchObject(expectedBid);
|
||||
|
||||
// Reveal bid
|
||||
const result = spawnSync('laconic', ['cns', 'auction', 'bid', 'reveal', testAuctionId, bidRevealFilePath]);
|
||||
const outputObj = checkResultAndRetrieveOutput(result);
|
||||
|
||||
// Expected output
|
||||
expect(outputObj).toEqual({ success: true });
|
||||
|
||||
const revealObject = JSON.parse(fs.readFileSync(bidRevealFilePath, 'utf8'));
|
||||
expect(revealObject).toMatchObject({
|
||||
chainId: CHAIN_ID,
|
||||
auctionId: testAuctionId,
|
||||
bidderAddress: testAccount,
|
||||
bidAmount: `${bidAmount}aphoton`
|
||||
});
|
||||
}, (COMMIT_DURATION + 5) * 1000);
|
||||
});
|
||||
|
||||
describe('Name authority operations (post auction)', () => {
|
||||
@ -289,97 +345,3 @@ describe('Test laconic CLI commands', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Helper methods
|
||||
|
||||
function checkResultAndRetrieveOutput(result: SpawnSyncReturns<Buffer>): any {
|
||||
expect(result.status).toBe(0);
|
||||
|
||||
const errorOutput = result.stderr.toString().trim();
|
||||
expect(errorOutput).toBe('');
|
||||
|
||||
const output = result.stdout.toString().trim();
|
||||
expect(output.length).toBeGreaterThan(0);
|
||||
|
||||
return JSON.parse(output);
|
||||
}
|
||||
|
||||
function createBond(quantity: number): { bondId: string } {
|
||||
const result = spawnSync('laconic', ['cns', 'bond', 'create', '--type', TOKEN_TYPE, '--quantity', quantity.toString(), '--gas', '200000', '--fees', `200000${TOKEN_TYPE}`]);
|
||||
const output = result.stdout.toString().trim();
|
||||
|
||||
return JSON.parse(output);
|
||||
}
|
||||
|
||||
function getBondObj(params: { id: string, owner: string, balance: number}): any {
|
||||
return {
|
||||
id: params.id,
|
||||
owner: params.owner,
|
||||
balance: [
|
||||
{
|
||||
type: TOKEN_TYPE,
|
||||
quantity: params.balance
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function getAccountObj(params: { address: string, balance?: number }): any {
|
||||
const balanceObj: any = { type: TOKEN_TYPE };
|
||||
if (params.balance) {
|
||||
balanceObj.quantity = params.balance;
|
||||
}
|
||||
|
||||
return {
|
||||
address: params.address,
|
||||
balance: [balanceObj]
|
||||
};
|
||||
}
|
||||
|
||||
function getRecordObj(recordFilePath: string, params: { bondId: string, recordId: string }): any {
|
||||
const recordContent = yaml.load(fs.readFileSync(recordFilePath, 'utf8')) as any;
|
||||
|
||||
return {
|
||||
id: params.recordId,
|
||||
names: null,
|
||||
bondId: params.bondId,
|
||||
attributes: recordContent.record
|
||||
};
|
||||
}
|
||||
|
||||
function getAuthorityObj(params: { status: string, auction: any }): any {
|
||||
return {
|
||||
ownerAddress: '',
|
||||
ownerPublicKey: '',
|
||||
status: params.status,
|
||||
bondId: '',
|
||||
auction: params.auction || null
|
||||
};
|
||||
}
|
||||
|
||||
function getAuctionObj(params: { owner: string, status?: string, bids?: any[] }): any {
|
||||
const auctionFees = {
|
||||
commit: 1000000,
|
||||
reveal: 1000000,
|
||||
minimumBid: 5000000
|
||||
};
|
||||
|
||||
return {
|
||||
status: params.status || 'commit',
|
||||
ownerAddress: params.owner,
|
||||
commitFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: auctionFees.commit
|
||||
},
|
||||
revealFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: auctionFees.reveal
|
||||
},
|
||||
minimumBid: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: auctionFees.minimumBid
|
||||
},
|
||||
winnerAddress: '',
|
||||
bids: params.bids || []
|
||||
};
|
||||
}
|
||||
|
120
test/helpers.ts
Normal file
120
test/helpers.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import fs from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import { SpawnSyncReturns, spawnSync } from 'child_process';
|
||||
|
||||
export const CHAIN_ID = 'laconic_9000-1';
|
||||
export const TOKEN_TYPE = 'aphoton';
|
||||
export const AUCTION_FEES = {
|
||||
commit: 1000000,
|
||||
reveal: 1000000,
|
||||
minimumBid: 5000000
|
||||
};
|
||||
export const COMMIT_DURATION = 60; // 60s
|
||||
|
||||
export function checkResultAndRetrieveOutput(result: SpawnSyncReturns<Buffer>): any {
|
||||
expect(result.status).toBe(0);
|
||||
|
||||
const errorOutput = result.stderr.toString().trim();
|
||||
expect(errorOutput).toBe('');
|
||||
|
||||
const output = result.stdout.toString().trim();
|
||||
expect(output.length).toBeGreaterThan(0);
|
||||
|
||||
return JSON.parse(output);
|
||||
}
|
||||
|
||||
export function createBond(quantity: number): { bondId: string } {
|
||||
const result = spawnSync('laconic', ['cns', 'bond', 'create', '--type', TOKEN_TYPE, '--quantity', quantity.toString(), '--gas', '200000', '--fees', `200000${TOKEN_TYPE}`]);
|
||||
const output = result.stdout.toString().trim();
|
||||
|
||||
return JSON.parse(output);
|
||||
}
|
||||
|
||||
export function getBondObj(params: { id: string, owner: string, balance: number}): any {
|
||||
return {
|
||||
id: params.id,
|
||||
owner: params.owner,
|
||||
balance: [
|
||||
{
|
||||
type: TOKEN_TYPE,
|
||||
quantity: params.balance
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
export function getAccountObj(params: { address: string, balance?: number }): any {
|
||||
const balanceObj: any = { type: TOKEN_TYPE };
|
||||
if (params.balance) {
|
||||
balanceObj.quantity = params.balance;
|
||||
}
|
||||
|
||||
return {
|
||||
address: params.address,
|
||||
balance: [balanceObj]
|
||||
};
|
||||
}
|
||||
|
||||
export function getRecordObj(recordFilePath: string, params: { bondId: string, recordId: string }): any {
|
||||
const recordContent = yaml.load(fs.readFileSync(recordFilePath, 'utf8')) as any;
|
||||
|
||||
return {
|
||||
id: params.recordId,
|
||||
names: null,
|
||||
bondId: params.bondId,
|
||||
attributes: recordContent.record
|
||||
};
|
||||
}
|
||||
|
||||
export function getAuthorityObj(params: { status: string, auction: any }): any {
|
||||
return {
|
||||
ownerAddress: '',
|
||||
ownerPublicKey: '',
|
||||
status: params.status,
|
||||
bondId: '',
|
||||
auction: params.auction || null
|
||||
};
|
||||
}
|
||||
|
||||
export function getAuctionObj(params: { owner: string, status?: string }): any {
|
||||
return {
|
||||
status: params.status || 'commit',
|
||||
ownerAddress: params.owner,
|
||||
commitFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: AUCTION_FEES.commit
|
||||
},
|
||||
revealFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: AUCTION_FEES.reveal
|
||||
},
|
||||
minimumBid: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: AUCTION_FEES.minimumBid
|
||||
},
|
||||
winnerAddress: '',
|
||||
};
|
||||
}
|
||||
|
||||
export function getBidObject(params: { bidder: string, status?: string }): any {
|
||||
return {
|
||||
bidderAddress: params.bidder,
|
||||
status: params.status || 'commit',
|
||||
commitFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: AUCTION_FEES.commit
|
||||
},
|
||||
revealFee: {
|
||||
type: TOKEN_TYPE,
|
||||
quantity: AUCTION_FEES.reveal
|
||||
},
|
||||
bidAmount: {
|
||||
type: '',
|
||||
quantity: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function delay(ms: number): Promise<any> {
|
||||
return new Promise(res => setTimeout(res, ms))
|
||||
}
|
Loading…
Reference in New Issue
Block a user