From fa9ce0680bd1fb9b7e092a7e00dff6c6b9f11b91 Mon Sep 17 00:00:00 2001 From: Niels Mokkenstorm Date: Sun, 9 Aug 2026 09:36:00 +0200 Subject: [PATCH] test: seed twenty social collectors --- e2e/devnet/Caddyfile | 2 +- e2e/devnet/create-test-accounts.sh | 20 ++++++++- e2e/devnet/docker-compose.yml | 15 +++++++ e2e/devnet/seed-social.sh | 70 +++++++++++++++++++++++++++++- e2e/tests/adoption.spec.ts | 3 +- e2e/tests/edit-inbox.spec.ts | 3 +- e2e/tests/oauth-error.spec.ts | 4 +- 7 files changed, 109 insertions(+), 8 deletions(-) diff --git a/e2e/devnet/Caddyfile b/e2e/devnet/Caddyfile index 4db2a9d..275349a 100644 --- a/e2e/devnet/Caddyfile +++ b/e2e/devnet/Caddyfile @@ -3,7 +3,7 @@ # internal` — no mkcert or other external tooling needed. } -alice.test, bob.test, carol.test, dave.test, erin.test { +alice.test, bob.test, carol.test, dave.test, erin.test, faye.test, gideon.test, hana.test, ivan.test, june.test, kai.test, lina.test, malik.test, nora.test, otis.test, priya.test, quinn.test, rosa.test, sam.test, theo.test { tls internal reverse_proxy pds:3000 } diff --git a/e2e/devnet/create-test-accounts.sh b/e2e/devnet/create-test-accounts.sh index 5654ecc..9baf985 100755 --- a/e2e/devnet/create-test-accounts.sh +++ b/e2e/devnet/create-test-accounts.sh @@ -6,12 +6,15 @@ set -euo pipefail PASSWORD="${TEST_ACCOUNT_PASSWORD:-e2e-test-password}" +ALICE_PASSWORD="${ALICE_TEST_ACCOUNT_PASSWORD:-alice}" create() { local handle="$1" + local password="$PASSWORD" + [[ "$handle" == "alice.test" ]] && password="$ALICE_PASSWORD" echo "creating $handle..." docker exec crate-devnet-pds-1 goat pds admin account create \ - --handle "$handle" --password "$PASSWORD" --email "${handle%.test}@example.com" \ + --handle "$handle" --password "$password" --email "${handle%.test}@example.com" \ || echo " (already exists, or creation failed — check above)" } @@ -20,3 +23,18 @@ create bob.test create carol.test create dave.test create erin.test +create faye.test +create gideon.test +create hana.test +create ivan.test +create june.test +create kai.test +create lina.test +create malik.test +create nora.test +create otis.test +create priya.test +create quinn.test +create rosa.test +create sam.test +create theo.test diff --git a/e2e/devnet/docker-compose.yml b/e2e/devnet/docker-compose.yml index a74347e..27ac020 100644 --- a/e2e/devnet/docker-compose.yml +++ b/e2e/devnet/docker-compose.yml @@ -115,6 +115,21 @@ services: - carol.test - dave.test - erin.test + - faye.test + - gideon.test + - hana.test + - ivan.test + - june.test + - kai.test + - lina.test + - malik.test + - nora.test + - otis.test + - priya.test + - quinn.test + - rosa.test + - sam.test + - theo.test # Caddy's `tls internal` CA is generated into its own data volume; export # the root cert so slingshot (below) can be told to trust it. diff --git a/e2e/devnet/seed-social.sh b/e2e/devnet/seed-social.sh index 0bf8548..f168740 100755 --- a/e2e/devnet/seed-social.sh +++ b/e2e/devnet/seed-social.sh @@ -21,6 +21,7 @@ fi PDS="${PDS_URL:-http://localhost:2584}" PASSWORD="${TEST_ACCOUNT_PASSWORD:-e2e-test-password}" +ALICE_PASSWORD="${ALICE_TEST_ACCOUNT_PASSWORD:-alice}" # Every string value below is JSON-encoded through this instead of hand-quoted, # so a title/artist/note containing a quote, backslash, or newline can never @@ -46,9 +47,12 @@ T2="$(ts_offset $((NOW_EPOCH + 7200)))" T_PAST="$(ts_offset $((NOW_EPOCH - 90000)))" session() { + local handle="$1" + local password="$PASSWORD" + [[ "$handle" == "alice.test" ]] && password="$ALICE_PASSWORD" curl -sf "$PDS/xrpc/com.atproto.server.createSession" \ -H 'content-type: application/json' \ - -d "{\"identifier\":$(json_str "$1"),\"password\":$(json_str "$PASSWORD")}" + -d "{\"identifier\":$(json_str "$handle"),\"password\":$(json_str "$password")}" } did_of() { echo "$1" | grep -o '"did":"[^"]*"' | head -1 | cut -d'"' -f4; } @@ -245,8 +249,19 @@ upload_fixture_cover() { echo "warning: fixture cover upload failed for $handle" >&2 } +declare -a HANDLES=( + alice.test bob.test carol.test dave.test erin.test + faye.test gideon.test hana.test ivan.test june.test + kai.test lina.test malik.test nora.test otis.test + priya.test quinn.test rosa.test sam.test theo.test +) +declare -a NEW_HANDLES=( + faye.test gideon.test hana.test ivan.test june.test + kai.test lina.test malik.test nora.test otis.test + priya.test quinn.test rosa.test sam.test theo.test +) declare -A DID JWT COVER RELEASE -for handle in alice.test bob.test carol.test dave.test erin.test; do +for handle in "${HANDLES[@]}"; do s="$(session "$handle")" DID[$handle]="$(did_of "$s")" JWT[$handle]="$(jwt_of "$s")" @@ -265,6 +280,18 @@ follow "${JWT[dave.test]}" "${DID[dave.test]}" "${DID[alice.test]}" follow "${JWT[dave.test]}" "${DID[dave.test]}" "${DID[bob.test]}" follow "${JWT[dave.test]}" "${DID[dave.test]}" "${DID[carol.test]}" follow "${JWT[dave.test]}" "${DID[dave.test]}" "${DID[erin.test]}" + +# The larger demo population forms a ring, follows alice as a common social +# anchor, and follows one collector from the original genre neighborhoods. +ORIGINAL_NEIGHBORS=(bob.test carol.test dave.test erin.test) +for i in "${!NEW_HANDLES[@]}"; do + handle="${NEW_HANDLES[$i]}" + next="${NEW_HANDLES[$(((i + 1) % ${#NEW_HANDLES[@]}))]}" + neighbor="${ORIGINAL_NEIGHBORS[$((i % ${#ORIGINAL_NEIGHBORS[@]}))]}" + follow "${JWT[$handle]}" "${DID[$handle]}" "${DID[alice.test]}" + follow "${JWT[$handle]}" "${DID[$handle]}" "${DID[$next]}" + follow "${JWT[$handle]}" "${DID[$handle]}" "${DID[$neighbor]}" +done echo "follow graph seeded" FIXTURE_COVERS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/fixtures/covers" @@ -273,6 +300,13 @@ COVER[bob.test]="$(upload_fixture_cover bob.test "${JWT[bob.test]}" "$FIXTURE_CO COVER[carol.test]="$(upload_fixture_cover carol.test "${JWT[carol.test]}" "$FIXTURE_COVERS/carol.png")" COVER[dave.test]="$(upload_fixture_cover dave.test "${JWT[dave.test]}" "$FIXTURE_COVERS/dave.png")" COVER[erin.test]="$(upload_fixture_cover erin.test "${JWT[erin.test]}" "$FIXTURE_COVERS/erin.png")" +for i in "${!NEW_HANDLES[@]}"; do + handle="${NEW_HANDLES[$i]}" + COVER[$handle]="$(make_cover_blob "$handle" "${JWT[$handle]}" \ + "$(((53 * i + 70) % 190 + 40))" \ + "$(((97 * i + 30) % 190 + 40))" \ + "$(((151 * i + 10) % 190 + 40))")" +done echo "cover art seeded" # Small shared catalog: alice mints most of it, bob mints a couple, matching @@ -390,4 +424,36 @@ wanted_entry "${JWT[erin.test]}" "${DID[erin.test]}" "William Basinski" "The Dis wanted_entry "${JWT[erin.test]}" "${DID[erin.test]}" "Stars of the Lid" "The Tired Sounds of Stars of the Lid" ambient "${RELEASE[R14]}" wanted_entry "${JWT[erin.test]}" "${DID[erin.test]}" "Tim Hecker" "Ravedeath, 1972" ambient "${RELEASE[R15]}" +# Fifteen additional collectors make Connections, overlap, and grouped feed +# views dense enough to explore. Each owns one unique release, adopts one +# shared release, and wants another shared release. +EXTRA_ARTISTS=( + "Arooj Aftab" "Nala Sinephro" "Yusef Lateef" "Cocteau Twins" "Basic Channel" + "Nina Simone" "Fela Kuti" "Beverly Glenn-Copeland" "Talk Talk" "DJ Rashad" + "Milton Nascimento" "The Raincoats" "Ryuichi Sakamoto" "Low" "Terry Riley" +) +EXTRA_TITLES=( + "Vulture Prince" "Space 1.8" "Eastern Sounds" "Heaven or Las Vegas" "BCD" + "Pastel Blues" "Expensive Shit" "Keyboard Fantasies" "Spirit of Eden" "Double Cup" + "Clube da Esquina" "The Raincoats" "Async" "Things We Lost in the Fire" "A Rainbow in Curved Air" +) +EXTRA_GENRES=(jazz jazz jazz dream-pop techno soul afrobeat ambient art-rock footwork mpb post-punk ambient slowcore minimalism) +SHARED_OWNED=(R1 R3 R5 R6 R8 R2 R4 R6 R5 R4 R1 R3 R6 R8 R2) +SHARED_WANTED=(R6 R8 R2 R5 R3 R1 R6 R4 R8 R5 R3 R1 R5 R2 R4) + +for i in "${!NEW_HANDLES[@]}"; do + handle="${NEW_HANDLES[$i]}" + key="R$((16 + i))" + RELEASE[$key]="$(mint_release "${JWT[$handle]}" "${DID[$handle]}" \ + "${EXTRA_ARTISTS[$i]}" "${EXTRA_TITLES[$i]}" "$((1968 + i * 3))" "${EXTRA_GENRES[$i]}")" + owned_entry "${JWT[$handle]}" "${DID[$handle]}" \ + "${EXTRA_ARTISTS[$i]}" "${EXTRA_TITLES[$i]}" NM VG+ 4 "${EXTRA_GENRES[$i]}" \ + "A fixture favorite from the local demo shelf." "${COVER[$handle]}" "${RELEASE[$key]}" + owned_entry "${JWT[$handle]}" "${DID[$handle]}" \ + "Shared discovery" "Friends keep recommending this pressing" VG+ VG 4 social \ + "Added through the collector graph." "${COVER[$handle]}" "${RELEASE[${SHARED_OWNED[$i]}]}" + wanted_entry "${JWT[$handle]}" "${DID[$handle]}" \ + "Shared want" "On several nearby wantlists" social "${RELEASE[${SHARED_WANTED[$i]}]}" +done + echo "crate entries seeded" diff --git a/e2e/tests/adoption.spec.ts b/e2e/tests/adoption.spec.ts index 6f48a25..1385205 100644 --- a/e2e/tests/adoption.spec.ts +++ b/e2e/tests/adoption.spec.ts @@ -3,6 +3,7 @@ import { loginAs } from "../fixtures/login.js"; import { xrpcPath } from "../fixtures/xrpc.js"; const PASSWORD = process.env.TEST_ACCOUNT_PASSWORD || "e2e-test-password"; +const ALICE_PASSWORD = process.env.ALICE_TEST_ACCOUNT_PASSWORD || "alice"; async function addFirstSearchResult(page: Page, query: string): Promise { await page.goto("/add"); @@ -30,7 +31,7 @@ test("bob adopts alice's already-published release instead of minting a duplicat }) => { const alice = await browser.newContext(); const alicePage = await alice.newPage(); - await loginAs(alicePage, "alice.test", PASSWORD); + await loginAs(alicePage, "alice.test", ALICE_PASSWORD); await addFirstSearchResult(alicePage, "aphex twin selected ambient works"); diff --git a/e2e/tests/edit-inbox.spec.ts b/e2e/tests/edit-inbox.spec.ts index da84808..35780dd 100644 --- a/e2e/tests/edit-inbox.spec.ts +++ b/e2e/tests/edit-inbox.spec.ts @@ -3,6 +3,7 @@ import { loginAs } from "../fixtures/login.js"; import { xrpcPath } from "../fixtures/xrpc.js"; const PASSWORD = process.env.TEST_ACCOUNT_PASSWORD || "e2e-test-password"; +const ALICE_PASSWORD = process.env.ALICE_TEST_ACCOUNT_PASSWORD || "alice"; async function addFirstSearchResult(page: Page, query: string): Promise { await page.goto("/add"); @@ -38,7 +39,7 @@ test("alice proposes a correction on bob's record; bob reviews and applies it", const alice = await browser.newContext(); const alicePage = await alice.newPage(); - await loginAs(alicePage, "alice.test", PASSWORD); + await loginAs(alicePage, "alice.test", ALICE_PASSWORD); await addFirstSearchResult(alicePage, "boards of canada music has the right to children"); // Alice's copy adopted bob's canonical release, so amending it is a diff --git a/e2e/tests/oauth-error.spec.ts b/e2e/tests/oauth-error.spec.ts index c315e9c..d073eee 100644 --- a/e2e/tests/oauth-error.spec.ts +++ b/e2e/tests/oauth-error.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; -const PASSWORD = process.env.TEST_ACCOUNT_PASSWORD || "e2e-test-password"; +const ALICE_PASSWORD = process.env.ALICE_TEST_ACCOUNT_PASSWORD || "alice"; // The login error panel is driven by a stable ?error= code the server // attaches on failed OAuth redirects. The app clears the query string on @@ -40,7 +40,7 @@ test("denying authorization at the PDS lands on the error panel", async ({ await page.click("text=LOG IN WITH ATPROTO"); await page.waitForURL(/oauth\/authorize/, { timeout: 15_000 }); - await page.fill('input[type="password"]', PASSWORD); + await page.fill('input[type="password"]', ALICE_PASSWORD); await page.click('button:has-text("Sign in")'); const deny = page.locator('button:has-text("Deny")'); -- 2.51.2