feat(tests): test suite almost done

This commit is contained in:
perf3ct 2025-06-17 14:48:47 +00:00
parent babe5a6e46
commit 9d7348423a
3 changed files with 451 additions and 0 deletions

116
Makefile Normal file
View File

@ -0,0 +1,116 @@
.PHONY: help test test-unit test-integration test-frontend test-e2e test-all test-watch test-clean test-logs test-shell dev-up dev-down dev-logs build clean
# Default target
help:
@echo "Readur Development and Testing Commands"
@echo "======================================"
@echo ""
@echo "Testing Commands:"
@echo " make test - Run all tests in isolated environment"
@echo " make test-unit - Run unit tests only"
@echo " make test-integration - Run integration tests only"
@echo " make test-frontend - Run frontend tests only"
@echo " make test-e2e - Run E2E tests (when implemented)"
@echo " make test-watch - Run tests and keep containers running"
@echo " make test-clean - Clean up test environment"
@echo " make test-logs - View test container logs"
@echo " make test-shell - Open shell in test container"
@echo ""
@echo "Development Commands:"
@echo " make dev-up - Start development environment"
@echo " make dev-down - Stop development environment"
@echo " make dev-logs - View development logs"
@echo " make build - Build all Docker images"
@echo " make clean - Clean all Docker resources"
# Testing targets
test: test-all
test-all:
@./run-tests.sh all
test-unit:
@./run-tests.sh unit
test-integration:
@./run-tests.sh integration
test-frontend:
@./run-tests.sh frontend
test-e2e:
@./run-tests.sh e2e
test-watch:
@./run-tests.sh all keep-running
test-clean:
@echo "Cleaning test environment..."
@docker-compose -f docker-compose.test.yml -p readur_test down -v --remove-orphans 2>/dev/null || true
@docker rm -f readur_postgres_test readur_app_test readur_frontend_test 2>/dev/null || true
@docker network rm readur_test_network 2>/dev/null || true
@rm -rf /tmp/test_uploads /tmp/test_watch 2>/dev/null || true
test-logs:
@docker-compose -f docker-compose.test.yml -p readur_test logs -f
test-shell:
@docker-compose -f docker-compose.test.yml -p readur_test exec readur_test /bin/bash
# Development targets
dev-up:
@echo "Starting development environment..."
@docker-compose up -d
dev-down:
@echo "Stopping development environment..."
@docker-compose down
dev-logs:
@docker-compose logs -f
# Build targets
build:
@echo "Building all images..."
@docker-compose build
@docker-compose -f docker-compose.test.yml build
# Clean targets
clean:
@echo "Cleaning all Docker resources..."
@docker-compose down -v --remove-orphans
@docker-compose -f docker-compose.test.yml -p readur_test down -v --remove-orphans
@docker system prune -f
# Specific test scenarios
test-ocr:
@echo "Running OCR-specific tests..."
@docker-compose -f docker-compose.test.yml -p readur_test exec -T readur_test \
cargo test ocr --no-fail-fast
test-webdav:
@echo "Running WebDAV-specific tests..."
@docker-compose -f docker-compose.test.yml -p readur_test exec -T readur_test \
cargo test webdav --no-fail-fast
test-performance:
@echo "Running performance tests..."
@docker-compose -f docker-compose.test.yml -p readur_test exec -T readur_test \
cargo test performance --no-fail-fast
# Database operations
test-db-reset:
@echo "Resetting test database..."
@docker-compose -f docker-compose.test.yml -p readur_test exec -T postgres_test \
psql -U readur_test -d postgres -c "DROP DATABASE IF EXISTS readur_test; CREATE DATABASE readur_test;"
@docker-compose -f docker-compose.test.yml -p readur_test exec -T readur_test \
sqlx migrate run
# CI/CD helpers
ci-test:
@./run-tests.sh all
# Quick test for local development (runs faster subset)
quick-test:
@echo "Running quick test suite..."
@./run-tests.sh unit

112
docker-compose.test.yml Normal file
View File

