import { NodePorts } from "./port_allocator.js"; import type { System } from "../create_system.js"; import { type ActorRef } from "../actor.js"; /** * Handle to a test node running in a forked child process. */ export interface TestNodeHandle { /** The nodeId of this test node */ readonly nodeId: string; /** The allocated ports for this node */ readonly ports: NodePorts; /** Reference to the NodeAgent actor on this node (callable from controller) */ readonly agent: ActorRef; /** Kill the OS process (simulates crash). Signal defaults to SIGKILL. */ kill(signal?: NodeJS.Signals): void; /** Graceful shutdown via NodeAgent */ shutdown(): Promise; /** * Simulate a network partition: isolate this node from the specified target nodes. * Blocks both ZeroMQ transport and UDP gossip in both directions. * Requires the cluster to be created with `faultInjection: true`. */ partition(...targetNodeIds: string[]): Promise; /** * Heal a network partition: restore connectivity to the specified target nodes. * If no targets are specified, heals ALL partitions on this node. * Requires the cluster to be created with `faultInjection: true`. */ heal(...targetNodeIds: string[]): Promise; } /** * Configuration for creating a test cluster. */ export interface TestClusterConfig { /** Number of worker nodes to spawn. Default: 2 */ size?: number; /** Shared cookie for authentication. Default: "test-cluster-cookie" */ cookie?: string; /** Paths to modules exporting actor classes for workers to register */ actorModules?: string[]; /** Cluster formation timeout in ms. Default: 30000 */ timeout?: number; /** Base nodeId prefix. Nodes are named "{prefix}-0", "{prefix}-1", etc. Default: "test-node" */ nodeIdPrefix?: string; /** * Enable fault injection (FaultyTransport + FaultyGossipUDP). * When true, all nodes (workers and controller) boot with fault injection * wrappers, enabling partition()/heal() on TestNodeHandle. * Default: false */ faultInjection?: boolean; } /** * TestCluster — spawns a multi-process libeam cluster for integration testing. * * Creates a controller node (in the current process) and N worker nodes * (each in a forked child process). All nodes form a real distributed * cluster using ZeroMQ transport and UDP gossip. * * @example * ```typescript * const cluster = await TestCluster.create({ size: 2 }); * * // Spawn an actor on node 0 * await cluster.nodes[0].agent.call({ method: "spawn", args: ["Counter", { name: "c1", args: [0] }] }); * * // Call it from the controller * const ref = await cluster.system.getActorByName("c1"); * const value = await ref!.call({ method: "get", args: [] }); * * await cluster.teardown(); * ``` * * @example Fault injection * ```typescript * const cluster = await TestCluster.create({ size: 2, faultInjection: true }); * * // Partition node 0 from node 1 * await cluster.nodes[0].partition(cluster.nodes[1].nodeId); * * // Heal all partitions on node 0 * await cluster.nodes[0].heal(); * * await cluster.teardown(); * ``` */ export declare class TestCluster { /** The controller's own libeam System (part of the cluster) */ readonly system: System; /** Handles to all spawned worker nodes */ readonly nodes: TestNodeHandle[]; /** The controller's nodeId */ readonly controllerId: string; private readonly childProcesses; private tornDown; /** FaultyTransport on the controller node (if faultInjection enabled) */ private readonly controllerFaultyTransport?; /** FaultyGossipUDP on the controller node (if faultInjection enabled) */ private readonly controllerFaultyGossip?; /** Map from nodeId to gossip address (e.g., "127.0.0.1:5002") */ private readonly nodeGossipAddresses; private constructor(); /** * Create a test cluster with N worker nodes + 1 controller node. * * 1. Allocates unique ports for all nodes (workers + controller) * 2. Forks NodeWorker child processes for each worker * 3. Boots a controller system in the current process * 4. Waits for all nodes to join the cluster * 5. Resolves NodeAgent refs for each worker */ static create(config?: TestClusterConfig): Promise; /** * Get a node handle by nodeId. */ node(id: string): TestNodeHandle; /** * Partition the controller node from the specified target nodes. * Only available when faultInjection is enabled. */ partitionController(...targetNodeIds: string[]): void; /** * Heal the controller's partitions to the specified target nodes. * If no targets specified, heals all controller partitions. */ healController(...targetNodeIds: string[]): void; /** * Teardown the entire cluster. Shuts down all workers and the controller. * Safe to call multiple times. */ teardown(): Promise; } //# sourceMappingURL=test_cluster.d.ts.map