Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
103 lines
3.5 KiB
Java
103 lines
3.5 KiB
Java
package ru.pdguard;
|
|
|
|
import static io.restassured.RestAssured.given;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import io.restassured.path.json.JsonPath;
|
|
import java.util.Map;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
|
|
|
/** Демонстрационное плечо: потребитель → маскирование → LLM → демаскирование. */
|
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
class ProxyResourceTest {
|
|
|
|
@LocalServerPort int port;
|
|
|
|
private static final String PROMPT =
|
|
"Составь письмо клиенту Иванову Ивану Ивановичу, паспорт 4509 123456, почта ivan@mail.ru";
|
|
|
|
private JsonPath proxy(String prompt) {
|
|
return given()
|
|
.port(port)
|
|
.contentType("application/json")
|
|
.body(Map.of("prompt", prompt))
|
|
.when()
|
|
.post("/proxy")
|
|
.then()
|
|
.statusCode(200)
|
|
.extract()
|
|
.jsonPath();
|
|
}
|
|
|
|
@Test
|
|
void personalDataDoesNotReachTheModel() {
|
|
JsonPath json = proxy(PROMPT);
|
|
String toModel = json.getString("prompt_masked");
|
|
|
|
assertFalse(toModel.contains("Иванову Ивану Ивановичу"), toModel);
|
|
assertFalse(toModel.contains("4509 123456"), toModel);
|
|
assertFalse(toModel.contains("ivan@mail.ru"), toModel);
|
|
}
|
|
|
|
@Test
|
|
void consumerGetsTheAnswerWithOriginalValues() {
|
|
JsonPath json = proxy(PROMPT);
|
|
String answer = json.getString("response");
|
|
|
|
assertTrue(answer.contains("Иванову Ивану Ивановичу"), answer);
|
|
assertTrue(answer.contains("4509 123456"), answer);
|
|
assertTrue(answer.contains("ivan@mail.ru"), answer);
|
|
}
|
|
|
|
@Test
|
|
void responseShowsTheWholeChain() {
|
|
JsonPath json = proxy(PROMPT);
|
|
|
|
assertTrue(
|
|
json.getString("prompt_masked").contains("[FIO_1]"),
|
|
"в модель уходит обратимая подстановка: " + json.getString("prompt_masked"));
|
|
assertTrue(
|
|
json.getString("llm_response_masked").contains("[FIO_1]"),
|
|
"ответ модели ещё содержит подстановки");
|
|
assertFalse(json.getString("response").contains("[FIO_1]"), "потребителю подстановки не видны");
|
|
assertEquals("заглушка", json.getString("llm"));
|
|
assertFalse(json.getMap("replaced").isEmpty(), "таблица замен не должна быть пустой");
|
|
}
|
|
|
|
@Test
|
|
void textWithoutPersonalDataPassesThrough() {
|
|
JsonPath json = proxy("Объясни разницу между вкладом и накопительным счётом");
|
|
assertEquals(
|
|
"Объясни разницу между вкладом и накопительным счётом", json.getString("prompt_masked"));
|
|
}
|
|
|
|
@Test
|
|
void rejectsEmptyPrompt() {
|
|
given()
|
|
.port(port)
|
|
.contentType("application/json")
|
|
.body(Map.of("prompt", " "))
|
|
.when()
|
|
.post("/proxy")
|
|
.then()
|
|
.statusCode(400);
|
|
}
|
|
|
|
@Test
|
|
void disabledSystemIsRefused() {
|
|
given()
|
|
.port(port)
|
|
.contentType("application/json")
|
|
.header("X-System-Id", "disabled")
|
|
.body(Map.of("prompt", PROMPT))
|
|
.when()
|
|
.post("/proxy")
|
|
.then()
|
|
.statusCode(403);
|
|
}
|
|
}
|