Commit all scripts
This commit is contained in:
@@ -0,0 +1,403 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user