Skip to content

Commit

Permalink
[Backend API] Implement endpoint for view event details (#318)
Browse files Browse the repository at this point in the history
  • Loading branch information
sikutisa authored Sep 23, 2024
1 parent c7991e7 commit f2dc471
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 18 deletions.
35 changes: 30 additions & 5 deletions src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Azure;

using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Services;

Expand Down Expand Up @@ -107,12 +109,35 @@ public static RouteHandlerBuilder AddGetAdminEvent(this WebApplication app)
{
// Todo: Issue #19 https://github.com/aliencube/azure-openai-sdk-proxy/issues/19
// Need authorization by admin
var builder = app.MapGet(AdminEndpointUrls.AdminEventDetails, (
[FromRoute] string eventId) =>
var builder = app.MapGet(AdminEndpointUrls.AdminEventDetails, async (
[FromRoute] Guid eventId,
IAdminEventService service,
ILoggerFactory loggerFactory) =>
{
// Todo: Issue #208 https://github.com/aliencube/azure-openai-sdk-proxy/issues/208
return Results.Ok();
// Todo: Issue #208
var logger = loggerFactory.CreateLogger(nameof(AdminEventEndpoints));
logger.LogInformation($"Received request to fetch details for event with ID: {eventId}");
try
{
var details = await service.GetEvent(eventId);
return Results.Ok(details);
}
catch(RequestFailedException ex)
{
if(ex.Status == 404)
{
logger.LogError($"Failed to get event details of {eventId}");
return Results.NotFound();
}
logger.LogError(ex, $"Error occurred while fetching event details of {eventId} with status {ex.Status}");
return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
}
catch(Exception ex)
{
logger.LogError(ex, $"Error occurred while fetching event details of {eventId}");
return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
}
})
.Produces<AdminEventDetails>(statusCode: StatusCodes.Status200OK, contentType: "application/json")
.Produces(statusCode: StatusCodes.Status401Unauthorized)
Expand Down
17 changes: 17 additions & 0 deletions src/AzureOpenAIProxy.ApiApp/PartitionKeys.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AzureOpenAIProxy.ApiApp;

/// <summary>
/// This represents the partition keys for azure table storage
/// </summary>
public class PartitionKeys
{
/// <summary>
/// Partition key for event details
/// </summary>
public const string EventDetails = "event-details";

/// <summary>
/// Partition key for resource details
/// </summary>
public const string ResourceDetails = "resource-details";
}
18 changes: 17 additions & 1 deletion src/AzureOpenAIProxy.ApiApp/Repositories/AdminEventRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,30 @@ public async Task<List<AdminEventDetails>> GetEvents()
/// <inheritdoc />
public async Task<AdminEventDetails> GetEvent(Guid eventId)
{
throw new NotImplementedException();
TableClient tableClient = await GetTableClientAsync();

var eventDetail = await tableClient.GetEntityAsync<AdminEventDetails>(
rowKey: eventId.ToString(),
partitionKey: PartitionKeys.EventDetails
).ConfigureAwait(false);

return eventDetail.Value;
}

/// <inheritdoc />
public async Task<AdminEventDetails> UpdateEvent(Guid eventId, AdminEventDetails eventDetails)

Check warning on line 77 in src/AzureOpenAIProxy.ApiApp/Repositories/AdminEventRepository.cs

View workflow job for this annotation

GitHub Actions / build-test-deploy

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 77 in src/AzureOpenAIProxy.ApiApp/Repositories/AdminEventRepository.cs

View workflow job for this annotation

GitHub Actions / build-test-deploy

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 77 in src/AzureOpenAIProxy.ApiApp/Repositories/AdminEventRepository.cs

View workflow job for this annotation

GitHub Actions / build-test-deploy

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
throw new NotImplementedException();
}

private async Task<TableClient> GetTableClientAsync()
{
TableClient tableClient = _tableServiceClient.GetTableClient(_storageAccountSettings.TableStorage.TableName);

await tableClient.CreateIfNotExistsAsync().ConfigureAwait(false);

return tableClient;
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using Azure.Data.Tables;
using Azure;
using Azure.Data.Tables;

using AzureOpenAIProxy.ApiApp.Configurations;
using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Repositories;

using Castle.Core.Configuration;

using FluentAssertions;

using Microsoft.Extensions.DependencyInjection;

using NSubstitute;
using NSubstitute.ExceptionExtensions;

namespace AzureOpenAIProxy.ApiApp.Tests.Repositories;

Expand Down Expand Up @@ -88,20 +88,59 @@ public void Given_Instance_When_GetEvents_Invoked_Then_It_Should_Throw_Exception
func.Should().ThrowAsync<NotImplementedException>();
}

[Fact]
public void Given_Instance_When_GetEvent_Invoked_Then_It_Should_Throw_Exception()
[Theory]
[InlineData(404)]
[InlineData(500)]
public async Task Given_Failure_In_Get_Entity_When_GetEvent_Invoked_Then_It_Should_Throw_Exception(int statusCode)
{
// Arrange
var settings = Substitute.For<StorageAccountSettings>();
var tableServiceClient = Substitute.For<TableServiceClient>();
var eventId = Guid.NewGuid();
var repository = new AdminEventRepository(tableServiceClient, settings);

var exception = new RequestFailedException(statusCode, "Request Error", default, default);

var tableClient = Substitute.For<TableClient>();
tableServiceClient.GetTableClient(Arg.Any<string>()).Returns(tableClient);
tableClient.GetEntityAsync<AdminEventDetails>(Arg.Any<string>(), Arg.Any<string>())
.ThrowsAsync(exception);

// Act
Func<Task> func = async () => await repository.GetEvent(eventId);
Func<Task> func = () => repository.GetEvent(eventId);

// Assert
func.Should().ThrowAsync<NotImplementedException>();
var assertion = await func.Should().ThrowAsync<RequestFailedException>();
assertion.Which.Status.Should().Be(statusCode);
}

[Theory]
[InlineData("c355cc28-d847-4637-aad9-2f03d39aa51f", "event-details")]
public async Task Given_Exist_EventId_When_GetEvent_Invoked_Then_It_Should_Return_AdminEventDetails(string eventId, string partitionKey)
{
// Arrange
var settings = Substitute.For<StorageAccountSettings>();
var tableServiceClient = Substitute.For<TableServiceClient>();
var repository = new AdminEventRepository(tableServiceClient, settings);

var eventDetails = new AdminEventDetails
{
RowKey = eventId,
PartitionKey = partitionKey
};

var response = Response.FromValue(eventDetails, Substitute.For<Response>());

var tableClient = Substitute.For<TableClient>();
tableServiceClient.GetTableClient(Arg.Any<string>()).Returns(tableClient);
tableClient.GetEntityAsync<AdminEventDetails>(partitionKey, eventId)
.Returns(Task.FromResult(response));

// Act
var result = await repository.GetEvent(Guid.Parse(eventId));

// Assert
result.Should().BeEquivalentTo(eventDetails);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using AzureOpenAIProxy.ApiApp.Models;
using Azure;

using AzureOpenAIProxy.ApiApp.Models;
using AzureOpenAIProxy.ApiApp.Repositories;
using AzureOpenAIProxy.ApiApp.Services;

Expand All @@ -7,6 +9,7 @@
using Microsoft.Extensions.DependencyInjection;

using NSubstitute;
using NSubstitute.ExceptionExtensions;

namespace AzureOpenAIProxy.ApiApp.Tests.Services;

Expand Down Expand Up @@ -54,19 +57,51 @@ public void Given_Instance_When_GetEvents_Invoked_Then_It_Should_Throw_Exception
func.Should().ThrowAsync<NotImplementedException>();
}

[Fact]
public void Given_Instance_When_GetEvent_Invoked_Then_It_Should_Throw_Exception()

[Theory]
[InlineData(404)]
[InlineData(500)]
public async Task Given_Failure_In_Get_Entity_When_GetEvent_Invoked_Then_It_Should_Throw_Exception(int statusCode)
{
// Arrange
var eventId = Guid.NewGuid();
var repository = Substitute.For<IAdminEventRepository>();
var service = new AdminEventService(repository);

var exception = new RequestFailedException(statusCode, "Request Failed", default, default);

repository.GetEvent(Arg.Any<Guid>()).ThrowsAsync(exception);

// Act
Func<Task> func = async () => await service.GetEvent(eventId);
Func<Task> func = () => service.GetEvent(eventId);

// Assert
func.Should().ThrowAsync<NotImplementedException>();
var assertion = await func.Should().ThrowAsync<RequestFailedException>();
assertion.Which.Status.Should().Be(statusCode);
}

[Theory]
[InlineData("c355cc28-d847-4637-aad9-2f03d39aa51f")]
public async Task Given_Exist_EventId_When_GetEvent_Invoked_Then_It_Should_Return_AdminEventDetails(string eventId)
{
// Arrange
var repository = Substitute.For<IAdminEventRepository>();
var service = new AdminEventService(repository);

var eventDetails = new AdminEventDetails
{
RowKey = eventId
};

var guid = Guid.Parse(eventId);

repository.GetEvent(guid).Returns(Task.FromResult(eventDetails));

// Act
var result = await service.GetEvent(guid);

// Assert
result.Should().BeEquivalentTo(eventDetails);
}

[Fact]
Expand Down

0 comments on commit f2dc471

Please sign in to comment.