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); } }