Skip to content
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e93e518
add : Azure.Data.Tables 패키지 추가
tae0y Aug 31, 2024
b507d99
add : aspire.bicep 테이블 스토리지 추가
tae0y Aug 31, 2024
75d7042
add : 테이블 스토리지 연결, 데이터 생성 코드 준비
tae0y Aug 31, 2024
f4172b7
update : 병합 충돌 해소
tae0y Aug 31, 2024
b94bd2c
update : 테이블 스토리지 bicep 파일 분리, 별도 브랜치에서 작업
tae0y Sep 1, 2024
45b8e0c
update : events로 테이블명 변경
tae0y Sep 1, 2024
eaa6972
merge : 서비스, 레포지토리 추가 병합
tae0y Sep 1, 2024
290d971
update : 빌드오류 임시조치
tae0y Sep 1, 2024
9177a70
Merge branch 'aliencube:main' into feature/213-admin-event-create
tae0y Sep 3, 2024
9ad61bf
Merge branch 'aliencube:main' into feature/213-admin-event-create
tae0y Sep 6, 2024
b729ad0
Merge main into feature/213-admin-event-create
tae0y Sep 13, 2024
c158308
update : 작업내용 placeholder 추가
tae0y Sep 13, 2024
9b82301
update : ITableEntity 구현, TableClient 의존성 주입
tae0y Sep 14, 2024
954c43e
update : 객체 영속성 저장후 재조회
tae0y Sep 14, 2024
419a973
update : AdminEventDetails 역직렬화시 Etag 제외
tae0y Sep 14, 2024
30e911c
Merge branch 'main' into feature/213-admin-event-create
tae0y Sep 14, 2024
f17bd29
commit message 변경후 conflict 해소
tae0y Sep 14, 2024
719d973
update : null, 응답코드 처리 추가
tae0y Sep 14, 2024
a521674
add : 테스트 추가
tae0y Sep 14, 2024
ec396dd
update : repository/service 레이어별 로직 분리, 테스트 추가
tae0y Sep 15, 2024
b6f66f2
Merge branch 'main' into feature/213-admin-event-create
tae0y Sep 16, 2024
ada1f22
Merge branch 'main' into feature/213-admin-event-create
tae0y Sep 21, 2024
9385d2f
update : AdminEventDetails 불필요 ITableEntity 구현 제거
tae0y Sep 21, 2024
69f35d3
update : AdminEventService 필수값체크 및 PartitionKey 불필요 로직제거
tae0y Sep 21, 2024
17c9799
delete : 불필요 로컬 파일 제거
tae0y Sep 21, 2024
9548f5f
update : 테이블이름 하드코딩→동적조회
tae0y Sep 21, 2024
9b50e75
update : tableClient 이름변경
tae0y Sep 21, 2024
ca183e0
update : 저장후 재조회 로직 제거
tae0y Sep 21, 2024
1c6c2d6
update : 불필요 변경사항 롤백
tae0y Sep 21, 2024
9bef6ab
update : tableclient 조회 wrapper 메서드 추가
tae0y Sep 21, 2024
a836420
update : aspire.bicep 병합/변경충돌 정리
tae0y Sep 21, 2024
7a7d848
Merge branch 'main' into feature/213-admin-event-create
tae0y Sep 25, 2024
55db6d6
update : 병합후 repository 테이블 클라이언트, 파티션키 로직변경
tae0y Sep 25, 2024
473da19
update : 단위테스트 수정
tae0y Sep 25, 2024
2b466c7
update : 빌드오류 방지 임시조치
tae0y Sep 28, 2024
d77ca2c
update : OpenAIApiClient 빌드오류 임시조치 원복
tae0y Sep 28, 2024
3f4b1e1
Merge branch 'main' into feature/213-admin-event-create
tae0y Oct 2, 2024
74d9674
update : repository 불필요 각주 제거
tae0y Oct 4, 2024
9516436
update : unit test tableclient 목킹 추가
tae0y Oct 4, 2024
a083391
update : unit test AddEntityAsync 목킹 추가
tae0y Oct 4, 2024
6274ead
remote build 재시도
tae0y Oct 4, 2024
bbdbd68
update : 작업사항 목록화
tae0y Oct 12, 2024
0ff2663
Merge branch 'main' into feature/213-admin-event-create
tae0y Oct 12, 2024
f695a7c
update : Endpoint 유효성검사 필요여부 확인
tae0y Oct 12, 2024
4b5a1bd
update : RepositoryTests 예외발생 관점으로 테스트작성
tae0y Oct 12, 2024
78ffc92
update : ServiceTests 예외발생 관점으로 테스트작성, 필수값 없을 때는 payload 언마샬 실패로 테스트 불요
tae0y Oct 12, 2024
e503167
Merge branch 'main' into feature/213-admin-event-create
tae0y Oct 12, 2024
1988f7f
Merge branch 'main' into feature/213-admin-event-create
tae0y Oct 17, 2024
2587bd6
update : repo/service 반환값 검사하는 테스트로 수정
tae0y Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/AzureOpenAIProxy.ApiApp/Endpoints/AdminEventEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,20 @@ public static RouteHandlerBuilder AddNewAdminEvent(this WebApplication app)
return Results.BadRequest("Payload is null");
}

