Skip to content

Commit

Permalink
[WIP #165] DONE integration tests for api/delegates.
Browse files Browse the repository at this point in the history
Fix small bug on forgingDisable method;
Added boolean type to forgemodule.isForgeEnabledOn.
  • Loading branch information
mcanever committed Apr 19, 2018
1 parent 968ff6c commit 0b55c37
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/apis/delegatesAPI.ts
Expand Up @@ -272,7 +272,7 @@ export class DelegatesAPI {
throw new APIError('Invalid passphrase', 200);
}

if (typeof(this.forgeModule.isForgeEnabledOn(pk)) === 'undefined') {
if (!this.forgeModule.isForgeEnabledOn(pk)) {
throw new APIError('Forging is already disabled', 200);
}

Expand Down
2 changes: 1 addition & 1 deletion src/modules/forge.ts
Expand Up @@ -72,7 +72,7 @@ export class ForgeModule implements IForgeModule {
.filter((pk) => this.enabledKeys[pk] === true);
}

public isForgeEnabledOn(pk?: publicKey | IKeypair) {
public isForgeEnabledOn(pk?: publicKey | IKeypair): boolean {
let thePK: publicKey;
if (typeof(pk) === 'object') {
thePK = pk.publicKey.toString('hex');
Expand Down
10 changes: 9 additions & 1 deletion tests/integration/api/accounts.spec.ts
Expand Up @@ -11,6 +11,7 @@ describe('api/accounts', () => {
describe('/', () => {
checkAddress('address', '/api/accounts/');
checkPubKey('publicKey', '/api/accounts/');

it('should throw if no address nor pubkey is provided', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/')
Expand All @@ -20,6 +21,7 @@ describe('api/accounts', () => {
expect(response.body.error).to.be.eq('Missing required property: address or publicKey');
});
});

it('should throw if both address and pubkey are provided but relates to different account', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/?publicKey=f4654563e34c93a22a90bcdb12dbe1edc42fc148cee5f21dde668748acf5f89d&address=11316019077384178848R')
Expand All @@ -29,6 +31,7 @@ describe('api/accounts', () => {
expect(response.body.error).to.be.eq('Account publicKey does not match address');
});
});

it('should throw if account cannot be found', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/?address=1R')
Expand All @@ -38,6 +41,7 @@ describe('api/accounts', () => {
expect(response.body.error).to.be.eq('Account not found');
});
});

it('should return account data if all ok', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/?address=12333350760210376657R')
Expand Down Expand Up @@ -109,6 +113,7 @@ describe('api/accounts', () => {
expect(response.body.error).to.contain('Missing required property: address');
});
});

it('should return Account not foundif account is not found', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/getPublicKey?address=1R')
Expand All @@ -118,7 +123,8 @@ describe('api/accounts', () => {
expect(response.body.error).to.be.eq('Account not found');

});
});
});

it('should return correct publicKey and unconfirmedBalance in return object', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/getPublicKey?address=12324540900396688540R')
Expand All @@ -141,6 +147,7 @@ describe('api/accounts', () => {
expect(response.body.error).to.contain('Missing required property: address');
});
});

it('should return Account not foundif account is not found', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/delegates?address=1R')
Expand All @@ -151,6 +158,7 @@ describe('api/accounts', () => {

});
});

it('should return correct voted delegates', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/accounts/delegates?address=8832350072536010884R')
Expand Down
6 changes: 4 additions & 2 deletions tests/integration/api/blocks.spec.ts
Expand Up @@ -18,6 +18,7 @@ describe('api/blocks', () => {
checkIntParam('offset', '/api/blocks/', { min: 0 });
});
checkPubKey('generatorPublicKey', '/api/blocks');

it('should return an array of blocks', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/blocks')
Expand All @@ -27,7 +28,6 @@ describe('api/blocks', () => {
expect(response.body).to.haveOwnProperty('blocks');
expect(response.body.blocks).to.be.an('array');
expect(response.body.blocks.length).to.be.eq(1);

});
});
});
Expand Down Expand Up @@ -132,6 +132,7 @@ describe('api/blocks', () => {
expect(response.body.fees).to.haveOwnProperty('multisignature');
});
});

