- Удалены поле maxChars, параметр конструктора и метод evictWhileOverLimit. - Хранилище теперь ограничено только TTL (ttl-minutes), без вытеснения по объёму. - Конструкторы переведены на (int ttlMinutes) и (int ttlMinutes, SharedIndex, PayloadCipher). - Обновлены тесты и PipelineWarmup на новые сигнатуры.
109 lines
4.0 KiB
Java
109 lines
4.0 KiB
Java
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.assertTrue;
|
||
|
||
import java.util.Set;
|
||
import java.util.UUID;
|
||
import java.util.regex.Matcher;
|
||
import java.util.regex.Pattern;
|
||
import org.junit.jupiter.api.Test;
|
||
import ru.pdguard.config.SystemPolicy;
|
||
import ru.pdguard.core.PayloadStore;
|
||
import ru.pdguard.core.Pipeline;
|
||
import ru.pdguard.detect.RuleRegistry;
|
||
import ru.pdguard.detect.Validators;
|
||
import ru.pdguard.mask.MaskMode;
|
||
import ru.pdguard.mask.Masker;
|
||
|
||
/** Виды замены: звёздочки, токены, правдоподобные значения. */
|
||
class MaskModeTest {
|
||
|
||
private final Pipeline pipeline =
|
||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||
|
||
private SystemPolicy policy(MaskMode mode) {
|
||
return new SystemPolicy(
|
||
SystemPolicy.DEFAULT_NAME,
|
||
true,
|
||
true,
|
||
mode,
|
||
Set.of(SystemPolicy.ALL),
|
||
SystemPolicy.DEFAULT.requireCompanion(),
|
||
null);
|
||
}
|
||
|
||
private String mask(MaskMode mode, String text) {
|
||
return pipeline.process(text, UUID.randomUUID().toString(), policy(mode));
|
||
}
|
||
|
||
@Test
|
||
void strictModeHidesEverythingIncludingFio() {
|
||
String masked = mask(MaskMode.STRICT, "Клиент Иванов Иван Иванович, паспорт 4509 123456");
|
||
|
||
assertFalse(masked.contains("Иванов"), masked);
|
||
assertFalse(
|
||
masked.contains("И. И. И."), "STRICT не должен превращать ФИО в инициалы: " + masked);
|
||
assertTrue(
|
||
masked.contains("****** **** ********"),
|
||
"ожидались звёздочки по длине каждого слова: " + masked);
|
||
assertTrue(masked.contains("**** ******"), "край паспорта не должен открываться: " + masked);
|
||
}
|
||
|
||
@Test
|
||
void tokenModeNumbersEachType() {
|
||
String masked = mask(MaskMode.TOKEN, "Клиент Иванов Иван Иванович, почта ivan@mail.ru");
|
||
assertTrue(masked.contains("[FIO_1]"), masked);
|
||
assertTrue(masked.contains("[EMAIL_1]"), masked);
|
||
}
|
||
|
||
@Test
|
||
void sameValueGetsSameTokenWithinRequest() {
|
||
String masked =
|
||
mask(MaskMode.TOKEN, "ivan@mail.ru и ещё раз ivan@mail.ru, а также petr@mail.ru");
|
||
assertEquals(2, count(masked, "[EMAIL_1]"), masked);
|
||
assertEquals(1, count(masked, "[EMAIL_2]"), masked);
|
||
}
|
||
|
||
@Test
|
||
void syntheticModeProducesPlausibleValues() {
|
||
String masked = mask(MaskMode.SYNTHETIC, "Карта 4111 1111 1111 1111 клиента Иванова Ивана");
|
||
|
||
assertFalse(masked.contains("4111 1111 1111 1111"), masked);
|
||
assertFalse(masked.contains("*"), "подстановка должна выглядеть настоящей: " + masked);
|
||
|
||
Matcher card = Pattern.compile("\\d{4} \\d{4} \\d{4} \\d{4}").matcher(masked);
|
||
assertTrue(card.find(), masked);
|
||
assertTrue(
|
||
Validators.luhn(card.group()), "подставленный номер карты обязан проходить проверку Луна");
|
||
}
|
||
|
||
@Test
|
||
void syntheticValuesAreStable() {
|
||
String text = "Почта ivan@mail.ru, паспорт 4509 123456";
|
||
assertEquals(mask(MaskMode.SYNTHETIC, text), mask(MaskMode.SYNTHETIC, text));
|
||
}
|
||
|
||
@Test
|
||
void unmaskingWorksInEveryMode() {
|
||
String original = "Клиент Иванов Иван Иванович, карта 4111 1111 1111 1111, почта ivan@mail.ru";
|
||
for (MaskMode mode : MaskMode.values()) {
|
||
String id = "mode-" + mode;
|
||
String masked = pipeline.process(original, id, policy(mode));
|
||
assertFalse(masked.contains("Иванов Иван Иванович"), mode + ": " + masked);
|
||
assertEquals(original, pipeline.process(masked, id, policy(mode)), mode.name());
|
||
}
|
||
}
|
||
|
||
private static int count(String text, String fragment) {
|
||
int n = 0;
|
||
for (int i = text.indexOf(fragment);
|
||
i >= 0;
|
||
i = text.indexOf(fragment, i + fragment.length())) {
|
||
n++;
|
||
}
|
||
return n;
|
||
}
|
||
}
|