refs #703: route schema metadata through MyBatis

This commit is contained in:
devmrko
2026-07-23 10:29:22 +09:00
parent a7ea010f5c
commit 94c7bc2e07
7 changed files with 372 additions and 143 deletions

View File

@@ -1,34 +1,101 @@
package com.cloudhandson.vpdbackoffice.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.cloudhandson.vpdbackoffice.config.CatalogProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.cloudhandson.vpdbackoffice.domain.schemametadata.SchemaMetadataAnnotationRow;
import com.cloudhandson.vpdbackoffice.domain.schemametadata.SchemaMetadataColumnRow;
import com.cloudhandson.vpdbackoffice.domain.schemametadata.SchemaMetadataView;
import com.cloudhandson.vpdbackoffice.domain.structured.StructuredDataTable;
import com.cloudhandson.vpdbackoffice.mapper.SchemaMetadataMapper;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
class SchemaMetadataServiceTest {
@Test
void rejectsAnnotationChangesForConfiguredViewsBeforeAnyDdl() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
DataCatalog catalog = new EnvironmentDataCatalog(
new CatalogProperties("ADMIN", """
[{"key":"employee-view","tableName":"HMM_EMPLOYEE_VIEW","objectType":"VIEW",
"businessName":"직원 뷰","description":"읽기 전용 직원 뷰"}]
"""),
new ObjectMapper());
StructuredDataService structuredDataService =
new StructuredDataService(jdbcTemplate, catalog);
SchemaMetadataService service =
new SchemaMetadataService(jdbcTemplate, structuredDataService);
private static final StructuredDataTable GAME_USERS = new StructuredDataTable(
"game-users", "CZN_COMN_USER_MST", "게임 사용자", "카제나 게임 사용자 마스터");
assertThatThrownBy(() ->
service.updateTableAnnotation("employee-view", "DISPLAY_NAME", "직원"))
private SchemaMetadataMapper mapper;
private SchemaMetadataService service;
@BeforeEach
void setUp() {
mapper = mock(SchemaMetadataMapper.class);
StructuredDataService structuredDataService = mock(StructuredDataService.class);
when(structuredDataService.requireTable("game-users")).thenReturn(GAME_USERS);
when(structuredDataService.tables()).thenReturn(List.of(GAME_USERS));
when(structuredDataService.defaultKey()).thenReturn("game-users");
service = new SchemaMetadataService(mapper, structuredDataService);
}
@Test
void readsOnlyTheSelectedSmilegateTableThroughMapper() {
when(mapper.findTableComment("SGMP_POC", "CZN_COMN_USER_MST"))
.thenReturn("게임별 사용자 기준 정보");
when(mapper.findAnnotations("SGMP_POC", "CZN_COMN_USER_MST")).thenReturn(List.of(
new SchemaMetadataAnnotationRow(null, "BUSINESS_TERM", "게임 사용자"),
new SchemaMetadataAnnotationRow("GUID", "BUSINESS_TERM", "사용자 고유 식별자"),
new SchemaMetadataAnnotationRow("GUID", "BUSINESS_TERM", "고객 계정 식별자")
));
when(mapper.findColumns("SGMP_POC", "CZN_COMN_USER_MST")).thenReturn(List.of(
new SchemaMetadataColumnRow("GUID", "VARCHAR2(64)", "N", "사용자 GUID")
));
SchemaMetadataView view = service.find("game-users");
assertThat(view.tableComment()).isEqualTo("게임별 사용자 기준 정보");
assertThat(view.tableAnnotations()).singleElement()
.extracting(annotation -> annotation.name(), annotation -> annotation.value())
.containsExactly("BUSINESS_TERM", "게임 사용자");
assertThat(view.columns()).singleElement()
.satisfies(column -> {
assertThat(column.columnName()).isEqualTo("GUID");
assertThat(column.nullable()).isFalse();
assertThat(column.annotations()).singleElement()
.extracting(annotation -> annotation.value())
.isEqualTo("사용자 고유 식별자\n--- duplicate annotation value ---\n고객 계정 식별자");
});
verify(mapper).findAnnotations("SGMP_POC", "CZN_COMN_USER_MST");
verify(mapper).findColumns("SGMP_POC", "CZN_COMN_USER_MST");
}
@Test
void replacesAnExistingColumnAnnotationUsingMapperDdl() {
when(mapper.countColumn("SGMP_POC", "CZN_COMN_USER_MST", "GUID")).thenReturn(1);
when(mapper.countColumnAnnotation("SGMP_POC", "CZN_COMN_USER_MST", "GUID", "BUSINESS_TERM"))
.thenReturn(1);
service.updateColumnAnnotation("game-users", "guid", "business_term", "사용자 고유 식별자");
verify(mapper).dropColumnAnnotation("SGMP_POC", "CZN_COMN_USER_MST", "GUID", "BUSINESS_TERM");
verify(mapper).addColumnAnnotation(
"SGMP_POC", "CZN_COMN_USER_MST", "GUID", "BUSINESS_TERM", "'사용자 고유 식별자'");
}
@Test
void clearsAnExistingTableAnnotationWithoutAddingAnEmptyValue() {
when(mapper.countTableAnnotation("SGMP_POC", "CZN_COMN_USER_MST", "BUSINESS_TERM"))
.thenReturn(1);
service.updateTableAnnotation("game-users", "business_term", " ");
verify(mapper).dropTableAnnotation("SGMP_POC", "CZN_COMN_USER_MST", "BUSINESS_TERM");
verify(mapper, never()).addTableAnnotation(anyString(), anyString(), anyString(), anyString());
}
@Test
void rejectsAColumnThatIsNotPresentInTheSelectedTable() {
when(mapper.countColumn("SGMP_POC", "CZN_COMN_USER_MST", "UNKNOWN_COL")).thenReturn(0);
assertThatThrownBy(() -> service.updateColumnComment("game-users", "unknown_col", "설명"))
.isInstanceOf(AppException.class)
.hasMessageContaining("TABLE 객체에서만");
verifyNoInteractions(jdbcTemplate);
.hasMessage("선택한 테이블에 존재하지 않는 컬럼입니다.");
}
}