# Attune Common Library - Integration Tests This directory contains integration tests for the Attune common library, specifically testing the database repository layer and migrations. ## Overview The test suite includes: - **Migration Tests** (`migration_tests.rs`) - Verify database schema, migrations, and constraints - **Repository Tests** - Comprehensive CRUD and transaction tests for each repository: - `pack_repository_tests.rs` - Pack repository operations - `action_repository_tests.rs` - Action repository operations - Additional repository tests for all other entities - **Test Helpers** (`helpers.rs`) - Fixtures, utilities, and common test setup ## Prerequisites Before running the tests, ensure you have: 1. **PostgreSQL** installed and running 2. **Test database** created and configured 3. **Environment variables** set (via `.env.test`) ### Setting Up the Test Database ```bash # Create the test database make db-test-create # Run migrations on test database make db-test-migrate # Or do both at once make db-test-setup ``` To reset the test database: ```bash make db-test-reset ``` ## Running Tests ### Run All Integration Tests ```bash # Automatic setup and run make test-integration # Or manually cargo test --test '*' -p attune-common -- --test-threads=1 ``` ### Run Specific Test Files ```bash # Run only migration tests cargo test --test migration_tests -p attune-common # Run only pack repository tests cargo test --test pack_repository_tests -p attune-common # Run only action repository tests cargo test --test action_repository_tests -p attune-common ``` ### Run Specific Tests ```bash # Run a single test by name cargo test test_create_pack -p attune-common # Run tests matching a pattern cargo test test_create -p attune-common # Run with output cargo test test_create_pack -p attune-common -- --nocapture ``` ## Test Configuration Test configuration is loaded from `.env.test` in the project root. Key settings: ```bash # Test database URL ATTUNE__DATABASE__URL=postgresql://postgres:postgres@localhost:5432/attune_test # Enable SQL logging for debugging ATTUNE__DATABASE__LOG_STATEMENTS=true # Verbose logging ATTUNE__LOG__LEVEL=debug RUST_LOG=debug,sqlx=warn ``` ## Test Structure ### Test Helpers (`helpers.rs`) The helpers module provides: - **Database Setup**: `create_test_pool()`, `clean_database()` - **Fixtures**: Builder pattern for creating test data - `PackFixture` - Create test packs - `ActionFixture` - Create test actions - `RuntimeFixture` - Create test runtimes - And more for all entities - **Utilities**: Transaction helpers, assertions Example fixture usage: ```rust use helpers::*; let pool = create_test_pool().await.unwrap(); clean_database(&pool).await.unwrap(); let pack_repo = PackRepository::new(&pool); // Use fixture to create test data let pack = PackFixture::new("test.pack") .with_version("2.0.0") .with_name("Custom Pack Name") .create(&pack_repo) .await .unwrap(); ``` ### Test Organization Each test file follows this pattern: 1. **Import helpers module**: `mod helpers;` 2. **Setup phase**: Create pool and clean database 3. **Test execution**: Perform operations 4. **Assertions**: Verify expected outcomes 5. **Cleanup**: Automatic via `clean_database()` or transactions Example test: ```rust #[tokio::test] async fn test_create_pack() { // Setup let pool = create_test_pool().await.unwrap(); clean_database(&pool).await.unwrap(); let repo = PackRepository::new(&pool); // Execute let pack = PackFixture::new("test.pack") .create(&repo) .await .unwrap(); // Assert assert_eq!(pack.ref_name, "test.pack"); assert!(pack.created_at.timestamp() > 0); } ``` ## Test Categories ### CRUD Operations Tests verify basic Create, Read, Update, Delete operations: - Creating entities with valid data - Retrieving entities by ID and other fields - Listing and pagination - Updating partial and full records - Deleting entities ### Constraint Validation Tests verify database constraints: - Unique constraints (e.g., pack ref_name + version) - Foreign key constraints - NOT NULL constraints - Check constraints ### Transaction Support Tests verify transaction behavior: - Commit preserves changes - Rollback discards changes - Isolation between transactions ### Error Handling Tests verify proper error handling: - Duplicate key violations - Foreign key violations - Not found scenarios ### Cascading Deletes Tests verify cascade delete behavior: - Deleting a pack deletes associated actions - Deleting a runtime deletes associated workers - And other cascade relationships ## Best Practices ### 1. Clean Database Before Tests Always clean the database at the start of each test: ```rust let pool = create_test_pool().await.unwrap(); clean_database(&pool).await.unwrap(); ``` ### 2. Use Fixtures for Test Data Use fixture builders instead of manual creation: ```rust // Good let pack = PackFixture::new("test.pack").create(&repo).await.unwrap(); // Avoid let create = CreatePack { /* ... */ }; let pack = repo.create(&create).await.unwrap(); ``` ### 3. Test Isolation Each test should be independent: - Don't rely on data from other tests - Clean database between tests - Use unique names/IDs ### 4. Single-Threaded Execution Run integration tests single-threaded to avoid race conditions: ```bash cargo test -- --test-threads=1 ``` ### 5. Descriptive Test Names Use clear, descriptive test names: ```rust #[tokio::test] async fn test_create_pack_duplicate_ref_version() { /* ... */ } ``` ### 6. Test Both Success and Failure Test both happy paths and error cases: ```rust #[tokio::test] async fn test_create_pack() { /* success case */ } #[tokio::test] async fn test_create_pack_duplicate_ref_version() { /* error case */ } ``` ## Debugging Tests ### Enable SQL Logging Set in `.env.test`: ```bash ATTUNE__DATABASE__LOG_STATEMENTS=true RUST_LOG=debug,sqlx=debug ``` ### Run with Output ```bash cargo test test_name -- --nocapture ``` ### Use Transaction Rollback Wrap tests in transactions that rollback to inspect state: ```rust let mut tx = pool.begin().await.unwrap(); // ... test operations ... // Drop tx without commit to rollback ``` ### Check Database State Connect to test database directly: ```bash psql -d attune_test -U postgres ``` ## Continuous Integration For CI environments: ```bash # Setup test database createdb attune_test DATABASE_URL=postgresql://postgres:postgres@localhost:5432/attune_test sqlx migrate run # Run tests cargo test --test '*' -p attune-common -- --test-threads=1 ``` ## Common Issues ### Database Connection Errors **Issue**: Cannot connect to database **Solution**: - Ensure PostgreSQL is running - Check credentials in `.env.test` - Verify test database exists ### Migration Errors **Issue**: Migrations fail **Solution**: - Run `make db-test-reset` to reset test database - Ensure migrations are in `migrations/` directory ### Flaky Tests **Issue**: Tests fail intermittently **Solution**: - Run single-threaded: `--test-threads=1` - Clean database before each test - Avoid time-dependent assertions ### Foreign Key Violations **Issue**: Cannot delete entity due to foreign keys **Solution**: - Use `clean_database()` which handles dependencies - Test cascade deletes explicitly - Delete in correct order (children before parents) ## Adding New Tests To add tests for a new repository: 1. Create test file: `tests/_repository_tests.rs` 2. Import helpers: `mod helpers;` 3. Create fixtures in `helpers.rs` if needed 4. Write comprehensive CRUD tests 5. Test constraints and error cases 6. Test transactions 7. Run and verify: `cargo test --test _repository_tests` ## Test Coverage To generate test coverage reports: ```bash # Install tarpaulin cargo install cargo-tarpaulin # Generate coverage cargo tarpaulin --out Html --output-dir coverage --test '*' -p attune-common ``` ## Additional Resources - [SQLx Documentation](https://docs.rs/sqlx) - [Tokio Testing Guide](https://tokio.rs/tokio/topics/testing) - [Rust Testing Best Practices](https://doc.rust-lang.org/book/ch11-00-testing.html) ## Support For issues or questions: - Check existing tests for examples - Review helper functions in `helpers.rs` - Consult the main project documentation - Open an issue on the project repository