Reduce sample to network smoke test

This commit is contained in:
Sergey Chernov 2026-07-30 23:02:12 +04:00
parent e24914e76a
commit 4f0f66cf19
3 changed files with 20 additions and 101 deletions

View File

@ -1,6 +1,6 @@
# u-js-sample # u-js-sample
A small Node.js command-line example using `universa-core2@2.0.0-alpha.1`. A minimal network smoke test using `universa-core2@2.0.0-alpha.1`.
## Initialize and test ## Initialize and test
@ -9,14 +9,6 @@ npm ci
scripts/test-network.sh scripts/test-network.sh
``` ```
The test loads `src/universa.json` through `Topology`, connects with `Network`, The test loads `src/universa.json`, initializes `Network`, connects to the
authenticates to every available node, and verifies `sping=spong`. The alpha available topology, and asserts that the network returns `sping=spong`. The
package intentionally has no bundled default topology, so applications must alpha package intentionally has no bundled default topology.
provide one explicitly.
## Examples
```sh
npm start -- --generate-key
npm start -- --test-network
```

View File

@ -1,17 +1,14 @@
{ {
"name": "u-js-sample", "name": "u-js-sample",
"version": "0.1.0", "version": "0.1.0",
"description": "A small universa-core2 Node.js sample.", "description": "A minimal universa-core2 network smoke test.",
"type": "module", "type": "module",
"private": true, "private": true,
"bin": {
"u-js-sample": "./src/index.js"
},
"scripts": { "scripts": {
"start": "node src/index.js", "start": "node src/index.js",
"test:network": "bash scripts/test-network.sh", "test:network": "bash scripts/test-network.sh",
"check": "node --check src/index.js", "check": "node --check src/index.js",
"test": "npm run check && npm run test:network" "test": "npm run test:network"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"

View File

@ -1,5 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises'; import { readFile } from 'node:fs/promises';
import { dirname, resolve } from 'node:path'; import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
@ -13,91 +14,20 @@ import {
const sourceDirectory = dirname(fileURLToPath(import.meta.url)); const sourceDirectory = dirname(fileURLToPath(import.meta.url));
const topologyFile = resolve(sourceDirectory, 'universa.json'); const topologyFile = resolve(sourceDirectory, 'universa.json');
async function withTimeout(promise, milliseconds, message) { await unicryptoReady;
let timeoutId;
const timeout = new Promise((_, reject) => {
timeoutId = setTimeout(() => reject(new Error(message)), milliseconds);
});
try { const topologyData = JSON.parse(await readFile(topologyFile, 'utf8'));
return await Promise.race([promise, timeout]); const topology = await Topology.load(topologyData);
} finally { const privateKey = await PrivateKey.generate({ strength: 2048 });
clearTimeout(timeoutId); const network = new Network(privateKey, {
} topology,
} directConnection: true
});
async function loadTopology() { console.log(`Connecting to ${topology.size()} Universa nodes from ${topologyFile}`);
const packed = JSON.parse(await readFile(topologyFile, 'utf8')); await network.connect();
return Topology.load(packed);
}
async function testNetwork(privateKey) { const response = await network.command('sping');
const topology = await loadTopology(); assert.equal(response?.sping, 'spong', 'unexpected network state response');
const network = new Network(privateKey, {
topology,
directConnection: true
});
console.log(`Testing ${topology.size()} Universa nodes from ${topologyFile}`); console.log(`Universa network is functioning: ${network.size()} nodes, sping=spong`);
await withTimeout(network.connect(), 15_000, 'Network connection timed out');
const nodes = Object.entries(network.topology.nodes);
const results = await Promise.all(nodes.map(async ([id, node]) => {
try {
const connection = await withTimeout(
network.nodeConnection(id),
10_000,
`${node.name} connection timed out`
);
const response = await connection.command('sping', {}, { timeout: 5_000 });
if (response?.sping !== 'spong') throw new Error('unexpected sping response');
console.log(`PASS ${node.name}: authenticated, sping=spong`);
return true;
} catch (error) {
console.error(`FAIL ${node.name}: ${error instanceof Error ? error.message : error}`);
return false;
}
}));
const passed = results.filter(Boolean).length;
const quorum = Math.max(1, Math.ceil(nodes.length * 0.4));
if (passed < quorum) {
throw new Error(`Network quorum failed: ${passed}/${nodes.length} nodes passed; ${quorum} required`);
}
console.log(`Universa network is functioning: ${passed}/${nodes.length} nodes passed`);
}
function printHelp() {
console.log(`Usage: u-js-sample [options]
Options:
--generate-key Generate a private key and print its short address
--test-network Test every node in src/universa.json
--help Show this help`);
}
async function main() {
const options = new Set(process.argv.slice(2));
if (options.size === 0 || options.has('--help')) return printHelp();
const unknown = [...options].find((option) => (
option !== '--generate-key' && option !== '--test-network'
));
if (unknown) throw new Error(`Unknown option: ${unknown}`);
if (options.has('--generate-key') || options.has('--test-network')) {
await unicryptoReady;
const privateKey = await PrivateKey.generate({ strength: 2048 });
console.log(`Universa short address: ${privateKey.publicKey.shortAddress58}`);
if (options.has('--test-network')) await testNetwork(privateKey);
}
}
try {
await main();
} catch (error) {
console.error(error instanceof Error ? error.message : error);
process.exitCode = 1;
}