A minimal AT Protocol Personal Data Server written in JavaScript.
atproto
pds
1// test/helpers/docker-services.js
2import { execSync } from 'node:child_process';
3
4const RELAY_URL = 'http://localhost:2470';
5const PLC_URL = 'http://localhost:2582';
6const MINIO_URL = 'http://localhost:9000';
7const USE_S3 = process.env.BLOB_STORAGE === 's3';
8
9/**
10 * Wait for a service to respond
11 * @param {string} url
12 * @param {string} name
13 * @param {number} maxAttempts
14 */
15async function waitForService(url, name, maxAttempts = 30) {
16 for (let i = 0; i < maxAttempts; i++) {
17 try {
18 const res = await fetch(url);
19 if (res.ok) {
20 console.log(`${name} is ready`);
21 return;
22 }
23 } catch {
24 // Service not ready yet
25 }
26 await new Promise((r) => setTimeout(r, 1000));
27 }
28 throw new Error(`${name} failed to start after ${maxAttempts} attempts`);
29}
30
31/**
32 * Ensure docker-compose services are running
33 * Always resets volumes for clean state each test run
34 */
35export async function ensureDockerServices() {
36 console.log('Resetting docker services for clean state...');
37
38 // Always reset volumes to avoid stale relay subscriptions
39 execSync('docker compose down -v', { stdio: 'inherit' });
40 execSync('docker compose up -d', { stdio: 'inherit' });
41
42 // Wait for services to be ready
43 await waitForService(PLC_URL, 'PLC');
44 await waitForService(RELAY_URL, 'Relay');
45 if (USE_S3) {
46 await waitForService(`${MINIO_URL}/minio/health/ready`, 'MinIO');
47 }
48
49 // Configure relay to accept new PDS subscriptions
50 // Fresh relay database defaults perDayLimit to 0, blocking all subscriptions
51 await configureRelayLimits();
52
53 console.log('Docker services are ready');
54}
55
56/**
57 * Configure relay rate limits for local testing
58 * Sets perDayLimit to allow new PDS subscriptions
59 */
60async function configureRelayLimits() {
61 const res = await fetch(`${RELAY_URL}/admin/subs/setPerDayLimit?limit=1000`, {
62 method: 'POST',
63 headers: {
64 Authorization: 'Bearer localdev',
65 },
66 });
67 if (!res.ok) {
68 throw new Error(`Failed to configure relay limits: ${res.status}`);
69 }
70 console.log('Relay configured for local testing');
71}
72
73/**
74 * Request the relay to crawl a PDS
75 * @param {string} hostname - PDS hostname (e.g., 'host.docker.internal:3000')
76 */
77export async function requestRelayCrawl(hostname) {
78 const res = await fetch(`${RELAY_URL}/admin/pds/requestCrawl`, {
79 method: 'POST',
80 headers: {
81 Authorization: 'Bearer localdev',
82 'Content-Type': 'application/json',
83 },
84 body: JSON.stringify({ hostname }),
85 });
86 if (!res.ok) {
87 throw new Error(`Failed to request crawl: ${res.status}`);
88 }
89}
90
91export { RELAY_URL, PLC_URL, MINIO_URL, USE_S3 };