# 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.
