[Developer] #567 add VPD SQL execution evidence

This commit is contained in:
devmrko
2026-07-01 13:47:30 +09:00
parent 07c090f6b0
commit bf393bffa5
13 changed files with 398 additions and 11 deletions

View File

@@ -122,4 +122,38 @@ class ProbeResultTest {
assertThat(result.effectiveSql()).contains("ADMIN.DOCUMENTS");
assertThat(result.rowCount()).isEqualTo(1);
}
@Test
void keepsDatabaseExecutionEvidenceSeparateFromTheReconstructedSql() {
SqlExecutionEvidence evidence = new SqlExecutionEvidence(
"4f2jz7n2k0s3p",
1,
"SELECT d.doc_id FROM ADMIN.CB_V_SEARCH_DOCUMENTS d WHERE ROWNUM <= :1",
"2026-07-01T10:00:00",
3,
12,
35,
120,
"Predicate Information (identified by operation id):\n1 - filter(DEPT_CODE = SYS_CONTEXT(...))"
);
ProbeResult result = new ProbeResult(
ProbeStatus.SUCCESS,
List.of("DOC_ID"),
List.of(Map.of("DOC_ID", 1)),
1,
List.of(),
null,
null,
null,
null,
null,
null
).withSqlTrace("DEPT_CODE = SYS_CONTEXT(...)", "SELECT ... WHERE (...)")
.withExecutionEvidence(evidence, null);
assertThat(result.hasExecutionEvidence()).isTrue();
assertThat(result.executionEvidence().sqlId()).isEqualTo("4f2jz7n2k0s3p");
assertThat(result.executionEvidence().hasPredicatePlan()).isTrue();
assertThat(result.effectiveSql()).contains("WHERE");
}
}

View File

@@ -95,7 +95,8 @@ class GuidedFlowTemplateTest {
.doesNotContain("name=\"tokenKeyId\"");
assertThat(result)
.contains("적용된 사용자와 권한")
.contains("토큰 적용 후 SQL")
.contains("DB 실행 증적")
.contains("권한 조건 재현 SQL")
.contains("set_vpd_context 사용자 컨텍스트")
.contains("CB_AGENT_CTX.USER_ID")
.contains("벡터 유사도 검색 기준")
@@ -243,12 +244,16 @@ class GuidedFlowTemplateTest {
}
@Test
void probeResultExplainsVectorEffectiveSqlWhenTheHandlerReturnsTrace() throws IOException {
void probeResultSeparatesDbExecutionEvidenceFromReconstructedSql() throws IOException {
String result = template("fragments/probe-result.html");
String vectorSql = Files.readString(Path.of("sql/adb/29_agent_ords_vector_search_ords.sql"));
assertThat(result)
.contains("토큰 적용 후 SQL")
.contains("DB 실행 증적")
.contains("DB가 기록한 원문 SQL")
.contains("DBMS_XPLAN Predicate Information")
.contains("SQL_ID")
.contains("권한 조건 재현 SQL")
.contains("권한 적용 SQL")
.contains("VPD가 추가한 WHERE 조건")
.contains("ALL: 추가 행 필터 없음")

View File

@@ -0,0 +1,51 @@
package com.cloudhandson.vpdbackoffice.web;
import static org.assertj.core.api.Assertions.assertThat;
import com.cloudhandson.vpdbackoffice.domain.probe.ProbeResult;
import com.cloudhandson.vpdbackoffice.domain.probe.ProbeStatus;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.FileTemplateResolver;
class ProbeResultTemplateRenderTest {
@Test
void rendersRecentSqlEvidenceUnavailableMessageAsTextNotAsABoolean() {
var resolver = new FileTemplateResolver();
resolver.setPrefix(Path.of("src/main/resources/templates").toAbsolutePath() + "/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML");
resolver.setCacheable(false);
var engine = new SpringTemplateEngine();
engine.setTemplateResolver(resolver);
ProbeResult result = new ProbeResult(
ProbeStatus.SUCCESS,
List.of("DOC_ID"),
List.of(Map.of("DOC_ID", 1)),
1,
List.of(),
null,
null,
"{}",
"{}",
"{}",
"{}"
).withExecutionEvidence(null, "최근 SQL_ID를 찾지 못했습니다.");
var context = new Context(Locale.KOREAN);
context.setVariable("result", result);
context.setVariable("vectorSearch", false);
context.setVariable("tokenContext", null);
context.setVariable("selectedObject", null);
String rendered = engine.process("fragments/probe-result", context);
assertThat(rendered).contains("최근 SQL_ID를 찾지 못했습니다.");
}
}