max / makenotwork
3 files changed,
+111 insertions,
-12 deletions
| @@ -187,18 +187,16 @@ Modules with 1-3 tests that need expansion, plus missing modules for features we | |||
| 187 | 187 | ||
| 188 | 188 | ### Phase 3: Harness optimization | |
| 189 | 189 | ||
| 190 | - | #### New helper: `create_creator_with_stripe` | |
| 191 | - | - [ ] Combines `create_creator` + mock Stripe Connect setup (stripe_account_id, charges_enabled, onboarding_complete) | |
| 192 | - | - [ ] Returns `CreatorSetup` with stripe account info for webhook tests | |
| 193 | - | - [ ] Eliminates repeated 5-line SQL blocks across stripe_webhooks, mock_payment_flows, fan_plus, tier_enforcement | |
| 194 | - | ||
| 195 | - | #### New helper: `create_buyers(n)` | |
| 196 | - | - [ ] Batch-create n buyer accounts for tests needing multiple purchasers | |
| 197 | - | - [ ] Returns Vec<UserId> for concurrent purchase tests | |
| 198 | - | ||
| 199 | - | #### Harness speedups | |
| 200 | - | - [ ] `TestHarness::minimal()` alias — skips storage/stripe/scanner setup for auth-only tests | |
| 201 | - | - [ ] Document test database requirements in tests/README.md (PostgreSQL version, template DB, TEST_DATABASE_URL) | |
| 190 | + | #### New helpers (added to harness/mod.rs) | |
| 191 | + | - [x] `connect_stripe(user_id, account_id)` — sets stripe_account_id + charges_enabled + onboarding + payouts in one call | |
| 192 | + | - [x] `create_creator_with_stripe(username)` — create_creator + grant_tier + connect_stripe in one call | |
| 193 | + | - [x] `create_buyers(count)` — batch-create buyer accounts, returns Vec<UserId> | |
| 194 | + | ||
| 195 | + | #### Documentation | |
| 196 | + | - [x] `tests/README.md` — documents all test types, harness features, constructors, running instructions, and fixtures | |
| 197 | + | ||
| 198 | + | #### Not needed | |
| 199 | + | - `TestHarness::minimal()` — `new()` is already the minimal constructor (DB only, no extras) | |
| 202 | 200 | ||
| 203 | 201 | --- | |
| 204 | 202 |
| @@ -0,0 +1,64 @@ | |||
| 1 | + | # MNW Server Tests | |
| 2 | + | ||
| 3 | + | ## Prerequisites | |
| 4 | + | ||
| 5 | + | - PostgreSQL running locally (default: `postgres://localhost/postgres`) | |
| 6 | + | - Set `TEST_DATABASE_URL` if using a non-default admin connection | |
| 7 | + | ||
| 8 | + | ## Test Types | |
| 9 | + | ||
| 10 | + | ### Unit Tests (`cargo test --lib`) | |
| 11 | + | ||
| 12 | + | 986 tests covering pure logic: pricing, validation, formatting, enums, error handling, CSRF, RSS, file scanning, import parsing, etc. No database required. | |
| 13 | + | ||
| 14 | + | ### Integration Tests (`cargo test --test integration`) | |
| 15 | + | ||
| 16 | + | 679 tests across 78 workflow modules. Each test gets an isolated PostgreSQL database cloned from a shared template (migrations applied once per test run). | |
| 17 | + | ||
| 18 | + | **Harness features:** | |
| 19 | + | - In-process Axum app (no network, uses `tower::ServiceExt::oneshot`) | |
| 20 | + | - Cookie-aware HTTP client with automatic CSRF token management | |
| 21 | + | - Mock Stripe (`MockPaymentProvider`) — captures checkout sessions, supports webhook signing | |
| 22 | + | - Mock email (`MockEmailTransport`) — captures all sent emails for assertion | |
| 23 | + | - Mock S3 (`InMemoryStorage`) — in-memory file storage | |
| 24 | + | - Direct SQL helpers for test setup (`grant_creator`, `grant_tier`, `connect_stripe`, etc.) | |
| 25 | + | ||
| 26 | + | **Harness constructors:** | |
| 27 | + | - `TestHarness::new()` — DB only (fastest, for auth/CRUD tests) | |
| 28 | + | - `with_storage()` — adds in-memory S3 | |
| 29 | + | - `with_mocks()` — mock Stripe + email (for payment flow tests) | |
| 30 | + | - `with_stripe()` — real Stripe SDK with test keys | |
| 31 | + | - `with_admin()` — pre-created admin user | |
| 32 | + | - `with_storage_and_scanner()` — file scanning pipeline | |
| 33 | + | - `with_git_repos(path)` — git repository support | |
| 34 | + | ||
| 35 | + | ### Load Tests (`cargo test --test load -- --ignored --nocapture`) | |
| 36 | + | ||
| 37 | + | Multi-scenario virtual user simulation. Requires `--ignored` flag. Configurable via env vars: | |
| 38 | + | - `LOAD_VUS` — virtual users (default: 20) | |
| 39 | + | - `LOAD_DURATION_SECS` — duration (default: 30) | |
| 40 | + | - `LOAD_RAMP_SECS` — ramp-up (default: 5) | |
| 41 | + | ||
| 42 | + | ### Health Tests (`cargo test --test health`) | |
| 43 | + | ||
| 44 | + | External HTTP tests against a running server at `http://localhost:3000`. Skips gracefully if server is not running. | |
| 45 | + | ||
| 46 | + | ## Running | |
| 47 | + | ||
| 48 | + | ```bash | |
| 49 | + | # Unit tests only (fast, no DB) | |
| 50 | + | cargo test --lib | |
| 51 | + | ||
| 52 | + | # Integration tests (requires PostgreSQL) | |
| 53 | + | cargo test --test integration | |
| 54 | + | ||
| 55 | + | # Specific workflow | |
| 56 | + | cargo test --test integration sandbox | |
| 57 | + | ||
| 58 | + | # All tests | |
| 59 | + | cargo test | |
| 60 | + | ``` | |
| 61 | + | ||
| 62 | + | ## Fixtures | |
| 63 | + | ||
| 64 | + | Test media files in `tests/fixtures/`: `.mp3`, `.mp4`, `.flac`, `.webm`, `.ogg`, `.wav`, `.m4a` |
| @@ -491,6 +491,43 @@ impl TestHarness { | |||
| 491 | 491 | CreatorSetup { user_id, project_id, item_id, slug } | |
| 492 | 492 | } | |
| 493 | 493 | ||
| 494 | + | /// Connect a user's Stripe account via direct SQL. | |
| 495 | + | /// Sets stripe_account_id, stripe_charges_enabled, and stripe_onboarding_complete. | |
| 496 | + | /// Use after `create_creator()` for tests that need a Stripe-connected seller. | |
| 497 | + | pub async fn connect_stripe(&self, user_id: UserId, account_id: &str) { | |
| 498 | + | sqlx::query( | |
| 499 | + | "UPDATE users SET stripe_account_id = $2, stripe_charges_enabled = true, \ | |
| 500 | + | stripe_onboarding_complete = true, stripe_payouts_enabled = true WHERE id = $1", | |
| 501 | + | ) | |
| 502 | + | .bind(user_id) | |
| 503 | + | .bind(account_id) | |
| 504 | + | .execute(&self.db) | |
| 505 | + | .await | |
| 506 | + | .expect("Failed to connect Stripe"); | |
| 507 | + | } | |
| 508 | + | ||
| 509 | + | /// Create a test creator with Stripe connected. Shorthand for `create_creator` + `grant_tier` + `connect_stripe`. | |
| 510 | + | /// Returns the user ID. Creator is logged in afterward. | |
| 511 | + | pub async fn create_creator_with_stripe(&mut self, username: &str) -> UserId { | |
| 512 | + | let user_id = self.create_creator(username).await; | |
| 513 | + | self.grant_tier(user_id, "small_files").await; | |
| 514 | + | self.connect_stripe(user_id, &format!("acct_mock_{}", username)).await; | |
| 515 | + | user_id | |
| 516 | + | } | |
| 517 | + | ||
| 518 | + | /// Batch-create buyer accounts. Returns a Vec of user IDs. | |
| 519 | + | /// Each buyer gets username "buyer{n}", email "buyer{n}@test.com", password "password123". | |
| 520 | + | /// The last buyer is left logged in. | |
| 521 | + | pub async fn create_buyers(&mut self, count: usize) -> Vec<UserId> { | |
| 522 | + | let mut ids = Vec::with_capacity(count); | |
| 523 | + | for i in 0..count { | |
| 524 | + | let username = format!("buyer{}", i); | |
| 525 | + | let id = self.signup(&username, &format!("{}@test.com", username), "password123").await; | |
| 526 | + | ids.push(id); | |
| 527 | + | } | |
| 528 | + | ids | |
| 529 | + | } | |
| 530 | + | ||
| 494 | 531 | /// Publish both a project and an item. | |
| 495 | 532 | pub async fn publish_project_and_item(&mut self, project_id: &str, item_id: &str) { | |
| 496 | 533 | self.client |