Skip to content

Commit

Permalink
feat: integration tests (#2)
Browse files Browse the repository at this point in the history
* tmp: add integration tests

* fix: fix

* fix tests

* ignore cosmopark file

* tmp

* kek

* tests run

* add gaia client for tests

* review fixes

* add waitResult

* tests almost pass

* fix tests

* add incorrect stage checks

* finish tests

* remove old manual tests

---------

Co-authored-by: Sergey Ratiashvili <[email protected]>
  • Loading branch information
NeverHappened and ratik authored Oct 17, 2023
1 parent fa144d9 commit 784d5d3
Show file tree
Hide file tree
Showing 79 changed files with 6,029 additions and 2,795 deletions.
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions integration-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
/docker-compose-*.yml
.__cosmopark
File renamed without changes.
2 changes: 2 additions & 0 deletions integration-tests/.rtx.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tools]
node = "16"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added integration-tests/artifacts/credits.wasm
Binary file not shown.
Binary file not shown.
700 changes: 700 additions & 0 deletions integration-tests/artifacts/scripts/init-neutrond.sh

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions integration-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "neutron-airdrop-transfer-integration-tests",
"version": "1.0.0",
"main": "vitest",
"license": "MIT",
"scripts": {
"test": "vitest --run",
"test:satellite": "vitest satellite",
"watch": "vitest",
"build-ts-client": "ts-node ../../lionco-integration-tests/src/rebuild-client.ts"
},
"dependencies": {
"@cosmjs/amino": "^0.31.0",
"@cosmjs/cosmwasm-stargate": "^0.31.0",
"@cosmjs/proto-signing": "^0.31.0",
"@cosmjs/stargate": "^0.31.0",
"@neutron-org/client-ts": "^1.4.0",
"@neutron-org/contracts2ts": "^1.3.1",
"@neutron-org/cosmopark": "^1.2.9",
"@neutron-org/neutronjsplus": "0.0.15",
"crypto-js": "^4.1.1"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"@vitest/ui": "^0.34.1",
"eslint": "^8.46.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.1",
"ts-node": "^10.9.1",
"typescript": "^5.1.6",
"vitest": "^0.34.1"
},
"description": "Lido on Cosmos integration test",
"repository": "[email protected]:hadronlabs-org/lionco-integration-tests.git"
}
37 changes: 37 additions & 0 deletions integration-tests/src/helpers/gaia_client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {IgniteClient} from "@neutron-org/client-ts/src/client";
import {Module as CosmosAdminmoduleAdminmodule} from "@neutron-org/client-ts/src/cosmos.adminmodule.adminmodule";
import {Module as CosmosAuthV1Beta1} from "@neutron-org/client-ts/src/cosmos.auth.v1beta1";
import {Module as CosmosAuthzV1Beta1} from "@neutron-org/client-ts/src/cosmos.authz.v1beta1";
import {Module as CosmosBankV1Beta1} from "@neutron-org/client-ts/src/cosmos.bank.v1beta1";
import {Module as CosmosBaseTendermintV1Beta1} from "@neutron-org/client-ts/src/cosmos.base.tendermint.v1beta1";
import {Module as CosmosCrisisV1Beta1} from "@neutron-org/client-ts/src/cosmos.crisis.v1beta1";
import {Module as CosmosEvidenceV1Beta1} from "@neutron-org/client-ts/src/cosmos.evidence.v1beta1";
import {Module as CosmosFeegrantV1Beta1} from "@neutron-org/client-ts/src/cosmos.feegrant.v1beta1";
import {Module as CosmosParamsV1Beta1} from "@neutron-org/client-ts/src/cosmos.params.v1beta1";
import {Module as CosmosSlashingV1Beta1} from "@neutron-org/client-ts/src/cosmos.slashing.v1beta1";
import {Module as CosmosTxV1Beta1} from "@neutron-org/client-ts/src/cosmos.tx.v1beta1";
import {Module as CosmosUpgradeV1Beta1} from "@neutron-org/client-ts/src/cosmos.upgrade.v1beta1";
import {Module as CosmosVestingV1Beta1} from "@neutron-org/client-ts/src/cosmos.vesting.v1beta1";
import {Module as CosmwasmWasmV1} from "@neutron-org/client-ts/src/cosmwasm.wasm.v1";
import {Module as GaiaGlobalfeeV1Beta1} from "@neutron-org/client-ts/src/gaia.globalfee.v1beta1";
import {
Module as IbcApplicationsInterchainAccountsControllerV1
} from "@neutron-org/client-ts/src/ibc.applications.interchain_accounts.controller.v1";
import {
Module as IbcApplicationsInterchainAccountsHostV1
} from "@neutron-org/client-ts/src/ibc.applications.interchain_accounts.host.v1";
import {Module as IbcCoreChannelV1} from "@neutron-org/client-ts/src/ibc.core.channel.v1";
import {Module as IbcCoreClientV1} from "@neutron-org/client-ts/src/ibc.core.client.v1";
import {Module as IbcCoreConnectionV1} from "@neutron-org/client-ts/src/ibc.core.connection.v1";
import {
Module as InterchainSecurityCcvConsumerV1
} from "@neutron-org/client-ts/src/interchain_security.ccv.consumer.v1";
import {
Module as InterchainSecurityCcvProviderV1
} from "@neutron-org/client-ts/src/interchain_security.ccv.provider.v1";
import {Module as InterchainSecurityCcvV1} from "@neutron-org/client-ts/src/interchain_security.ccv.v1";
import {Module as RouterV1} from "@neutron-org/client-ts/src/router.v1";

