# FitPub Federation Testing Guide This guide explains how to test the instance-to-instance federation functionality by running two FitPub instances locally. ## Docker Compose Setup (Recommended) The easiest way to test federation is using Docker Compose, which automatically sets up two complete FitPub instances with separate databases and proper networking. ### Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ Docker Network (fitpub-federation) │ │ │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ Instance 1 │ │ Instance 2 │ │ │ │ (instance1.local) │◄─────►│ (instance2.local) │ │ │ │ Port: 8080 │ │ Port: 8081 │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ PostgreSQL 1 │ │ PostgreSQL 2 │ │ │ │ (postgres1) │ │ (postgres2) │ │ │ │ Port: 5432 │ │ Port: 5433 │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ ▲ ▲ │ │ localhost:8080 localhost:8081 ``` ### Quick Start 1. **Start both instances**: ```bash docker-compose -f docker-compose.federation-test.yml up -d ``` 2. **Check status**: ```bash docker-compose -f docker-compose.federation-test.yml ps ``` 3. **Access the instances**: - Instance 1: http://localhost:8080 - Instance 2: http://localhost:8081 4. **Follow the [Test Scenarios](#test-scenarios) below** to verify federation functionality 5. **View logs** (in separate terminals): ```bash # Instance 1 logs docker-compose -f docker-compose.federation-test.yml logs -f fitpub1 # Instance 2 logs docker-compose -f docker-compose.federation-test.yml logs -f fitpub2 ``` 6. **Stop and clean up**: ```bash # Stop containers docker-compose -f docker-compose.federation-test.yml down # Stop and remove volumes (complete cleanup) docker-compose -f docker-compose.federation-test.yml down -v ``` ### Service Overview The Docker Compose setup includes: - **postgres1**: PostgreSQL 16 with PostGIS 3.4 for Instance 1 - Database: `fitpub1` - Port: 5432 (internal), 5434 (on host) - **postgres2**: PostgreSQL 16 with PostGIS 3.4 for Instance 2 - Database: `fitpub2` - Port: 5432 (internal), 5433 (on host) - **fitpub1**: FitPub Instance 1 - Domain: `instance1.local:8080` - Port: 8080 - Network alias: `instance1.local` - **fitpub2**: FitPub Instance 2 - Domain: `instance2.local:8081` - Port: 8081 - Network alias: `instance2.local` ### Docker-Specific Commands **Access database directly**: ```bash # Instance 1 database docker exec -it fitpub-postgres1 psql -U fitpub -d fitpub1 # Instance 2 database docker exec -it fitpub-postgres2 psql -U fitpub -d fitpub2 ``` **Inspect network**: ```bash docker network inspect fitpub-federation ``` **View container details**: ```bash docker inspect fitpub-instance1 docker inspect fitpub-instance2 ``` **Restart a single service**: ```bash docker-compose -f docker-compose.federation-test.yml restart fitpub1 docker-compose -f docker-compose.federation-test.yml restart fitpub2 ``` **Rebuild images** (after code changes): ```bash docker-compose -f docker-compose.federation-test.yml build docker-compose -f docker-compose.federation-test.yml up -d ``` ### Docker Troubleshooting **Container won't start**: ```bash # Check logs for errors docker-compose -f docker-compose.federation-test.yml logs fitpub1 docker-compose -f docker-compose.federation-test.yml logs fitpub2 # Check health status docker ps -a | grep fitpub ``` **Database connection issues**: ```bash # Verify database is healthy docker-compose -f docker-compose.federation-test.yml ps postgres1 docker-compose -f docker-compose.federation-test.yml ps postgres2 # Check database logs docker-compose -f docker-compose.federation-test.yml logs postgres1 ``` **Network connectivity issues**: ```bash # Test DNS resolution from inside container docker exec -it fitpub-instance1 ping instance2.local docker exec -it fitpub-instance2 ping instance1.local # Test HTTP connectivity docker exec -it fitpub-instance1 curl http://instance2.local:8081/.well-known/webfinger ``` **Port already in use**: ```bash # Find process using port 8080 lsof -ti:8080 | xargs kill -9 # Or use different external ports in docker-compose.yml ``` **Volume permission issues**: ```bash # Remove all volumes and start fresh docker-compose -f docker-compose.federation-test.yml down -v docker-compose -f docker-compose.federation-test.yml up -d ``` **Platform warning on Apple Silicon (M1/M2/M3 Macs)**: ``` The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) ``` This is expected and safe to ignore. Docker will use emulation (Rosetta 2) to run the amd64 images. Performance may be slightly slower than native ARM images, but fully functional for testing. --- ## Manual Setup (Alternative) If you prefer to run the instances directly without Docker, follow these instructions: ### Prerequisites - Java 17+ - Maven 3.8+ - PostgreSQL 13+ with PostGIS extension - Two separate PostgreSQL databases - Two different port numbers for the applications ## Setup ### Step 1: Create Two PostgreSQL Databases ```bash # Connect to PostgreSQL psql -U postgres # Create databases CREATE DATABASE fitpub_instance1; CREATE DATABASE fitpub_instance2; # Enable PostGIS extension for both databases \c fitpub_instance1 CREATE EXTENSION IF NOT EXISTS postgis; \c fitpub_instance2 CREATE EXTENSION IF NOT EXISTS postgis; \q ``` ### Step 2: Prepare Application Profiles Create two separate application configuration files: #### `application-instance1.yml` ```yaml server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/fitpub_instance1 username: postgres password: your_password jpa: hibernate: ddl-auto: validate fitpub: base-url: http://localhost:8080 domain: localhost:8080 logging: level: org.operaton.fitpub: DEBUG ``` #### `application-instance2.yml` ```yaml server: port: 8081 spring: datasource: url: jdbc:postgresql://localhost:5432/fitpub_instance2 username: postgres password: your_password jpa: hibernate: ddl-auto: validate fitpub: base-url: http://localhost:8081 domain: localhost:8081 logging: level: org.operaton.fitpub: DEBUG ``` ### Step 3: Build the Application ```bash mvn clean package -DskipTests ``` ## Running the Instances ### Terminal 1: Start Instance 1 ```bash java -jar target/feditrack-1.0-SNAPSHOT.jar --spring.profiles.active=instance1 ``` Wait for the application to start completely. You should see: ``` Started FitPubApplication in X.XXX seconds ``` ### Terminal 2: Start Instance 2 ```bash java -jar target/feditrack-1.0-SNAPSHOT.jar --spring.profiles.active=instance2 ``` ## Test Scenarios ### Test 1: User Registration **Instance 1 (http://localhost:8080)** 1. Navigate to http://localhost:8080/register 2. Register user: `alice` / `alice@localhost1.test` / `password123` 3. Login **Instance 2 (http://localhost:8081)** 1. Navigate to http://localhost:8081/register 2. Register user: `bob` / `bob@localhost2.test` / `password123` 3. Login ### Test 2: WebFinger Discovery **From Instance 1, discover Bob on Instance 2:** ```bash curl http://localhost:8080/.well-known/webfinger?resource=acct:bob@localhost:8081 ``` Expected response: ```json { "subject": "acct:bob@localhost:8081", "aliases": [ "http://localhost:8081/users/bob" ], "links": [ { "rel": "self", "type": "application/activity+json", "href": "http://localhost:8081/users/bob" } ] } ``` **From Instance 2, discover Alice on Instance 1:** ```bash curl http://localhost:8081/.well-known/webfinger?resource=acct:alice@localhost:8080 ``` ### Test 3: Remote User Discovery via UI **On Instance 1 (Alice following Bob):** 1. Login as Alice 2. Navigate to http://localhost:8080/discover 3. In the "Follow Remote Users" section, enter: `bob@localhost:8081` 4. Click "Search" 5. Verify Bob's profile appears with avatar, display name, and bio 6. Click "Follow" button 7. Verify notification appears: "Follow request sent to bob@localhost:8081" **Verify on Instance 2 (Bob's perspective):** 1. Login as Bob on http://localhost:8081 2. Check notifications - you should see: "alice@localhost:8080 followed you" 3. Navigate to http://localhost:8081/users/bob/followers 4. Verify alice@localhost:8080 appears in followers list ### Test 4: Following Relationship Check **Check via API:** ```bash # From Instance 2, check Bob's followers curl http://localhost:8081/api/users/bob/followers | jq # Expected: Alice should be in the list ``` **Check via UI:** On Instance 2: 1. Navigate to http://localhost:8081/users/bob 2. Check "Followers" count - should be 1 3. Click on "Followers" - Alice should be listed On Instance 1: 1. Navigate to http://localhost:8080/users/alice 2. Check "Following" count - should be 1 3. Click on "Following" - Bob should be listed ### Test 5: Activity Federation **Bob uploads a workout on Instance 2:** 1. Login as Bob on http://localhost:8081 2. Navigate to http://localhost:8081/upload 3. Upload a FIT file (use test file from `src/test/resources/`) 4. Set title: "Morning 10K Run" 5. Set visibility: "Public" 6. Click "Upload" **Verify on Instance 1 (Alice's federated timeline):** 1. Login as Alice on http://localhost:8080 2. Navigate to http://localhost:8080/timeline/federated 3. Verify Bob's "Morning 10K Run" activity appears with: - Federation badge: "🌐 Remote" - Bob's avatar and @bob@localhost:8081 - Map preview (if map image URL is available) - Metrics (distance, duration, pace, elevation) - Link to view on origin server ### Test 6: Remote Activity Details **Click on Remote Activity:** From Alice's federated timeline: 1. Click on Bob's "Morning 10K Run" activity title 2. Verify it opens Bob's activity on Instance 2 (http://localhost:8081/activities/{id}) in a new tab 3. Alternatively, click "View on Origin Server" button ### Test 7: Incoming Activity via ActivityPub **Test with manual ActivityPub POST:** ```bash # Create a test activity cat > test-activity.json <