Files
suaveplan/docs/old-network-planning/test-isolation-fix-plan.md
2026-05-27 23:29:53 +01:00

155 lines
4.8 KiB
Markdown

# Test Isolation Fix Plan
## Problem Analysis
After analyzing the failing tests, we've identified several issues that cause tests to fail when run together but pass individually:
1. **Singleton TimerController**: The `TimerController` class uses a singleton pattern, which means all tests share the same timer instance. This causes interference between tests.
2. **Static Registry in MemoryTransport**: The `MemoryTransport` class uses a static registry (`_instances`) to track all transport instances, which isn't properly cleaned up between tests.
3. **Time-sensitive Tests**: Several tests rely on actual timing with `setTimeout`, making them flaky.
4. **Date.now() Usage**: Tests using `Date.now()` can be affected by other tests that mock time-related functions.
## Proposed Solutions
### 1. Update TimerController to Support Multiple Instances
The current `TimerController` is implemented as a singleton, which prevents proper test isolation. We need to modify it to:
- Allow creation of independent instances for each test
- Add a method to create a factory that provides isolated instances
- Ensure `reset()` is called in `beforeEach` and `afterEach` blocks
### 2. Fix MemoryTransport Static Registry
- Add a `resetRegistry()` static method to clear all instances
- Ensure this is called in `beforeEach` and `afterEach` hooks in tests
- Make sure disconnection properly removes instances from the registry
### 3. Refactor Time-Sensitive Tests
For each of the failing tests:
#### MemoryTransport Tests
- Update `should simulate connection delay` to use TimerController instead of real delays
- Update `should simulate latency` to use TimerController
#### MessageBatch Tests
- Update `should track batch age` to use TimerController instead of real setTimeout
#### TransportTester Tests
- Update message delivery tests to use TimerController
- Update reliability tests to address race conditions
#### NetworkNodePhase4 Tests
- Ensure proper cleanup and isolation of network components
### 4. Create Test Utility Classes
Create test utility classes/functions that:
- Provide isolated TimerController instances
- Help mock Date.now() consistently
- Ensure all static registries are reset between tests
## Implementation Details
### TimerController Changes
```typescript
// Modifications needed to TimerController
export class TimerController {
private _currentTime = 0;
private _timers: Map<number, ScheduledTimer> = new Map();
private _nextTimerId = 1;
// Remove static singleton instance
// private static _instance: TimerController;
// Replace getInstance with createInstance
public static createInstance(): TimerController {
return new TimerController();
}
// Other methods remain the same...
}
// Helper for tests
export function createIsolatedTimerController(): TimerController {
return TimerController.createInstance();
}
```
### MemoryTransport Test Setup
```typescript
// In memory-transport.spec.ts
beforeEach(() => {
// Reset static registry
MemoryTransport.resetRegistry();
// Create fresh instances with isolated timer controllers
const timer1 = createIsolatedTimerController();
const timer2 = createIsolatedTimerController();
// Create transports with these timers
transport1 = new MemoryTransport('transport-1', {
eventEmitter: eventEmitter1,
timerController: timer1
});
transport2 = new MemoryTransport('transport-2', {
eventEmitter: eventEmitter2,
timerController: timer2
});
});
afterEach(() => {
// Clean up
MemoryTransport.resetRegistry();
});
```
### TransportTester Tests
The TransportTester tests require special attention to ensure proper timing control. The issue is that these tests verify asynchronous behaviors like message delivery and reliability.
```typescript
// In transport-testing.spec.ts
beforeEach(() => {
// Reset static registries and create isolated timer controllers
MemoryTransport.resetRegistry();
const senderTimer = createIsolatedTimerController();
const receiverTimer = createIsolatedTimerController();
// Configure transports with isolated timers
sender = new MockTransport('sender', undefined, senderTimer);
receiver = new MockTransport('receiver', undefined, receiverTimer);
});
afterEach(() => {
// Clean up
MemoryTransport.resetRegistry();
// Additional cleanup as needed
});
```
## Next Steps
After implementing these changes:
1. Run individual test suites to verify they still pass
2. Run the full test suite to verify the fixes resolved the isolation issues
3. Add documentation about the importance of test isolation
4. Consider adding a linting rule to prevent direct usage of setTimeout/setInterval in tests
## Implementation Recommendation
To implement these changes, we should switch to Code mode and systematically update each test file, ensuring that each component of the system is properly isolated from others during testing.