From 757e87efd69183ebe33537b835cdc59f00c4ba58 Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Thu, 5 Sep 2024 18:15:16 +0300 Subject: [PATCH] add tests for cron module --- package.json | 7 +- src/helpers/constants.ts | 1 + src/testcases/parallel/governance.test.ts | 83 +++--- src/testcases/run_in_band/cron.test.ts | 291 ++++++++++++++++++++++ yarn.lock | 12 +- 5 files changed, 345 insertions(+), 49 deletions(-) create mode 100644 src/testcases/run_in_band/cron.test.ts diff --git a/package.json b/package.json index d5898c53..1997e74f 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "scripts": { "test": "yarn test:parallel && yarn test:run_in_band", "test:parallel": "vitest --run src/testcases/parallel --bail 1 --reporter=basic", - "test:run_in_band": "yarn test:feemarket && yarn test:globalfee && yarn test:interchaintx && yarn test:interchain_kv_query && yarn test:interchain_tx_query_plain && yarn test:tokenomics && yarn test:reserve && yarn test:ibc_hooks && yarn test:float && yarn test:parameters && yarn test:dex_grpc && yarn test:dex_bindings && yarn test:slinky && yarn test:chain_manager && yarn test:tokenfactory", + "test:run_in_band": "yarn test:feemarket && yarn test:globalfee && yarn test:interchaintx && yarn test:interchain_kv_query && yarn test:interchain_tx_query_plain && yarn test:tokenomics && yarn test:reserve && yarn test:ibc_hooks && yarn test:float && yarn test:parameters && yarn test:dex_grpc && yarn test:dex_bindings && yarn test:slinky && yarn test:chain_manager && yarn test:tokenfactory && yarn test:cron", "test:ibc_transfer": "vitest --run src/testcases/parallel/ibc_transfer --bail 1", "test:slinky": "vitest --run src/testcases/run_in_band/slinky --bail 1", + "test:cron": "vitest --run src/testcases/run_in_band/cron --bail 1", "test:grpc_queries": "vitest --run src/testcases/parallel/grpc_queries --bail 1", "test:interchaintx": "vitest --run src/testcases/run_in_band/interchaintx --bail 1", "test:interchain_kv_query": "vitest --run src/testcases/run_in_band/interchain_kv_query --bail 1", @@ -42,7 +43,7 @@ "@cosmjs/stargate": "0.32.4", "@cosmjs/tendermint-rpc": "^0.32.4", "@neutron-org/neutronjs": "4.2.0", - "@neutron-org/neutronjsplus": "0.5.0", + "@neutron-org/neutronjsplus": "https://github.com/neutron-org/neutronjsplus.git#90419a2508b4a62e646c9449c983a4640643ad83", "@types/lodash": "^4.14.182", "axios": "1.6.0", "commander": "^10.0.0", @@ -85,4 +86,4 @@ "engines": { "node": ">=20.0" } -} +} \ No newline at end of file diff --git a/src/helpers/constants.ts b/src/helpers/constants.ts index 6f6c440c..b183490d 100644 --- a/src/helpers/constants.ts +++ b/src/helpers/constants.ts @@ -59,6 +59,7 @@ export const CONTRACTS = { FLOATY: '../contracts_thirdparty/floaty_2.0.wasm', DEX_GRPC: 'dex_grpc.wasm', DEX_DEV: 'dex.wasm', + CRON: 'cron.wasm', // TGE liquidity migration related contracts with fixed versions diff --git a/src/testcases/parallel/governance.test.ts b/src/testcases/parallel/governance.test.ts index fedf542c..f9f3d903 100644 --- a/src/testcases/parallel/governance.test.ts +++ b/src/testcases/parallel/governance.test.ts @@ -312,14 +312,17 @@ describe('Neutron / Governance', () => { 'Proposal #11', '', '1000', - 'proposal11', - 5, - [ - { - contract: contractAddress, - msg: '{"test_msg": {"return_err": false, "arg": "proposal_11"}}', - }, - ], + { + name: 'proposal11', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"test_msg": {"return_err": false, "arg": "proposal_11"}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_BEGIN_BLOCKER', + }, ); }); @@ -330,7 +333,7 @@ describe('Neutron / Governance', () => { 'Proposal #12', '', '1000', - 'proposal11', + { name: 'proposal11' }, ); }); @@ -341,22 +344,25 @@ describe('Neutron / Governance', () => { 'Proposal #13', '', '1000', - 'proposal13', - 5, - [ - { - contract: contractAddress, - msg: '{"test_msg": {"return_err": true, "arg": ""}}', - }, - { - contract: contractAddress, - msg: '{"incorrect_format": {"return_err": false, "arg": "proposal_11"}}', - }, - { - contract: contractAddress, - msg: '{"test_msg": {"return_err": false, "arg": "three_messages"}}', - }, - ], + { + name: 'proposal13', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"test_msg": {"return_err": true, "arg": ""}}', + }, + { + contract: contractAddress, + msg: '{"incorrect_format": {"return_err": false, "arg": "proposal_11"}}', + }, + { + contract: contractAddress, + msg: '{"test_msg": {"return_err": false, "arg": "three_messages"}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_BEGIN_BLOCKER', + }, ); }); @@ -367,18 +373,21 @@ describe('Neutron / Governance', () => { 'Proposal #14', '', '1000', - 'proposal14', - 5, - [ - { - contract: contractAddress, - msg: '{"test_msg": {"return_err": false, "arg": "correct_msg"}}', - }, - { - contract: contractAddress, - msg: '{"test_msg": {"return_err": true, "arg": ""}}', - }, - ], + { + name: 'proposal14', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"test_msg": {"return_err": false, "arg": "correct_msg"}}', + }, + { + contract: contractAddress, + msg: '{"test_msg": {"return_err": true, "arg": ""}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_BEGIN_BLOCKER', + }, ); }); diff --git a/src/testcases/run_in_band/cron.test.ts b/src/testcases/run_in_band/cron.test.ts new file mode 100644 index 00000000..2d64a608 --- /dev/null +++ b/src/testcases/run_in_band/cron.test.ts @@ -0,0 +1,291 @@ +import '@neutron-org/neutronjsplus'; +import { LocalState } from '../../helpers/local_state'; +import { Wallet } from '../../helpers/wallet'; +import { CONTRACTS } from '../../helpers/constants'; +import { + Dao, + DaoMember, + getDaoContracts, + getNeutronDAOCore, +} from '@neutron-org/neutronjsplus/dist/dao'; +import { RunnerTestSuite, inject } from 'vitest'; +import { NEUTRON_DENOM } from '../../helpers/constants'; +import { QueryClientImpl as CronQueryClient } from '@neutron-org/neutronjs/neutron/cron/query.rpc.Query'; +import { QueryClientImpl as AdminQueryClient } from '@neutron-org/neutronjs/cosmos/adminmodule/adminmodule/query.rpc.Query'; +import { SigningNeutronClient } from '../../helpers/signing_neutron_client'; +import config from '../../config.json'; + +describe('Neutron / Cron', () => { + let testState: LocalState; + let neutronWallet: Wallet; + let neutronClient: SigningNeutronClient; + let mainDao: Dao; + let daoMember: DaoMember; + + let chainManagerAddress: string; + let contractAddress: string; + let proposalId: number; + + let cronQuerier: CronQueryClient; + + beforeAll(async (suite: RunnerTestSuite) => { + testState = await LocalState.create(config, inject('mnemonics'), suite); + neutronWallet = await testState.nextWallet('neutron'); + neutronClient = await SigningNeutronClient.connectWithSigner( + testState.rpcNeutron, + neutronWallet.directwallet, + neutronWallet.address, + ); + const neutronRpcClient = await testState.neutronRpcClient(); + const daoCoreAddress = await getNeutronDAOCore( + neutronClient, + neutronRpcClient, + ); // add assert for some addresses + const daoContracts = await getDaoContracts(neutronClient, daoCoreAddress); + mainDao = new Dao(neutronClient, daoContracts); + daoMember = new DaoMember( + mainDao, + neutronClient.client, + neutronWallet.address, + NEUTRON_DENOM, + ); + + const queryClient = new AdminQueryClient(neutronRpcClient); + const admins = await queryClient.admins(); + chainManagerAddress = admins.admins[0]; + + cronQuerier = new CronQueryClient(neutronRpcClient); + }); + + describe('Contracts', () => { + let codeId: number; + test('store contract', async () => { + codeId = await neutronClient.upload(CONTRACTS.CRON); + expect(codeId).toBeGreaterThan(0); + }); + test('instantiate', async () => { + contractAddress = await neutronClient.instantiate(codeId, {}); + }); + }); + + describe('prepare: bond funds', () => { + test('bond from wallet', async () => { + await daoMember.bondFunds('10000'); + await neutronClient.getWithAttempts( + async () => await mainDao.queryVotingPower(daoMember.user), + async (response) => response.power == 10000, + 20, + ); + }); + }); + + describe('send a bit funds to core contracts', () => { + test('send funds from wallet', async () => { + const res = await neutronClient.sendTokens( + mainDao.contracts.core.address, + [ + { + denom: NEUTRON_DENOM, + amount: '1000', + }, + ], + { + gas: '4000000', + amount: [{ denom: NEUTRON_DENOM, amount: '10000' }], + }, + ); + expect(res.code).toEqual(0); + }); + }); + + describe('create proposal #1', () => { + test('add schedule #1', async () => { + proposalId = await daoMember.submitAddSchedule( + chainManagerAddress, + 'Proposal #1', + '', + '1000', + { + name: 'schedule1', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"add_begin_blocker_schedule": {"name": "schedule1"}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_BEGIN_BLOCKER', + }, + ); + + await daoMember.voteYes(proposalId); + await mainDao.checkPassedProposal(proposalId); + await daoMember.executeProposalWithAttempts(proposalId); + }); + + test('check that schedule was added', async () => { + const res = await cronQuerier.schedules(); + expect(res.schedules.length).toEqual(1); + }); + + test('check that msg from schedule was executed', async () => { + await neutronClient.waitBlocks(15); + + const queryResult: number = + await neutronClient.queryContractSmart(contractAddress, { + get_begin_blocker_schedule_counter: { + name: 'schedule1', + }, + }); + + expect(queryResult).toBeGreaterThanOrEqual(2); + }); + }); + + describe('create proposal #2', () => { + test('remove schedule #1', async () => { + proposalId = await daoMember.submitRemoveSchedule( + chainManagerAddress, + 'Proposal #2', + '', + '1000', + { + name: 'schedule1', + }, + ); + + await daoMember.voteYes(proposalId); + await mainDao.checkPassedProposal(proposalId); + await daoMember.executeProposalWithAttempts(proposalId); + }); + + test('check that schedule was removed', async () => { + const res = await cronQuerier.schedules(); + expect(res.schedules.length).toEqual(0); + }); + + test('check that msg from schedule was not executed because schedule was removed', async () => { + const oldQueryResult: number = + await neutronClient.queryContractSmart(contractAddress, { + get_begin_blocker_schedule_counter: { + name: 'schedule1', + }, + }); + + await neutronClient.waitBlocks(10); + + const newQueryResult: number = + await neutronClient.queryContractSmart(contractAddress, { + get_begin_blocker_schedule_counter: { + name: 'schedule1', + }, + }); + + expect(newQueryResult).toEqual(oldQueryResult); + }); + }); + + describe('create proposal #3', () => { + test('add schedule #2', async () => { + proposalId = await daoMember.submitAddSchedule( + chainManagerAddress, + 'Proposal #3', + '', + '1000', + { + name: 'schedule2', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"add_begin_blocker_schedule": {"name": "schedule2"}}', + }, + { + contract: contractAddress, + msg: '{"unknown_msg": {"name": "schedule2"}}', + }, + { + contract: contractAddress, + msg: '{"add_begin_blocker_schedule": {"name": "schedule2"}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_BEGIN_BLOCKER', + }, + ); + + await daoMember.voteYes(proposalId); + await mainDao.checkPassedProposal(proposalId); + await daoMember.executeProposalWithAttempts(proposalId); + }); + + test('check that schedule was added', async () => { + const res = await cronQuerier.schedules(); + expect(res.schedules.length).toEqual(1); + }); + + test('check that no msgs from schedule were executed because there is an error in the second msg', async () => { + await neutronClient.waitBlocks(10); + + const queryResult: number = + await neutronClient.queryContractSmart(contractAddress, { + get_end_blocker_schedule_counter: { + name: 'schedule2', + }, + }); + + expect(queryResult).toEqual(null); + }); + }); + + describe('create proposal #4', () => { + test('add schedule #3', async () => { + proposalId = await daoMember.submitAddSchedule( + chainManagerAddress, + 'Proposal #4', + '', + '1000', + { + name: 'shedule3', + period: 5, + msgs: [ + { + contract: contractAddress, + msg: '{"add_end_blocker_schedule": {"name": "schedule3"}}', + }, + { + contract: contractAddress, + msg: '{"add_end_blocker_schedule": {"name": "schedule3"}}', + }, + { + contract: contractAddress, + msg: '{"add_end_blocker_schedule": {"name": "schedule3"}}', + }, + ], + execution_stage: 'EXECUTION_STAGE_END_BLOCKER', + }, + ); + + await daoMember.voteYes(proposalId); + await mainDao.checkPassedProposal(proposalId); + await daoMember.executeProposalWithAttempts(proposalId); + }); + + test('check that schedule was added', async () => { + const res = await cronQuerier.schedules(); + expect(res.schedules.length).toEqual(2); + }); + + test('check that msgs from schedule was executed', async () => { + await neutronClient.waitBlocks(15); + + let queryResult: number = + await neutronClient.queryContractSmart(contractAddress, { + get_end_blocker_schedule_counter: { + name: 'schedule3', + }, + }); + + expect(queryResult).toBeGreaterThanOrEqual(6); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 862ec492..6d1c80be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1302,25 +1302,19 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@neutron-org/cosmjs-types@0.9.2-rc1": - version "0.9.2-rc1" - resolved "https://registry.yarnpkg.com/@neutron-org/cosmjs-types/-/cosmjs-types-0.9.2-rc1.tgz#ca1fc1dc9566858dbd765e8f82c8a70097bcc84b" - integrity sha512-ju2AqJ14yO4+JF8RwY4ZVy7f2HVjhdf66SfhS6y4ucBZm997/E/yYVMnpWmUncVg8ARooISOKaOYNagqz0am6Q== - "@neutron-org/neutronjs@4.2.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@neutron-org/neutronjs/-/neutronjs-4.2.0.tgz#7d98d4bc1568f22c015736d6fbe768ddfba14798" integrity sha512-l3ILkT8H6bO522RoNb37NMQkqlp8qvKNm7v6QlzORtClqbM7VbRv2/INgy8wn8USV5AmcnCdl9M4KfvvGw5k9w== -"@neutron-org/neutronjsplus@0.5.0": +"@neutron-org/neutronjsplus@https://github.com/neutron-org/neutronjsplus.git#90419a2508b4a62e646c9449c983a4640643ad83": version "0.5.0" - resolved "https://registry.yarnpkg.com/@neutron-org/neutronjsplus/-/neutronjsplus-0.5.0.tgz#d68afb8142ee0bd2d3eee21916901507503360a3" - integrity sha512-dzWL9hTVorMskWzW/ZEUK3Cruw0AkOlC8fk6pFIyli4XkNooJKL/H7V8PSxiwIyx3k+EpIZ0I5FpzCL9EitNMg== + resolved "https://github.com/neutron-org/neutronjsplus.git#90419a2508b4a62e646c9449c983a4640643ad83" dependencies: "@cosmjs/cosmwasm-stargate" "^0.32.4" "@cosmjs/proto-signing" "^0.32.4" "@cosmjs/stargate" "0.32.4" - "@neutron-org/cosmjs-types" "0.9.2-rc1" + "@neutron-org/neutronjs" "4.2.0" axios "1.6.0" bip39 "^3.1.0" long "^5.2.1"