package com.cloudhandson.vpdbackoffice.service; import static org.assertj.core.api.Assertions.assertThat; import com.cloudhandson.vpdbackoffice.config.BackofficeProperties; import com.cloudhandson.vpdbackoffice.config.McpProperties; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.jupiter.api.Test; class McpSseServiceTest { private final ObjectMapper objectMapper = new ObjectMapper(); private final SelectAiService selectAiService = new CapturingSelectAiService(); private final McpSseService service = new McpSseService( selectAiService, objectMapper, new BackofficeProperties( null, null, null, null, new BackofficeProperties.SelectAi("", "", "", "SGMP_POC_OCI_GPT54MINI") ), new McpProperties( "oracle.select_ai.test_data_text2sql", "테스트 데이터 Text2SQL", "테스트 데이터용 읽기 전용 SQL을 생성하고 실행합니다.", "테스트 데이터의 조회 내용을 입력합니다." ) ); @Test void listsOnlyVpdSelectAiToolWithPromptInput() { ObjectNode response = service.handle("default", request(1, "tools/list")); var tools = response.path("result").path("tools"); assertThat(tools).hasSize(1); var selectAi = tools.get(0); assertThat(selectAi.path("name").asText()).isEqualTo("oracle.select_ai.test_data_text2sql"); assertThat(selectAi.path("description").asText()).contains("SGMP_POC_OCI_GPT54MINI"); assertThat(selectAi.path("inputSchema").path("required")) .extracting(node -> node.asText()) .contains("prompt"); assertThat(selectAi.path("inputSchema").path("properties").has("bearerToken")).isFalse(); assertThat(selectAi.path("inputSchema").path("properties").has("limit")).isFalse(); assertThat(selectAi.path("inputSchema").path("properties").has("conversationId")).isFalse(); } @Test void callsVpdSelectAiThroughOrdsService() { ObjectNode request = request(2, "tools/call"); ObjectNode params = (ObjectNode) request.putObject("params"); params.put("name", "oracle.select_ai.test_data_text2sql"); ObjectNode arguments = params.putObject("arguments"); arguments.put("prompt", "카제나 AU를 조회해 줘"); ObjectNode response = service.handle("default", request, "user-bearer"); CapturingSelectAiService agentService = (CapturingSelectAiService) selectAiService; assertThat(agentService.bearerToken).isEqualTo("user-bearer"); assertThat(agentService.prompt).isEqualTo("카제나 AU를 조회해 줘"); assertThat(response.path("error").isMissingNode()).isTrue(); assertThat(response.path("result").path("isError").asBoolean()).isFalse(); String payload = response.path("result").path("content").get(0).path("text").asText(); assertThat(payload) .contains("SGMP_POC_OCI_GPT54MINI") .contains("SELECT 1 FROM DUAL") .contains("SHOWSQL_AND_EXECUTED") .contains("READ_ONLY_EXECUTED") .contains("RESULT"); } @Test void returnsToolLevelDeniedResultWhenVpdTokenIsMissing() { ObjectNode request = request(3, "tools/call"); ObjectNode params = (ObjectNode) request.putObject("params"); params.put("name", "oracle.select_ai.test_data_text2sql"); params.putObject("arguments").put("prompt", "카제나 AU를 조회해 줘"); ObjectNode response = service.handle("default", request, ""); assertThat(response.path("error").isMissingNode()).isTrue(); assertThat(response.path("result").path("isError").asBoolean()).isTrue(); assertThat(response.path("result").path("content").get(0).path("text").asText()) .contains("VPD_TOKEN_DENIED") .contains("권한이 없습니다"); } private ObjectNode request(int id, String method) { ObjectNode request = objectMapper.createObjectNode(); request.put("jsonrpc", "2.0"); request.put("id", id); request.put("method", method); return request; } private static final class CapturingSelectAiService extends SelectAiService { private String bearerToken; private String prompt; private CapturingSelectAiService() { super(null, null, null, new ObjectMapper()); } @Override public JsonNode generateAndExecute(String bearerToken, String prompt) { this.bearerToken = bearerToken; this.prompt = prompt; ObjectNode response = new ObjectMapper().createObjectNode() .put("profile", "SGMP_POC_OCI_GPT54MINI") .put("generatedSql", "SELECT 1 FROM DUAL") .put("status", "SHOWSQL_AND_EXECUTED") .put("execution", "READ_ONLY_EXECUTED") .put("rowCount", 1); response.putArray("items").addObject().put("RESULT", 1); return response; } } }