it('should use provided height', async () => {
return supertest(initializer.appManager.expressApp)
.get('/api/blocks/getFees?height=10000&asd=asd')
Expand Down Expand Up @@ -166,13 +167,15 @@ describe('api/blocks', () => {
'/api/blocks/getReward'
);
});

describe('/getSupply', () => {
checkReturnObjKeyVal(
'supply',
10999999991000000, // height 1 - 10 has reward 0
'/api/blocks/getSupply'
);
});

describe('/getStatus', () => {
checkReturnObjKeyVal('nethash', 'e4c527bd888c257377c18615d021e9cedd2bc2fd6de04b369f22a8780264c2f6', '/api/blocks/getStatus');
checkReturnObjKeyVal('broadhash', 'e4c527bd888c257377c18615d021e9cedd2bc2fd6de04b369f22a8780264c2f6', '/api/blocks/getStatus');
Expand All @@ -182,5 +185,4 @@ describe('api/blocks', () => {
checkReturnObjKeyVal('reward', 0, '/api/blocks/getStatus');
checkReturnObjKeyVal('supply', 10999999991000000, '/api/blocks/getStatus');
});

});
165 changes: 153 additions & 12 deletions tests/integration/api/delegates.spec.ts
Expand Up @@ -10,6 +10,10 @@ import { IBlocksModule } from '../../../src/ioc/interfaces/modules';
import { Symbols } from '../../../src/ioc/symbols';
import { ISlots } from '../../../src/ioc/interfaces/helpers';
import { AppConfig } from '../../../src/types/genericTypes';
import {
confirmTransactions, createSendTransaction, createWallet, getRandomDelegateWallet
} from '../common/utils';
import { IForgeModule } from '../../../src/ioc/interfaces/modules/IForgeModule';
chai.use(chaiSorted);

const {expect} = chai;
Expand Down Expand Up @@ -356,8 +360,10 @@ describe('api/delegates', () => {
cfg.forging.access.whiteList = [ '127.0.0.1', '::ffff:127.0.0.1'];
});

// checkPostRequiredParam('secret', '/api/delegates/forging/enable?secret=aaa&publickKey=241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14');
// checkPostPubKey('publicKey', '/api/delegates/forging/enable?secret=aaa');
checkPostRequiredParam('secret', '/api/delegates/forging/enable', {
publicKey: '241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14',
});
checkPostPubKey('publicKey', '/api/delegates/forging/enable', {secret: 'aaa'});

it('should disallow request from unallowed ip', async () => {
cfg.forging.access.whiteList = [];
Expand All @@ -368,23 +374,86 @@ describe('api/delegates', () => {
});
});

it('should throw error if given publicKey differs from computed pk');
it('should throw error if given publicKey differs from computed pk', async () => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/enable')
.send({
publicKey: '241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14',
secret: 'sensereduceweirdpluck',
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Invalid passphrase');
});
});

it('should throw error if forging is already enabled for such account');
it('should throw error if forging is already enabled for such account', async () => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/enable')
.send({
publicKey: '241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14',
secret: 'sense reduce weird pluck result business unable dust garage gaze business anchor',
}).expect(200)
.then((response) => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/enable')
.send({
publicKey: '241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14',
secret: 'sense reduce weird pluck result business unable dust garage gaze business anchor',
}).expect(200)
.then((res) => {
expect(res.body.error).to.be.equal('Forging is already enabled');
});
});
});

it('should throw error if account is not found');
it('should throw error if account is not found', async () => {
// Key pair is valid but account does not exist
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/enable')
.send({
publicKey: '0cf75c0afa655b7658d971765d4989d8553d639eeed57eaa45b1991b61db1856',
secret: 'unable dust garage gaze business anchor sense reduce weird pluck result business',
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Account not found');
});
});

it('should throw error if account is not a delegate');
it('should throw error if account is not a delegate', async () => {
// Transfer some funds to a new account from a delegate
const secret = 'business anchor sense reduce weird pluck result business unable dust garage gaze';
const wallet = createWallet(secret);
const tx = await createSendTransaction(
0,
Math.ceil(Math.random() * 100),
getRandomDelegateWallet(),
wallet.address
);
await confirmTransactions([tx], 1);
// Try to enable forging on this new non-delegate account
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/enable')
.send({
publicKey: wallet.publicKey,
secret,
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Delegate not found');
});
});
});

describe('/forging/disable', () => {
let cfg: AppConfig;
beforeEach(async () => {
cfg = initializer.appManager.container.get<AppConfig>(Symbols.generic.appConfig);
cfg.forging.access.whiteList = [ '127.0.0.1', '::ffff:127.0.0.1'];
});

// checkPostRequiredParam('secret', '/api/delegates/forging/disable');
// checkPostPubKey('publicKey', '/api/delegates/forging/disable?secret=aaa');
checkPostRequiredParam('secret', '/api/delegates/forging/disable', {});
checkPostPubKey('publicKey', '/api/delegates/forging/disable', {
secret: 'aaa',
});

it('should disallow request from unallowed ip', async () => {
cfg.forging.access.whiteList = [];
Expand All @@ -394,10 +463,82 @@ describe('api/delegates', () => {
expect(response.body.error).to.be.equal('Delegates API access denied');
});
});
it('should throw error if given publicKey differs from computed pk');
it('should throw error if forging is already disabled for such account');
it('should throw error if account is not found');
it('should throw error if account is not a delegate');

it('should throw error if given publicKey differs from computed pk', async () => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/disable')
.send({
publicKey: '241cca788519fd0913265ebf1265d9d79eded91520d62b8c1ce700ebd15aff14',
secret: 'sensereduceweirdpluck',
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Invalid passphrase');
});
});

it('should throw error if forging is already disabled for such account', async () => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/disable')
.send({
publicKey: '21ba4bd249c3369c1a1c15a2f309ce993db9396c55d519f17d0138fafee36d66',
secret: 'chunk torch ice snow lunar cute school trigger portion gift home canal',
}).expect(200).then((res) => {
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/disable')
.send({
publicKey: '21ba4bd249c3369c1a1c15a2f309ce993db9396c55d519f17d0138fafee36d66',
secret: 'chunk torch ice snow lunar cute school trigger portion gift home canal',
}).expect(200).then((resp) => {
expect(resp.body.error).to.be.equal('Forging is already disabled');
});
});
});

