refactor: подтянуть Legal NER, переформатировать код и добавить тесты

Слияние с 685ec97 (третья ступень NER для юридических реквизитов),
код приведён к google-java-format, добавлены юнит-тесты
AdaptiveConcurrencyLimiter/SystemsConfig/PayloadCipher.
This commit is contained in:
Максименко Никита Владимирович
2026-09-23 22:02:45 +03:00
parent 84b5adcb3f
commit 573d94cca8
79 changed files with 7385 additions and 6430 deletions
+109 -108
View File
@@ -1,5 +1,11 @@
package ru.pdguard;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import ru.pdguard.config.SystemPolicy;
import ru.pdguard.core.PayloadStore;
@@ -8,132 +14,127 @@ import ru.pdguard.detect.PdTypes;
import ru.pdguard.detect.RuleRegistry;
import ru.pdguard.mask.Masker;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** Проверки маскирования и обратного преобразования без подъёма HTTP-слоя. */
class PipelineTest {
private static final String VALID_CARD = "4111 1111 1111 1111";
private static final String VALID_INN_12 = "770301234550";
private static final String VALID_SNILS = "112-233-445 95";
private static final String VALID_CARD = "4111 1111 1111 1111";
private static final String VALID_INN_12 = "770301234550";
private static final String VALID_SNILS = "112-233-445 95";
private Pipeline pipeline() {
return new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
private Pipeline pipeline() {
return new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
}
private String mask(Pipeline pipeline, String text) {
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
}
@Test
void masksCardNumber() {
String masked = mask(pipeline(), "Оплата картой " + VALID_CARD + " прошла");
assertFalse(masked.contains(VALID_CARD), "номер карты остался в тексте: " + masked);
assertTrue(masked.contains("41** **** **** **11"), masked);
assertTrue(masked.startsWith("Оплата картой "), "окружающий текст изменён: " + masked);
}
@Test
void keepsNumberThatFailsLuhn() {
String text = "Заказ 1234 5678 9012 3456 отгружен";
assertEquals(text, mask(pipeline(), text));
}
@Test
void masksEmailKeepingTopLevelDomain() {
String masked = mask(pipeline(), "Почта ivan.petrov@mail.ru для связи");
assertEquals("Почта i**********@m***.ru для связи", masked);
}
@Test
void masksPhoneInAnyNotation() {
Pipeline pipeline = pipeline();
for (String phone : new String[] {"+7 (916) 123-45-67", "89161234567", "8 916 123 45 67"}) {
String masked = mask(pipeline, "Телефон " + phone);
assertFalse(masked.contains(phone), "телефон остался в тексте: " + masked);
assertTrue(masked.endsWith("67"), masked);
}
}
private String mask(Pipeline pipeline, String text) {
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
}
@Test
void masksInnByContextAndByChecksum() {
Pipeline pipeline = pipeline();
assertFalse(mask(pipeline, "ИНН: " + VALID_INN_12).contains(VALID_INN_12));
assertFalse(mask(pipeline, "Реквизиты " + VALID_INN_12 + " проверены").contains(VALID_INN_12));
}
@Test
void masksCardNumber() {
String masked = mask(pipeline(), "Оплата картой " + VALID_CARD + " прошла");
assertFalse(masked.contains(VALID_CARD), "номер карты остался в тексте: " + masked);
assertTrue(masked.contains("41** **** **** **11"), masked);
assertTrue(masked.startsWith("Оплата картой "), "окружающий текст изменён: " + masked);
}
@Test
void masksSnils() {
String masked = mask(pipeline(), "СНИЛС " + VALID_SNILS);
assertFalse(masked.contains(VALID_SNILS), masked);
}
@Test
void keepsNumberThatFailsLuhn() {
String text = "Заказ 1234 5678 9012 3456 отгружен";
assertEquals(text, mask(pipeline(), text));
}
@Test
void unmaskingRestoresOriginalText() {
Pipeline pipeline = pipeline();
String original = "Карта " + VALID_CARD + ", почта ivan@mail.ru, телефон +7 916 123-45-67";
String id = "pair-1";
@Test
void masksEmailKeepingTopLevelDomain() {
String masked = mask(pipeline(), "Почта ivan.petrov@mail.ru для связи");
assertEquals("Почта i**********@m***.ru для связи", masked);
}
String masked = pipeline.process(original, id, SystemPolicy.DEFAULT);
assertNotEquals(original, masked);
@Test
void masksPhoneInAnyNotation() {
Pipeline pipeline = pipeline();
for (String phone : new String[]{"+7 (916) 123-45-67", "89161234567", "8 916 123 45 67"}) {
String masked = mask(pipeline, "Телефон " + phone);
assertFalse(masked.contains(phone), "телефон остался в тексте: " + masked);
assertTrue(masked.endsWith("67"), masked);
}
}
String restored = pipeline.process(masked, id, SystemPolicy.DEFAULT);
assertEquals(original, restored);
}
@Test
void masksInnByContextAndByChecksum() {
Pipeline pipeline = pipeline();
assertFalse(mask(pipeline, "ИНН: " + VALID_INN_12).contains(VALID_INN_12));
assertFalse(mask(pipeline, "Реквизиты " + VALID_INN_12 + " проверены").contains(VALID_INN_12));
}
@Test
void retryReturnsSameMask() {
Pipeline pipeline = pipeline();
String original = "Карта " + VALID_CARD;
String id = "retry-1";
@Test
void masksSnils() {
String masked = mask(pipeline(), "СНИЛС " + VALID_SNILS);
assertFalse(masked.contains(VALID_SNILS), masked);
}
String first = pipeline.process(original, id, SystemPolicy.DEFAULT);
String second = pipeline.process(original, id, SystemPolicy.DEFAULT);
assertEquals(first, second);
}
@Test
void unmaskingRestoresOriginalText() {
Pipeline pipeline = pipeline();
String original = "Карта " + VALID_CARD + ", почта ivan@mail.ru, телефон +7 916 123-45-67";
String id = "pair-1";
@Test
void unmasksWhenPayloadIdIsUnknown() {
Pipeline pipeline = pipeline();
String original = "Почта ivan@mail.ru";
String masked = pipeline.process(original, "lost-id", SystemPolicy.DEFAULT);
String masked = pipeline.process(original, id, SystemPolicy.DEFAULT);
assertNotEquals(original, masked);
assertEquals(original, pipeline.process(masked, "другой-идентификатор", SystemPolicy.DEFAULT));
}
String restored = pipeline.process(masked, id, SystemPolicy.DEFAULT);
assertEquals(original, restored);
}
@Test
void textWithoutPersonalDataIsUnchanged() {
String text = "Расскажи о погоде в Москве завтра";
assertEquals(text, mask(pipeline(), text));
}
@Test
void retryReturnsSameMask() {
Pipeline pipeline = pipeline();
String original = "Карта " + VALID_CARD;
String id = "retry-1";
@Test
void systemPolicyDisablesSelectedTypes() {
Pipeline pipeline = pipeline();
SystemPolicy onlyEmail = SystemPolicy.forTypes(PdTypes.EMAIL);
String masked =
pipeline.process("Карта " + VALID_CARD + ", почта ivan@mail.ru", "policy-1", onlyEmail);
String first = pipeline.process(original, id, SystemPolicy.DEFAULT);
String second = pipeline.process(original, id, SystemPolicy.DEFAULT);
assertEquals(first, second);
}
assertTrue(
masked.contains(VALID_CARD), "карта не должна маскироваться этой системой: " + masked);
assertFalse(masked.contains("ivan@mail.ru"), masked);
}
@Test
void unmasksWhenPayloadIdIsUnknown() {
Pipeline pipeline = pipeline();
String original = "Почта ivan@mail.ru";
String masked = pipeline.process(original, "lost-id", SystemPolicy.DEFAULT);
@Test
void handlesLargeText() {
Pipeline pipeline = pipeline();
String block = "Клиент написал с адреса ivan@mail.ru и оплатил картой " + VALID_CARD + ". ";
String large = block.repeat(4000);
assertEquals(original, pipeline.process(masked, "другой-идентификатор", SystemPolicy.DEFAULT));
}
long started = System.nanoTime();
String masked = pipeline.process(large, "large-1", SystemPolicy.DEFAULT);
long millis = (System.nanoTime() - started) / 1_000_000;
@Test
void textWithoutPersonalDataIsUnchanged() {
String text = "Расскажи о погоде в Москве завтра";
assertEquals(text, mask(pipeline(), text));
}
@Test
void systemPolicyDisablesSelectedTypes() {
Pipeline pipeline = pipeline();
SystemPolicy onlyEmail = SystemPolicy.forTypes(PdTypes.EMAIL);
String masked = pipeline.process("Карта " + VALID_CARD + ", почта ivan@mail.ru", "policy-1", onlyEmail);
assertTrue(masked.contains(VALID_CARD), "карта не должна маскироваться этой системой: " + masked);
assertFalse(masked.contains("ivan@mail.ru"), masked);
}
@Test
void handlesLargeText() {
Pipeline pipeline = pipeline();
String block = "Клиент написал с адреса ivan@mail.ru и оплатил картой " + VALID_CARD + ". ";
String large = block.repeat(4000);
long started = System.nanoTime();
String masked = pipeline.process(large, "large-1", SystemPolicy.DEFAULT);
long millis = (System.nanoTime() - started) / 1_000_000;
assertFalse(masked.contains("ivan@mail.ru"));
assertEquals(large, pipeline.process(masked, "large-1", SystemPolicy.DEFAULT));
assertTrue(millis < 1000, "обработка крупного текста заняла " + millis + " мс");
}
assertFalse(masked.contains("ivan@mail.ru"));
assertEquals(large, pipeline.process(masked, "large-1", SystemPolicy.DEFAULT));
assertTrue(millis < 1000, "обработка крупного текста заняла " + millis + " мс");
}
}