Skip to content

Commit

Permalink
E2E tests: split transactions test and use more before all instead of…
Browse files Browse the repository at this point in the history
… beforeEach (#2190)

# Goal
The goal of this PR is to clean up some some small things about the e2e
tests

Part of #2154

# Discussion

- Reduce the number of per test transactions by moving some `beforeEach`
actions to the `before` all
- Add some additional comments and logs for debugging errors
- Split up the transaction.test.ts file for parallelization

# Testing

`make e2e-tests`
  • Loading branch information
wilwade authored Oct 21, 2024
1 parent d031d41 commit 9fd47cf
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 123 deletions.
4 changes: 1 addition & 3 deletions e2e/capacity/capacity_rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ describe('Capacity RPC', function () {
let schemaId: u16;
let defaultPayload: AddProviderPayload;

// Because this is testing non-executing code, we can do this beforeAll instead of beforeEach
before(async function () {
// Create schemas for testing with Grant Delegation to test pay_with_capacity
schemaId = await getOrCreateGraphChangeSchema(fundingSource);
assert.notEqual(schemaId, undefined, 'setup should populate schemaId');
});

beforeEach(async function () {
capacityProviderKeys = createKeys('CapacityProviderKeys');
capacityProvider = await createMsaAndProvider(
fundingSource,
Expand Down
4 changes: 2 additions & 2 deletions e2e/capacity/staking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ describe('Capacity Staking Tests', function () {
describe('when staking an amount and account balance is too low', function () {
it('fails to stake and errors BalanceTooLowtoStake', async function () {
const stakingKeys = createKeys('stakingKeys');
const providerId = await createMsaAndProvider(fundingSource, stakingKeys, 'stakingKeys', 10n * CENTS);
const stakingAmount = 1n * DOLLARS;
const providerId = await createMsaAndProvider(fundingSource, stakingKeys, 'stakingKeys', 1n * DOLLARS);
const stakingAmount = 2n * DOLLARS;

const failStakeObj = ExtrinsicHelper.stake(stakingKeys, providerId, stakingAmount);
await assert.rejects(failStakeObj.signAndSend(), { name: 'BalanceTooLowtoStake' });
Expand Down
125 changes: 10 additions & 115 deletions e2e/capacity/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,15 @@ describe('Capacity Transactions', function () {
before(async function () {
capacityKeys = createKeys('CapacityKeys');
capacityProvider = await createMsaAndProvider(fundingSource, capacityKeys, 'CapacityProvider', FUNDS_AMOUNT);
const numberOfTests = BigInt(this.test!.parent!.tests.length);
// Stake the amount for each test
await assert.doesNotReject(
stakeToProvider(fundingSource, fundingSource, capacityProvider, numberOfTests * amountStaked)
);
});

beforeEach(async function () {
starting_block = (await ExtrinsicHelper.apiPromise.rpc.chain.getHeader()).number.toNumber();
// Stake each time so that we always have enough capacity to do the call
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));
});

it('successfully pays with Capacity for eligible transaction - addIPFSMessage', async function () {
Expand Down Expand Up @@ -249,11 +252,12 @@ describe('Capacity Transactions', function () {
[delegatorKeys, delegatorProviderId] = await createDelegator(fundingSource);
assert.notEqual(delegatorKeys, undefined, 'setup should populate delegator_key');
assert.notEqual(delegatorProviderId, undefined, 'setup should populate msa_id');
});

beforeEach(async function () {
// Stake each time so that we always have enough capacity to do the call
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));
// Stake the amount for each test
const numberOfTests = BigInt(this.test!.parent!.tests.length);
await assert.doesNotReject(
stakeToProvider(fundingSource, fundingSource, capacityProvider, numberOfTests * amountStaked)
);
});

it('successfully pays with Capacity for eligible transaction - applyItemActions', async function () {
Expand Down Expand Up @@ -757,113 +761,4 @@ describe('Capacity Transactions', function () {
});
});
});

describe('pay_with_capacity_batch_all', function () {
let capacityProviderKeys: KeyringPair;
let capacityProvider: u64;
let schemaId: u16;
let defaultPayload: AddProviderPayload;
const amountStaked = 9n * DOLLARS;

beforeEach(async function () {
capacityProviderKeys = createKeys('CapacityProviderKeys');
capacityProvider = await createMsaAndProvider(
fundingSource,
capacityProviderKeys,
'CapacityProvider',
FUNDS_AMOUNT
);
defaultPayload = {
authorizedMsaId: capacityProvider,
schemaIds: [schemaId],
};
});

it('successfully pays with Capacity for a batch of eligible transactions - [createSponsoredAccountWithDelegation, claimHandle]', async function () {
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));

const addProviderPayload = await generateDelegationPayload({ ...defaultPayload });
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);

const handle = getTestHandle();
const handle_vec = new Bytes(ExtrinsicHelper.api.registry, handle);
const expiration = (await getBlockNumber()) + 5;
const handlePayload = {
baseHandle: handle_vec,
expiration: expiration,
};
const claimHandlePayload: any = ExtrinsicHelper.api.registry.createType(
'CommonPrimitivesHandlesClaimHandlePayload',
handlePayload
);
const claimHandleProof = {
Sr25519: u8aToHex(delegatorKeys.sign(u8aWrapBytes(claimHandlePayload.toU8a()))),
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
claimHandleProof,
claimHandlePayload
);
const calls = [createSponsoredAccountWithDelegation, claimHandle];

const payWithCapacityBatchAllOp = ExtrinsicHelper.payWithCapacityBatchAll(capacityProviderKeys, calls);

const { target: batchCompletedEvent, eventMap } = await payWithCapacityBatchAllOp.signAndSend();

if (batchCompletedEvent && !ExtrinsicHelper.api.events.utility.BatchCompleted.is(batchCompletedEvent)) {
assert.fail('should return a BatchCompletedEvent');
}

assert.notEqual(eventMap['msa.DelegationGranted'], undefined, 'should have returned DelegationGranted event');
assert.notEqual(eventMap['handles.HandleClaimed'], undefined, 'should have returned HandleClaimed event');
});

it('batch fails if one transaction fails - [createSponsoredAccountWithDelegation, claimHandle]', async function () {
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));

const addProviderPayload = await generateDelegationPayload({ ...defaultPayload });
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);

const handle = 'test_handle_that_exceeds_the_byte_limit';
const handle_vec = new Bytes(ExtrinsicHelper.api.registry, handle);
const expiration = (await getBlockNumber()) + 5;
const handlePayload = {
baseHandle: handle_vec,
expiration: expiration,
};
const claimHandlePayload: any = ExtrinsicHelper.api.registry.createType(
'CommonPrimitivesHandlesClaimHandlePayload',
handlePayload
);
const calimHandleProof = {
Sr25519: u8aToHex(delegatorKeys.sign(u8aWrapBytes(claimHandlePayload.toU8a()))),
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
calimHandleProof,
claimHandlePayload
);
const calls = [createSponsoredAccountWithDelegation, claimHandle];

const payWithCapacityBatchAllOp = ExtrinsicHelper.payWithCapacityBatchAll(capacityProviderKeys, calls);

await assert.rejects(payWithCapacityBatchAllOp.signAndSend(), {
name: 'InvalidHandleByteLength',
});
});
});
});
132 changes: 132 additions & 0 deletions e2e/capacity/transactionsBatch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import '@frequency-chain/api-augment';
import { KeyringPair } from '@polkadot/keyring/types';
import { Bytes, u64, u16 } from '@polkadot/types';
import { u8aToHex } from '@polkadot/util/u8a/toHex';
import { u8aWrapBytes } from '@polkadot/util';
import assert from 'assert';
import { AddProviderPayload, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import {
createKeys,
createMsaAndProvider,
generateDelegationPayload,
getBlockNumber,
signPayloadSr25519,
stakeToProvider,
DOLLARS,
getTestHandle,
} from '../scaffolding/helpers';
import { getFundingSource } from '../scaffolding/funding';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-transactions-batch');

describe('Capacity Transactions Batch', function () {
describe('pay_with_capacity_batch_all', function () {
let capacityProviderKeys: KeyringPair;
let capacityProvider: u64;
let schemaId: u16;
let defaultPayload: AddProviderPayload;
const amountStaked = 9n * DOLLARS;

beforeEach(async function () {
capacityProviderKeys = createKeys('CapacityProviderKeys');
capacityProvider = await createMsaAndProvider(
fundingSource,
capacityProviderKeys,
'CapacityProvider',
FUNDS_AMOUNT
);
defaultPayload = {
authorizedMsaId: capacityProvider,
schemaIds: [schemaId],
};
});

it('successfully pays with Capacity for a batch of eligible transactions - [createSponsoredAccountWithDelegation, claimHandle]', async function () {
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));

const addProviderPayload = await generateDelegationPayload({ ...defaultPayload });
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);

const handle = getTestHandle();
const handle_vec = new Bytes(ExtrinsicHelper.api.registry, handle);
const expiration = (await getBlockNumber()) + 5;
const handlePayload = {
baseHandle: handle_vec,
expiration: expiration,
};
const claimHandlePayload: any = ExtrinsicHelper.api.registry.createType(
'CommonPrimitivesHandlesClaimHandlePayload',
handlePayload
);
const claimHandleProof = {
Sr25519: u8aToHex(delegatorKeys.sign(u8aWrapBytes(claimHandlePayload.toU8a()))),
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
claimHandleProof,
claimHandlePayload
);
const calls = [createSponsoredAccountWithDelegation, claimHandle];

const payWithCapacityBatchAllOp = ExtrinsicHelper.payWithCapacityBatchAll(capacityProviderKeys, calls);

const { target: batchCompletedEvent, eventMap } = await payWithCapacityBatchAllOp.signAndSend();

if (batchCompletedEvent && !ExtrinsicHelper.api.events.utility.BatchCompleted.is(batchCompletedEvent)) {
assert.fail('should return a BatchCompletedEvent');
}

assert.notEqual(eventMap['msa.DelegationGranted'], undefined, 'should have returned DelegationGranted event');
assert.notEqual(eventMap['handles.HandleClaimed'], undefined, 'should have returned HandleClaimed event');
});

it('batch fails if one transaction fails - [createSponsoredAccountWithDelegation, claimHandle]', async function () {
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));

const addProviderPayload = await generateDelegationPayload({ ...defaultPayload });
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);

const handle = 'test_handle_that_exceeds_the_byte_limit';
const handle_vec = new Bytes(ExtrinsicHelper.api.registry, handle);
const expiration = (await getBlockNumber()) + 5;
const handlePayload = {
baseHandle: handle_vec,
expiration: expiration,
};
const claimHandlePayload: any = ExtrinsicHelper.api.registry.createType(
'CommonPrimitivesHandlesClaimHandlePayload',
handlePayload
);
const calimHandleProof = {
Sr25519: u8aToHex(delegatorKeys.sign(u8aWrapBytes(claimHandlePayload.toU8a()))),
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
calimHandleProof,
claimHandlePayload
);
const calls = [createSponsoredAccountWithDelegation, claimHandle];

const payWithCapacityBatchAllOp = ExtrinsicHelper.payWithCapacityBatchAll(capacityProviderKeys, calls);

await assert.rejects(payWithCapacityBatchAllOp.signAndSend(), {
name: 'InvalidHandleByteLength',
});
});
});
});
8 changes: 7 additions & 1 deletion e2e/scaffolding/funding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const fundingSources = [
'capacity-rpcs',
'capacity-staking',
'capacity-transactions',
'capacity-transactions-batch',
'capacity-unstaking',
'check-metadata-hash',
'frequency-misc',
Expand All @@ -36,7 +37,12 @@ export const fundingSources = [
// Get the correct key for this Funding Source
export function getFundingSource(name: (typeof fundingSources)[number]) {
if (fundingSources.includes(name)) {
return keyring.addFromUri(`${coreFundingSourcesSeed}//${name}`, { name }, 'sr25519');
try {
return keyring.addFromUri(`${coreFundingSourcesSeed}//${name}`, { name }, 'sr25519');
} catch (e) {
console.error('Failed to build funding source: ', { name });
throw e;
}
}
throw new Error(`Unable to locate "${name}" in the list of funding sources`);
}
Expand Down
12 changes: 10 additions & 2 deletions e2e/scaffolding/globalHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@ import { fundingSources, getFundingSource, getRootFundingSource, getSudo } from
import { TEST_EPOCH_LENGTH, drainKeys, getNonce, setEpochLength } from './helpers';
import { isDev, providerUrl } from './env';

const SOURCE_AMOUNT = 100_000_000_000_000n;
const SOURCE_AMOUNT = 100_000_000_000_000n; // 1,000,000 UNIT per source

async function fundAllSources() {
const root = getRootFundingSource().keys;
console.log('Root funding source: ', root.address);
const nonce = await getNonce(root);
await Promise.all(
fundingSources.map((dest, i) => {
return ExtrinsicHelper.transferFunds(root, getFundingSource(dest), SOURCE_AMOUNT).signAndSend(nonce + i);
try {
const testFundingSource = getFundingSource(dest);
console.log(dest, testFundingSource.address.toString());
return ExtrinsicHelper.transferFunds(root, testFundingSource, SOURCE_AMOUNT).signAndSend(nonce + i);
} catch (e) {
console.error('Unable to fund soruce', { dest, nonce: nonce + i });
throw e;
}
})
);
console.log('Root funding complete!');
}

async function devSudoActions() {
Expand Down

0 comments on commit 9fd47cf

Please sign in to comment.