# Analysis of Test Failures in Network Library ## Failing Tests Overview When running `bun test libs/network/src`, these tests fail: ```sql ✗ MemoryTransport > Simulated network conditions > should simulate connection delay ✗ MemoryTransport > Simulated network conditions > should simulate latency ✗ VotingManager > session management > should get vote history ✗ NetworkNodePhase4 > initialization > should register core network reliability calculator ✗ NetworkNodePhase4 > host selection > should select the best host ✗ MessageBatch > Age tracking > should track batch age ✗ TransportTester > testMessageDelivery > should return true when message is delivered ✗ TransportTester > testReliability > should report perfect reliability when all messages delivered ✗ TransportTester > testReliability > should report partial reliability when some messages lost ``` However, when running each test file individually, all tests pass. This indicates an issue with test isolation. ## Root Cause Analysis for Each Failing Test ### 1. MemoryTransport - Connection Delay & Latency Tests **File:** `libs/network/src/transport/memory-transport.spec.ts` **Issues:** - Both tests use real `setTimeout` for time-based assertions - The `MemoryTransport` class uses a static `_instances` Map that isn't properly reset between tests - Tests make timing assertions that can be affected by other running tests **Relevant code:** ```typescript it('should simulate connection delay', async () => { const simulationOptions: MemoryTransportSimulationOptions = { connectionDelay: 50 }; const transport = new MemoryTransport('delayed-transport', { simulationOptions, eventEmitter: new NetworkEventEmitter() }); const startTime = Date.now(); await transport.connect(); const endTime = Date.now(); expect(endTime - startTime).toBeGreaterThanOrEqual(50); }); ``` **Solution:** 1. Update `MemoryTransport` to accept a `TimerController` instance 2. Add a static `resetRegistry` method to clear all instances 3. Refactor tests to use `TimerController` for time simulation ### 2. VotingManager - Vote History Test **File:** `libs/network/src/voting/voting-manager.spec.ts` **Issues:** - The test creates and completes multiple sessions - Some sessions may be added to history out of order due to timing issues - Depends on proper cleanup between tests **Relevant code:** ```typescript it('should get vote history', () => { // Create a vote session const sessionId = votingManager.createVoteSession(VoteType.HOST_SELECTION, 'session'); // Complete the session to move it to history const session = votingManager.getSession(sessionId); if (session) { // Add some votes (session as any)._testAddVote({ voteId: 'vote1', voterId: 'node1', value: { selectedHost: 'node1' }, timestamp: Date.now() }); // Force completion (session as any)._testSetStatus(VoteSessionStatus.COMPLETED); } // Get vote history const history = votingManager.getVoteHistory(); // Verify history expect(history.length).toBe(1); expect(history[0].id).toBe(sessionId); }); ``` **Solution:** 1. Ensure `VotingManager` properly cleans up between tests 2. Use a consistent timestamp source that can be controlled 3. Improve assertion to check if the expected session is in the history, not just the count ### 3. NetworkNodePhase4 - Initialization and Host Selection **File:** `libs/network/src/node/network-node-phase4.spec.ts` **Issues:** - The test creates multiple extensions in the same test file - Each extension registers calculators with shared resources - The host selection test depends on mocked responses that could be affected by other tests **Relevant code:** ```typescript it('should register core network reliability calculator', () => { // Spy on metrics manager const registerCalculatorSpy = jest.spyOn(nodePhase4.metricsManager, 'registerCalculator'); // Create a new extension to verify registration const newExtension = new NetworkNodePhase4(mockNode, eventEmitter); // Verify calculator was registered expect(registerCalculatorSpy).toHaveBeenCalled(); // Clean up newExtension.dispose(); }); ``` **Solution:** 1. Ensure proper cleanup between tests with more thorough `dispose()` methods 2. Isolate dependencies so that new instances don't interfere with each other 3. Replace event emitter instances in each test ### 4. MessageBatch - Age Tracking **File:** `libs/network/src/router/message-batch.spec.ts` **Issues:** - Uses real `setTimeout` which can be affected by other tests - Depends on actual timing for assertions **Relevant code:** ```typescript it('should track batch age', async () => { // Create a batch and wait a bit const initialAge = batch.age; // Wait at least 10ms await new Promise(resolve => setTimeout(resolve, 10)); // Age should have increased expect(batch.age).toBeGreaterThan(initialAge); expect(batch.age).toBeGreaterThanOrEqual(10); }); ``` **Solution:** 1. Update `MessageBatch` to optionally accept a `TimerController` 2. Refactor test to use controlled time advancement ### 5. TransportTester - Message Delivery and Reliability Tests **File:** `libs/network/src/transport/pdk/transport-testing.spec.ts` **Issues:** - Tests rely on asynchronous callbacks and real timing - MockTransport implementation uses real `setTimeout` - Race conditions can cause tests to fail when run concurrently **Relevant code:** ```typescript it('should return true when message is delivered', async () => { // Setup receiver to simulate receiving the message const testMessage = { test: true }; // We need to simulate the receipt of the message when the sender sends it sender.on(TransportEvents.MESSAGE_SENT, (msg) => { receiver.simulateMessageReceived(msg, sender.id); }); const result = await TransportTester.testMessageDelivery(sender, receiver, testMessage); expect(result).toBe(true); }); ``` **Solution:** 1. Update `MockTransport` to use `TimerController` 2. Modify `TransportTester` to optionally accept a `TimerController` 3. Use controlled time advancement rather than actual timeouts ## Common Patterns and Solution Strategy ### Core Issues 1. **Shared Static State**: Several classes use static properties or singletons 2. **Real Timing Dependency**: Tests rely on actual setTimeout/setInterval 3. **Timestamp Variations**: Inconsistent approaches to time tracking ### Solution Strategy 1. **Refactor TimerController**: - Remove the singleton pattern - Create factory for isolated instances - Ensure proper cleanup methods 2. **Update Key Classes**: ```typescript interface TimeOptions { timerController?: TimerController; useRealTime?: boolean; // Default to false in tests } ``` 3. **Consistent Cleanup Pattern**: ```typescript beforeEach(() => { // Create isolated timer instances for each test const timer = TimerController.createInstance(); // Reset any static state MemoryTransport.resetRegistry(); // Create test instances with isolated timers testInstance = new ClassUnderTest({ timerController: timer }); }); afterEach(() => { // Clean up instances testInstance.dispose(); // Reset any static state again MemoryTransport.resetRegistry(); }); ``` 4. **Time-based Assertions**: ```typescript // Before const startTime = Date.now(); await someAsyncOperation(); const elapsed = Date.now() - startTime; expect(elapsed).toBeGreaterThanOrEqual(expectedTime); // After const timer = TimerController.createInstance(); const startTime = timer.getCurrentTime(); // Start the operation without await const operation = someAsyncOperation(); // Advance time timer.advanceTime(expectedTime + 10); // Now wait for the operation to complete await operation; // Check the operation had the expected effect // But don't assert based on actual elapsed time ``` By implementing these changes systematically across the test suite, we can ensure proper test isolation and eliminate the timing-related test failures.