Skip to content

Commit

Permalink
test: e2e test of kitchen-sink.contract.js
Browse files Browse the repository at this point in the history
- tests a contract that uses orchestrate/async-flow in the multichain-testing environment
  • Loading branch information
0xpatrickdev committed Jul 10, 2024
1 parent 48f57ed commit 21742bd
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 2 deletions.
169 changes: 169 additions & 0 deletions multichain-testing/test/kitchen-sink.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
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<SetupContextWithWallets>;

const accounts = ['user1', 'user2'];

const contractName = 'kitchenSink';
const contractBuilder =
'../packages/builders/scripts/orchestration/init-kitchen-sink.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
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 KitchenSinkMakeAccountScenario {
chain: string;
chainId: string;
contractName: string;
// for faucet funds
denom: string;
expectedAddressPrefix: string;
wallet: string;
// the offer to execute
callPipe: string[];
offerArgs?: Record<string, unknown>;
}

const makeAccountScenario = test.macro(
async (t, scenario: KitchenSinkMakeAccountScenario) => {
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
// https://github.com/Agoric/agoric-sdk/issues/9643
// chain logs shows an UNPUBLISHED result
const _offerResult = await doOffer({
id: offerId,
invitationSpec: {
source: 'agoricContract',
instancePath: [scenario.contractName],
callPipe: [scenario.callPipe],
},
offerArgs: {
chainName: scenario.chain,
},
proposal: {},
});
t.true(_offerResult);
// t.is(await _offerResult, 'UNPUBLISHED', 'representation of continuing offer');

// TODO fix above so we don't have to poll for the offer result to be published
// https://github.com/Agoric/agoric-sdk/issues/9643
const currentWalletRecord = await retryUntilCondition(
() =>
vstorageClient.queryData(
`published.wallet.${wallets[scenario.wallet]}.current`,
),
({ offerToPublicSubscriberPaths }) =>
Object.fromEntries(offerToPublicSubscriberPaths)[offerId],
`${scenario.callPipe[0]} continuing invitation is in vstorage`,
);

const offerToPublicSubscriberMap = Object.fromEntries(
currentWalletRecord.offerToPublicSubscriberPaths,
);

const address = offerToPublicSubscriberMap[offerId]?.account
.split('.')
.pop();
t.log('Got address:', address);
t.regex(
address,
new RegExp(`^${scenario.expectedAddressPrefix}1`),
`address for ${scenario.chain} is valid`,
);

const latestWalletUpdate = await vstorageClient.queryData(
`published.wallet.${wallets[scenario.wallet]}`,
);
t.log('latest wallet update', latestWalletUpdate);
t.like(
latestWalletUpdate.status,
{
id: offerId,
numWantsSatisfied: 1,
result: 'UNPUBLISHED',
error: undefined,
},
'wallet offer satisfied without errors',
);
},
);

const chainConfigs = {
cosmoshub: {
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'],
},
};

for (const [chainName, config] of Object.entries(chainConfigs)) {
for (const wallet of accounts) {
const scenario = {
...config,
contractName: 'kitchenSink',
wallet,
};
test.serial(
`Create account on ${chainName} for ${wallet}`,
makeAccountScenario,
scenario,
);
}
}
2 changes: 1 addition & 1 deletion multichain-testing/test/stake-ica.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion multichain-testing/tools/agd-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const makeAgdTools = async (
execFileSync,
}: Pick<typeof import('child_process'), 'execFile' | 'execFileSync'>,
) => {
const bundleCache = unsafeMakeBundleCache('bundles');
const bundleCache = await unsafeMakeBundleCache('bundles');
const tools = await makeE2ETools(log, bundleCache, {
execFileSync,
execFile,
Expand Down

0 comments on commit 21742bd

Please sign in to comment.