name: Test Stalwart Installation Action on: push: branches: [main, develop] pull_request: branches: [main] workflow_dispatch: jobs: # Test basic installation without configuration test-basic-install: name: Basic Installation (No Config) runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y jq curl - name: Run basic installation uses: ./ # No inputs - should install with defaults - name: Wait for service to fully start run: | echo "Waiting for Stalwart to fully initialize..." sleep 15 - name: Verify Stalwart service is running run: | sleep 10 # Give service time to start # Check if systemd is available if command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then echo "Checking service status with systemd..." sudo systemctl status stalwart --no-pager || true if sudo systemctl is-active --quiet stalwart; then echo "✓ Stalwart service is running (systemd)" else echo "::warning::Stalwart service not active in systemd, checking process..." fi else echo "::warning::systemd not available, checking process directly..." fi # Check if process is running if pgrep -x stalwart >/dev/null; then echo "✓ Stalwart process is running" else echo "::error::Stalwart process is not running" ps aux | grep stalwart || true exit 1 fi - name: Check Stalwart binary run: | if [ ! -f /opt/stalwart/bin/stalwart ]; then echo "::error::Stalwart binary not found" exit 1 fi /opt/stalwart/bin/stalwart --version - name: Test web admin accessibility run: | # Wait for API to be ready for i in {1..30}; do if curl -sf http://localhost:8080/login >/dev/null 2>&1; then echo "✓ Web admin is accessible" exit 0 fi sleep 2 done echo "::error::Web admin not accessible after 60 seconds" exit 1 # Test installation with admin password test-with-password: name: Installation with Admin Password runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y jq curl - name: Install with admin password uses: ./ with: admin_password: 'TestPassword123!@#' - name: Wait for service to fully start run: | echo "Waiting for Stalwart to fully initialize..." sleep 15 - name: Verify service is running run: | # Check process if ! pgrep -x stalwart >/dev/null; then echo "::error::Stalwart process is not running" echo "Process list:" ps aux | grep stalwart || true echo "PID file:" cat /var/run/stalwart.pid 2>/dev/null || echo "No PID file" echo "Logs:" tail -50 /opt/stalwart/logs/*.log 2>/dev/null || echo "No logs" exit 1 fi echo "✓ Stalwart is running" - name: Test authentication with new password run: | # Wait for API to be ready echo "Waiting for Stalwart API..." for i in {1..30}; do if curl -sf http://localhost:8080/login >/dev/null 2>&1; then echo "✓ API is ready" break fi sleep 2 done # Test authentication with Basic Auth (the actual method Stalwart uses) HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -u "admin:TestPassword123!@#" \ http://localhost:8080/api/principal?types=domain&limit=1) if [ "$HTTP_CODE" != "200" ]; then echo "::error::Authentication failed with HTTP $HTTP_CODE" exit 1 fi echo "✓ Successfully authenticated with new password" # Test full configuration with domains and users test-full-config: name: Full Configuration (Domains + Users) runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y jq curl - name: Install with full configuration uses: ./ with: admin_password: 'AdminPass123!@#' domains: | [ { "name": "test1.local", "description": "Primary test domain" }, { "name": "test2.local", "description": "Secondary test domain" } ] users: | [ { "email": "user1@test1.local", "password": "UserPass123!", "name": "Test User One", "quota": 1073741824 }, { "email": "user2@test1.local", "password": "UserPass456!", "name": "Test User Two", "quota": 2147483648 }, { "email": "admin@test2.local", "password": "AdminUser789!", "name": "Admin User", "quota": 5368709120 } ] - name: Wait for service to fully start run: | echo "Waiting for Stalwart to fully initialize..." sleep 15 - name: Verify service is running run: | # Check process if ! pgrep -x stalwart >/dev/null; then echo "::error::Stalwart process is not running" echo "Process list:" ps aux | grep stalwart || true echo "PID file:" cat /var/run/stalwart.pid 2>/dev/null || echo "No PID file" echo "Logs:" tail -50 /opt/stalwart/logs/*.log 2>/dev/null || true exit 1 fi echo "✓ Stalwart is running" - name: Verify admin password was changed run: | # Wait for API to be ready echo "Waiting for Stalwart API..." for i in {1..30}; do if curl -sf http://localhost:8080/login >/dev/null 2>&1; then echo "✓ API is ready" break fi sleep 2 done # Test authentication with Basic Auth HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -u "admin:AdminPass123!@#" \ http://localhost:8080/api/principal?types=domain&limit=1) if [ "$HTTP_CODE" != "200" ]; then echo "::error::Authentication failed with HTTP $HTTP_CODE" exit 1 fi echo "✓ Admin authentication successful" - name: Verify domains were created run: | # List domains via API (using discovered endpoint structure) DOMAINS=$(curl -sf \ -u "admin:AdminPass123!@#" \ "http://localhost:8080/api/principal?types=domain&limit=100") echo "Domains response: $DOMAINS" # Check if our test domains exist in data.items array if echo "$DOMAINS" | jq -e '.data.items[] | select(.name == "test1.local")' >/dev/null; then echo "✓ Domain test1.local found" else echo "::warning::Domain test1.local not found" echo "$DOMAINS" | jq '.data.items[].name' || true fi - name: Verify users were created run: | # List accounts via API (using discovered endpoint structure) ACCOUNTS=$(curl -sf \ -u "admin:AdminPass123!@#" \ "http://localhost:8080/api/principal?types=individual&limit=100") echo "Accounts response: $ACCOUNTS" # Check if users exist in data.items array if echo "$ACCOUNTS" | jq -e '.data.items[] | select(.emails[] == "user1@test1.local")' >/dev/null; then echo "✓ User user1@test1.local found" else echo "::warning::User user1@test1.local not found" echo "$ACCOUNTS" | jq '.data.items[].emails[]' || true fi - name: Show logs on failure if: failure() run: | echo "=== Stalwart Service Status ===" if command -v systemctl >/dev/null 2>&1; then sudo systemctl status stalwart --no-pager || true fi echo -e "\n=== Process Status ===" ps aux | grep stalwart || true echo -e "\n=== Stalwart Logs ===" if command -v journalctl >/dev/null 2>&1; then sudo journalctl -u stalwart -n 100 --no-pager || true else sudo tail -n 100 /opt/stalwart/logs/*.log 2>/dev/null || true fi echo -e "\n=== Configuration File ===" sudo cat /opt/stalwart/etc/config.toml || true echo -e "\n=== Network Ports ===" sudo netstat -tuln | grep -E ':(25|587|465|993|8080)' || true sudo ss -tuln | grep -E ':(25|587|465|993|8080)' || true # Test error handling test-error-handling: name: Error Handling Tests runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Test invalid JSON (domains) id: test_invalid_domains continue-on-error: true uses: ./ with: admin_password: 'TestPass123' domains: 'invalid json string' - name: Verify invalid JSON was caught run: | if [ "${{ steps.test_invalid_domains.outcome }}" = "success" ]; then echo "::error::Action should have failed with invalid JSON" exit 1 fi echo "✓ Invalid domains JSON was properly rejected" - name: Clean up after failed test if: always() run: | # Stop service if command -v systemctl >/dev/null 2>&1; then sudo systemctl stop stalwart || true sudo systemctl disable stalwart || true fi # Kill process if still running sudo pkill -9 stalwart || true # Remove installation sudo rm -rf /opt/stalwart || true # Test on different Ubuntu versions test-ubuntu-versions: name: Test on Ubuntu ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-20.04, ubuntu-22.04, ubuntu-24.04] fail-fast: false steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y jq curl - name: Install Stalwart uses: ./ with: admin_password: 'TestPassword123' - name: Wait for service to fully start run: | echo "Waiting for Stalwart to fully initialize..." sleep 15 - name: Verify installation run: | # Check if process is running if pgrep -x stalwart >/dev/null; then echo "✓ Stalwart running on ${{ matrix.os }}" else echo "::error::Stalwart not running on ${{ matrix.os }}" ps aux | grep stalwart || true tail -50 /opt/stalwart/logs/*.log 2>/dev/null || true exit 1 fi - name: Test API accessibility run: | # Wait for API to be ready echo "Waiting for API on ${{ matrix.os }}..." for i in {1..30}; do if curl -sf http://localhost:8080/login >/dev/null 2>&1; then echo "✓ API accessible on ${{ matrix.os }}" exit 0 fi sleep 2 done echo "::error::API not accessible on ${{ matrix.os }}" tail -50 /opt/stalwart/logs/*.log 2>/dev/null || true exit 1 # Summary job test-summary: name: Test Summary runs-on: ubuntu-latest needs: [test-basic-install, test-with-password, test-full-config, test-ubuntu-versions] if: always() steps: - name: Check test results run: | echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- Basic Install: ${{ needs.test-basic-install.result }}" >> $GITHUB_STEP_SUMMARY echo "- With Password: ${{ needs.test-with-password.result }}" >> $GITHUB_STEP_SUMMARY echo "- Full Config: ${{ needs.test-full-config.result }}" >> $GITHUB_STEP_SUMMARY echo "- Ubuntu Versions: ${{ needs.test-ubuntu-versions.result }}" >> $GITHUB_STEP_SUMMARY # Fail if any required test failed if [ "${{ needs.test-basic-install.result }}" != "success" ] || \ [ "${{ needs.test-with-password.result }}" != "success" ] || \ [ "${{ needs.test-full-config.result }}" != "success" ]; then echo "::error::One or more tests failed" exit 1 fi echo "✓ All tests passed!"