From 78ec9cb8cfd7120a271b2b55445020c3ee931b6a Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 10 Jul 2024 01:28:06 -0400 Subject: [PATCH] test: e2e test of kitchen-sink.contract.js - tests a contract that uses orchestrate/async-flow in the multichain-testing environment --- multichain-testing/test/kitchen-sink.test.ts | 150 +++++++++++++++++++ multichain-testing/test/stake-ica.test.ts | 2 +- 2 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 multichain-testing/test/kitchen-sink.test.ts diff --git a/multichain-testing/test/kitchen-sink.test.ts b/multichain-testing/test/kitchen-sink.test.ts new file mode 100644 index 000000000000..077bccf41937 --- /dev/null +++ b/multichain-testing/test/kitchen-sink.test.ts @@ -0,0 +1,150 @@ +import anyTest from '@endo/ses-ava/prepare-endo.js'; +import type { TestFn } from 'ava'; +import { commonSetup, SetupContextWithWallets } from './support.js'; +import { makeDoOffer } from '../tools/e2e-tools.js'; + +const test = anyTest as TestFn; + +const accounts = ['user1']; + +const contractName = 'kitchenSink'; +const contractBuilder = + '../packages/builders/scripts/orchestration/init-kitchen-sink.js'; + +test.before(async t => { + const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); + // XXX not necessary for CI, but helpful for unexpected failures in + // active development (test.after cleanup doesn't run). + deleteTestKeys(accounts).catch(); + const wallets = await setupTestKeys(accounts); + t.context = { ...rest, wallets, deleteTestKeys }; + + t.log('bundle and install contract', contractName); + await t.context.deployBuilder(contractBuilder); + const vstorageClient = t.context.makeQueryTool(); + await t.context.retryUntilCondition( + () => vstorageClient.queryData(`published.agoricNames.instance`), + res => contractName in Object.fromEntries(res), + `${contractName} instance is available`, + ); +}); + +test.after(async t => { + const { deleteTestKeys } = t.context; + deleteTestKeys(accounts); +}); + +interface KitchenSinkScenario { + chain: string; + chainId: string; + contractName: string; + // for faucet funds + denom: string; + expectedAddressPrefix: string; + wallet: string; + // the offer to execute + callPipe: string[]; + offerArgs?: Record; +} + +const stakeScenario = test.macro(async (t, scenario: KitchenSinkScenario) => { + const { wallets, provisionSmartWallet, makeQueryTool, retryUntilCondition } = + t.context; + + const vstorageClient = makeQueryTool(); + + const wdUser1 = await provisionSmartWallet(wallets[scenario.wallet], { + BLD: 100n, + IST: 100n, + }); + t.log(`provisioning agoric smart wallet for ${wallets[scenario.wallet]}`); + + const doOffer = makeDoOffer(wdUser1); + t.log(`${scenario.callPipe.join('.')} offer`); + const offerId = `${scenario.callPipe.join('.')}-${Date.now()}`; + + // FIXME we get payouts but not an offer result; it times out + // chain logs shows an UNPUBLISHED result + const _offerResult = await doOffer({ + id: offerId, + invitationSpec: { + source: 'agoricContract', + instancePath: [scenario.contractName], + callPipe: [scenario.callPipe], + }, + offerArgs: { + chainName: 'cosmoshub', + }, + proposal: {}, + }); + t.true(_offerResult); + // t.is(await _offerResult, 'UNPUBLISHED', 'representation of continuing offer'); + + // XXX fix above so we don't have to wait for the offer result to be published + const { offerToPublicSubscriberPaths: makeAccountPublicSubscriberPaths } = + await retryUntilCondition( + () => + vstorageClient.queryData( + `published.wallet.${wallets[scenario.wallet]}.current`, + ), + ({ offerToPublicSubscriberPaths }) => + !!offerToPublicSubscriberPaths.length, + 'makeAccount offer result is in vstorage', + ); + + t.log(makeAccountPublicSubscriberPaths[0]); + t.regex( + makeAccountPublicSubscriberPaths[0][0], + new RegExp(scenario.callPipe[0]), + ); + + + const address = makeAccountPublicSubscriberPaths?.[0]?.[1]?.account + .split('.') + .pop(); + t.log('Got address:', address); + t.regex( + address, + new RegExp(`^${scenario.expectedAddressPrefix}1`), + `address for ${scenario.chain} is valid`, + ); +}); + +const chainConfigs = { + cosmos: { + chain: 'cosmoshub', + chainId: 'gaialocal', + denom: 'uatom', + expectedAddressPrefix: 'cosmos', + callPipe: ['makeCosmosOrchAcctInvitation'], + offerArgs: { chainName: 'cosmoshub' }, + }, + osmosis: { + chain: 'osmosis', + chainId: 'osmosislocal', + denom: 'uosmo', + expectedAddressPrefix: 'osmo', + callPipe: ['makeCosmosOrchAcctInvitation'], + offerArgs: { chainName: 'osmosis' }, + }, + agoric: { + chain: 'agoric', + chainId: 'agoriclocal', + denom: 'ubld', + expectedAddressPrefix: 'agoric', + callPipe: ['makeLocalOrchAcctInvitation'], + }, +}; + +const scenarios = Object.entries(chainConfigs).flatMap(([chainName, config]) => + accounts.map(wallet => ({ + ...config, + contractName: 'kitchenSink', + wallet, + testName: `Create account on ${chainName} for ${wallet}`, + })), +); + +scenarios.forEach(scenario => { + test.serial(scenario.testName, stakeScenario, scenario); +}); diff --git a/multichain-testing/test/stake-ica.test.ts b/multichain-testing/test/stake-ica.test.ts index 12f0e0bffe7e..1746e4f0194f 100644 --- a/multichain-testing/test/stake-ica.test.ts +++ b/multichain-testing/test/stake-ica.test.ts @@ -114,7 +114,7 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => { const queryClient = makeQueryClient(getRestEndpoint()); t.log('Requesting faucet funds'); - // XXX fails intermitently until https://github.com/cosmology-tech/starship/issues/417 + // XXX fails intermittently until https://github.com/cosmology-tech/starship/issues/417 await creditFromFaucet(address); const { balances } = await retryUntilCondition(