//try
//{
// var result = await service.CreateEvent(payload);

// logger.LogInformation("Created a new event");
try
{
var result = await service.CreateEvent(payload);

// return Results.Ok(result);
//}
//catch (Exception ex)
//{
// logger.LogError(ex, "Failed to create a new event");
logger.LogInformation("Created a new event");

// return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
//}
return Results.Ok(result);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to create a new event");

return await Task.FromResult(Results.Ok());
return Results.Problem(ex.Message, statusCode: StatusCodes.Status500InternalServerError);
}
})
.Accepts<AdminEventDetails>(contentType: "application/json")
.Produces<AdminEventDetails>(statusCode: StatusCodes.Status200OK, contentType: "application/json")
Expand Down
3 changes: 3 additions & 0 deletions src/AzureOpenAIProxy.ApiApp/Models/AdminEventDetails.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Text.Json.Serialization;

using Azure;
using Azure.Data.Tables;

namespace AzureOpenAIProxy.ApiApp.Models;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,18 @@
/// <inheritdoc />
public async Task<AdminEventDetails> CreateEvent(AdminEventDetails eventDetails)
{
throw new NotImplementedException();
// 테이블 클라이언트
TableClient tableClient = await GetTableClientAsync();

// 데이터 저장
await tableClient.AddEntityAsync(eventDetails).ConfigureAwait(false);

// 저장한 엔티티 반환
return eventDetails;
}

/// <inheritdoc />
public async Task<List<AdminEventDetails>> GetEvents()

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

View workflow job for this annotation

GitHub Actions / build-test

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();
}
Expand All @@ -74,7 +81,7 @@
}

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

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

View workflow job for this annotation

GitHub Actions / build-test

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();
}
Expand Down
10 changes: 7 additions & 3 deletions src/AzureOpenAIProxy.ApiApp/Services/AdminEventService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ public class AdminEventService(IAdminEventRepository repository) : IAdminEventSe
/// <inheritdoc />
public async Task<AdminEventDetails> CreateEvent(AdminEventDetails eventDetails)
{
var result = await this._repository.CreateEvent(eventDetails).ConfigureAwait(false);

return result;
// Validate
eventDetails.PartitionKey = PartitionKeys.EventDetails;
eventDetails.RowKey = eventDetails.EventId.ToString();

// Save
var response = await this._repository.CreateEvent(eventDetails).ConfigureAwait(false);
return response;
}

/// <inheritdoc />
Expand Down
57 changes: 30 additions & 27 deletions src/AzureOpenAIProxy.ApiApp/appsettings.Development.sample.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},

"Azure": {
"OpenAI": {
"Instances": [
{
"Endpoint": "https://{{location}}.api.cognitive.microsoft.com/",
"ApiKey": "{{api-key}}",
"DeploymentNames": [
"deployment-name-1",
"deployment-name-2"
]
}
]
},
"KeyVault": {
"VaultUri": "https://{{key-vault-name}}.vault.azure.net/",
"SecretName": "azure-openai-instances"
}
}
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},