export const GaiaClient = IgniteClient.plugin([
CosmosAdminmoduleAdminmodule, CosmosAuthV1Beta1, CosmosAuthzV1Beta1, CosmosBankV1Beta1, CosmosBaseTendermintV1Beta1, CosmosCrisisV1Beta1, CosmosEvidenceV1Beta1, CosmosFeegrantV1Beta1, CosmosParamsV1Beta1, CosmosSlashingV1Beta1, CosmosTxV1Beta1, CosmosUpgradeV1Beta1, CosmosVestingV1Beta1, CosmwasmWasmV1, GaiaGlobalfeeV1Beta1, IbcApplicationsInterchainAccountsControllerV1, IbcApplicationsInterchainAccountsHostV1, IbcCoreChannelV1, IbcCoreClientV1, IbcCoreConnectionV1, InterchainSecurityCcvConsumerV1, InterchainSecurityCcvProviderV1, InterchainSecurityCcvV1, RouterV1
]);
10 changes: 10 additions & 0 deletions integration-tests/src/helpers/ibc_denom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import crypto from "crypto";

export const getIBCDenom = (portName, channelName, denom: string): string => {
const uatomIBCHash = crypto
.createHash('sha256')
.update(`${portName}/${channelName}/${denom}`)
.digest('hex')
.toUpperCase();
return `ibc/${uatomIBCHash}`;
};
45 changes: 45 additions & 0 deletions integration-tests/src/helpers/sleep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
export const sleep = async (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));

export const waitFor = async (
fn: () => Promise<boolean>,
timeoutMs: number = 10000,
intervalMs: number = 600,
): Promise<void> => {
const start = Date.now();
// eslint-disable-next-line no-constant-condition
while (true) {
if (await fn()) {
break;
}
if (Date.now() - start > timeoutMs) {
throw new Error('Timeout waiting for condition');
}
await sleep(intervalMs);
}
};

export const waitForResult = async<T> (
fn: () => Promise<T>,
ready: (t: T) => boolean,
timeoutMs: number = 10000,
intervalMs: number = 600,
): Promise<T> => {
const start = Date.now()
let value: T

// eslint-disable-next-line no-constant-condition
while (true) {
value = await fn()
if (ready(value)) {
break;
}
if (Date.now() - start > timeoutMs) {
throw new Error('Timeout waiting for condition')
}
await sleep(intervalMs)
}

return value
};

221 changes: 221 additions & 0 deletions integration-tests/src/testSuite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import cosmopark, { CosmoparkConfig } from '@neutron-org/cosmopark';
import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { StargateClient } from '@cosmjs/stargate';
import { Client as NeutronClient } from '@neutron-org/client-ts';
import {waitFor} from "./helpers/sleep";
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';

const keys = [
'master',
'hermes',
'ibcrelayer',
'demowallet1',
'demo1',
'demo2',
'demo3',
] as const;

const networkConfigs = {
gaia: {
binary: 'gaiad',
chain_id: 'testgaia-1',
denom: 'uatom',
image: 'gaia-node',
prefix: 'cosmos',
validators: 1,
validators_balance: '1000000000',
genesis_opts: {
// 'app_state.staking.params.denom': 'uatom',
// 'app_state.staking.params.mint_denom': 'uatom',
'app_state.staking.params.bond_denom': 'uatom',

// 'app_state.slashing.params.downtime_jail_duration': '10s',
// 'app_state.slashing.params.signed_blocks_window': '10',
// 'app_state.staking.params.validator_bond_factor': '10',
'app_state.interchainaccounts.host_genesis_state.params.allow_messages': [
'*',
],
},
config_opts: {
'rpc.laddr': 'tcp://0.0.0.0:26657',
},
app_opts: {
'api.enable': true,
'api.swagger': true,
'grpc.enable': true,
'minimum-gas-prices': '0uatom',
'rosetta.enable': true,
},
},
neutron: {
binary: 'neutrond',
chain_id: 'testneutron-1',
denom: 'untrn',
image: 'neutron-node',
prefix: 'neutron',
trace: true,
type: 'ics',
upload: [
'./artifacts/contracts',
'./artifacts/contracts_thirdparty',
'./artifacts/scripts/init-neutrond.sh',
],
post_init: ['CHAINID=testneutron-1 CHAIN_DIR=/opt /opt/init-neutrond.sh'],
genesis_opts: {
'app_state.crisis.constant_fee.denom': 'untrn',
'app_state.interchainaccounts.host_genesis_state.params.allow_messages': [
'*',
],
},
config_opts: {
'consensus.timeout_commit': '1s',
'consensus.timeout_propose': '1s',
},
app_opts: {
'api.enable': 'true',
'api.swagger': 'true',
'grpc.enable': 'true',
'minimum-gas-prices': '0.0025untrn',
'rosetta.enable': 'true',
'telemetry.prometheus-retention-time': 1000,
},
},
};


