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 fs from 'fs';
|
||||||
import yaml from 'js-yaml';
|
|
||||||
import assert from 'assert';
|
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', () => {
|
describe('Test laconic CLI commands', () => {
|
||||||
test('laconic', async () => {
|
test('laconic', async () => {
|
||||||
@ -40,6 +52,9 @@ describe('Test laconic CLI commands', () => {
|
|||||||
const testAccount2 = 'ethm1vc62ysqu504at932jjq8pwrqgjt67rx6ggn5yu';
|
const testAccount2 = 'ethm1vc62ysqu504at932jjq8pwrqgjt67rx6ggn5yu';
|
||||||
assert(testAccount, 'TEST_ACCOUNT not set in env');
|
assert(testAccount, 'TEST_ACCOUNT not set in env');
|
||||||
|
|
||||||
|
const testAuthorityName = 'laconic';
|
||||||
|
let testAuctionId: string;
|
||||||
|
|
||||||
test('laconic cns status', async () => {
|
test('laconic cns status', async () => {
|
||||||
const result = spawnSync('laconic', ['cns', 'status']);
|
const result = spawnSync('laconic', ['cns', 'status']);
|
||||||
const outputObj = checkResultAndRetrieveOutput(result);
|
const outputObj = checkResultAndRetrieveOutput(result);
|
||||||
@ -47,7 +62,7 @@ describe('Test laconic CLI commands', () => {
|
|||||||
// Expect output object to have CNS status props
|
// Expect output object to have CNS status props
|
||||||
expect(outputObj).toHaveProperty('version');
|
expect(outputObj).toHaveProperty('version');
|
||||||
expect(outputObj).toHaveProperty('node');
|
expect(outputObj).toHaveProperty('node');
|
||||||
expect(outputObj).toHaveProperty('node.network', 'laconic_9000-1');
|
expect(outputObj).toHaveProperty('node.network', CHAIN_ID);
|
||||||
expect(outputObj).toHaveProperty('sync');
|
expect(outputObj).toHaveProperty('sync');
|
||||||
expect(Number(outputObj.sync.latest_block_height)).toBeGreaterThan(0);
|
expect(Number(outputObj.sync.latest_block_height)).toBeGreaterThan(0);
|
||||||
expect(outputObj).toHaveProperty('validator');
|
expect(outputObj).toHaveProperty('validator');
|
||||||
@ -67,7 +82,7 @@ describe('Test laconic CLI commands', () => {
|
|||||||
const outputObj = checkResultAndRetrieveOutput(result);
|
const outputObj = checkResultAndRetrieveOutput(result);
|
||||||
|
|
||||||
// Expect output object to have resultant bond id
|
// Expect output object to have resultant bond id
|
||||||
expect(outputObj).toHaveProperty('bondId');
|
expect(outputObj.bondId).toBeDefined();
|
||||||
|
|
||||||
bondId = outputObj.bondId;
|
bondId = outputObj.bondId;
|
||||||
});
|
});
|
||||||
@ -130,8 +145,8 @@ describe('Test laconic CLI commands', () => {
|
|||||||
|
|
||||||
expect(outputObj.length).toEqual(1);
|
expect(outputObj.length).toEqual(1);
|
||||||
expect(outputObj[0]).toMatchObject(expectedAccount);
|
expect(outputObj[0]).toMatchObject(expectedAccount);
|
||||||
expect(outputObj[0]).toHaveProperty('number');
|
expect(outputObj[0].number).toBeDefined();
|
||||||
expect(outputObj[0]).toHaveProperty('sequence');
|
expect(outputObj[0].sequence).toBeDefined();
|
||||||
|
|
||||||
balanceBeforeSend = Number(outputObj[0].balance[0].quantity);
|
balanceBeforeSend = Number(outputObj[0].balance[0].quantity);
|
||||||
expect(balanceBeforeSend).toBeGreaterThan(0);
|
expect(balanceBeforeSend).toBeGreaterThan(0);
|
||||||
@ -171,7 +186,7 @@ describe('Test laconic CLI commands', () => {
|
|||||||
const outputObj = checkResultAndRetrieveOutput(result);
|
const outputObj = checkResultAndRetrieveOutput(result);
|
||||||
|
|
||||||
// Expect output object to resultant bond id
|
// Expect output object to resultant bond id
|
||||||
expect(outputObj).toHaveProperty('id');
|
expect(outputObj.id).toBeDefined();
|
||||||
|
|
||||||
recordId = outputObj.id;
|
recordId = outputObj.id;
|
||||||
});
|
});
|
||||||
@ -185,9 +200,9 @@ describe('Test laconic CLI commands', () => {
|
|||||||
|
|
||||||
expect(outputObj.length).toEqual(1);
|
expect(outputObj.length).toEqual(1);
|
||||||
expect(outputObj[0]).toMatchObject(expectedRecord);
|
expect(outputObj[0]).toMatchObject(expectedRecord);
|
||||||
expect(outputObj[0]).toHaveProperty('createTime');
|
expect(outputObj[0].createTime).toBeDefined();
|
||||||
expect(outputObj[0]).toHaveProperty('expiryTime');
|
expect(outputObj[0].expiryTime).toBeDefined();
|
||||||
expect(outputObj[0]).toHaveProperty('owners');
|
expect(outputObj[0].owners).toBeDefined();
|
||||||
expect(outputObj[0].owners.length).toEqual(1);
|
expect(outputObj[0].owners.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -218,10 +233,8 @@ describe('Test laconic CLI commands', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Name authority operations (pre auction)', () => {
|
describe('Name authority operations (pre auction)', () => {
|
||||||
const authorityName = 'laconic';
|
|
||||||
|
|
||||||
test('laconic cns authority reserve <authority_name>', async () => {
|
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);
|
const outputObj = checkResultAndRetrieveOutput(result);
|
||||||
|
|
||||||
// Expect result
|
// Expect result
|
||||||
@ -229,7 +242,7 @@ describe('Test laconic CLI commands', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('laconic cns authority whois <authority_name>', async () => {
|
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);
|
const outputObj = checkResultAndRetrieveOutput(result);
|
||||||
|
|
||||||
// Expected authority (still in auction)
|
// Expected authority (still in auction)
|
||||||
@ -237,23 +250,66 @@ describe('Test laconic CLI commands', () => {
|
|||||||
|
|
||||||
expect(outputObj.length).toEqual(1);
|
expect(outputObj.length).toEqual(1);
|
||||||
expect(outputObj[0]).toMatchObject(expectedAuthority);
|
expect(outputObj[0]).toMatchObject(expectedAuthority);
|
||||||
expect(outputObj[0]).toHaveProperty('expiryTime');
|
expect(outputObj[0].expiryTime).toBeDefined();
|
||||||
expect(outputObj[0].height).toBeGreaterThan(0);
|
expect(outputObj[0].height).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
testAuctionId = outputObj[0].auction.id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Auction operations', () => {
|
describe('Auction operations', () => {
|
||||||
|
const bidAmount = 25000000;
|
||||||
|
let bidRevealFilePath: string;
|
||||||
|
|
||||||
test('laconic cns auction get <auction_id>', async () => {
|
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 () => {
|
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 () => {
|
test('laconic cns auction bid reveal <auction_id> <file_path>', async () => {
|
||||||
// TODO
|
// 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)', () => {
|
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