agoric 0.21.2-mainnet1B-dev-cfa7cb2.0 → 0.21.2-orchestration-dev-096c4e8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/start.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint @typescript-eslint/no-floating-promises: "warn" */
1
2
  /* global process setTimeout */
2
3
  import chalk from 'chalk';
3
4
  import { createHash } from 'crypto';
@@ -40,6 +41,7 @@ const DELEGATE0_COINS = `50000000${STAKING_DENOM}`;
40
41
  const SOLO_COINS = `13000000${STAKING_DENOM},500000000${CENTRAL_DENOM}`;
41
42
  const CHAIN_ID = 'agoriclocal';
42
43
 
44
+ const SERVERS_ROOT_DIR = '_agstate/agoric-servers';
43
45
  const FAKE_CHAIN_DELAY =
44
46
  process.env.FAKE_CHAIN_DELAY === undefined
45
47
  ? 0
@@ -69,10 +71,10 @@ export default async function startMain(progname, rawArgs, powers, opts) {
69
71
  const pspawnEnv = { ...process.env };
70
72
  if (opts.verbose > 1) {
71
73
  // Loudly verbose logs (nondeterministic).
72
- pspawnEnv.DEBUG = 'agoric,SwingSet:vat,SwingSet:ls';
74
+ pspawnEnv.DEBUG = 'agoric:debug,SwingSet:vat,SwingSet:ls';
73
75
  } else if (opts.verbose) {
74
76
  // Verbose vat logs (nondeterministic).
75
- pspawnEnv.DEBUG = 'SwingSet:vat,SwingSet:ls';
77
+ pspawnEnv.DEBUG = 'agoric:info,SwingSet:vat,SwingSet:ls';
76
78
  }
77
79
 
78
80
  const pspawn = makePspawn({ env: pspawnEnv, spawn, log, chalk });
@@ -151,6 +153,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
151
153
  ]);
152
154
 
153
155
  const exists = async file => {
156
+ await null;
154
157
  try {
155
158
  await fs.stat(file);
156
159
  return true;
@@ -159,6 +162,12 @@ export default async function startMain(progname, rawArgs, powers, opts) {
159
162
  }
160
163
  };
161
164
 
165
+ const rmVerbose = async filePath => {
166
+ log(chalk.green(`removing ${filePath}`));
167
+ // rm is available on all the unix-likes, so use it for speed.
168
+ await pspawn('rm', ['-rf', filePath]);
169
+ };
170
+
162
171
  let agSolo;
163
172
  let agSoloBuild;
164
173
  if (opts.dockerTag) {
@@ -171,12 +180,11 @@ export default async function startMain(progname, rawArgs, powers, opts) {
171
180
  const fakeDelay =
172
181
  popts.delay === undefined ? FAKE_CHAIN_DELAY : Number(popts.delay);
173
182
 
174
- const agServer = `_agstate/agoric-servers/${profileName}`;
183
+ const serverDir = `${SERVERS_ROOT_DIR}/${profileName}`;
175
184
 
185
+ await null;
176
186
  if (popts.reset) {
177
- log(chalk.green(`removing ${agServer}`));
178
- // rm is available on all the unix-likes, so use it for speed.
179
- await pspawn('rm', ['-rf', agServer]);
187
+ await rmVerbose(serverDir);
180
188
  }
181
189
 
182
190
  if (!opts.dockerTag) {
@@ -197,14 +205,14 @@ export default async function startMain(progname, rawArgs, powers, opts) {
197
205
  }
198
206
 
199
207
  const fakeGCI = 'sim-chain';
200
- const serverExists = await exists(agServer);
208
+ const serverExists = await exists(serverDir);
201
209
  if (!serverExists) {
202
210
  log(chalk.yellow(`initializing ${profileName}`));
203
211
  await pspawn(
204
212
  agSolo,
205
213
  ['init', profileName, '--egresses=fake', `--webport=${HOST_PORT}`],
206
214
  {
207
- cwd: '_agstate/agoric-servers',
215
+ cwd: SERVERS_ROOT_DIR,
208
216
  },
209
217
  );
210
218
  }
@@ -215,7 +223,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
215
223
  agSolo,
216
224
  ['set-fake-chain', `--delay=${fakeDelay}`, fakeGCI],
217
225
  {
218
- cwd: agServer,
226
+ cwd: serverDir,
219
227
  },
220
228
  );
221
229
  }
@@ -226,7 +234,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
226
234
  }
227
235
 
228
236
  const ps = pspawn(agSolo, [...debugOpts, 'start'], {
229
- cwd: agServer,
237
+ cwd: serverDir,
230
238
  env: nodeDebugEnv,
231
239
  });
232
240
  process.on('SIGINT', () => ps.childProcess.kill('SIGINT'));
@@ -246,6 +254,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
246
254
  }
