test: add ClientIntegrationTestBase with shared auth HttpClient
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
namespace JdeScoping.Api.IntegrationTests.ClientIntegration;
|
||||
|
||||
/// <summary>
|
||||
/// Collection definition for client integration tests.
|
||||
/// Prevents parallel execution to avoid auth state conflicts.
|
||||
/// </summary>
|
||||
[CollectionDefinition("ClientIntegration")]
|
||||
public class ClientIntegrationCollection : ICollectionFixture<TestWebApplicationFactory>
|
||||
{
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using JdeScoping.Client.Services;
|
||||
using JdeScoping.Core.Models.Auth;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
|
||||
namespace JdeScoping.Api.IntegrationTests.ClientIntegration;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for API client integration tests.
|
||||
/// Provides shared HttpClient with cookie handling for auth state.
|
||||
/// </summary>
|
||||
[Collection("ClientIntegration")]
|
||||
public abstract class ClientIntegrationTestBase : IClassFixture<TestWebApplicationFactory>
|
||||
{
|
||||
protected readonly TestWebApplicationFactory Factory;
|
||||
protected readonly HttpClient SharedClient;
|
||||
|
||||
// API clients share the authenticated HttpClient
|
||||
protected readonly SearchApiClient SearchClient;
|
||||
protected readonly LookupApiClient LookupClient;
|
||||
protected readonly AuthApiClient AuthClient;
|
||||
protected readonly FileApiClient FileClient;
|
||||
|
||||
protected ClientIntegrationTestBase(TestWebApplicationFactory factory)
|
||||
{
|
||||
Factory = factory;
|
||||
SharedClient = factory.CreateClient(new WebApplicationFactoryClientOptions
|
||||
{
|
||||
HandleCookies = true,
|
||||
AllowAutoRedirect = false
|
||||
});
|
||||
|
||||
// All clients share the same HttpClient (cookie container)
|
||||
SearchClient = new SearchApiClient(SharedClient);
|
||||
LookupClient = new LookupApiClient(SharedClient);
|
||||
FileClient = new FileApiClient(SharedClient);
|
||||
AuthClient = new AuthApiClient(SharedClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs login with encrypted credentials.
|
||||
/// </summary>
|
||||
protected async Task LoginAsync(string username = "testuser", string password = "testpass")
|
||||
{
|
||||
// Step 1: Get public key
|
||||
var publicKeyResult = await AuthClient.GetPublicKeyAsync();
|
||||
if (!publicKeyResult.IsSuccess)
|
||||
throw new Exception("Failed to get public key");
|
||||
|
||||
// Step 2: Encrypt credentials
|
||||
var loginModel = new LoginModel { Username = username, Password = password };
|
||||
var json = JsonSerializer.Serialize(loginModel);
|
||||
var plaintext = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
using var rsa = RSA.Create();
|
||||
rsa.ImportFromPem(publicKeyResult.Value.PublicKeyPem);
|
||||
var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);
|
||||
|
||||
// Step 3: Login
|
||||
var encryptedRequest = new EncryptedLoginRequest(Convert.ToBase64String(ciphertext));
|
||||
var loginResult = await AuthClient.LoginAsync(encryptedRequest);
|
||||
|
||||
if (!loginResult.IsSuccess || !loginResult.Value.Success)
|
||||
throw new Exception($"Login failed: {loginResult.Value?.ErrorMessage ?? "Unknown error"}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a fresh HttpClient without cookies for testing unauthorized scenarios.
|
||||
/// </summary>
|
||||
protected HttpClient CreateFreshClient() => Factory.CreateClient(new WebApplicationFactoryClientOptions
|
||||
{
|
||||
HandleCookies = false,
|
||||
AllowAutoRedirect = false
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user