it('should throw error if account is not found', async () => {
const forgeModule = initializer.appManager.container.get<IForgeModule>(Symbols.modules.forge);
forgeModule.enableForge({
privateKey: Buffer.from('aaaa', 'hex'),
publicKey: Buffer.from('b7717adf51800bce03b1aebdad444220734c423f0014944bfcdb8d615641c61e', 'hex'),
});
// Key pair is valid but account does not exist
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/disable')
.send({
publicKey: 'b7717adf51800bce03b1aebdad444220734c423f0014944bfcdb8d615641c61e',
secret: 'pluck result dust unable garage gaze business anchor sense reduce weird business',
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Account not found');
});
});

it('should throw error if account is not a delegate', async () => {
// Transfer some funds to a new account from a delegate
const secret = 'dust pluck sense reduce weird pluck result business unable dust sense gaze';
const wallet = createWallet(secret);
const tx = await createSendTransaction(
0,
Math.ceil(Math.random() * 100),
getRandomDelegateWallet(),
wallet.address
);
await confirmTransactions([tx], 1);
const forgeModule = initializer.appManager.container.get<IForgeModule>(Symbols.modules.forge);
forgeModule.enableForge({
privateKey: Buffer.from('aaaa', 'hex'),
publicKey: Buffer.from(wallet.publicKey, 'hex'),
});
// Try to disable forging on this new non-delegate account
return supertest(initializer.appManager.expressApp)
.post('/api/delegates/forging/disable')
.send({
publicKey: wallet.publicKey,
secret,
}).expect(200)
.then((response) => {
expect(response.body.error).to.be.equal('Delegate not found');
});
});
});

});
9 changes: 6 additions & 3 deletions tests/integration/api/utils.ts
Expand Up @@ -28,10 +28,12 @@ export const checkPubKey = (paramName: string, baseUrl: string) => {
});
};

export const checkPostPubKey = (paramName: string, baseUrl: string) => {
export const checkPostPubKey = (paramName: string, baseUrl: string, body: any) => {
it(`should throw if ${paramName} is not a valid publicKey`, async () => {
body[paramName] = '1';
return supertest(initializer.appManager.expressApp)
.post(`${baseUrl}?${paramName}=1`)
.post(`${baseUrl}`)
.send(body)
.expect(200)
.then((response) => {
expect(response.body.success).is.false;
Expand Down Expand Up @@ -104,7 +106,7 @@ export const checkRequiredParam = (paramName: string, validUrl: string) => {
});
}

export const checkPostRequiredParam = (paramName: string, validUrl: string) => {
export const checkPostRequiredParam = (paramName: string, validUrl: string, body: any) => {
it(`should throw if ${paramName} is not provided`, async () => {
const theURLOBJ = url.parse(validUrl, true);
delete theURLOBJ.query[paramName];
Expand All @@ -113,6 +115,7 @@ export const checkPostRequiredParam = (paramName: string, validUrl: string) => {
delete theURLOBJ.href;
return supertest(initializer.appManager.expressApp)
.post(url.format(theURLOBJ))
.send(body)
.expect(200)
.then((response) => {
expect(response.body.success).is.false;
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/common/utils.ts
Expand Up @@ -49,6 +49,10 @@ export const createRandomWallet = (): LiskWallet => {
return new dposOffline.wallets.LiskLikeWallet(uuid.v4(), 'R');
};

export const createWallet = (secret: string): LiskWallet => {
return new dposOffline.wallets.LiskLikeWallet(secret, 'R');
};

export const createVoteTransaction = async (confirmations: number, from: LiskWallet, to: publicKey, add: boolean, obj: any = {}): Promise<ITransaction> => {
const systemModule = initializer.appManager.container.get<ISystemModule>(Symbols.modules.system);
const tx = txCrafter.createVoteTransaction(from, systemModule.getFees().fees.vote, {
Expand Down

0 comments on commit 0b55c37

Please sign in to comment.