From 9fd47cf90b23b3030749790aceffbc726bd3dd40 Mon Sep 17 00:00:00 2001 From: Wil Wade Date: Mon, 21 Oct 2024 08:59:13 -0400 Subject: [PATCH] E2E tests: split transactions test and use more before all instead of 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` --- e2e/capacity/capacity_rpc.test.ts | 4 +- e2e/capacity/staking.test.ts | 4 +- e2e/capacity/transactions.test.ts | 125 ++--------------------- e2e/capacity/transactionsBatch.test.ts | 132 +++++++++++++++++++++++++ e2e/scaffolding/funding.ts | 8 +- e2e/scaffolding/globalHooks.ts | 12 ++- 6 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 e2e/capacity/transactionsBatch.test.ts diff --git a/e2e/capacity/capacity_rpc.test.ts b/e2e/capacity/capacity_rpc.test.ts index baa3429543..70e1ec84d1 100644 --- a/e2e/capacity/capacity_rpc.test.ts +++ b/e2e/capacity/capacity_rpc.test.ts @@ -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, diff --git a/e2e/capacity/staking.test.ts b/e2e/capacity/staking.test.ts index 7c10299227..b3f84a3d36 100644 --- a/e2e/capacity/staking.test.ts +++ b/e2e/capacity/staking.test.ts @@ -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' }); diff --git a/e2e/capacity/transactions.test.ts b/e2e/capacity/transactions.test.ts index 29c5466e0a..ae5b341515 100644 --- a/e2e/capacity/transactions.test.ts +++ b/e2e/capacity/transactions.test.ts @@ -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 () { @@ -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 () { @@ -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', - }); - }); - }); }); diff --git a/e2e/capacity/transactionsBatch.test.ts b/e2e/capacity/transactionsBatch.test.ts new file mode 100644 index 0000000000..b8845411ee --- /dev/null +++ b/e2e/capacity/transactionsBatch.test.ts @@ -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', + }); + }); + }); +}); diff --git a/e2e/scaffolding/funding.ts b/e2e/scaffolding/funding.ts index ea337e1240..67b868ae70 100644 --- a/e2e/scaffolding/funding.ts +++ b/e2e/scaffolding/funding.ts @@ -13,6 +13,7 @@ export const fundingSources = [ 'capacity-rpcs', 'capacity-staking', 'capacity-transactions', + 'capacity-transactions-batch', 'capacity-unstaking', 'check-metadata-hash', 'frequency-misc', @@ -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`); } diff --git a/e2e/scaffolding/globalHooks.ts b/e2e/scaffolding/globalHooks.ts index 9b877bf0e0..33314d4c7f 100644 --- a/e2e/scaffolding/globalHooks.ts +++ b/e2e/scaffolding/globalHooks.ts @@ -7,7 +7,7 @@ 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; @@ -15,9 +15,17 @@ async function fundAllSources() { 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() {