247
255
 
248
256
  const { cosmosChain, cosmosChainBuild } = getSDKBinaries(sdkPrefixes);
257
+ await null;
249
258
  if (popts.pull || popts.rebuild) {
250
259
  if (popts.dockerTag) {
251
260
  const exitStatus = await pspawn('docker', ['pull', SDK_IMAGE]);
@@ -263,17 +272,15 @@ export default async function startMain(progname, rawArgs, powers, opts) {
263
272
  }
264
273
  }
265
274
 
266
- const agServer = `_agstate/agoric-servers/${profileName}-${portNum}`;
275
+ const serverDir = `${SERVERS_ROOT_DIR}/${profileName}-${portNum}`;
267
276
  if (popts.reset) {
268
- log(chalk.green(`removing ${agServer}`));
269
- // rm is available on all the unix-likes, so use it for speed.
270
- await pspawn('rm', ['-rf', agServer]);
277
+ await rmVerbose(serverDir);
271
278
  }
272
279
 
273
280
  let chainSpawn;
274
281
  if (!popts.dockerTag) {
275
282
  chainSpawn = (args, spawnOpts = undefined) => {
276
- return pspawn(cosmosChain, [...args, `--home=${agServer}`], spawnOpts);
283
+ return pspawn(cosmosChain, [...args, `--home=${serverDir}`], spawnOpts);
277
284
  };
278
285
  } else {
279
286
  chainSpawn = (args, spawnOpts = undefined, dockerArgs = []) =>
@@ -287,13 +294,13 @@ export default async function startMain(progname, rawArgs, powers, opts) {
287
294
  ...terminalOnlyFlags(`-it`),
288
295
  SDK_IMAGE,
289
296
  ...args,
290
- `--home=/usr/src/dapp/${agServer}`,
297
+ `--home=/usr/src/dapp/${serverDir}`,
291
298
  ],
292
299
  spawnOpts,
293
300
  );
294
301
  }
295
302
 
