Skip to content

Commit

Permalink
Merge pull request #8829 from Agoric/8381-integration-test-with-dapp-…
Browse files Browse the repository at this point in the history
…offer-up

feat(integration-test): use dapp-offer-up as target for getting-start…
  • Loading branch information
mergify[bot] authored Mar 13, 2024
2 parents 6793c14 + 794d8fe commit 7ba058a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 137 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
# Prerequisites
- uses: ./.github/actions/restore-node
with:
node-version: 16.x
node-version: 18.18
keep-endo: 'true'

# Select a branch on dapp to test against by adding text to the body of the
Expand Down
169 changes: 33 additions & 136 deletions packages/agoric-cli/tools/getting-started.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global process setTimeout clearTimeout setInterval clearInterval */
/* global process setTimeout setInterval clearInterval */

import fs from 'fs';
import path from 'path';
Expand All @@ -10,32 +10,21 @@ import { spawn } from 'child_process';

import { makePspawn } from '../src/helpers.js';

const TIMEOUT_SECONDS = 20 * 60;
const TIMEOUT_SECONDS = 3 * 60;

const dirname = new URL('./', import.meta.url).pathname;

// To keep in sync with https://agoric.com/documentation/getting-started/
// To keep in sync with https://docs.agoric.com/guides/getting-started/

// Note that we currently only test:
// agoric init dapp-foo
// agoric install
// agoric start --reset
// agoric deploy ./contract/deploy.js ./api/deploy.js
// (For simple-exchange and autoswap, the above also makes and accepts offers)
// cd ui && yarn install
// cd ui && yarn start
// yarn install
// yarn start:docker
// yarn start:contract
// yarn start:ui