"Azure": {
"OpenAI": {
"Instances": [
{
"Endpoint": "https://{{location}}.api.cognitive.microsoft.com/",
"ApiKey": "{{api-key}}",
"DeploymentNames": [
"deployment-name-1",
"deployment-name-2"
]
}
]
},
"KeyVault": {
"VaultUri": "https://{{key-vault-name}}.vault.azure.net/",
"SecretNames": {
"OpenAI": "azure-openai-instances",
"Storage": "storage-connection-string"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
var tableServiceClient = default(TableServiceClient);

// Act
Action action = () => new AdminEventRepository(tableServiceClient, settings);

Check warning on line 40 in test/AzureOpenAIProxy.ApiApp.Tests/Repositories/AdminEventRepositoryTests.cs

View workflow job for this annotation

GitHub Actions / build-test

Possible null reference argument for parameter 'tableServiceClient' in 'AdminEventRepository.AdminEventRepository(TableServiceClient tableServiceClient, StorageAccountSettings storageAccountSettings)'.

// Assert
action.Should().Throw<ArgumentNullException>();
Expand All @@ -51,26 +51,53 @@
var tableServiceClient = Substitute.For<TableServiceClient>();

// Act
Action action = () => new AdminEventRepository(tableServiceClient, settings);

Check warning on line 54 in test/AzureOpenAIProxy.ApiApp.Tests/Repositories/AdminEventRepositoryTests.cs

View workflow job for this annotation

GitHub Actions / build-test

Possible null reference argument for parameter 'storageAccountSettings' in 'AdminEventRepository.AdminEventRepository(TableServiceClient tableServiceClient, StorageAccountSettings storageAccountSettings)'.

// Assert
action.Should().Throw<ArgumentNullException>();
}

[Fact]
public void Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception()
public async Task Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Not_Throw_Exception()
{
// Arrange
var settings = Substitute.For<StorageAccountSettings>();
var tableServiceClient = Substitute.For<TableServiceClient>();
var tableClient = Substitute.For<TableClient>();
tableServiceClient.GetTableClient(Arg.Any<string>()).Returns(tableClient);
tableClient.AddEntityAsync<AdminEventDetails>(Arg.Any<AdminEventDetails>())
.Returns(Task.FromResult(default(Response)));
var eventDetails = new AdminEventDetails();
var repository = new AdminEventRepository(tableServiceClient, settings);

// Act
Func<Task> func = () => repository.CreateEvent(eventDetails);

// Assert
await func.Should().NotThrowAsync<InvalidOperationException>();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래에서 예외가 발생한다는 것을 테스트했고, 여기서는 예외가 발생하지 않고 결과를 반환한다는 것을 테스트하면 좋겠습니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repository.CreateEvent는 예외가 발생하지 않으면 메서드 인수를 그대로 반환합니다.
그래서 result.Should().BeEquivalentTo(eventDetails); 리턴값이 인수와 동일한지 확인했습니다!


[Fact]
public async Task Given_Failure_In_Add_Entity_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception()
{
// Arrange
var settings = Substitute.For<StorageAccountSettings>();
var tableServiceClient = Substitute.For<TableServiceClient>();
var repository = new AdminEventRepository(tableServiceClient, settings);
var eventDetails = new AdminEventDetails();

var exception = new InvalidOperationException("Invalid Operation Error : check duplicate, null or empty values");

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

// Act
Func<Task> func = async () => await repository.CreateEvent(eventDetails);
Func<Task> func = () => repository.CreateEvent(eventDetails);

// Assert
func.Should().ThrowAsync<NotImplementedException>();
await func.Should().ThrowAsync<InvalidOperationException>();
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

using FluentAssertions;

using Microsoft.AspNetCore.Authentication;

using Microsoft.Extensions.DependencyInjection;

using NSubstitute;
Expand All @@ -29,18 +31,39 @@ public void Given_ServiceCollection_When_AddAdminEventService_Invoked_Then_It_Sh
}

[Fact]
public void Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception()
public async Task Given_Instance_When_CreateEvent_Invoked_Then_It_Should_Not_Throw_Exception()
{
// Arrange
var eventDetails = new AdminEventDetails();

var repository = Substitute.For<IAdminEventRepository>();
var service = new AdminEventService(repository);

repository.CreateEvent(Arg.Any<AdminEventDetails>()).Returns(eventDetails);

// Act
Func<Task> func = async () => await service.CreateEvent(eventDetails);
Func<Task> func = () => service.CreateEvent(eventDetails);

// Assert
func.Should().ThrowAsync<NotImplementedException>();
await func.Should().NotThrowAsync<InvalidOperationException>();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 마찬가지로 예외를 반환하지 않고 결과값을 반환한다는 것을 테스트합니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다!


[Fact]
public async Task Given_Failure_In_Add_Entity_When_CreateEvent_Invoked_Then_It_Should_Throw_Exception()
{
// Arrange
var eventDetails = new AdminEventDetails();
var repository = Substitute.For<IAdminEventRepository>();
var service = new AdminEventService(repository);

var exception = new InvalidOperationException("Invalid Operation Error : check duplicate, null or empty values");
repository.CreateEvent(Arg.Any<AdminEventDetails>()).ThrowsAsync(exception);

// Act
Func<Task> func = () => service.CreateEvent(eventDetails);

// Assert
await func.Should().ThrowAsync<InvalidOperationException>();
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace AzureOpenAIProxy.AppHost.Tests.ApiApp.Endpoints;

public class AdminGetEventsOpenApiTests(AspireAppHostFixture host) : IClassFixture<AspireAppHostFixture>
{
// TODO: [tae0y] 테스트코드 작성하기
[Fact]
public async Task Given_Resource_When_Invoked_Endpoint_Then_It_Should_Return_Path()
{
Expand Down
Loading