mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
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
256 lines
9.1 KiB
Markdown
256 lines
9.1 KiB
Markdown
# 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
|
||
```
|