296
- const serverExists = await exists(agServer);
303
+ const serverExists = await exists(serverDir);
297
304
  if (!serverExists) {
298
305
  const exitStatus = await chainSpawn([
299
306
  'init',
@@ -308,7 +315,6 @@ export default async function startMain(progname, rawArgs, powers, opts) {
308
315
  // Get or create the essential addresses.
309
316
  const addrs = {};
310
317
  for (const keyName of ['provision', 'delegate0']) {
311
- /* eslint-disable no-await-in-loop */
312
318
  let statusOut = showKey(keyName);
313
319
  const exitStatusOut = await statusOut[0];
314
320
  if (exitStatusOut) {
@@ -331,7 +337,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
331
337
  /* eslint-enable no-await-in-loop */
332
338
  }
333
339
 
334
- const genesisFile = `${agServer}/config/genesis.json`;
340
+ const genesisFile = `${serverDir}/config/genesis.json`;
335
341
  const stampExists = await exists(`${genesisFile}.stamp`);
336
342
  if (!stampExists) {
337
343
  let exitStatus;
@@ -361,7 +367,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
361
367
  `--keyring-dir=${keysHome}`,
362
368
  '--keyring-backend=test',
363
369
  `--chain-id=${CHAIN_ID}`,
364
- `${DELEGATE0_COINS}`,
370
+ DELEGATE0_COINS,
365
371
  ]);
366
372
  if (exitStatus) {
367
373
  return exitStatus;
@@ -382,8 +388,8 @@ export default async function startMain(progname, rawArgs, powers, opts) {
382
388
 
383
389
  // Complete the genesis file and launch the chain.
384
390
  log('read ag-chain-cosmos config');
385
- const configFile = `${agServer}/config/config.toml`;
386
- const appFile = `${agServer}/config/app.toml`;
391
+ const configFile = `${serverDir}/config/config.toml`;
392
+ const appFile = `${serverDir}/config/app.toml`;
387
393
  const [genesisJson, configToml, appToml] = await Promise.all([
388
394
  fs.readFile(genesisFile, 'utf-8'),
389
395
  fs.readFile(configFile, 'utf-8'),
@@ -446,9 +452,10 @@ export default async function startMain(progname, rawArgs, powers, opts) {
446
452
  return 1;
447
453
  }
448
454
 
449
- const agServer = `_agstate/agoric-servers/${profileName}-${portNum}`;
455
+ const serverDir = `${SERVERS_ROOT_DIR}/${profileName}-${portNum}`;
450
456
 
451
457
  const { cosmosClientBuild } = getSDKBinaries(sdkPrefixes);
458
+ await null;
452
459
  if (popts.pull || popts.rebuild) {
453
460
  if (popts.dockerTag) {
454
461
  const exitStatus = await pspawn('docker', ['pull', SDK_IMAGE]);
@@ -474,9 +481,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
474
481
  }
475
482
 
476
483
  if (popts.reset) {
477
- log(chalk.green(`removing ${agServer}`));
478
- // rm is available on all the unix-likes, so use it for speed.
479
- await pspawn('rm', ['-rf', agServer]);
484
+ await rmVerbose(serverDir);
480
485
  }
481
486
 
482
487
  let soloSpawn;
@@ -491,7 +496,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
491
496
  'run',
492
497
  `--volume=${process.cwd()}:/usr/src/dapp`,
493
498
  `--volume=${process.env.HOME}/.agoric:/root/.agoric`,
494
- `-eAG_SOLO_BASEDIR=/usr/src/dapp/${agServer}`,
499
+ `-eAG_SOLO_BASEDIR=/usr/src/dapp/${serverDir}`,
495
500
  `--rm`,
496
501
  ...terminalOnlyFlags(`-it`),
497
502
  `--entrypoint=ag-solo`,
@@ -503,7 +508,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
503
508
  );
504
509
  }
505
510
 
506
- const serverExists = await exists(agServer);
511
+ const serverExists = await exists(serverDir);
507
512
  // Initialise the solo directory and key.
508
513
  if (!serverExists) {
509
514
  const initArgs = [`--webport=${portNum}`];
@@ -511,7 +516,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
511
516
  initArgs.push(`--webhost=0.0.0.0`);
512
517
  }
513
518
  const exitStatus = await soloSpawn(
514
- ['init', agServer, ...initArgs],
519
+ ['init', serverDir, ...initArgs],
515
520
  undefined,
516
521
  [`--workdir=/usr/src/dapp`],
517
522
  );
@@ -522,15 +527,15 @@ export default async function startMain(progname, rawArgs, powers, opts) {
522
527
 
523
528
  // Create the full economy chain config.
524
529
  const agServerResolve = spec =>
525
- require.resolve(spec, { paths: [agServer] });
530
+ require.resolve(spec, { paths: [serverDir] });
526
531
  const coreConfigPath = agServerResolve(
527
- '@agoric/vats/decentral-core-config.json',
532
+ '@agoric/vm-config/decentral-core-config.json',
528
533
  );
529
534
  const economyTemplPath = agServerResolve(
530
535
  '@agoric/cosmic-swingset/economy-template.json',
531
536
  );
532
537
  const [rawSoloAddr, coreConfigJson, economyTemplJson] = await Promise.all([
533
- fs.readFile(`${agServer}/ag-cosmos-helper-address`, 'utf-8'),
538
+ fs.readFile(`${serverDir}/ag-cosmos-helper-address`, 'utf-8'),
534
539
  fs.readFile(coreConfigPath, 'utf-8'),
535
540
  fs.readFile(economyTemplPath, 'utf-8'),
536
541
  ]);
@@ -541,7 +546,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
541
546
  const economyConfig = JSON.parse(coreConfigJson);
542
547
  economyConfig.coreProposals = economyProposals;
543
548
  await fs.writeFile(
544
- `${agServer}/decentral-economy-config.json`,
549
+ `${serverDir}/decentral-economy-config.json`,
545
550
  JSON.stringify(economyConfig, null, 2),
546
551
  );
547
552
 
@@ -549,13 +554,12 @@ export default async function startMain(progname, rawArgs, powers, opts) {
549
554
  return 0;
550
555
  }
551
556
 
552
- const gciFile = `_agstate/agoric-servers/local-chain-${CHAIN_PORT}/config/genesis.json.sha256`;
557
+ const gciFile = `${SERVERS_ROOT_DIR}/local-chain-${CHAIN_PORT}/config/genesis.json.sha256`;
553
558
  process.stdout.write(`Waiting for local-chain-${CHAIN_PORT} to start...`);
554
559
  let hasGci = false;
555
560
  for await (const _ of untilTrue(() => hasGci)) {
556
561
  process.stdout.write('.');
557
562
 
558
- // eslint-disable-next-line no-await-in-loop
559
563
  await new Promise((resolve, reject) => {
560
564
  fs.stat(gciFile).then(
561
565
  _2 => {
@@ -576,7 +580,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
576
580
 
577
581
  const spawnOpts = {};
578
582
  if (!popts.dockerTag) {
579
- spawnOpts.cwd = agServer;
583
+ spawnOpts.cwd = serverDir;
580
584
  }
581
585
 
582
586
  const rpcAddrs = [`localhost:${CHAIN_PORT}`];
@@ -590,7 +594,6 @@ export default async function startMain(progname, rawArgs, powers, opts) {
590
594
  let bestRpcAddr;
591
595
  for await (const _ of untilTrue(() => bestRpcAddr)) {
592
596
  for await (const rpcAddr of rpcAddrs) {
593
- // eslint-disable-next-line no-await-in-loop
594
597
  exitStatus = await keysSpawn([
595
598
  'query',
596
599
  'swingset',
@@ -639,7 +642,6 @@ export default async function startMain(progname, rawArgs, powers, opts) {
639
642
  ];
640
643
  for (/* await */ const cmd of provCmds) {
641
644
  const statusOut = capture(keysSpawn, cmd, true);
642
- // eslint-disable-next-line no-await-in-loop
643
645
  exitStatus = await statusOut[0];
644
646
  if (!exitStatus) {
645
647
  const json = statusOut[1].replace(/^gas estimate: \d+$/m, '');
@@ -664,7 +666,6 @@ export default async function startMain(progname, rawArgs, powers, opts) {
664
666
  }
665
667
  }
666
668
  if (!bestRpcAddr) {
667
- // eslint-disable-next-line no-await-in-loop
668
669
  await delay(2000);
669
670
  }
670
671
  }
@@ -690,6 +691,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
690
691
  }
691
692
 
692
693
  async function startTestnetDocker(profileName, startArgs, popts) {
694
+ await null;
693
695
  if (popts.dockerTag && popts.pull) {
694
696
  const exitStatus = await pspawn('docker', ['pull', SOLO_IMAGE]);
695
697
  if (exitStatus) {
@@ -699,12 +701,10 @@ export default async function startMain(progname, rawArgs, powers, opts) {
699
701
 
700
702
  const port = startArgs[0] || PORT;
701
703
  const netconfig = startArgs[1] || DEFAULT_NETCONFIG;
702
- const agServer = `_agstate/agoric-servers/${profileName}-${port}`;
704
+ const serverDir = `${SERVERS_ROOT_DIR}/${profileName}-${port}`;
703
705
 
704
706
  if (popts.reset) {
705
- log(chalk.green(`removing ${agServer}`));
706
- // rm is available on all the unix-likes, so use it for speed.
707
- await pspawn('rm', ['-rf', agServer]);
707
+ await rmVerbose(serverDir);
708
708
  }
709
709
 
710
710
  const setupRun = (...bonusArgs) =>
@@ -712,7 +712,7 @@ export default async function startMain(progname, rawArgs, powers, opts) {
712
712
  'run',
713
713
  `-p127.0.0.1:${HOST_PORT}:${port}`,
714
714
  `--volume=${process.cwd()}:/usr/src/dapp`,
715
- `-eAG_SOLO_BASEDIR=/usr/src/dapp/${agServer}`,
715
+ `-eAG_SOLO_BASEDIR=/usr/src/dapp/${serverDir}`,
716
716
  `--rm`,
717
717
  ...terminalOnlyFlags(`-it`),
718
718
  SOLO_IMAGE,
@@ -727,44 +727,38 @@ export default async function startMain(progname, rawArgs, powers, opts) {
727
727
  async function startTestnetSdk(profileName, startArgs, popts) {
728
728
  const port = startArgs[0] || PORT;
729
729
  const netconfig = startArgs[1] || DEFAULT_NETCONFIG;
730
- const agServer = `_agstate/agoric-servers/${profileName}-${port}`;
730
+ const serverDir = `${SERVERS_ROOT_DIR}/${profileName}-${port}`;
731
731
 
732
+ await null;
732
733
  if (popts.reset) {
733
- log(chalk.green(`removing ${agServer}`));
734
- // rm is available on all the unix-likes, so use it for speed.
735
- await pspawn('rm', ['-rf', agServer]);
734
+ await rmVerbose(serverDir);
736
735
  }
737
736
 
738
737
  const setupRun = (...bonusArgs) =>
739
738
  pspawn(agSolo, [`--webport=${port}`, ...bonusArgs], {
740
- env: { ...pspawnEnv, AG_SOLO_BASEDIR: agServer },
739
+ env: { ...pspawnEnv, AG_SOLO_BASEDIR: serverDir },
741
740
  });
742
741
 
743
742
  return setupRun('setup', `--netconfig=${netconfig}`);
744
743
  }
745
744
 
746
745
  const profiles = {
746
+ __proto__: null,
747
747
  dev: startFakeChain,
748
748
  'local-chain': startLocalChain,
749
749
  'local-solo': startLocalSolo,
750
750
  testnet: opts.dockerTag ? startTestnetDocker : startTestnetSdk,
751
751
  };
752
752
 
753
- const popts = opts;
754
-
755
- const args = rawArgs.slice(1);
756
- const profileName = args[0] || 'dev';
753
+ const [_command = 'start', profileName = 'dev', ...args] = rawArgs;
757
754
  const startFn = profiles[profileName];
758
755
  if (!startFn) {
756
+ const profileNames = Object.keys(profiles).join(', ');
759
757
  log.error(
760
- `unrecognized profile name ${profileName}; use one of: ${Object.keys(
761
- profiles,
762
- )
763
- .sort()
764
- .join(', ')}`,
758
+ `unrecognized profile name ${profileName}; use one of: ${profileNames}`,
765
759
  );
766
760
  return 1;
767
761
  }
768
762
 
769
- return startFn(profileName, args[0] ? args.slice(1) : args, popts);
763
+ return startFn(profileName, args, opts);
770
764
  }
@@ -0,0 +1,273 @@
1
+ /* global process setTimeout clearTimeout setInterval clearInterval */
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import tmp from 'tmp';
6
+ import { makePromiseKit } from '@endo/promise-kit';
7
+ import { request } from 'http';
8
+
9
+ import { spawn } from 'child_process';
10
+
11
+ import { makePspawn } from '../src/helpers.js';
12
+
13
+ const TIMEOUT_SECONDS = 20 * 60;
14
+
15
+ const dirname = new URL('./', import.meta.url).pathname;
16
+
17
+ // To keep in sync with https://agoric.com/documentation/getting-started/
18
+
19
+ // Note that we currently only test:
20
+ // agoric init dapp-foo
21
+ // agoric install
22
+ // agoric start --reset
23
+ // agoric deploy ./contract/deploy.js ./api/deploy.js
24
+ // (For simple-exchange and autoswap, the above also makes and accepts offers)
25
+ // cd ui && yarn install
26
+ // cd ui && yarn start
27
+
28
+ export const gettingStartedWorkflowTest = async (t, options = {}) => {
29
+ const {
30
+ init: initOptions = [],
31
+ install: installOptions = [],
32
+ start: startOptions = [],
33
+ testUnsafePlugins = false,
34
+ } = options;
35
+ // FIXME: Do a search for an unused port or allow specification.
36
+ const PORT = '7999';
37
+ process.env.PORT = PORT;
38
+
39
+ const pspawn = makePspawn({ spawn });
40
+
41
+ // Kill an entire process group.
42
+ const pkill = (cp, signal = 'SIGINT') => process.kill(-cp.pid, signal);
43
+
44
+ function pspawnStdout(...args) {
45
+ const ps = pspawn(...args);
46
+ ps.childProcess.stdout.on('data', chunk => {
47
+ process.stdout.write(chunk);
48
+ });
49
+ // ps.childProcess.unref();
50
+ return ps;
51
+ }
52
+
53
+ const defaultAgoricCmd = () => {
54
+ // Run all main programs with the '--sdk' flag if we are in agoric-sdk.
55
+ const extraArgs = fs.existsSync(`${dirname}/../../cosmic-swingset`)
56
+ ? ['--sdk']
57
+ : [];
58
+ const localCli = path.join(dirname, '..', 'bin', 'agoric');
59
+ return [localCli, ...extraArgs];
60
+ };
61
+ const { AGORIC_CMD = JSON.stringify(defaultAgoricCmd()) } = process.env;
62
+ const agoricCmd = JSON.parse(AGORIC_CMD);
63
+ function myMain(args, opts = {}) {
64
+ // console.error('running agoric-cli', ...extraArgs, ...args);
65
+ return pspawnStdout(agoricCmd[0], [...agoricCmd.slice(1), ...args], {
66
+ stdio: ['ignore', 'pipe', 'inherit'],
67
+ env: { ...process.env, DEBUG: 'agoric:debug' },
68
+ detached: true,
69
+ ...opts,
70
+ });
71
+ }
72
+
73
+ const olddir = process.cwd();
74
+ const { name } = tmp.dirSync({
75
+ unsafeCleanup: true,
76
+ prefix: 'agoric-cli-test-',
77
+ });
78
+
79
+ const finalizers = [];
80
+ const runFinalizers = sig => {
81
+ while (finalizers.length) {
82
+ const f = finalizers.shift();
83
+ try {
84
+ f();
85
+ } catch (e) {
86
+ // console.log(e);
87
+ }
88
+ }
89
+ if (sig) {
90
+ // We're dying due to signal.
91
+ process.exit(1);
92
+ }
93
+ };
94
+
95
+ await null;
96
+ try {
97
+ process.on('SIGINT', runFinalizers);
98
+ process.on('exit', runFinalizers);
99
+ process.chdir(name);
100
+
101
+ // ==============
102
+ // agoric init dapp-foo
103
+ if (process.env.AGORIC_INIT_OPTIONS) {
104
+ const opts = JSON.parse(process.env.AGORIC_INIT_OPTIONS);
105
+ initOptions.push(...opts);
106
+ }
107
+ t.is(
108
+ await myMain([
109
+ 'init',
110
+ '--dapp-template',
111
+ 'dapp-fungible-faucet',
112
+ ...initOptions,
113
+ 'dapp-foo',
114
+ ]),
115
+ 0,
116
+ 'init dapp-foo works',
117
+ );
118
+ process.chdir('dapp-foo');
119
+
120
+ // ==============
121
+ // agoric install
122
+ if (process.env.AGORIC_INSTALL_OPTIONS) {
123
+ const opts = JSON.parse(process.env.AGORIC_INSTALL_OPTIONS);
124
+ installOptions.push(...opts);
125
+ }
126
+ t.is(await myMain(['install', ...installOptions]), 0, 'install works');
127
+
128
+ // ==============
129
+ // agoric start --reset
130
+ const startResult = makePromiseKit();
131
+
132
+ if (process.env.AGORIC_START_OPTIONS) {
133
+ const opts = JSON.parse(process.env.AGORIC_START_OPTIONS);
134
+ startOptions.push(...opts);
135
+ }
136
+
137
+ // TODO: Allow this to work even if the port is already used.
138
+ const startP = myMain(['start', '--reset', ...startOptions]);
139
+ finalizers.push(() => pkill(startP.childProcess, 'SIGINT'));
140
+
141
+ let stdoutStr = '';
142
+ if (startP.childProcess.stdout) {
143
+ startP.childProcess.stdout.on('data', chunk => {
144
+ // console.log('stdout:', chunk.toString());
145
+ stdoutStr += chunk.toString();
146
+ if (stdoutStr.match(/(^|:\s+)swingset running$/m)) {
147
+ startResult.resolve(true);
148
+ }
149
+ });
150
+ }
151
+ startP.childProcess.on('close', code =>
152
+ startResult.reject(Error(`early termination: ${code}`)),
153
+ );
154
+
155
+ const timeout = setTimeout(
156
+ startResult.reject,
157
+ TIMEOUT_SECONDS * 1000,
158
+ 'timeout',
159
+ );
160
+ t.is(await startResult.promise, true, `swingset running before timeout`);
161
+ clearTimeout(timeout);
162
+
163
+ const openP = myMain(['open', '--no-browser'], {
164
+ stdio: ['ignore', 'pipe', 'inherit'],
165
+ });
166
+ t.is(await openP, 0, `open --no-browser exits successfully`);
167
+
168
+ const testDeploy = async (deployCmd, opts = {}) => {
169
+ const deployResult = makePromiseKit();
170
+ const deployP = myMain(
171
+ ['deploy', `--hostport=127.0.0.1:${PORT}`, ...deployCmd],
172
+ {
173
+ stdio: [opts.stdin ? 'pipe' : 'ignore', 'pipe', 'inherit'],
174
+ },
175
+ );
176
+
177
+ if (opts.stdin) {
178
+ // Write the input to stdin.
179
+ deployP.childProcess.stdin.write(opts.stdin);
180
+ deployP.childProcess.stdin.end();
181
+ }
182
+
183
+ finalizers.push(() => pkill(deployP.childProcess, 'SIGINT'));
184
+ const to = setTimeout(
185
+ deployResult.resolve,
186
+ TIMEOUT_SECONDS * 1000,
187
+ 'timeout',
188
+ );
189
+ const done = await Promise.race([deployResult.promise, deployP]);
190
+ t.is(done, 0, `deploy ${deployCmd.join(' ')} successful before timeout`);
191
+ clearTimeout(to);
192
+ };
193
+
194
+ // ==============
195
+ // agoric deploy ./contract/deploy.js ./api/deploy.js
196
+ await testDeploy(['./contract/deploy.js', './api/deploy.js']);
197
+
198
+ for (const [suffix, code] of [
199
+ ['/notthere', 404],
200
+ ['', 200],
201
+ ]) {
202
+ let urlResolve;
203
+ const url = `http://127.0.0.1:${PORT}${suffix}`;
204
+ const urlP = new Promise(resolve => (urlResolve = resolve));
205
+ const urlReq = request(url, res => urlResolve(res.statusCode));
206
+ urlReq.setTimeout(2000);
207
+ urlReq.on('error', err => urlResolve(`Cannot connect to ${url}: ${err}`));
208
+ urlReq.end();
209
+ const urlTimeout = setTimeout(urlResolve, 3000, 'timeout');
210
+ const urlDone = await urlP;
211
+ clearTimeout(urlTimeout);
212
+ t.is(urlDone, code, `${url} gave status ${code}`);
213
+ }
214
+
215
+ // ==============
216
+ // cd ui && yarn start
217
+ const uiStartP = pspawn(`yarn`, ['start'], {
218
+ stdio: ['ignore', 'inherit', 'inherit'],
219
+ cwd: 'ui',
220
+ env: { ...process.env, PORT: '3000' },
221
+ detached: true,
222
+ });
223
+ finalizers.push(() => pkill(uiStartP.childProcess, 'SIGINT'));
224
+ const uiListening = makePromiseKit();
225
+ let retries = 0;
226
+ const ival = setInterval(() => {
227
+ try {
228
+ const resolve = status => {
229
+ clearInterval(ival);
230
+ uiListening.resolve(status);
231
+ };
232
+
233
+ retries += 1;
234
+ if (retries > 8) {
235
+ resolve('too many retries');
236
+ return;
237
+ }
238
+
239
+ const req = request('http://localhost:3000/', _res => {
240
+ resolve('listening');
241
+ });
242
+ req.setTimeout(2000);
243
+ req.on('error', err => {
244
+ if (err.code !== 'ECONNREFUSED') {
245
+ resolve(`Cannot connect to UI server: ${err}`);
246
+ }
247
+ });
248
+ req.end();
249
+ } catch (e) {
250
+ console.error('cannot make request', e);
251
+ }
252
+ }, 3000);
253
+ t.is(
254
+ await Promise.race([uiStartP, uiListening.promise]),
255
+ 'listening',
256
+ `cd ui && yarn start succeeded`,
257
+ );
258
+ clearInterval(ival);
259
+
260
+ // Test that the Node.js `-r esm`-dependent plugin works.
261
+ await (testUnsafePlugins &&
262
+ testDeploy(
263
+ ['--allow-unsafe-plugins', `${dirname}/resm-plugin/deploy.js`],
264
+ { stdin: 'yes\n' },
265
+ ));
266
+
267
+ // TODO: When it exists, Test that the Node.js native ESM plugin works.
268
+ } finally {
269
+ runFinalizers();
270
+ process.off('SIGINT', runFinalizers);
271
+ process.chdir(olddir);
272
+ }
273
+ };
@@ -0,0 +1,18 @@
1
+ /* globals setTimeout */
2
+ import { E } from '@endo/eventual-send';
3
+
4
+ const PONG_TIMEOUT = 10_000;
5
+
6
+ export default async function deployPlugin(
7
+ homePromise,
8
+ { installUnsafePlugin },
9
+ ) {
10
+ const plugin = await installUnsafePlugin('./src/plugin.js', {});
11
+ const result = await Promise.race([
12
+ E(plugin).ping(),
13
+ new Promise(resolve => setTimeout(resolve, PONG_TIMEOUT, 'timeout')),
14
+ ]);
15
+ if (result !== 'pong') {
16
+ throw Error(`ping failed ${result}`);
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@agoric/test-resm-plugin",
3
+ "version": "1.0.0",
4
+ "type": "commonjs",
5
+ "dependencies": {
6
+ "@endo/eventual-send": "^0.17.2",
7
+ "@endo/marshal": "^0.8.5"
8
+ },
9
+ "typeCoverage": {
10
+ "atLeast": 0
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ export const start = 'Started plugin';