From 68f8357a87adc70518e3f65a68bfe49bf9b784ea Mon Sep 17 00:00:00 2001 From: juhangil Date: Sun, 18 Aug 2024 18:12:38 +0900 Subject: [PATCH 01/16] Add Get event details endpoint by admin --- .../Endpoints/AdminEventDetailsEndpoint.cs | 60 +++++++++++++++++++ .../Endpoints/EndpointUrls.cs | 7 ++- .../Models/AdminEventDetails.cs | 9 +++ src/AzureOpenAIProxy.ApiApp/Program.cs | 1 + 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs create mode 100644 src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs new file mode 100644 index 00000000..26f62244 --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs @@ -0,0 +1,60 @@ +using AzureOpenAIProxy.ApiApp.Attributes; +using AzureOpenAIProxy.ApiApp.Models; + +using Microsoft.AspNetCore.Mvc; + +namespace AzureOpenAIProxy.ApiApp.Endpoints; + +/// +/// This represents the endpoint entity for get event details by admin +/// +public static class AdminEventDetailsEndpoint +{ + /// + /// Adds the get event details by admin endpoint + /// + /// instance. + /// Returns instance. + public static RouteHandlerBuilder AddAdminEventDetails(this WebApplication app) + { + // Todo: Issue #19 https://github.com/aliencube/azure-openai-sdk-proxy/issues/19 + // Need authorization by admin + var builder = app.MapGet(EndpointUrls.AdminEventDetails, ( + [FromRoute] string eventID, + ILoggerFactory loggerFactory) => + { + var logger = loggerFactory.CreateLogger(nameof(AdminEventDetailsEndpoint)); + logger.LogInformation($"Received a admin event detail request id: {eventID}"); + + try + { + // Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208 + // Fake implementation, just return recieved event id. + var result = new AdminEventDetails { EventId = eventID }; + + return Results.Ok(result); + // Todo: Issue #208 + } + catch (Exception ex) + { + logger.LogError(ex, "Failed to invoke the admin detail get request"); + + return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError); + } + }) + .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") + .Produces(statusCode: StatusCodes.Status401Unauthorized) + .Produces(statusCode: StatusCodes.Status500InternalServerError, contentType: "text/plain") + .WithTags("admin") + .WithName("GetAdminEventDetails") + .WithOpenApi(operation => + { + operation.Summary = "Get event details by admin"; + operation.Description = "Get event details by event id, api for admin users"; + + return operation; + }); + + return builder; + } +} diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs index be5b3e79..357fae6f 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs @@ -14,4 +14,9 @@ public static class EndpointUrls /// Declares the chat completions endpoint. /// public const string ChatCompletions = "/openai/deployments/{deploymentName}/chat/completions"; -} + + /// + /// Declares the admin event details endpoint. + /// + public const string AdminEventDetails = "/admin/events/{eventID}"; +} \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs new file mode 100644 index 00000000..bdbc13fe --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -0,0 +1,9 @@ +namespace AzureOpenAIProxy.ApiApp.Models; + +// Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208 +// Fake implementation, just return recieved event id. +public class AdminEventDetails +{ + public string? EventId { get; set; } +} +// Todo: Issue #208 \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index 39464608..ac3925db 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -38,5 +38,6 @@ app.AddWeatherForecast(); app.AddChatCompletions(); +app.AddAdminEventDetails(); await app.RunAsync(); From 7d79152180fd3a0e1374214e964e247d3dc78ddc Mon Sep 17 00:00:00 2001 From: juhangil Date: Sun, 18 Aug 2024 22:48:17 +0900 Subject: [PATCH 02/16] Update GetAdminEventDetails OpenAPI description --- .../Endpoints/AdminEventDetailsEndpoint.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs index 26f62244..9d3ed5d3 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs @@ -49,8 +49,8 @@ public static RouteHandlerBuilder AddAdminEventDetails(this WebApplication app) .WithName("GetAdminEventDetails") .WithOpenApi(operation => { - operation.Summary = "Get event details by admin"; - operation.Description = "Get event details by event id, api for admin users"; + operation.Summary = "Gets event details from the given event ID"; + operation.Description = "This endpoint gets the event details from the given event ID."; return operation; }); From 88974a8aa327ad6af92391dd85588f0e19437aca Mon Sep 17 00:00:00 2001 From: juhangil Date: Sun, 18 Aug 2024 23:43:00 +0900 Subject: [PATCH 03/16] Update Admin event endpoint files - remove fake implementation in admin event details endpoint - Replace event details url file, EndpointUrls.cs to AdminEndpointUrls.cs - Rename AdminEventDetailsEndpoint.cs to AdminEventEndpoints.cs - Change url route parameter eventID to eventId --- .../Endpoints/AdminEndpointUrls.cs | 9 ++++++ ...ailsEndpoint.cs => AdminEventEndpoints.cs} | 31 +++++-------------- .../Endpoints/EndpointUrls.cs | 5 --- src/AzureOpenAIProxy.ApiApp/Program.cs | 3 ++ 4 files changed, 19 insertions(+), 29 deletions(-) create mode 100644 src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEndpointUrls.cs rename src/AzureOpenAIProxy.ApiApp/Endpoints/{AdminEventDetailsEndpoint.cs => AdminEventEndpoints.cs} (54%) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEndpointUrls.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEndpointUrls.cs new file mode 100644 index 00000000..3fdb5d0c --- /dev/null +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEndpointUrls.cs @@ -0,0 +1,9 @@ +namespace AzureOpenAIProxy.ApiApp.Endpoints; + +public static class AdminEndpointUrls +{ + /// + /// Declares the admin event details endpoint. + /// + public const string AdminEventDetails = "/admin/events/{eventId}"; +} \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs similarity index 54% rename from src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs rename to src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs index 9d3ed5d3..a255bb20 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventDetailsEndpoint.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs @@ -1,5 +1,4 @@ -using AzureOpenAIProxy.ApiApp.Attributes; -using AzureOpenAIProxy.ApiApp.Models; +using AzureOpenAIProxy.ApiApp.Models; using Microsoft.AspNetCore.Mvc; @@ -8,7 +7,7 @@ namespace AzureOpenAIProxy.ApiApp.Endpoints; /// /// This represents the endpoint entity for get event details by admin /// -public static class AdminEventDetailsEndpoint +public static class AdminEventEndpoints { /// /// Adds the get event details by admin endpoint @@ -19,28 +18,12 @@ public static RouteHandlerBuilder AddAdminEventDetails(this WebApplication app) { // Todo: Issue #19 https://github.com/aliencube/azure-openai-sdk-proxy/issues/19 // Need authorization by admin - var builder = app.MapGet(EndpointUrls.AdminEventDetails, ( - [FromRoute] string eventID, - ILoggerFactory loggerFactory) => + var builder = app.MapGet(AdminEndpointUrls.AdminEventDetails, ( + [FromRoute] string eventId) => { - var logger = loggerFactory.CreateLogger(nameof(AdminEventDetailsEndpoint)); - logger.LogInformation($"Received a admin event detail request id: {eventID}"); - - try - { - // Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208 - // Fake implementation, just return recieved event id. - var result = new AdminEventDetails { EventId = eventID }; - - return Results.Ok(result); - // Todo: Issue #208 - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to invoke the admin detail get request"); - - return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError); - } + // Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208 + return Results.Ok(); + // Todo: Issue #208 }) .Produces(statusCode: StatusCodes.Status200OK, contentType: "application/json") .Produces(statusCode: StatusCodes.Status401Unauthorized) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs index 357fae6f..a5c6d5d2 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/EndpointUrls.cs @@ -14,9 +14,4 @@ public static class EndpointUrls /// Declares the chat completions endpoint. /// public const string ChatCompletions = "/openai/deployments/{deploymentName}/chat/completions"; - - /// - /// Declares the admin event details endpoint. - /// - public const string AdminEventDetails = "/admin/events/{eventID}"; } \ No newline at end of file diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index ac3925db..c3d704c4 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -38,6 +38,9 @@ app.AddWeatherForecast(); app.AddChatCompletions(); + +#region Admin Event Endpoint app.AddAdminEventDetails(); +#endregion await app.RunAsync(); From a22f7c80b848ca664a533ebd272a054218cc8b8a Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 00:16:07 +0900 Subject: [PATCH 04/16] Update admin event endpoint - AddAdminEventDetails to AddAdminEvents - Replace region to comment --- src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs | 2 +- src/AzureOpenAIProxy.ApiApp/Program.cs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs index a255bb20..d64ac5f0 100644 --- a/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs +++ b/src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs @@ -14,7 +14,7 @@ public static class AdminEventEndpoints /// /// instance. /// Returns instance. - public static RouteHandlerBuilder AddAdminEventDetails(this WebApplication app) + public static RouteHandlerBuilder AddAdminEvents(this WebApplication app) { // Todo: Issue #19 https://github.com/aliencube/azure-openai-sdk-proxy/issues/19 // Need authorization by admin diff --git a/src/AzureOpenAIProxy.ApiApp/Program.cs b/src/AzureOpenAIProxy.ApiApp/Program.cs index c3d704c4..2331dc75 100644 --- a/src/AzureOpenAIProxy.ApiApp/Program.cs +++ b/src/AzureOpenAIProxy.ApiApp/Program.cs @@ -39,8 +39,7 @@ app.AddWeatherForecast(); app.AddChatCompletions(); -#region Admin Event Endpoint -app.AddAdminEventDetails(); -#endregion +// Admin Endpoints +app.AddAdminEvents(); await app.RunAsync(); From fac97dfad714304454ddf89bf54a2334066fc5ae Mon Sep 17 00:00:00 2001 From: Justin Yoo Date: Mon, 19 Aug 2024 13:47:44 +0900 Subject: [PATCH 05/16] Add some test sample --- .../ApiApp/AdminEventEndpointsOpenApiTests.cs | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs new file mode 100644 index 00000000..a7bca3b9 --- /dev/null +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs @@ -0,0 +1,190 @@ +using System.Text.Json; + +using FluentAssertions; + +namespace AzureOpenAIProxy.AppHost.Tests.ApiApp; + +public class AdminEventEndpointsOpenApiTests +{ + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .TryGetProperty("/admin/events/{eventId}", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Verb() + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .TryGetProperty("get", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Theory] + [InlineData("admin")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tags(string tag) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .TryGetProperty("tags", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Array); + result.EnumerateArray().Select(p => p.GetString()).Should().Contain(tag); + } + + [Theory] + [InlineData("summary")] + [InlineData("description")] + [InlineData("operationId")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Value(string attribute) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.String); + } + + [Theory] + [InlineData("parameters")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Array(string attribute) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Array); + } + + [Theory] + [InlineData("eventId")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path_Parameter(string name) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .GetProperty("parameters") + .EnumerateArray() + .Where(p => p.GetProperty("in").GetString() == "path") + .Select(p => p.GetProperty("name").ToString()); + result.Should().Contain(name); + } + + [Theory] + [InlineData("responses")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Object(string attribute) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Theory] + [InlineData("200")] + [InlineData("401")] + [InlineData("500")] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response(string attribute) + { + // Arrange + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + await using var app = await appHost.BuildAsync(); + await app.StartAsync(); + + // Act + var httpClient = app.CreateHttpClient("apiapp"); + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("paths") + .GetProperty("/admin/events/{eventId}") + .GetProperty("get") + .GetProperty("responses") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + // TODO: Add more tests for the component section +} From 4a5ea724f85227ecd29b0097b896af694da0f354 Mon Sep 17 00:00:00 2001 From: Justin Yoo Date: Mon, 19 Aug 2024 13:58:08 +0900 Subject: [PATCH 06/16] Update name of namespace/class --- .../AdminGetEventEventDetailsOpenApiTests.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/AzureOpenAIProxy.AppHost.Tests/ApiApp/{AdminEventEndpointsOpenApiTests.cs => Endpoints/AdminGetEventEventDetailsOpenApiTests.cs} (98%) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs similarity index 98% rename from test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs rename to test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs index a7bca3b9..7ca1023d 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/AdminEventEndpointsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs @@ -2,9 +2,9 @@ using FluentAssertions; -namespace AzureOpenAIProxy.AppHost.Tests.ApiApp; +namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; -public class AdminEventEndpointsOpenApiTests +public class AdminGetEventEventDetailsOpenApiTests { [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() From b4dc2a068b1255b3950cbd073b4c274daad98657 Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 16:50:17 +0900 Subject: [PATCH 07/16] Add aspire host fixture in AppHost xunit test --- .../AdminGetEventEventDetailsOpenApiTests.cs | 44 +++++-------------- .../AppHostProgramTests.cs | 9 ++-- .../Fixture/AspireHostFixture.cs | 27 ++++++++++++ 3 files changed, 42 insertions(+), 38 deletions(-) create mode 100644 test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs index 7ca1023d..ad7f3d32 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs @@ -1,21 +1,20 @@ using System.Text.Json; +using AzureOpenAIProxy.AppHost.Tests.Fixture; + using FluentAssertions; namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; -public class AdminGetEventEventDetailsOpenApiTests +public class AdminGetEventEventDetailsOpenApiTests(AspireHostFixture host) : IClassFixture { [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -29,12 +28,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Pat public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Verb() { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -50,12 +46,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Ver public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tags(string tag) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -75,12 +68,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Tag public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Value(string attribute) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -97,12 +87,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Val public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Array(string attribute) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -119,12 +106,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Arr public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path_Parameter(string name) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -144,12 +128,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Pat public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Object(string attribute) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); @@ -168,12 +149,9 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Obj public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response(string attribute) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient("apiapp"); // Act - var httpClient = app.CreateHttpClient("apiapp"); var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); diff --git a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs index 880bf4d7..4dfda920 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs @@ -1,10 +1,12 @@ using System.Net; +using AzureOpenAIProxy.AppHost.Tests.Fixture; + using FluentAssertions; namespace AzureOpenAIProxy.Tests; -public class AppHostProgramTests +public class AppHostProgramTests(AspireHostFixture host) : IClassFixture { [Theory] [InlineData("apiapp", "/health", HttpStatusCode.OK)] @@ -12,12 +14,9 @@ public class AppHostProgramTests public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Healthy(string resourceName, string endpoint, HttpStatusCode statusCode) { // Arrange - var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); - await using var app = await appHost.BuildAsync(); - await app.StartAsync(); + using var httpClient = host.App!.CreateHttpClient(resourceName); // Act - var httpClient = app.CreateHttpClient(resourceName); var response = await httpClient.GetAsync(endpoint); // Assert diff --git a/test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs b/test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs new file mode 100644 index 00000000..7b526052 --- /dev/null +++ b/test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs @@ -0,0 +1,27 @@ +namespace AzureOpenAIProxy.AppHost.Tests.Fixture; + +/// +/// This class instance is automatically created before run test. +/// To use, inherit IClassFixture and inject on constructor. +/// +public class AspireHostFixture : IAsyncLifetime +{ + public DistributedApplication? App { get; private set; } + + public async Task InitializeAsync() + { + var appHost = await DistributedApplicationTestingBuilder.CreateAsync(); + this.App = await appHost.BuildAsync(); + await App.StartAsync(); + + Assert.NotNull(App); + } + + public async Task DisposeAsync() + { + if (App == null) return; + + await App.StopAsync(); + await App.DisposeAsync(); + } +} From ec7de289d3733c47b0b7d658cd0b014596b74c7b Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 17:08:26 +0900 Subject: [PATCH 08/16] Update fixtures namespace --- .../ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs | 4 ++-- test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs | 4 ++-- .../AspireHostFixture.cs => Fixtures/AspireAppHostFixture.cs} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename test/AzureOpenAIProxy.AppHost.Tests/{Fixture/AspireHostFixture.cs => Fixtures/AspireAppHostFixture.cs} (86%) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs index ad7f3d32..6aaad3ff 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs @@ -1,12 +1,12 @@ using System.Text.Json; -using AzureOpenAIProxy.AppHost.Tests.Fixture; +using AzureOpenAIProxy.AppHost.Tests.Fixtures; using FluentAssertions; namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; -public class AdminGetEventEventDetailsOpenApiTests(AspireHostFixture host) : IClassFixture +public class AdminGetEventEventDetailsOpenApiTests(AspireAppHostFixture host) : IClassFixture { [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() diff --git a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs index 4dfda920..50e1a11a 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/AppHostProgramTests.cs @@ -1,12 +1,12 @@ using System.Net; -using AzureOpenAIProxy.AppHost.Tests.Fixture; +using AzureOpenAIProxy.AppHost.Tests.Fixtures; using FluentAssertions; namespace AzureOpenAIProxy.Tests; -public class AppHostProgramTests(AspireHostFixture host) : IClassFixture +public class AppHostProgramTests(AspireAppHostFixture host) : IClassFixture { [Theory] [InlineData("apiapp", "/health", HttpStatusCode.OK)] diff --git a/test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs b/test/AzureOpenAIProxy.AppHost.Tests/Fixtures/AspireAppHostFixture.cs similarity index 86% rename from test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs rename to test/AzureOpenAIProxy.AppHost.Tests/Fixtures/AspireAppHostFixture.cs index 7b526052..668bb116 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/Fixture/AspireHostFixture.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/Fixtures/AspireAppHostFixture.cs @@ -1,10 +1,10 @@ -namespace AzureOpenAIProxy.AppHost.Tests.Fixture; +namespace AzureOpenAIProxy.AppHost.Tests.Fixtures; /// /// This class instance is automatically created before run test. /// To use, inherit IClassFixture and inject on constructor. /// -public class AspireHostFixture : IAsyncLifetime +public class AspireAppHostFixture : IAsyncLifetime { public DistributedApplication? App { get; private set; } From 38642995be2a385a0ae399fcbd1442543725d9b0 Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 18:22:03 +0900 Subject: [PATCH 09/16] Rename to AdminGetEventDetailsOpenApiTest --- ...etailsOpenApiTests.cs => AdminGetEventDetailsOpenApiTest.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/{AdminGetEventEventDetailsOpenApiTests.cs => AdminGetEventDetailsOpenApiTest.cs} (98%) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs similarity index 98% rename from test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs rename to test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs index 6aaad3ff..2eee9c5a 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs @@ -6,7 +6,7 @@ namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; -public class AdminGetEventEventDetailsOpenApiTests(AspireAppHostFixture host) : IClassFixture +public class AdminGetEventDetailsOpenApiTest(AspireAppHostFixture host) : IClassFixture { [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() From fc6ca774b882176005fe40af5151880aef7b3e0a Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 20:50:29 +0900 Subject: [PATCH 10/16] Add Reponse model and test method --- .../Models/AdminEventDetails.cs | 18 +++++++++++---- .../AdminGetEventDetailsOpenApiTest.cs | 23 +++++++++++++++++++ .../AzureOpenAIProxy.AppHost.Tests.csproj | 1 + 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index bdbc13fe..68908b52 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -1,9 +1,19 @@ namespace AzureOpenAIProxy.ApiApp.Models; -// Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208 -// Fake implementation, just return recieved event id. public class AdminEventDetails { public string? EventId { get; set; } -} -// Todo: Issue #208 \ No newline at end of file + public string? Title { get; set; } + public string? Summary { get; set; } + public string? Description { get; set; } + public DateTime? DateStart { get; set; } + public DateTime? DateEnd { get; set; } + public string? TimeZone { get; set; } + public bool IsActive { get; set; } + public string? OrganizerName { get; set; } + public string? OrganizerEmail { get; set; } + public string? CoorganizerName { get; set; } + public string? CoorganizerEmail { get; set; } + public int MaxTokenCap { get; set; } + public int DailyRequestCap { get; set; } +} \ No newline at end of file diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs index 2eee9c5a..885b9cb7 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs @@ -1,5 +1,6 @@ using System.Text.Json; +using AzureOpenAIProxy.ApiApp.Models; using AzureOpenAIProxy.AppHost.Tests.Fixtures; using FluentAssertions; @@ -165,4 +166,26 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Res } // TODO: Add more tests for the component section + [Theory] + [InlineData(typeof(AdminEventDetails))] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response_Property(Type type) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var component = openapi!.RootElement.GetProperty("components") + .GetProperty("schemas") + .GetProperty(type.Name) + .GetProperty("properties"); + foreach (var prop in type.GetProperties()) + { + var name = JsonNamingPolicy.CamelCase.ConvertName(prop.Name); + component.TryGetProperty(name, out var temp).Should().BeTrue(); + } + } } diff --git a/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj b/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj index f7cc56ea..16d0c64e 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj +++ b/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj @@ -25,6 +25,7 @@ + From a67de9d57bffc826894a7f6ff054d6da6329d6e2 Mon Sep 17 00:00:00 2001 From: juhangil Date: Mon, 19 Aug 2024 20:59:16 +0900 Subject: [PATCH 11/16] Update component test method for property check --- .../ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs index 885b9cb7..f1682649 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs @@ -182,10 +182,12 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Res .GetProperty("schemas") .GetProperty(type.Name) .GetProperty("properties"); + foreach (var prop in type.GetProperties()) { - var name = JsonNamingPolicy.CamelCase.ConvertName(prop.Name); - component.TryGetProperty(name, out var temp).Should().BeTrue(); + var propName = JsonNamingPolicy.CamelCase.ConvertName(prop.Name); + component.TryGetProperty(propName, out var jsonProp).Should().BeTrue(); + jsonProp.ValueKind.Should().Be(JsonValueKind.Object); } } } From 845aa3349026d7f0cbedad622b9e3c2167dab855 Mon Sep 17 00:00:00 2001 From: juhangil Date: Tue, 20 Aug 2024 00:32:00 +0900 Subject: [PATCH 12/16] Rename to AdminGetEventDetailsOpenApiTests --- ...etailsOpenApiTest.cs => AdminGetEventDetailsOpenApiTests.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/{AdminGetEventDetailsOpenApiTest.cs => AdminGetEventDetailsOpenApiTests.cs} (98%) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs similarity index 98% rename from test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs rename to test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs index f1682649..7421ae2e 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTest.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs @@ -7,7 +7,7 @@ namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; -public class AdminGetEventDetailsOpenApiTest(AspireAppHostFixture host) : IClassFixture +public class AdminGetEventDetailsOpenApiTests(AspireAppHostFixture host) : IClassFixture { [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path() From fb48e25af07c3706808553830467f36bc3ee7a59 Mon Sep 17 00:00:00 2001 From: juhangil Date: Tue, 20 Aug 2024 01:34:10 +0900 Subject: [PATCH 13/16] Update AdminEventDetails comment --- .../Models/AdminEventDetails.cs | 80 ++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs index 68908b52..19a20eed 100644 --- a/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs +++ b/src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs @@ -1,19 +1,77 @@ namespace AzureOpenAIProxy.ApiApp.Models; +/// +/// This represent the event detail data for response by admin event endpoint. +/// public class AdminEventDetails { - public string? EventId { get; set; } - public string? Title { get; set; } - public string? Summary { get; set; } + /// + /// Gets or sets the event id. + /// + public required string? EventId { get; set; } + + /// + /// Gets or sets the event title name. + /// + public required string? Title { get; set; } + + /// + /// Gets or sets the event summary. + /// + public required string? Summary { get; set; } + + /// + /// Gets or sets the event description. + /// public string? Description { get; set; } - public DateTime? DateStart { get; set; } - public DateTime? DateEnd { get; set; } - public string? TimeZone { get; set; } - public bool IsActive { get; set; } - public string? OrganizerName { get; set; } - public string? OrganizerEmail { get; set; } + + /// + /// Gets or sets the event start date. + /// + public required DateTimeOffset? DateStart { get; set; } + + /// + /// Gets or sets the event end date. + /// + public required DateTimeOffset? DateEnd { get; set; } + + /// + /// Gets or sets the event start to end date timezone. + /// + public required string? TimeZone { get; set; } + + /// + /// Gets or sets the event active status. + /// + public required bool? IsActive { get; set; } + + /// + /// Gets or sets the event organizer name. + /// + public required string? OrganizerName { get; set; } + + /// + /// Gets or sets the event organizer email. + /// + public required string? OrganizerEmail { get; set; } + + /// + /// Gets or sets the event coorganizer name. + /// public string? CoorganizerName { get; set; } + + /// + /// Gets or sets the event coorganizer email. + /// public string? CoorganizerEmail { get; set; } - public int MaxTokenCap { get; set; } - public int DailyRequestCap { get; set; } + + /// + /// Gets or sets the Azure OpenAI Service request max token capacity. + /// + public required int? MaxTokenCap { get; set; } + + /// + /// Gets or sets the Azure OpenAI Service daily request capacity. + /// + public required int? DailyRequestCap { get; set; } } \ No newline at end of file From 9a8d082cb625c4aaaead818aa05830e7c8238ba8 Mon Sep 17 00:00:00 2001 From: juhangil Date: Tue, 20 Aug 2024 15:24:41 +0900 Subject: [PATCH 14/16] Update Admin event detail component unit test --- .../AdminGetEventDetailsOpenApiTests.cs | 127 +++++++++++++++--- .../AzureOpenAIProxy.AppHost.Tests.csproj | 1 - 2 files changed, 112 insertions(+), 16 deletions(-) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs index 7421ae2e..36e2850d 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs @@ -1,9 +1,10 @@ using System.Text.Json; -using AzureOpenAIProxy.ApiApp.Models; -using AzureOpenAIProxy.AppHost.Tests.Fixtures; - using FluentAssertions; +using IdentityModel.Client; + +using AzureOpenAIProxy.AppHost.Tests.Fixtures; +using System.ComponentModel; namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; @@ -166,28 +167,124 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Res } // TODO: Add more tests for the component section + public static IEnumerable AttributeData => + new List + { + new object[] {"eventId", true, "string"}, + new object[] {"title", true, "string"}, + new object[] {"summary", true, "string"}, + new object[] {"description", false, "string"}, + new object[] {"dateStart", true, "string"}, + new object[] {"dateEnd", true, "string"}, + new object[] {"timeZone", true, "string"}, + new object[] {"isActive", true, "boolean"}, + new object[] {"organizerName", true, "string"}, + new object[] {"organizerEmail", true, "string"}, + new object[] {"coorganizerName", false, "string"}, + new object[] {"coorganizerEmail", false, "string"}, + new object[] {"maxTokenCap", true, "integer"}, + new object[] {"dailyRequestCap", true, "integer"} + }; + + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Schemas() + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("components") + .TryGetProperty("schemas", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Fact] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Model() + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("components") + .GetProperty("schemas") + .TryGetProperty("AdminEventDetails", out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + [Theory] - [InlineData(typeof(AdminEventDetails))] - public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Response_Property(Type type) + [MemberData(nameof(AttributeData))] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Required + (string attribute, bool isRequired, string type) { // Arrange using var httpClient = host.App!.CreateHttpClient("apiapp"); + var isReq = isRequired; + var typeStr = type; // Act var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); var openapi = JsonSerializer.Deserialize(json); // Assert - var component = openapi!.RootElement.GetProperty("components") - .GetProperty("schemas") - .GetProperty(type.Name) - .GetProperty("properties"); + var result = openapi!.RootElement.GetProperty("components") + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .TryGetStringArray("required") + .ToList(); + result.Contains(attribute).Should().Be(isRequired); + } - foreach (var prop in type.GetProperties()) - { - var propName = JsonNamingPolicy.CamelCase.ConvertName(prop.Name); - component.TryGetProperty(propName, out var jsonProp).Should().BeTrue(); - jsonProp.ValueKind.Should().Be(JsonValueKind.Object); - } + [Theory] + [MemberData(nameof(AttributeData))] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Property + (string attribute, bool isRequired, string type) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + var isReq = isRequired; + var typeStr = type; + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("components") + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .GetProperty("properties") + .TryGetProperty(attribute, out var property) ? property : default; + result.ValueKind.Should().Be(JsonValueKind.Object); + } + + [Theory] + [MemberData(nameof(AttributeData))] + public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Type + (string attribute, bool isRequired, string type) + { + // Arrange + using var httpClient = host.App!.CreateHttpClient("apiapp"); + var isReq = isRequired; + var typeStr = type; + + // Act + var json = await httpClient.GetStringAsync("/swagger/v1.0.0/swagger.json"); + var openapi = JsonSerializer.Deserialize(json); + + // Assert + var result = openapi!.RootElement.GetProperty("components") + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .GetProperty("properties") + .GetProperty(attribute); + result.TryGetString("type").Should().Be(type); } } diff --git a/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj b/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj index 16d0c64e..f7cc56ea 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj +++ b/test/AzureOpenAIProxy.AppHost.Tests/AzureOpenAIProxy.AppHost.Tests.csproj @@ -25,7 +25,6 @@ - From 00073a1df2aa4e3c5de74be26d3e5374489daccd Mon Sep 17 00:00:00 2001 From: juhangil Date: Tue, 20 Aug 2024 17:09:24 +0900 Subject: [PATCH 15/16] Update admin event test code style --- .../AdminGetEventDetailsOpenApiTests.cs | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs index 36e2850d..6ef9bea9 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs @@ -4,7 +4,6 @@ using IdentityModel.Client; using AzureOpenAIProxy.AppHost.Tests.Fixtures; -using System.ComponentModel; namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints; @@ -166,25 +165,23 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Res result.ValueKind.Should().Be(JsonValueKind.Object); } - // TODO: Add more tests for the component section public static IEnumerable AttributeData => - new List - { - new object[] {"eventId", true, "string"}, - new object[] {"title", true, "string"}, - new object[] {"summary", true, "string"}, - new object[] {"description", false, "string"}, - new object[] {"dateStart", true, "string"}, - new object[] {"dateEnd", true, "string"}, - new object[] {"timeZone", true, "string"}, - new object[] {"isActive", true, "boolean"}, - new object[] {"organizerName", true, "string"}, - new object[] {"organizerEmail", true, "string"}, - new object[] {"coorganizerName", false, "string"}, - new object[] {"coorganizerEmail", false, "string"}, - new object[] {"maxTokenCap", true, "integer"}, - new object[] {"dailyRequestCap", true, "integer"} - }; + [ + ["eventId", true, "string"], + ["title", true, "string"], + ["summary", true, "string"], + ["description", false, "string"], + ["dateStart", true, "string"], + ["dateEnd", true, "string"], + ["timeZone", true, "string"], + ["isActive", true, "boolean"], + ["organizerName", true, "string"], + ["organizerEmail", true, "string"], + ["coorganizerName", false, "string"], + ["coorganizerEmail", false, "string"], + ["maxTokenCap", true, "integer"], + ["dailyRequestCap", true, "integer"] + ]; [Fact] public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Schemas() @@ -198,7 +195,7 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Sch // Assert var result = openapi!.RootElement.GetProperty("components") - .TryGetProperty("schemas", out var property) ? property : default; + .TryGetProperty("schemas", out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Object); } @@ -214,8 +211,8 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Mod // Assert var result = openapi!.RootElement.GetProperty("components") - .GetProperty("schemas") - .TryGetProperty("AdminEventDetails", out var property) ? property : default; + .GetProperty("schemas") + .TryGetProperty("AdminEventDetails", out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Object); } @@ -235,10 +232,10 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Req // Assert var result = openapi!.RootElement.GetProperty("components") - .GetProperty("schemas") - .GetProperty("AdminEventDetails") - .TryGetStringArray("required") - .ToList(); + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .TryGetStringArray("required") + .ToList(); result.Contains(attribute).Should().Be(isRequired); } @@ -258,10 +255,10 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Pro // Assert var result = openapi!.RootElement.GetProperty("components") - .GetProperty("schemas") - .GetProperty("AdminEventDetails") - .GetProperty("properties") - .TryGetProperty(attribute, out var property) ? property : default; + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .GetProperty("properties") + .TryGetProperty(attribute, out var property) ? property : default; result.ValueKind.Should().Be(JsonValueKind.Object); } @@ -281,10 +278,10 @@ public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Typ // Assert var result = openapi!.RootElement.GetProperty("components") - .GetProperty("schemas") - .GetProperty("AdminEventDetails") - .GetProperty("properties") - .GetProperty(attribute); + .GetProperty("schemas") + .GetProperty("AdminEventDetails") + .GetProperty("properties") + .GetProperty(attribute); result.TryGetString("type").Should().Be(type); } } From 46f2f2882b0e780d5862b0ef50d599e67caef01a Mon Sep 17 00:00:00 2001 From: juhangil Date: Tue, 20 Aug 2024 17:27:42 +0900 Subject: [PATCH 16/16] Update admin event test package import style --- .../ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs index 6ef9bea9..73c32654 100644 --- a/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs +++ b/test/AzureOpenAIProxy.AppHost.Tests/ApiApp/Endpoints/AdminGetEventDetailsOpenApiTests.cs @@ -1,6 +1,7 @@ using System.Text.Json; using FluentAssertions; + using IdentityModel.Client; using AzureOpenAIProxy.AppHost.Tests.Fixtures;