re-uploading work
This commit is contained in:
391
crates/common/tests/README.md
Normal file
391
crates/common/tests/README.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# 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/<entity>_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 <entity>_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
|
||||
Reference in New Issue
Block a user