using System.Net; using System.Net.Http.Json; using IdentityShroud.Core; using IdentityShroud.Core.Model; using IdentityShroud.Core.Tests.Fixtures; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace IdentityShroud.Api.Tests.Apis; public class ClientApiTests : IClassFixture { private readonly ApplicationFactory _factory; public ClientApiTests(ApplicationFactory factory) { _factory = factory; using var scope = _factory.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); if (!db.Database.EnsureCreated()) { db.Database.ExecuteSqlRaw("TRUNCATE realm CASCADE;"); } } [Theory] [InlineData(null, false, "ClientId")] [InlineData("", false, "ClientId")] [InlineData("my-client", true, "")] public async Task Create_Validation(string? clientId, bool succeeds, string fieldName) { // setup Realm realm = await CreateRealmAsync("test-realm", "Test Realm"); var client = _factory.CreateClient(); // act var response = await client.PostAsync( $"/api/v1/realms/{realm.Id}/clients", JsonContent.Create(new { ClientId = clientId }), TestContext.Current.CancellationToken); #if DEBUG string contents = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); #endif if (succeeds) { Assert.Equal(HttpStatusCode.Created, response.StatusCode); } else { Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); var problemDetails = await response.Content.ReadFromJsonAsync( TestContext.Current.CancellationToken); Assert.Contains(problemDetails!.Errors, e => e.Key == fieldName); } } [Fact] public async Task Create_Success_ReturnsCreatedWithLocation() { // setup Realm realm = await CreateRealmAsync("create-realm", "Create Realm"); var client = _factory.CreateClient(); // act var response = await client.PostAsync( $"/api/v1/realms/{realm.Id}/clients", JsonContent.Create(new { ClientId = "new-client", Name = "New Client" }), TestContext.Current.CancellationToken); #if DEBUG string contents = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); #endif // verify Assert.Equal(HttpStatusCode.Created, response.StatusCode); var body = await response.Content.ReadFromJsonAsync( TestContext.Current.CancellationToken); Assert.NotNull(body); Assert.Equal("new-client", body.ClientId); Assert.True(body.Id > 0); } [Fact] public async Task Create_UnknownRealm_ReturnsNotFound() { var client = _factory.CreateClient(); var response = await client.PostAsync( $"/api/v1/realms/{Guid.NewGuid()}/clients", JsonContent.Create(new { ClientId = "some-client" }), TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] public async Task Get_Success() { // setup Realm realm = await CreateRealmAsync("get-realm", "Get Realm"); Client dbClient = await CreateClientAsync(realm, "get-client", "Get Client"); var httpClient = _factory.CreateClient(); // act var response = await httpClient.GetAsync( $"/api/v1/realms/{realm.Id}/clients/{dbClient.Id}", TestContext.Current.CancellationToken); #if DEBUG string contents = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); #endif // verify Assert.Equal(HttpStatusCode.OK, response.StatusCode); var body = await response.Content.ReadFromJsonAsync( TestContext.Current.CancellationToken); Assert.NotNull(body); Assert.Equal(dbClient.Id, body.Id); Assert.Equal("get-client", body.ClientId); Assert.Equal("Get Client", body.Name); Assert.Equal(realm.Id, body.RealmId); } [Fact] public async Task Get_UnknownClient_ReturnsNotFound() { // setup Realm realm = await CreateRealmAsync("notfound-realm", "NotFound Realm"); var httpClient = _factory.CreateClient(); // act var response = await httpClient.GetAsync( $"/api/v1/realms/{realm.Id}/clients/99999", TestContext.Current.CancellationToken); // verify Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } private async Task CreateRealmAsync(string slug, string name) { using var scope = _factory.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var realm = new Realm { Slug = slug, Name = name }; db.Realms.Add(realm); await db.SaveChangesAsync(TestContext.Current.CancellationToken); return realm; } private async Task CreateClientAsync(Realm realm, string clientId, string? name = null) { using var scope = _factory.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var client = new Client { RealmId = realm.Id, ClientId = clientId, Name = name, CreatedAt = DateTime.UtcNow, }; db.Clients.Add(client); await db.SaveChangesAsync(TestContext.Current.CancellationToken); return client; } }