Files
PHANTOM/e2e/README.md
Claude c8ac2cb609 Add dynamic pricing E2E test suite with Playwright
Implement comprehensive E2E tests to validate the surge pricing pipeline:
- Test SimpleSurgePricer with configurable thresholds (high=3, surge=1.5x)
- Verify discount pricing when demand is below low_threshold
- Test multi-product differential pricing based on demand signals
- Validate price propagation from pipeline through Redis to API

Test infrastructure:
- Playwright configuration with custom fixtures
- Python pipeline worker for direct test execution (bypasses Airflow)
- API client for event ingestion and price verification
- Event generator for creating realistic interaction sequences
- docker-compose.e2e.yml with minimal services for testing
2025-12-26 09:35:07 +00:00

256 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PHANTOM Dynamic Pricing E2E Test Suite
End-to-end tests validating the dynamic pricing pipeline, including SimpleSurgePricer and SessionAwarePricer functionality.
## System Under Test (SUT)
```
┌─────────────────────────────────────────────────────────────────────────┐
│ PHANTOM Pricing Pipeline │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ Test Runner │───▶│ Backend API │───▶│ Kafka (user-interactions)│ │
│ │ (Playwright)│ │ POST /ingest │ │ │ │
│ └──────────────┘ └──────────────┘ └────────────┬─────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────────────┐ │
│ │ │ Pipeline Worker │ │
│ │ │ - Fetch interactions │ │
│ │ │ - Compute demand │ │
│ │ │ - Apply surge pricing │ │
│ │ └────────────┬─────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────────────┐ │
│ │ │ Redis (Model Registry) │ │
│ │ │ - prices:latest │ │
│ │ └────────────┬─────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────┐ ┌──────────────────────────┐ │
│ └────▶│ Pricing API │◀──────────│ Pricing Provider │ │
│ │ GET /price │ │ (serves from Redis) │ │
│ └──────────────┘ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
## Test Scenarios
| Scenario | Description | Expected Outcome |
|----------|-------------|------------------|
| **Baseline** | No interactions for product | Price = base_price (markup = 1.0) |
| **Surge** | 5+ interactions (above threshold) | Price = base_price × 1.5 |
| **Discount** | 1 interaction (at threshold) | Price = base_price × 0.9 |
| **Multi-Product** | Different demand per product | Each product priced by its demand |
| **Propagation** | Pipeline → Redis → API | Prices visible via API |
| **Event Types** | Mix of view, click, cart | All events counted in demand |
| **Multi-Session** | Events from different sessions | Demand aggregated correctly |
## Test Configuration
The tests use aggressive thresholds for fast feedback:
```typescript
pricing: {
highThreshold: 3, // Surge after 3 interactions
lowThreshold: 1, // Discount at ≤1 interaction
surgeMultiplier: 1.5, // 50% price increase
discountMultiplier: 0.9, // 10% discount
windowSize: 10_000, // 10 second window
}
```
## Quick Start
### 1. Start E2E Services
```bash
# Start minimal services for E2E testing
docker compose -f docker-compose.e2e.yml up -d
# Wait for services to be healthy
docker compose -f docker-compose.e2e.yml ps
# Optional: Start with Kafka UI for debugging
docker compose -f docker-compose.e2e.yml --profile debug up -d
```
### 2. Install Test Dependencies
```bash
cd e2e
npm install
npx playwright install
```
### 3. Run Tests
```bash
# Run all E2E tests
npm test
# Run with UI (interactive mode)
npm run test:ui
# Run specific test file
npm run test:pricing
# Run in debug mode
npm run test:debug
# View test report
npm run test:report
```
### 4. Cleanup
```bash
docker compose -f docker-compose.e2e.yml down -v
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `BACKEND_URL` | `http://localhost:5000` | Backend API URL |
| `PROVIDER_URL` | `http://localhost:5001` | Pricing Provider URL |
| `REDIS_HOST` | `localhost` | Redis host |
| `REDIS_PORT` | `6378` | Redis port |
| `KAFKA_HOST` | `localhost` | Kafka host |
| `KAFKA_PORT` | `9092` | Kafka port |
## Test Architecture
```
e2e/
├── playwright.config.ts # Playwright configuration
├── global-setup.ts # Service health checks
├── global-teardown.ts # Cleanup
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── lib/
│ ├── api-client.ts # API interaction utilities
│ ├── event-generator.ts # Test event factory
│ ├── pipeline-runner.ts # TypeScript pipeline wrapper
│ ├── pipeline-worker.py # Python pipeline executor
│ ├── fixtures.ts # Playwright test fixtures
│ └── index.ts # Re-exports
└── tests/
└── dynamic-pricing.spec.ts # Main test file
```
## Pipeline Worker
The tests use a dedicated Python pipeline worker (`lib/pipeline-worker.py`) instead of Airflow for faster, more reliable test execution.
```bash
# Run pipeline manually
python3 lib/pipeline-worker.py \
--store-mode hotel \
--high-threshold 3 \
--surge-multiplier 1.5 \
--json-output
# Dry run (no Redis publish)
python3 lib/pipeline-worker.py --dry-run
```
## Debugging
### View Kafka Events
```bash
# Via API
curl "http://localhost:5000/api/kafka/dump?topic=user-interactions&last_n=10"
# Via Redpanda Console (if started with --profile debug)
open http://localhost:8080
```
### Check Redis State
```bash
docker exec -it PHANTOM-e2e-redis redis-cli
> GET prices:latest
> KEYS *
```
### View Pipeline Logs
The pipeline worker logs detailed information:
```
[INFO] Starting E2E pricing pipeline: mode=hotel, high_threshold=3, surge_multiplier=1.5
[INFO] Fetched 15 interaction records
[INFO] Computed demand for 3 products
[INFO] Applied surge pricing:
e2e-test...: base=$100.00 -> optimal=$150.00 (demand=5, markup=1.50x)
[INFO] Published 3 prices to Redis
```
## Writing New Tests
```typescript
import { test, expect } from '../lib/fixtures';
import { generateTestProductId } from '../lib/event-generator';
test('my new pricing test', async ({ api, events, triggerPriceUpdate }) => {
// 1. Create unique product ID
const productId = generateTestProductId('my-test');
// 2. Log base price
await api.logPrice({
productId,
price: 100.0,
sessionId: events.session,
storeMode: 'hotel',
});
// 3. Generate events
const surgeEvents = events.generateSurgeSequence(productId, 5);
await api.ingestEvents(surgeEvents);
// 4. Trigger pipeline
const result = await triggerPriceUpdate();
// 5. Verify results
expect(result.success).toBe(true);
const pricedProduct = result.prices?.find(p => p.productId === productId);
expect(pricedProduct?.optimal_price).toBeGreaterThan(100);
});
```
## Troubleshooting
### "Backend not available"
Ensure services are running:
```bash
docker compose -f docker-compose.e2e.yml ps
docker compose -f docker-compose.e2e.yml logs backend
```
### "No interactions found"
Check Kafka topic has events:
```bash
curl "http://localhost:5000/api/kafka/dump?topic=user-interactions"
```
### "Pipeline timeout"
Increase timeout in `playwright.config.ts`:
```typescript
timeout: 180_000, // 3 minutes
```
### "Price not updated"
Check Redis has latest prices:
```bash
docker exec -it PHANTOM-e2e-redis redis-cli GET prices:latest
```