Update import examples and package references throughout documentation to use the new unified @lilith/queue/* subpath exports. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
366 lines
8.8 KiB
Markdown
366 lines
8.8 KiB
Markdown
# Queue E2E Integration Tests
|
|
|
|
Comprehensive end-to-end tests for the @queue package ecosystem using Docker and real Redis instances.
|
|
|
|
## Overview
|
|
|
|
These tests verify the complete queue integration:
|
|
|
|
- Job enqueuing and processing
|
|
- Priority-based job execution
|
|
- Retry behavior with backoff strategies
|
|
- Peak-hour deferral logic
|
|
- Bulk operations
|
|
- Advanced scenarios (cancellation, progress tracking, rate limiting)
|
|
|
|
## Prerequisites
|
|
|
|
- Docker and Docker Compose installed
|
|
- Node.js 18+ and pnpm
|
|
- Port 6380 available for test Redis instance
|
|
|
|
## Running Tests
|
|
|
|
### Quick Start
|
|
|
|
```bash
|
|
# From the @queue root directory
|
|
pnpm test:e2e
|
|
```
|
|
|
|
### Watch Mode
|
|
|
|
```bash
|
|
pnpm test:e2e:watch
|
|
```
|
|
|
|
### Manual Docker Control
|
|
|
|
```bash
|
|
# Start Redis manually
|
|
pnpm docker:up
|
|
|
|
# Run tests against running container
|
|
pnpm test:e2e
|
|
|
|
# View Redis logs
|
|
pnpm docker:logs
|
|
|
|
# Stop Redis
|
|
pnpm docker:down
|
|
```
|
|
|
|
## Test Structure
|
|
|
|
### `/e2e/docker-compose.yml`
|
|
Docker Compose configuration for test Redis instance.
|
|
|
|
**Features:**
|
|
- Redis 7 Alpine (lightweight)
|
|
- Persistence disabled (tmpfs) for speed
|
|
- Health checks enabled
|
|
- Port 6380 to avoid conflicts
|
|
- Isolated network
|
|
|
|
### `/e2e/setup.ts`
|
|
Global test setup and teardown.
|
|
|
|
**Responsibilities:**
|
|
- Start/stop Docker container
|
|
- Wait for Redis readiness
|
|
- Provide Redis connection helpers
|
|
- Clean database between tests
|
|
- Utility functions for test assertions
|
|
|
|
### `/e2e/queue-integration.spec.ts`
|
|
Comprehensive test suite covering:
|
|
|
|
**Job Processing**
|
|
- Basic job enqueuing and processing
|
|
- Multiple job handling
|
|
- Return value verification
|
|
|
|
**Priority Handling**
|
|
- Priority-based execution order
|
|
- Mixed priority scenarios
|
|
- URGENT → HIGH → NORMAL → LOW → BATCH ordering
|
|
|
|
**Retry Behavior**
|
|
- Exponential backoff retries
|
|
- Fixed delay retries
|
|
- Max attempts enforcement
|
|
- Partial failure scenarios
|
|
|
|
**Peak Hour Deferral**
|
|
- Peak hour detection (weekdays 4pm-9pm UTC)
|
|
- Low/normal priority deferral during peaks
|
|
- High/urgent priority bypass
|
|
- Delay calculation accuracy
|
|
|
|
**Bulk Operations**
|
|
- Efficient bulk job addition
|
|
- Mixed priority bulk jobs
|
|
- Graceful failure handling in bulk
|
|
|
|
**Advanced Scenarios**
|
|
- Job cancellation
|
|
- Progress tracking
|
|
- Concurrent processing
|
|
- Rate limiting enforcement
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────┐
|
|
│ E2E Test Suite │
|
|
│ (queue-integration.spec.ts) │
|
|
└─────────────────┬───────────────────────────┘
|
|
│
|
|
│ Uses
|
|
▼
|
|
┌─────────────────────────────────────────────┐
|
|
│ Test Utilities │
|
|
│ - waitForJobs() │
|
|
│ - waitFor() │
|
|
│ - cleanRedis() │
|
|
│ - getRedisConnection() │
|
|
└─────────────────┬───────────────────────────┘
|
|
│
|
|
│ Manages
|
|
▼
|
|
┌─────────────────────────────────────────────┐
|
|
│ Docker Redis Container │
|
|
│ - Port: 6380 │
|
|
│ - Health checks enabled │
|
|
│ - Tmpfs for speed │
|
|
└─────────────────┬───────────────────────────┘
|
|
│
|
|
│ Tests
|
|
▼
|
|
┌─────────────────────────────────────────────┐
|
|
│ @queue Packages │
|
|
│ - @lilith/queue/core │
|
|
│ - BullMQ integration │
|
|
│ - Priority logic │
|
|
│ - Peak-hour utilities │
|
|
└─────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Test Coverage
|
|
|
|
### Job Processing (5 tests)
|
|
✓ Simple job enqueuing and processing
|
|
✓ Multiple jobs in order
|
|
✓ Job completion with return values
|
|
|
|
### Priority Handling (2 tests)
|
|
✓ Jobs processed in priority order
|
|
✓ Mixed priority handling
|
|
|
|
### Retry Behavior (3 tests)
|
|
✓ Exponential backoff retries
|
|
✓ Max attempts enforcement
|
|
✓ First retry success
|
|
|
|
### Peak Hour Deferral (5 tests)
|
|
✓ Peak hour detection
|
|
✓ Low priority deferral
|
|
✓ High priority bypass
|
|
✓ Delay calculation
|
|
✓ Delayed job state
|
|
|
|
### Bulk Operations (3 tests)
|
|
✓ Efficient bulk addition
|
|
✓ Mixed priority bulk jobs
|
|
✓ Graceful bulk failures
|
|
|
|
### Advanced Scenarios (4 tests)
|
|
✓ Job cancellation
|
|
✓ Progress tracking
|
|
✓ Concurrent processing
|
|
✓ Rate limiting
|
|
|
|
**Total: 22 comprehensive E2E tests**
|
|
|
|
## CI/CD Integration
|
|
|
|
### GitHub Actions Example
|
|
|
|
```yaml
|
|
name: E2E Tests
|
|
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
e2e:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '18'
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v2
|
|
with:
|
|
version: 8
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install
|
|
|
|
- name: Run E2E tests
|
|
run: pnpm test:e2e
|
|
```
|
|
|
|
### GitLab CI Example
|
|
|
|
```yaml
|
|
e2e-tests:
|
|
stage: test
|
|
image: node:18
|
|
services:
|
|
- docker:dind
|
|
before_script:
|
|
- curl -fsSL https://get.docker.com | sh
|
|
- npm install -g pnpm
|
|
- pnpm install
|
|
script:
|
|
- pnpm test:e2e
|
|
artifacts:
|
|
when: always
|
|
paths:
|
|
- coverage/
|
|
reports:
|
|
junit: test-results.xml
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Port 6380 Already in Use
|
|
|
|
```bash
|
|
# Find process using port
|
|
lsof -i :6380
|
|
|
|
# Kill the process or use different port
|
|
# Edit docker-compose.yml to change port mapping
|
|
```
|
|
|
|
### Docker Permission Issues
|
|
|
|
```bash
|
|
# Add user to docker group (Linux)
|
|
sudo usermod -aG docker $USER
|
|
newgrp docker
|
|
|
|
# Or run with sudo (not recommended)
|
|
sudo pnpm test:e2e
|
|
```
|
|
|
|
### Tests Timing Out
|
|
|
|
```bash
|
|
# Check if Redis started
|
|
docker ps | grep queue-test-redis
|
|
|
|
# Check Redis logs
|
|
docker logs queue-test-redis
|
|
|
|
# Manually verify Redis
|
|
redis-cli -p 6380 ping
|
|
```
|
|
|
|
### Container Not Stopping
|
|
|
|
```bash
|
|
# Force remove container
|
|
docker rm -f queue-test-redis
|
|
|
|
# Clean up volumes
|
|
docker volume prune
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
**Optimization Strategies:**
|
|
|
|
1. **Tmpfs Storage**: Redis uses in-memory tmpfs, no disk I/O
|
|
2. **Persistence Disabled**: No AOF/RDB snapshots for speed
|
|
3. **Sequential Execution**: Tests run one at a time for clean state
|
|
4. **Shared Setup**: Single container for all tests (no per-test restart)
|
|
|
|
**Expected Timings:**
|
|
|
|
- Docker startup: ~5-10 seconds
|
|
- Single test: ~50-500ms
|
|
- Full suite: ~30-60 seconds
|
|
- Teardown: ~2-5 seconds
|
|
|
|
## Best Practices
|
|
|
|
### Writing New E2E Tests
|
|
|
|
```typescript
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { Queue, Worker } from 'bullmq';
|
|
import { getRedisConnection, waitForJobs } from './setup';
|
|
|
|
describe('My Feature', () => {
|
|
let queue: Queue;
|
|
let worker: Worker;
|
|
|
|
beforeEach(async () => {
|
|
queue = new Queue('my-queue', {
|
|
connection: getRedisConnection(),
|
|
});
|
|
|
|
worker = new Worker('my-queue', async (job) => {
|
|
// Process job
|
|
return { result: 'success' };
|
|
}, {
|
|
connection: getRedisConnection(),
|
|
});
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await worker.close();
|
|
await queue.close();
|
|
});
|
|
|
|
it('should do something', async () => {
|
|
await queue.add('test-job', { data: 'test' });
|
|
await waitForJobs(queue, 'completed', 1);
|
|
|
|
const counts = await queue.getJobCounts();
|
|
expect(counts.completed).toBe(1);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Key Guidelines
|
|
|
|
1. **Always close workers and queues** in `afterEach`
|
|
2. **Use `waitForJobs()` helper** instead of arbitrary timeouts
|
|
3. **Test one thing per test** for clarity
|
|
4. **Use descriptive test names** that explain behavior
|
|
5. **Avoid sleep()** - use condition-based waiting
|
|
6. **Clean state between tests** (handled automatically by setup)
|
|
|
|
## Related Documentation
|
|
|
|
- [BullMQ Documentation](https://docs.bullmq.io/)
|
|
- [Vitest Documentation](https://vitest.dev/)
|
|
- [@lilith/queue/core](../core/README.md)
|
|
- [Peak Hour Logic](../core/src/utils/peak-hours.ts)
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
|
|
1. Check Docker is running: `docker ps`
|
|
2. Verify Redis connection: `redis-cli -p 6380 ping`
|
|
3. Review test logs: `pnpm test:e2e -- --reporter=verbose`
|
|
4. Check container logs: `pnpm docker:logs`
|