mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 01:38:32 +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>
113 lines
3.9 KiB
TypeScript
113 lines
3.9 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
// Update validator set on DataHaven substrate chain
|
|
import { $ } from "bun";
|
|
import invariant from "tiny-invariant";
|
|
import { logger } from "../utils/index";
|
|
|
|
interface UpdateValidatorSetOptions {
|
|
rpcUrl: string;
|
|
}
|
|
|
|
/**
|
|
* Sends the validator set to the DataHaven chain through Snowbridge
|
|
*
|
|
* @param options - Configuration options for update
|
|
* @param options.rpcUrl - The RPC URL to connect to
|
|
* @returns Promise resolving to true if validator set was sent successfully, false if skipped
|
|
*/
|
|
export const updateValidatorSet = async (options: UpdateValidatorSetOptions): Promise<boolean> => {
|
|
const { rpcUrl } = options;
|
|
|
|
// Validate RPC URL
|
|
invariant(rpcUrl, "❌ RPC URL is required");
|
|
|
|
// Get cast path for transactions
|
|
const { stdout: castPath } = await $`which cast`.quiet();
|
|
const castExecutable = castPath.toString().trim();
|
|
|
|
// Get the owner's private key for transaction signing from the .env
|
|
const ownerPrivateKey =
|
|
process.env.AVS_OWNER_PRIVATE_KEY ||
|
|
"0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e"; // Sixth pre-funded account from Anvil
|
|
|
|
// Get deployed contract addresses from the deployments file
|
|
const deploymentPath = path.resolve("../contracts/deployments/anvil.json");
|
|
|
|
if (!fs.existsSync(deploymentPath)) {
|
|
logger.error(`Deployment file not found: ${deploymentPath}`);
|
|
return false;
|
|
}
|
|
|
|
const deployments = JSON.parse(fs.readFileSync(deploymentPath, "utf8"));
|
|
|
|
// Prepare command to send validator set
|
|
const serviceManagerAddress = deployments.ServiceManager;
|
|
invariant(serviceManagerAddress, "ServiceManager address not found in deployments");
|
|
|
|
// Using cast to send the transaction
|
|
const executionFee = "100000000000000000"; // 0.1 ETH
|
|
const relayerFee = "200000000000000000"; // 0.2 ETH
|
|
const value = "300000000000000000"; // 0.3 ETH (sum of fees)
|
|
|
|
const sendCommand = `${castExecutable} send --private-key ${ownerPrivateKey} --value ${value} ${serviceManagerAddress} "sendNewValidatorSet(uint128,uint128)" ${executionFee} ${relayerFee} --rpc-url ${rpcUrl}`;
|
|
|
|
logger.debug(`Running command: ${sendCommand}`);
|
|
|
|
const { exitCode, stderr } = await $`sh -c ${sendCommand}`.nothrow().quiet();
|
|
|
|
if (exitCode !== 0) {
|
|
logger.error(`Failed to send validator set: ${stderr.toString()}`);
|
|
return false;
|
|
}
|
|
|
|
logger.success("Validator set sent to Snowbridge Gateway");
|
|
|
|
// Check if the validator set has been queued on the substrate side (placeholder)
|
|
logger.debug("Checking validator set on substrate chain (not implemented)");
|
|
/*
|
|
// PLACEHOLDER: Code to check if validator set has been queued on substrate
|
|
// This requires a connection to the DataHaven substrate node which is not available yet
|
|
|
|
// Example of what this might look like:
|
|
const substrateApi = await ApiPromise.create({ provider: new WsProvider('ws://localhost:9944') });
|
|
const validatorSetModule = substrateApi.query.validatorSet;
|
|
const queuedValidators = await validatorSetModule.queuedValidators();
|
|
|
|
if (queuedValidators.length === validators.length) {
|
|
logger.success('Validator set successfully queued on substrate chain');
|
|
} else {
|
|
logger.warn('Validator set not properly queued on substrate chain');
|
|
}
|
|
*/
|
|
|
|
return true;
|
|
};
|
|
|
|
// Allow script to be run directly with CLI arguments
|
|
if (import.meta.main) {
|
|
const args = process.argv.slice(2);
|
|
const options: {
|
|
rpcUrl?: string;
|
|
} = {};
|
|
|
|
// Extract RPC URL
|
|
const rpcUrlIndex = args.indexOf("--rpc-url");
|
|
if (rpcUrlIndex !== -1 && rpcUrlIndex + 1 < args.length) {
|
|
options.rpcUrl = args[rpcUrlIndex + 1];
|
|
}
|
|
|
|
// Check required parameters
|
|
if (!options.rpcUrl) {
|
|
console.error("Error: --rpc-url parameter is required");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Run update
|
|
updateValidatorSet({
|
|
rpcUrl: options.rpcUrl
|
|
}).catch((error) => {
|
|
console.error("Validator set update failed:", error);
|
|
process.exit(1);
|
|
});
|
|
}
|