404 lines
11 KiB
Markdown
404 lines
11 KiB
Markdown
# ColaFlow Identity Module - Integration Tests
|
|
|
|
Professional .NET Integration Test project for Day 5 Refresh Token and RBAC functionality.
|
|
|
|
## Project Overview
|
|
|
|
This test project provides comprehensive integration testing for:
|
|
- **Phase 1**: Refresh Token functionality (token refresh, rotation, revocation)
|
|
- **Phase 2**: Role-Based Access Control (RBAC) (role assignment, JWT claims, role persistence)
|
|
- **Day 4 Regression**: Authentication basics (registration, login, password hashing)
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
ColaFlow.Modules.Identity.IntegrationTests/
|
|
├── Infrastructure/
|
|
│ ├── ColaFlowWebApplicationFactory.cs # Custom WebApplicationFactory
|
|
│ ├── DatabaseFixture.cs # In-Memory database fixture
|
|
│ ├── RealDatabaseFixture.cs # PostgreSQL database fixture
|
|
│ └── TestAuthHelper.cs # Authentication test utilities
|
|
├── Identity/
|
|
│ ├── AuthenticationTests.cs # Day 4 regression tests
|
|
│ ├── RefreshTokenTests.cs # Day 5 Phase 1 tests
|
|
│ └── RbacTests.cs # Day 5 Phase 2 tests
|
|
├── appsettings.Testing.json # Test configuration
|
|
└── ColaFlow.Modules.Identity.IntegrationTests.csproj
|
|
|
|
```
|
|
|
|
## Test Categories
|
|
|
|
### 1. Authentication Tests (Day 4 Regression)
|
|
- RegisterTenant with valid/invalid data
|
|
- Login with correct/incorrect credentials
|
|
- Protected endpoint access with/without token
|
|
- JWT token claims validation
|
|
- Password hashing verification
|
|
- Complete auth flow (register → login → access)
|
|
|
|
**Total Tests**: 10
|
|
|
|
### 2. Refresh Token Tests (Day 5 Phase 1)
|
|
- RegisterTenant returns access + refresh tokens
|
|
- Login returns access + refresh tokens
|
|
- RefreshToken returns new token pair
|
|
- Old refresh token cannot be reused (token rotation)
|
|
- Invalid refresh token fails
|
|
- Logout revokes refresh token
|
|
- Refresh token maintains user identity
|
|
- Multiple refresh operations work
|
|
- Expired refresh token fails
|
|
|
|
**Total Tests**: 9
|
|
|
|
### 3. RBAC Tests (Day 5 Phase 2)
|
|
- RegisterTenant assigns TenantOwner role
|
|
- JWT contains role claims
|
|
- Login preserves role
|
|
- RefreshToken preserves role
|
|
- /api/auth/me returns user role
|
|
- JWT contains all required role claims
|
|
- Multiple token refresh maintains role
|
|
- Protected endpoint access with valid role succeeds
|
|
- Protected endpoint access without token fails
|
|
- Protected endpoint access with invalid token fails
|
|
- Role consistency across all authentication flows
|
|
|
|
**Total Tests**: 11
|
|
|
|
**Grand Total**: **30 Integration Tests**
|
|
|
|
## Test Infrastructure
|
|
|
|
### WebApplicationFactory
|
|
|
|
The `ColaFlowWebApplicationFactory` supports two database modes:
|
|
|
|
#### 1. In-Memory Database (Default)
|
|
- Fast, isolated tests
|
|
- No external dependencies
|
|
- Each test class gets its own database instance
|
|
- **Recommended for CI/CD pipelines**
|
|
|
|
```csharp
|
|
var factory = new ColaFlowWebApplicationFactory(useInMemoryDatabase: true);
|
|
```
|
|
|
|
#### 2. Real PostgreSQL Database
|
|
- Tests actual database behavior
|
|
- Verifies migrations and real database constraints
|
|
- Requires PostgreSQL running on localhost
|
|
- **Recommended for local testing**
|
|
|
|
```csharp
|
|
var factory = new ColaFlowWebApplicationFactory(useInMemoryDatabase: false);
|
|
```
|
|
|
|
### Database Fixtures
|
|
|
|
#### DatabaseFixture (In-Memory)
|
|
- Implements `IClassFixture<DatabaseFixture>`
|
|
- Provides isolated database per test class
|
|
- Automatic cleanup after tests
|
|
|
|
#### RealDatabaseFixture (PostgreSQL)
|
|
- Implements `IClassFixture<RealDatabaseFixture>`
|
|
- Creates unique test database per test run
|
|
- Automatic cleanup (database deletion) after tests
|
|
|
|
## NuGet Packages
|
|
|
|
| Package | Version | Purpose |
|
|
|---------|---------|---------|
|
|
| `xunit` | 2.9.2 | Test framework |
|
|
| `xunit.runner.visualstudio` | 2.8.2 | Visual Studio test runner |
|
|
| `Microsoft.AspNetCore.Mvc.Testing` | 9.0.0 | WebApplicationFactory |
|
|
| `Microsoft.EntityFrameworkCore.InMemory` | 9.0.0 | In-Memory database |
|
|
| `Npgsql.EntityFrameworkCore.PostgreSQL` | 9.0.4 | PostgreSQL provider |
|
|
| `FluentAssertions` | 7.0.0 | Fluent assertion library |
|
|
| `System.IdentityModel.Tokens.Jwt` | 8.14.0 | JWT token parsing |
|
|
|
|
## Running Tests
|
|
|
|
### Prerequisites
|
|
|
|
**For In-Memory Tests** (No external dependencies):
|
|
- .NET 9.0 SDK installed
|
|
|
|
**For PostgreSQL Tests**:
|
|
- PostgreSQL running on `localhost:5432`
|
|
- Username: `postgres`
|
|
- Password: `postgres`
|
|
- Database: `colaflow_test` (auto-created)
|
|
|
|
### Command Line
|
|
|
|
#### Run All Tests
|
|
```bash
|
|
cd c:\Users\yaoji\git\ColaCoder\product-master\colaflow-api
|
|
dotnet test tests/Modules/Identity/ColaFlow.Modules.Identity.IntegrationTests
|
|
```
|
|
|
|
#### Run Specific Test Class
|
|
```bash
|
|
# Refresh Token Tests only
|
|
dotnet test --filter "FullyQualifiedName~RefreshTokenTests"
|
|
|
|
# RBAC Tests only
|
|
dotnet test --filter "FullyQualifiedName~RbacTests"
|
|
|
|
# Authentication Tests only
|
|
dotnet test --filter "FullyQualifiedName~AuthenticationTests"
|
|
```
|
|
|
|
#### Run Specific Test Method
|
|
```bash
|
|
dotnet test --filter "FullyQualifiedName~RefreshToken_ShouldReturnNewTokenPair"
|
|
```
|
|
|
|
#### Verbose Output
|
|
```bash
|
|
dotnet test --logger "console;verbosity=detailed"
|
|
```
|
|
|
|
#### Generate Coverage Report
|
|
```bash
|
|
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.lcov
|
|
```
|
|
|
|
### Visual Studio / Rider
|
|
|
|
1. **Visual Studio**:
|
|
- Open Test Explorer (Test → Test Explorer)
|
|
- Right-click project → Run Tests
|
|
- Or right-click individual test → Run Test
|
|
|
|
2. **JetBrains Rider**:
|
|
- Open Unit Tests window (View → Tool Windows → Unit Tests)
|
|
- Right-click project → Run Unit Tests
|
|
- Or use `Ctrl+U, Ctrl+R` shortcut
|
|
|
|
### Parallel Execution
|
|
|
|
By default, xUnit runs test classes in parallel but tests within a class sequentially. This is perfect for integration tests because:
|
|
- Each test class uses its own `DatabaseFixture` (isolated database)
|
|
- Tests within a class share the same database (sequential execution prevents conflicts)
|
|
|
|
To disable parallelization (for debugging):
|
|
```csharp
|
|
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
|
```
|
|
|
|
## Test Configuration
|
|
|
|
### appsettings.Testing.json
|
|
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"IdentityConnection": "Host=localhost;Port=5432;Database=colaflow_test;Username=postgres;Password=postgres"
|
|
},
|
|
"Jwt": {
|
|
"SecretKey": "test-secret-key-min-32-characters-long-12345678901234567890",
|
|
"Issuer": "ColaFlow.API.Test",
|
|
"Audience": "ColaFlow.Web.Test",
|
|
"ExpirationMinutes": "15",
|
|
"RefreshTokenExpirationDays": "7"
|
|
},
|
|
"Logging": {
|
|
"LogLevel": {
|
|
"Default": "Warning"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Override Configuration
|
|
|
|
You can override configuration in tests:
|
|
|
|
```csharp
|
|
builder.ConfigureAppConfiguration((context, config) =>
|
|
{
|
|
config.AddInMemoryCollection(new Dictionary<string, string>
|
|
{
|
|
["Jwt:ExpirationMinutes"] = "5",
|
|
["Jwt:RefreshTokenExpirationDays"] = "1"
|
|
});
|
|
});
|
|
```
|
|
|
|
## Test Helpers
|
|
|
|
### TestAuthHelper
|
|
|
|
Provides convenient methods for common test scenarios:
|
|
|
|
```csharp
|
|
// Register and get tokens
|
|
var (accessToken, refreshToken) = await TestAuthHelper.RegisterAndGetTokensAsync(client);
|
|
|
|
// Login and get tokens
|
|
var (accessToken, refreshToken) = await TestAuthHelper.LoginAndGetTokensAsync(
|
|
client, "tenant-slug", "email@test.com", "password");
|
|
|
|
// Parse JWT token
|
|
var claims = TestAuthHelper.ParseJwtToken(accessToken);
|
|
|
|
// Get specific claim
|
|
var userId = TestAuthHelper.GetClaimValue(accessToken, "user_id");
|
|
|
|
// Check role
|
|
bool isOwner = TestAuthHelper.HasRole(accessToken, "TenantOwner");
|
|
```
|
|
|
|
## CI/CD Integration
|
|
|
|
### GitHub Actions
|
|
|
|
```yaml
|
|
name: Integration Tests
|
|
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v3
|
|
with:
|
|
dotnet-version: 9.0.x
|
|
- name: Restore dependencies
|
|
run: dotnet restore
|
|
- name: Build
|
|
run: dotnet build --no-restore
|
|
- name: Run Integration Tests
|
|
run: dotnet test tests/Modules/Identity/ColaFlow.Modules.Identity.IntegrationTests --no-build --verbosity normal
|
|
```
|
|
|
|
### Azure DevOps
|
|
|
|
```yaml
|
|
trigger:
|
|
- main
|
|
|
|
pool:
|
|
vmImage: 'ubuntu-latest'
|
|
|
|
steps:
|
|
- task: UseDotNet@2
|
|
inputs:
|
|
version: '9.0.x'
|
|
- task: DotNetCoreCLI@2
|
|
displayName: 'Restore'
|
|
inputs:
|
|
command: 'restore'
|
|
- task: DotNetCoreCLI@2
|
|
displayName: 'Build'
|
|
inputs:
|
|
command: 'build'
|
|
- task: DotNetCoreCLI@2
|
|
displayName: 'Test'
|
|
inputs:
|
|
command: 'test'
|
|
projects: '**/ColaFlow.Modules.Identity.IntegrationTests.csproj'
|
|
```
|
|
|
|
## Test Coverage Goals
|
|
|
|
- **Line Coverage**: ≥ 80%
|
|
- **Branch Coverage**: ≥ 70%
|
|
- **Critical Paths**: 100% coverage for:
|
|
- Token generation and refresh
|
|
- Role assignment and persistence
|
|
- Authentication flows
|
|
|
|
## Troubleshooting
|
|
|
|
### Test Failures
|
|
|
|
#### "Database connection failed"
|
|
- Ensure PostgreSQL is running (`RealDatabaseFixture` only)
|
|
- Check connection string in `appsettings.Testing.json`
|
|
- Use In-Memory database for tests that don't need real database
|
|
|
|
#### "Token validation failed"
|
|
- Verify `Jwt:SecretKey` matches between test config and API config
|
|
- Check token expiration time is sufficient
|
|
- Ensure clock skew tolerance is configured
|
|
|
|
#### "Test isolation issues"
|
|
- Ensure each test class uses `IClassFixture<DatabaseFixture>`
|
|
- Verify tests don't share global state
|
|
- Use unique tenant slugs and emails (`Guid.NewGuid()`)
|
|
|
|
#### "Port already in use"
|
|
- The test server uses a random port by default
|
|
- No need to stop the real API server
|
|
- If issues persist, use `_factory.Server` instead of `_factory.CreateClient()`
|
|
|
|
### Debug Tips
|
|
|
|
#### Enable Detailed Logging
|
|
```csharp
|
|
builder.ConfigureLogging(logging =>
|
|
{
|
|
logging.ClearProviders();
|
|
logging.AddConsole();
|
|
logging.SetMinimumLevel(LogLevel.Debug);
|
|
});
|
|
```
|
|
|
|
#### Inspect Database State
|
|
```csharp
|
|
using var scope = Factory.Services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<IdentityDbContext>();
|
|
var users = db.Users.ToList();
|
|
// Inspect users...
|
|
```
|
|
|
|
#### Pause Test Execution
|
|
```csharp
|
|
await Task.Delay(TimeSpan.FromSeconds(30)); // Inspect state manually
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use In-Memory Database for most tests**: Faster, no dependencies
|
|
2. **Use Real Database for critical paths**: Migrations, constraints, transactions
|
|
3. **Isolate tests**: Each test should be independent
|
|
4. **Use unique identifiers**: `Guid.NewGuid()` for slugs, emails
|
|
5. **Clean up after tests**: Use `IDisposable` fixtures
|
|
6. **Use FluentAssertions**: More readable assertions
|
|
7. **Test happy paths AND error cases**: Both success and failure scenarios
|
|
8. **Use descriptive test names**: `MethodName_Scenario_ExpectedResult`
|
|
|
|
## Future Enhancements
|
|
|
|
- [ ] Add Testcontainers for PostgreSQL (no manual setup required)
|
|
- [ ] Add performance benchmarks
|
|
- [ ] Add load testing (k6 integration)
|
|
- [ ] Add Swagger/OpenAPI contract tests
|
|
- [ ] Add mutation testing (Stryker.NET)
|
|
- [ ] Add E2E tests with Playwright
|
|
|
|
## Contributing
|
|
|
|
When adding new tests:
|
|
1. Follow existing test structure and naming conventions
|
|
2. Use `TestAuthHelper` for common operations
|
|
3. Ensure tests are isolated and don't depend on execution order
|
|
4. Add test documentation in this README
|
|
5. Verify tests pass with both In-Memory and Real database
|
|
|
|
## License
|
|
|
|
This test project is part of ColaFlow and follows the same license.
|
|
|
|
---
|
|
|
|
**Questions?** Contact the QA team or refer to the main ColaFlow documentation.
|