mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
## Implement E2E Testing Framework with Isolated Networks ### Summary Refactors the existing E2E testing infrastructure to provide isolated test environments with parallel execution support. Each test suite now runs in its own network namespace, preventing resource conflicts. ### Key Changes - **New Testing Framework** (`test/framework/`): Base classes for test lifecycle management with automatic setup/teardown - **Launcher Module** (`test/launcher/`): Extracted network orchestration logic from CLI handlers for reusability - **Parallel Execution**: Added `test-parallel.ts` script with concurrency limits to prevent resource exhaustion - **Test Isolation**: Each suite gets unique network IDs (format: `suiteName-timestamp`) and Docker networks - **Improved Test Organization**: Migrated tests to new framework, deprecated old test structure ### Test Improvements - Added 4 new test suites demonstrating framework usage. : - `contracts.test.ts` - Smart contract deployment/interaction - `datahaven-substrate.test.ts` - Substrate API operations - `cross-chain.test.ts` - Snowbridge cross-chain messaging - `ethereum-basic.test.ts` - Ethereum network operations > [!WARNING] The test suites themselves are bad and shouldn't be consider examples of good tests. They were AI generated just to test the concurrency of test runners ### Documentation - Added comprehensive framework overview (`E2E_FRAMEWORK_OVERVIEW.md`) - Updated README with parallel testing commands - Added test patterns and best practices ### Breaking Changes - Old test suites moved to `e2e - DEPRECATED/` directory - Test execution now requires extending `BaseTestSuite` class ### Testing Run tests with: `bun test:e2e` or `bun test:e2e:parallel` (with concurrency limits) ### TODO - [ ] Implement good test examples. - [ ] Implement useful test utils (like waiting for an event to show up in DataHaven or Ethereum). - [ ] Enforce tests with CI (currently cannot be done due to intermittent error when sending a transaction with PAPI). --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: undercover-cactus <lola@moonsonglabs.com>
111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
import invariant from "tiny-invariant";
|
|
import { confirmWithTimeout, logger, printDivider, printHeader } from "utils";
|
|
import {
|
|
checkDataHavenRunning,
|
|
cleanDataHavenContainers,
|
|
launchLocalDataHavenSolochain,
|
|
registerNodes
|
|
} from "../../../launcher/datahaven";
|
|
import type { LaunchedNetwork } from "../../../launcher/types/launchedNetwork";
|
|
import { type LaunchOptions, NETWORK_ID } from ".";
|
|
|
|
// 2 validators (Alice and Bob) are used for local & CI testing
|
|
// <repo_root>/operator/runtime/stagenet/src/genesis_config_presets.rs#L98
|
|
const CLI_AUTHORITY_IDS = ["alice", "bob"] as const;
|
|
|
|
/**
|
|
* Launches a DataHaven solochain network for testing.
|
|
*
|
|
* @param options - Configuration options for launching the network.
|
|
* @param launchedNetwork - An instance of LaunchedNetwork to track the network's state.
|
|
*/
|
|
export const launchDataHavenSolochain = async (
|
|
options: LaunchOptions,
|
|
launchedNetwork: LaunchedNetwork
|
|
) => {
|
|
printHeader("Starting DataHaven Network");
|
|
|
|
let shouldLaunchDataHaven = options.datahaven;
|
|
|
|
if (shouldLaunchDataHaven === undefined) {
|
|
shouldLaunchDataHaven = await confirmWithTimeout(
|
|
"Do you want to launch the DataHaven network?",
|
|
true,
|
|
10
|
|
);
|
|
} else {
|
|
logger.info(
|
|
`🏳️ Using flag option: ${shouldLaunchDataHaven ? "will launch" : "will not launch"} DataHaven network`
|
|
);
|
|
}
|
|
|
|
if (!shouldLaunchDataHaven) {
|
|
logger.info("👍 Skipping DataHaven network launch. Done!");
|
|
|
|
await registerNodes(NETWORK_ID, launchedNetwork);
|
|
printDivider();
|
|
return;
|
|
}
|
|
|
|
if (await checkDataHavenRunning()) {
|
|
// If the user wants to launch the DataHaven network, we ask them if they want
|
|
// to clean the existing containers/network or just continue with the existing
|
|
// containers/network.
|
|
if (shouldLaunchDataHaven) {
|
|
let shouldRelaunch = options.cleanNetwork;
|
|
|
|
if (shouldRelaunch === undefined) {
|
|
shouldRelaunch = await confirmWithTimeout(
|
|
"Do you want to clean and relaunch the DataHaven containers?",
|
|
true,
|
|
10
|
|
);
|
|
}
|
|
|
|
// Case: User wants to keep existing containers/network
|
|
if (!shouldRelaunch) {
|
|
logger.info("👍 Keeping existing DataHaven containers/network.");
|
|
|
|
await registerNodes(NETWORK_ID, launchedNetwork);
|
|
printDivider();
|
|
return;
|
|
}
|
|
|
|
// Case: User wants to clean and relaunch the DataHaven containers
|
|
await cleanDataHavenContainers(NETWORK_ID);
|
|
}
|
|
}
|
|
|
|
invariant(options.datahavenImageTag, "❌ DataHaven image tag not defined");
|
|
|
|
let shouldBuildDataHaven = options.buildDatahaven;
|
|
if (shouldBuildDataHaven === undefined) {
|
|
shouldBuildDataHaven = await confirmWithTimeout(
|
|
"Do you want to build the DataHaven node local Docker image?",
|
|
true,
|
|
10
|
|
);
|
|
} else {
|
|
logger.info(
|
|
`🏳️ Using flag option: ${shouldBuildDataHaven ? "will build" : "will not build"} DataHaven node local Docker image`
|
|
);
|
|
}
|
|
|
|
if (!shouldBuildDataHaven) {
|
|
logger.info("👍 Skipping DataHaven node local Docker image build. Done!");
|
|
}
|
|
|
|
await launchLocalDataHavenSolochain(
|
|
{
|
|
networkId: NETWORK_ID,
|
|
datahavenImageTag: options.datahavenImageTag,
|
|
relayerImageTag: options.relayerImageTag,
|
|
authorityIds: CLI_AUTHORITY_IDS,
|
|
buildDatahaven: shouldBuildDataHaven,
|
|
datahavenBuildExtraArgs: options.datahavenBuildExtraArgs
|
|
},
|
|
launchedNetwork
|
|
);
|
|
|
|
printDivider();
|
|
};
|