@ -0,0 +1,112 @@
services:
postgres_test:
image: postgres:16-alpine
container_name: readur_postgres_test
environment:
POSTGRES_USER: readur_test
POSTGRES_PASSWORD: readur_test
POSTGRES_DB: readur_test
volumes:
# Using tmpfs for ephemeral test data
- type: tmpfs
target: /var/lib/postgresql/data
ports:
- "5433:5432" # Different port to avoid conflict
healthcheck:
test: ["CMD-SHELL", "pg_isready -U readur_test"]
interval: 5s
timeout: 3s
retries: 5
networks:
- readur_test_network
readur_test:
build:
context: .
dockerfile: Dockerfile
container_name: readur_app_test
environment:
# Database configuration
DATABASE_URL: postgresql://readur_test:readur_test@postgres_test/readur_test
# Server configuration
SERVER_HOST: 0.0.0.0
SERVER_PORT: 8001 # Different port from dev
# Security
JWT_SECRET: test-jwt-secret-key
# File paths (using temporary directories)
UPLOAD_PATH: /tmp/test_uploads
WATCH_FOLDER: /tmp/test_watch
# OCR configuration
OCR_LANGUAGE: eng
CONCURRENT_OCR_JOBS: 2 # Lower for tests
OCR_TIMEOUT_SECONDS: 60 # Shorter timeout for tests
MAX_FILE_SIZE_MB: 10 # Smaller for tests
# Performance (reduced for testing)
MEMORY_LIMIT_MB: 256
CPU_PRIORITY: normal
# File watching
ALLOWED_FILE_TYPES: pdf,txt,doc,docx,png,jpg,jpeg
WATCH_INTERVAL_SECONDS: 5 # Faster for tests
FILE_STABILITY_CHECK_MS: 500
MAX_FILE_AGE_HOURS: 1
# Test-specific environment variables
RUST_LOG: debug
TEST_ENV: true
ports:
- "8001:8001" # Different port from dev
volumes:
# Using tmpfs for faster test execution
- type: tmpfs
target: /tmp/test_uploads
- type: tmpfs
target: /tmp/test_watch
# Mount migrations for SQLx
- ./migrations:/app/migrations:ro
depends_on:
postgres_test:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/api/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
networks:
- readur_test_network
# Frontend test runner service
frontend_test:
image: node:18-alpine
container_name: readur_frontend_test
working_dir: /app
environment:
NODE_ENV: test
VITE_API_BASE_URL: http://readur_test:8001
CI: true
volumes:
- ./frontend:/app:ro
- /app/node_modules # Prevent mounting host node_modules
command: ["sh", "-c", "npm ci && npm test -- --run --reporter=verbose"]
networks:
- readur_test_network
profiles:
- frontend-tests
networks:
readur_test_network:
name: readur_test_network
driver: bridge
# No persistent volumes - everything is ephemeral for tests

223
run-tests.sh Executable file
View File

