This document outlines the comprehensive testing strategy for the LiveLink application, focusing on race conditions, complexity reduction, and code quality.
- Testing Setup
- Test Types
- Running Tests
- Test Helpers
- Race Condition Testing
- Test Coverage
- Test Matrix
The LiveLink project uses Jest for unit and integration testing. The setup includes:
- Jest: Main testing framework
- ts-jest: TypeScript support for Jest
- jest-mock-extended: Advanced mocking capabilities
- TimerMock: Custom timer mocking for time-based tests
jest.config.js: Main Jest configurationjest.setup.js: Global test setup and teardowntsconfig.test.json: TypeScript configuration for tests
The testing strategy includes several types of tests:
Unit tests focus on testing individual components in isolation. They use mocks for dependencies and verify the behavior of a single unit of code.
Example: queue_service.test.ts
These tests specifically target potential race conditions in the codebase by simulating concurrent operations, delayed responses, and out-of-order completions.
Example: stream_manager.race.test.ts
Integration tests verify that multiple components work together correctly. They focus on the interaction between components and ensure proper behavior across boundaries.
Example: skipWatchedStreams.test.ts
To run the tests, use the following npm scripts:
# Run all tests
npm run test:jest
# Run tests in watch mode
npm run test:jest:watch
# Generate coverage report
npm run test:jest:coverage
# Run only race condition tests
npm run test:raceSeveral helper utilities have been created to facilitate testing:
delay(): Creates a promise that resolves after a specified timecreateDeferred(): Creates a deferred promise that can be resolved externallyexecuteWithDelay(): Executes promises with controlled timingexecuteStaggered(): Executes tasks in parallel with staggered start timesExecutionTracker: Tracks the order of async operations
createMockChildProcess(): Creates a mock child processcreateMockEventEmitter(): Creates a mock event emittercreateMockStreamSource(): Creates a mock stream sourcecreateMockConfig(): Creates a mock configurationcreateMockServices(): Creates mock servicescreateFetchMock(): Creates a controlled fetch mock
TimerMock: Provides precise control over timers in testsadvanceTime(): Advances time by a specified amountrunAllTimers(): Runs all pending timersrunOnlyPendingTimers(): Runs only currently pending timers
Race conditions are particularly challenging to test. Our approach includes:
- Controlled Timing: Using custom timer mocks to control when operations occur
- Execution Tracking: Recording the order of operations to verify correct sequencing
- Concurrent Operations: Simulating multiple operations happening simultaneously
- Delayed Responses: Testing behavior when operations complete out of order
- Network Failures: Simulating network failures and verifying recovery
test('should prevent concurrent handleStreamEnd calls for the same screen', async () => {
// Set up test data
// Execute multiple operations concurrently
await executeStaggered([
() => streamManager.handleStreamEnd(1),
() => streamManager.handleStreamEnd(1),
() => streamManager.handleStreamEnd(1)
], 10);
// Verify correct behavior
expect(streamManager.startStream).toHaveBeenCalledTimes(1);
});The test coverage report can be generated using:
npm run test:jest:coverageThis will generate a coverage report in the coverage directory, which includes:
- Line coverage
- Branch coverage
- Function coverage
- Statement coverage
- Unit Tests: 80%+ coverage of core services
- Race Condition Tests: Coverage of all identified race condition scenarios
- Integration Tests: Coverage of key user workflows
The following matrix outlines the key test scenarios covered:
| Component | Unit Tests | Race Tests | Integration Tests |
|---|---|---|---|
| StreamManager | ✅ | ✅ | ✅ |
| PlayerService | ✅ | ✅ | ✅ |
| QueueService | ✅ | ❌ | ✅ |
| skipWatchedStreams | ✅ | ✅ | ✅ |
| Network Resilience | ✅ | ✅ | ❌ |
| Resource Cleanup | ✅ | ✅ | ❌ |
-
Stream Processing
- Concurrent stream processing
- Stream end handling
- Queue management
-
Network Resilience
- Network failure handling
- Retry mechanisms
- Backoff strategies
-
Resource Management
- Timer cleanup
- Process cleanup
- Memory leak prevention
-
skipWatchedStreams Feature
- Global setting behavior
- Screen-specific setting behavior
- Interaction with favorites
-
Race Conditions
- Multiple simultaneous stream starts
- Network race conditions
- Concurrent queue updates