const relayersConfig = {
hermes: {
balance: '1000000000',
binary: 'hermes',
config: {
'chains.0.trusting_period': '14days',
'chains.0.unbonding_period': '504h0m0s',
},
image: 'hermes',
log_level: 'trace',
type: 'hermes',
},
neutron: {
balance: '1000000000',
binary: 'neutron-query-relayer',
image: 'neutron-org/neutron-query-relayer',
log_level: 'info',
type: 'neutron',
},
};

type Keys = (typeof keys)[number];

const awaitFirstBlock = async (rpc: string): Promise<void> =>
waitFor(async () => {
try {
const tendermintClient = await Tendermint34Client.connect(rpc);
const client= await StargateClient.create(tendermintClient);

// const client = await StargateClient.connect(rpc);
const block = await client.getBlock();
// console.log('block: ' + block.id)
if (block.header.height > 1) {
// console.log(`First block found for ${rpc}`)
return true;
}
} catch (e) {
// console.log(`Exception trying to find block for ${rpc}. Error: ${e.stack}`)
return false;
}
}, 20_000);

const awaitNeutronChannels = async (rest: string, rpc: string): Promise<void> =>
waitFor(async () => {
try {
const client = new NeutronClient({
apiURL: `http://${rest}`,
rpcURL: rpc,
prefix: 'neutron',
});
const res = await client.IbcCoreChannelV1.query.queryChannels();
if (res.data.channels.length > 0) {
let channels = res.data.channels;
if (channels.every((c) => c.state === 'STATE_OPEN')) {
return true;
}
}
} catch (e) {
console.log('failed to find channels: ' + e.message)
return false;
}
}, 60_000);

export const generateWallets = async (): Promise<Record<Keys, string>> =>
keys.reduce(
async (acc, key) => {
const accObj = await acc;
const wallet = await DirectSecp256k1HdWallet.generate(12, {
prefix: 'neutron',
});
accObj[key] = wallet.mnemonic;
return accObj;
},
Promise.resolve({} as Record<Keys, string>),
);

export const setupPark = async (
context = 'lido',
networks: string[] = [],
needRelayers = false,
): Promise<cosmopark> => {
const wallets = await generateWallets();
const config: CosmoparkConfig = {
context,
networks: {},
master_mnemonic: wallets.master,
multicontext: true,
wallets: {
demowallet1: { mnemonic: wallets.demowallet1, balance: '1000000000' },
demo1: { mnemonic: wallets.demo1, balance: '1000000000' },
demo2: { mnemonic: wallets.demo2, balance: '1000000000' },
demo3: { mnemonic: wallets.demo3, balance: '1000000000' },
},
};
for (const network of networks) {
config.networks[network] = networkConfigs[network];
}
if (needRelayers) {
config.relayers = [
{
...relayersConfig.hermes,
networks,
connections: [networks],
mnemonic: wallets.hermes,
} as any,
{
...relayersConfig.neutron,
networks,
mnemonic: wallets.ibcrelayer,
},
];
}
const instance = await cosmopark.create(config);
// console.log('instance created')
await Promise.all(
Object.entries(instance.ports).map(([network, ports]) => {
// console.log(`await first block: ${ports.rpc}`);
return awaitFirstBlock(`127.0.0.1:${ports.rpc}`).catch((e) => {
console.log(`Failed to await first block for ${network}: ${e}`);
throw e;
})
}
),
);
// console.log('all first blocks found')
if (needRelayers) {
await awaitNeutronChannels(
`127.0.0.1:${instance.ports['neutron'].rest}`,
`127.0.0.1:${instance.ports['neutron'].rpc}`,
).catch((e) => {
// console.log(`Failed to await neutron channels: ${e}`);
throw e;
});
}
return instance;
};
Loading

0 comments on commit 784d5d3

Please sign in to comment.