@ -0,0 +1,223 @@
#!/bin/bash
# Test runner script for Readur
# This script orchestrates all tests in an isolated environment
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
COMPOSE_FILE="docker-compose.test.yml"
COMPOSE_PROJECT_NAME="readur_test"
TEST_TIMEOUT=600 # 10 minutes timeout for all tests
# Function to print colored output
print_status() {
echo -e "${BLUE}[TEST]${NC} $1"
}
print_success() {
echo -e "${GREEN}[✓]${NC} $1"
}
print_error() {
echo -e "${RED}[✗]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
# Function to cleanup test environment
cleanup() {
print_status "Cleaning up test environment..."
docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME down -v --remove-orphans 2>/dev/null || true
# Force remove any lingering containers with our test names
docker rm -f readur_postgres_test readur_app_test readur_frontend_test 2>/dev/null || true
# Force remove the test network if it exists
docker network rm readur_test_network 2>/dev/null || true
# Remove any test artifacts
rm -rf /tmp/test_uploads /tmp/test_watch 2>/dev/null || true
}
# Function to wait for service to be healthy
wait_for_service() {
local service=$1
local max_attempts=30
local attempt=0
print_status "Waiting for $service to be healthy..."
while [ $attempt -lt $max_attempts ]; do
if docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME ps | grep -q "${service}.*healthy"; then
print_success "$service is healthy"
return 0
fi
attempt=$((attempt + 1))
sleep 2
done
print_error "$service failed to become healthy after $max_attempts attempts"
return 1
}
# Parse command line arguments
TEST_TYPE="${1:-all}"
KEEP_RUNNING="${2:-false}"
# Trap to ensure cleanup on exit
trap cleanup EXIT INT TERM
# Main test execution
main() {
print_status "Starting Readur test suite (type: $TEST_TYPE)"
# Force cleanup any existing test environment to avoid conflicts
print_status "Ensuring clean test environment..."
cleanup
# Extra cleanup for stubborn resources
print_status "Removing any conflicting resources..."
docker ps -a | grep -E "readur_(postgres|app|frontend)_test" | awk '{print $1}' | xargs -r docker rm -f 2>/dev/null || true
docker network ls | grep "readur_test_network" | awk '{print $1}' | xargs -r docker network rm 2>/dev/null || true
# Load test environment variables
if [ -f .env.test ]; then
print_status "Loading test environment variables..."
export $(grep -v '^#' .env.test | xargs)
fi
# Build test images
print_status "Building test images..."
docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME build
# Start test infrastructure
print_status "Starting test infrastructure..."
docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME up -d postgres_test
# Wait for PostgreSQL to be ready
wait_for_service "postgres_test"
# The application runs SQLx migrations automatically at startup
print_status "Application will run database migrations on startup..."
# Start the application
print_status "Starting Readur test instance..."
docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME up -d readur_test
# Wait for application to be ready
wait_for_service "readur_test"
# Execute tests based on type
case $TEST_TYPE in
unit)
run_unit_tests
;;
integration)
run_integration_tests
;;
frontend)
run_frontend_tests
;;
e2e)
run_e2e_tests
;;
all)
run_unit_tests
run_integration_tests
run_frontend_tests
;;
*)
print_error "Invalid test type: $TEST_TYPE"
echo "Usage: $0 [unit|integration|frontend|e2e|all] [keep-running]"
exit 1
;;
esac
# Keep containers running if requested (useful for debugging)
if [ "$KEEP_RUNNING" = "keep-running" ]; then
print_warning "Keeping test containers running. Press Ctrl+C to stop and cleanup."
print_status "Test services:"
echo " - PostgreSQL: localhost:5433"
echo " - Readur API: http://localhost:8001"
echo " - Logs: docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME logs -f"
# Wait for user to press Ctrl+C
read -r -d '' _ </dev/tty
fi
}
# Function to run unit tests
run_unit_tests() {
print_status "Running unit tests..."
# Run tests locally with test database URL
if DATABASE_URL="postgresql://readur_test:readur_test@localhost:5433/readur_test" \
cargo test --lib --no-fail-fast; then
print_success "Unit tests passed"
else
print_error "Unit tests failed"
exit 1
fi
}
# Function to run integration tests
run_integration_tests() {
print_status "Running integration tests..."
# Run integration tests locally with test database URL and API URL
if DATABASE_URL="postgresql://readur_test:readur_test@localhost:5433/readur_test" \
TEST_DATABASE_URL="postgresql://readur_test:readur_test@localhost:5433/readur_test" \
API_URL="http://localhost:8001" \
cargo test --test '*' --no-fail-fast; then
print_success "Integration tests passed"
else
print_error "Integration tests failed"
exit 1
fi
}
# Function to run frontend tests
run_frontend_tests() {
print_status "Running frontend tests..."
# Run frontend tests in a separate container
if docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME \
--profile frontend-tests run --rm frontend_test; then
print_success "Frontend tests passed"
else
print_error "Frontend tests failed"
exit 1
fi
}
# Function to run E2E tests (placeholder for future implementation)
run_e2e_tests() {
print_warning "E2E tests not yet implemented"
# TODO: Add E2E test implementation using Playwright or Cypress
}
# Function to show test results summary
show_summary() {
print_status "Test Summary:"
docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME logs readur_test | \
grep -E "(test result:|passed|failed)" | tail -20
}
# Run main function
main
# Show summary
show_summary
print_success "All tests completed successfully!"