export const gettingStartedWorkflowTest = async (t, options = {}) => {
const {
init: initOptions = [],
install: installOptions = [],
start: startOptions = [],
testUnsafePlugins = false,
} = options;
// FIXME: Do a search for an unused port or allow specification.
const PORT = '7999';
process.env.PORT = PORT;

const { init: initOptions = [] } = options;
const pspawn = makePspawn({ spawn });

// Kill an entire process group.
Expand All @@ -61,7 +50,6 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
const { AGORIC_CMD = JSON.stringify(defaultAgoricCmd()) } = process.env;
const agoricCmd = JSON.parse(AGORIC_CMD);
function myMain(args, opts = {}) {
// console.error('running agoric-cli', ...extraArgs, ...args);
return pspawnStdout(agoricCmd[0], [...agoricCmd.slice(1), ...args], {
stdio: ['ignore', 'pipe', 'inherit'],
env: { ...process.env, DEBUG: 'agoric:debug' },
Expand All @@ -70,6 +58,14 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
});
}

function yarn(args) {
return pspawnStdout('yarn', args, {
stdio: ['ignore', 'pipe', 'inherit'],
env: { ...process.env },
detached: true,
});
}

const olddir = process.cwd();
const { name } = tmp.dirSync({
unsafeCleanup: true,
Expand All @@ -83,7 +79,7 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
try {
f();
} catch (e) {
// console.log(e);
console.log(e);
}
}
if (sig) {
Expand All @@ -105,122 +101,32 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
initOptions.push(...opts);
}
t.is(
await myMain([
'init',
'--dapp-template',
'dapp-fungible-faucet',
...initOptions,
'dapp-foo',
]),
await myMain(['init', ...initOptions, 'dapp-foo']),
0,
'init dapp-foo works',
);
process.chdir('dapp-foo');

// ==============
// agoric install
if (process.env.AGORIC_INSTALL_OPTIONS) {
const opts = JSON.parse(process.env.AGORIC_INSTALL_OPTIONS);
installOptions.push(...opts);
}
t.is(await myMain(['install', ...installOptions]), 0, 'install works');
// yarn install
t.is(await yarn(['install']), 0, 'yarn install works');

// ==============
// agoric start --reset
const startResult = makePromiseKit();

if (process.env.AGORIC_START_OPTIONS) {
const opts = JSON.parse(process.env.AGORIC_START_OPTIONS);
startOptions.push(...opts);
}

// TODO: Allow this to work even if the port is already used.
const startP = myMain(['start', '--reset', ...startOptions]);
finalizers.push(() => pkill(startP.childProcess, 'SIGINT'));

let stdoutStr = '';
if (startP.childProcess.stdout) {
startP.childProcess.stdout.on('data', chunk => {
// console.log('stdout:', chunk.toString());
stdoutStr += chunk.toString();
if (stdoutStr.match(/(^|:\s+)swingset running$/m)) {
startResult.resolve(true);
}
});
}
startP.childProcess.on('close', code =>
startResult.reject(Error(`early termination: ${code}`)),
);
// yarn start:docker
t.is(await yarn(['start:docker']), 0, 'yarn start:docker works');

const timeout = setTimeout(
startResult.reject,
TIMEOUT_SECONDS * 1000,
'timeout',
);
t.is(await startResult.promise, true, `swingset running before timeout`);
clearTimeout(timeout);

const openP = myMain(['open', '--no-browser'], {
stdio: ['ignore', 'pipe', 'inherit'],
});
t.is(await openP, 0, `open --no-browser exits successfully`);

const testDeploy = async (deployCmd, opts = {}) => {
const deployResult = makePromiseKit();
const deployP = myMain(
['deploy', `--hostport=127.0.0.1:${PORT}`, ...deployCmd],
{
stdio: [opts.stdin ? 'pipe' : 'ignore', 'pipe', 'inherit'],
},
);

if (opts.stdin) {
// Write the input to stdin.
deployP.childProcess.stdin.write(opts.stdin);
deployP.childProcess.stdin.end();
}

finalizers.push(() => pkill(deployP.childProcess, 'SIGINT'));
const to = setTimeout(
deployResult.resolve,
TIMEOUT_SECONDS * 1000,
'timeout',
);
const done = await Promise.race([deployResult.promise, deployP]);
t.is(done, 0, `deploy ${deployCmd.join(' ')} successful before timeout`);
clearTimeout(to);
};
// XXX: use abci_info endpoint to get block height
// sleep to let contract start
await new Promise(resolve => setTimeout(resolve, TIMEOUT_SECONDS));

// ==============
// agoric deploy ./contract/deploy.js ./api/deploy.js
await testDeploy(['./contract/deploy.js', './api/deploy.js']);

for (const [suffix, code] of [
['/notthere', 404],
['', 200],
]) {
let urlResolve;
const url = `http://127.0.0.1:${PORT}${suffix}`;
const urlP = new Promise(resolve => (urlResolve = resolve));
const urlReq = request(url, res => urlResolve(res.statusCode));
urlReq.setTimeout(2000);
urlReq.on('error', err => urlResolve(`Cannot connect to ${url}: ${err}`));
urlReq.end();
const urlTimeout = setTimeout(urlResolve, 3000, 'timeout');
const urlDone = await urlP;
clearTimeout(urlTimeout);
t.is(urlDone, code, `${url} gave status ${code}`);
}
// yarn start:contract
t.is(await yarn(['start:contract']), 0, 'yarn start:contract works');

// ==============
// cd ui && yarn start
const uiStartP = pspawn(`yarn`, ['start'], {
stdio: ['ignore', 'inherit', 'inherit'],
cwd: 'ui',
env: { ...process.env, PORT: '3000' },
detached: true,
});
finalizers.push(() => pkill(uiStartP.childProcess, 'SIGINT'));
// yarn start:ui
const startUiP = yarn(['start:ui']);
finalizers.push(() => pkill(startUiP.childProcess, 'SIGINT'));
const uiListening = makePromiseKit();
let retries = 0;
const ival = setInterval(() => {
Expand All @@ -236,7 +142,7 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
return;
}

const req = request('http://localhost:3000/', _res => {
const req = request('http://localhost:5173/', _res => {
resolve('listening');
});
req.setTimeout(2000);
Expand All @@ -251,20 +157,11 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
}
}, 3000);
t.is(
await Promise.race([uiStartP, uiListening.promise]),
await Promise.race([startUiP, uiListening.promise]),
'listening',
`cd ui && yarn start succeeded`,
`yarn start:ui succeeded`,
);
clearInterval(ival);

// Test that the Node.js `-r esm`-dependent plugin works.
await (testUnsafePlugins &&
testDeploy(
['--allow-unsafe-plugins', `${dirname}/resm-plugin/deploy.js`],
{ stdin: 'yes\n' },
));

// TODO: When it exists, Test that the Node.js native ESM plugin works.
} finally {
runFinalizers();
process.off('SIGINT', runFinalizers);
Expand Down

0 comments on commit 7ba058a

Please sign in to comment.