refactor: убрать ограничение maxChars из хранилища соответствий
- Удалены поле maxChars, параметр конструктора и метод evictWhileOverLimit. - Хранилище теперь ограничено только TTL (ttl-minutes), без вытеснения по объёму. - Конструкторы переведены на (int ttlMinutes) и (int ttlMinutes, SharedIndex, PayloadCipher). - Обновлены тесты и PipelineWarmup на новые сигнатуры.
This commit is contained in:
@@ -24,9 +24,8 @@ import org.springframework.stereotype.Component;
|
|||||||
* было бы получить в ответ исходные значения из запроса другого потребителя. Разделение
|
* было бы получить в ответ исходные значения из запроса другого потребителя. Разделение
|
||||||
* ограничивает это пределами одной системы, которая и так видит свои данные.
|
* ограничивает это пределами одной системы, которая и так видит свои данные.
|
||||||
*
|
*
|
||||||
* <p>Хранилище ограничено по суммарному объёму строк, а записи живут ограниченное время:
|
* <p>Записи живут ограниченное время: персональные данные не должны залёживаться в памяти.
|
||||||
* персональные данные не должны залёживаться в памяти, а крупные тексты не должны исчерпать кучу.
|
* Протухшие записи убираются в порядке добавления прямо на записи — отдельного потока и внешней
|
||||||
* Вытеснение идёт в порядке добавления и выполняется прямо на записи — отдельного потока и внешней
|
|
||||||
* библиотеки кеширования не требуется.
|
* библиотеки кеширования не требуется.
|
||||||
*
|
*
|
||||||
* <p>Когда включён общий слой ({@link SharedIndex}), соответствие пишется ещё и туда, а чтение при
|
* <p>Когда включён общий слой ({@link SharedIndex}), соответствие пишется ещё и туда, а чтение при
|
||||||
@@ -58,26 +57,30 @@ public class PayloadStore {
|
|||||||
private final ConcurrentLinkedQueue<String> insertionOrder = new ConcurrentLinkedQueue<>();
|
private final ConcurrentLinkedQueue<String> insertionOrder = new ConcurrentLinkedQueue<>();
|
||||||
private final AtomicLong charsHeld = new AtomicLong();
|
private final AtomicLong charsHeld = new AtomicLong();
|
||||||
|
|
||||||
private final long maxChars;
|
|
||||||
private final long ttlMillis;
|
private final long ttlMillis;
|
||||||
private final SharedIndex shared;
|
private final SharedIndex shared;
|
||||||
private final PayloadCipher cipher;
|
private final PayloadCipher cipher;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PayloadStore(
|
public PayloadStore(
|
||||||
@Value("${pdguard.store.max-chars:134217728}") long maxChars,
|
|
||||||
@Value("${pdguard.store.ttl-minutes:30}") int ttlMinutes,
|
@Value("${pdguard.store.ttl-minutes:30}") int ttlMinutes,
|
||||||
SharedIndex shared,
|
SharedIndex shared,
|
||||||
PayloadCipher cipher) {
|
PayloadCipher cipher) {
|
||||||
this.maxChars = maxChars;
|
|
||||||
this.ttlMillis = ttlMinutes * 60_000L;
|
this.ttlMillis = ttlMinutes * 60_000L;
|
||||||
this.shared = shared;
|
this.shared = shared;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Конструктор для тестов: только локальная память, общий слой и шифрование выключены. */
|
/** Конструктор для тестов: только локальная память, общий слой и шифрование выключены. */
|
||||||
public PayloadStore(long maxChars, int ttlMinutes) {
|
public PayloadStore(int ttlMinutes) {
|
||||||
this(maxChars, ttlMinutes, SharedIndex.disabled(), PayloadCipher.disabled());
|
this(ttlMinutes, SharedIndex.disabled(), PayloadCipher.disabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Конструктор для тестов с явным общим слоем и шифрованием. */
|
||||||
|
public PayloadStore(int ttlMinutes, SharedIndex shared, PayloadCipher cipher) {
|
||||||
|
this.ttlMillis = ttlMinutes * 60_000L;
|
||||||
|
this.shared = shared;
|
||||||
|
this.cipher = cipher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(String system, String payloadId, String original, String masked) {
|
public void put(String system, String payloadId, String original, String masked) {
|
||||||
@@ -92,7 +95,6 @@ public class PayloadStore {
|
|||||||
charsHeld.addAndGet((long) entry.weight() - (replaced == null ? 0 : replaced.weight()));
|
charsHeld.addAndGet((long) entry.weight() - (replaced == null ? 0 : replaced.weight()));
|
||||||
|
|
||||||
sweepExpired(now);
|
sweepExpired(now);
|
||||||
evictWhileOverLimit();
|
|
||||||
|
|
||||||
shared.put(system, payloadId, encrypted, masked, entry.fingerprint());
|
shared.put(system, payloadId, encrypted, masked, entry.fingerprint());
|
||||||
}
|
}
|
||||||
@@ -154,22 +156,6 @@ public class PayloadStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void evictWhileOverLimit() {
|
|
||||||
while (charsHeld.get() > maxChars) {
|
|
||||||
String oldest = insertionOrder.poll();
|
|
||||||
if (oldest == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Entry entry = byId.get(oldest);
|
|
||||||
if (entry != null) {
|
|
||||||
// ponytail: если тот же payload_id записали повторно, в очереди остался
|
|
||||||
// старый след и здесь вытесняется свежая запись. Цена — одно лишнее
|
|
||||||
// обращение к маскированию; точный учёт потребовал бы двусвязного списка.
|
|
||||||
forget(oldest, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void forget(String idKey, Entry entry) {
|
private void forget(String idKey, Entry entry) {
|
||||||
if (byId.remove(idKey, entry)) {
|
if (byId.remove(idKey, entry)) {
|
||||||
byMaskFingerprint.remove(ScopedKey.of(entry.system(), entry.fingerprint()), entry);
|
byMaskFingerprint.remove(ScopedKey.of(entry.system(), entry.fingerprint()), entry);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class PipelineWarmup {
|
|||||||
}
|
}
|
||||||
long started = System.nanoTime();
|
long started = System.nanoTime();
|
||||||
Pipeline scratch =
|
Pipeline scratch =
|
||||||
new Pipeline(registry, masker, new PayloadStore(1_000_000L, 1), NameCascade.disabled());
|
new Pipeline(registry, masker, new PayloadStore(1), NameCascade.disabled());
|
||||||
SystemPolicy policy =
|
SystemPolicy policy =
|
||||||
new SystemPolicy(
|
new SystemPolicy(
|
||||||
SystemPolicy.DEFAULT_NAME,
|
SystemPolicy.DEFAULT_NAME,
|
||||||
|
|||||||
@@ -37,12 +37,6 @@ pdguard:
|
|||||||
systems-file: config/systems.json
|
systems-file: config/systems.json
|
||||||
store:
|
store:
|
||||||
backend: memory
|
backend: memory
|
||||||
# 128MB (было) держал store.chars упёртым в потолок под держащей нагрузкой —
|
|
||||||
# FIFO-вытеснение выкидывало свежую запись за миллисекунды, раньше, чем
|
|
||||||
# приходил её собственный демаскирующий запрос: см. k6 на датасете утечек,
|
|
||||||
# 6.1% неверных демасков при 2000 VU, при этом 0% на низкой конкурентности.
|
|
||||||
# На одном узле без соседей по хосту память есть — 512MB даёт запас на порядок.
|
|
||||||
max-chars: 536870912
|
|
||||||
ttl-minutes: 30
|
ttl-minutes: 30
|
||||||
# 32 байта в hex; AES-256 ключ шифрования хранилища
|
# 32 байта в hex; AES-256 ключ шифрования хранилища
|
||||||
encryption-key: "46a38b200c6df557a5fd2c8a57ad3fec6b710b9f3e1fef1451d121a094f63573"
|
encryption-key: "46a38b200c6df557a5fd2c8a57ad3fec6b710b9f3e1fef1451d121a094f63573"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class BankTypesTest {
|
class BankTypesTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private void assertHidden(String text, String secret) {
|
private void assertHidden(String text, String secret) {
|
||||||
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class BenchmarkTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(10_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Набор, на котором правила отлаживались. Пороги здесь высокие: любое падение означает, что
|
* Набор, на котором правила отлаживались. Пороги здесь высокие: любое падение означает, что
|
||||||
@@ -131,7 +131,7 @@ class BenchmarkTest {
|
|||||||
? new Pipeline(
|
? new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
||||||
: pipeline;
|
: pipeline;
|
||||||
Result result = measure(stage, "/benchmark-holdout3.txt", "второй контрольный набор");
|
Result result = measure(stage, "/benchmark-holdout3.txt", "второй контрольный набор");
|
||||||
@@ -158,7 +158,7 @@ class BenchmarkTest {
|
|||||||
? new Pipeline(
|
? new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
||||||
: pipeline;
|
: pipeline;
|
||||||
Result result = measure(stage, "/benchmark-holdout2.txt", "второй отложенный набор");
|
Result result = measure(stage, "/benchmark-holdout2.txt", "второй отложенный набор");
|
||||||
@@ -206,7 +206,7 @@ class BenchmarkTest {
|
|||||||
? new Pipeline(
|
? new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4))
|
||||||
: pipeline;
|
: pipeline;
|
||||||
Result result = measure(stage, "/benchmark-generated.txt", "сгенерированный набор");
|
Result result = measure(stage, "/benchmark-generated.txt", "сгенерированный набор");
|
||||||
@@ -232,7 +232,7 @@ class BenchmarkTest {
|
|||||||
new Pipeline(
|
new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4));
|
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4));
|
||||||
Result result =
|
Result result =
|
||||||
measure(withCascade, "/benchmark-holdout.txt", "отложенный набор, вторая ступень включена");
|
measure(withCascade, "/benchmark-holdout.txt", "отложенный набор, вторая ступень включена");
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class ContextDetectionTest {
|
class ContextDetectionTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class Dataset200Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void runCase(BenchmarkFixtures.Sample sample, int index) {
|
private void runCase(BenchmarkFixtures.Sample sample, int index) {
|
||||||
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(1_000_000L, 30));
|
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(30));
|
||||||
String payloadId = "dataset200-" + index;
|
String payloadId = "dataset200-" + index;
|
||||||
|
|
||||||
String masked = pipeline.process(sample.text(), payloadId, SystemPolicy.DEFAULT);
|
String masked = pipeline.process(sample.text(), payloadId, SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class DateAndAddressTest {
|
class DateAndAddressTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class FioTest {
|
class FioTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class HugeDatasetTest {
|
|||||||
|
|
||||||
private void runCase(int targetChars, int seed) {
|
private void runCase(int targetChars, int seed) {
|
||||||
Pipeline pipeline =
|
Pipeline pipeline =
|
||||||
new Pipeline(REGISTRY, MASKER, new PayloadStore(targetChars * 2L + 4096, 30));
|
new Pipeline(REGISTRY, MASKER, new PayloadStore(30));
|
||||||
BenchmarkFixtures.Sample sample = buildText(targetChars, seed);
|
BenchmarkFixtures.Sample sample = buildText(targetChars, seed);
|
||||||
String payloadId = "dataset-" + seed;
|
String payloadId = "dataset-" + seed;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class IdentityDocumentTest {
|
class IdentityDocumentTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private void assertHidden(String text, String secret) {
|
private void assertHidden(String text, String secret) {
|
||||||
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class LargeTextTest {
|
|||||||
BenchmarkFixtures.Sample large = buildLargeText(TARGET_CHARS, 1);
|
BenchmarkFixtures.Sample large = buildLargeText(TARGET_CHARS, 1);
|
||||||
Pipeline pipeline =
|
Pipeline pipeline =
|
||||||
new Pipeline(
|
new Pipeline(
|
||||||
new RuleRegistry(), new Masker(), new PayloadStore(large.text().length() * 2L, 30));
|
new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
long maskStarted = System.nanoTime();
|
long maskStarted = System.nanoTime();
|
||||||
String masked = pipeline.process(large.text(), "large-mixed-1", SystemPolicy.DEFAULT);
|
String masked = pipeline.process(large.text(), "large-mixed-1", SystemPolicy.DEFAULT);
|
||||||
@@ -102,7 +102,7 @@ class LargeTextTest {
|
|||||||
@Test
|
@Test
|
||||||
void recallHoldsAtScale() {
|
void recallHoldsAtScale() {
|
||||||
BenchmarkFixtures.Sample large = buildLargeText(TARGET_CHARS, 2);
|
BenchmarkFixtures.Sample large = buildLargeText(TARGET_CHARS, 2);
|
||||||
Pipeline pipeline = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1L, 30));
|
Pipeline pipeline = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
List<Span> found = pipeline.findPersonalData(large.text(), SystemPolicy.DEFAULT);
|
List<Span> found = pipeline.findPersonalData(large.text(), SystemPolicy.DEFAULT);
|
||||||
int hit = 0;
|
int hit = 0;
|
||||||
@@ -138,7 +138,7 @@ class LargeTextTest {
|
|||||||
new Pipeline(
|
new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(large.text().length() * 2L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4));
|
new NameCascade(ENGINE, Optional.of(MODEL_PATH), 16, 4));
|
||||||
|
|
||||||
long started = System.nanoTime();
|
long started = System.nanoTime();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class LeakDiagTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void checkLeaks() {
|
void checkLeaks() {
|
||||||
Pipeline p = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
Pipeline p = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
List<String> leaks = readDataset();
|
List<String> leaks = readDataset();
|
||||||
|
|
||||||
int fixed = 0;
|
int fixed = 0;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class LegalNerTest {
|
|||||||
"off", Optional.empty(),
|
"off", Optional.empty(),
|
||||||
"ru-legal-ner", Optional.of("models/ru-legal-ner")),
|
"ru-legal-ner", Optional.of("models/ru-legal-ner")),
|
||||||
16, 4);
|
16, 4);
|
||||||
Pipeline p = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30), cascade);
|
Pipeline p = new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30), cascade);
|
||||||
return p.findPersonalData(text, SystemPolicy.DEFAULT);
|
return p.findPersonalData(text, SystemPolicy.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class MaskModeTest {
|
class MaskModeTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private SystemPolicy policy(MaskMode mode) {
|
private SystemPolicy policy(MaskMode mode) {
|
||||||
return new SystemPolicy(
|
return new SystemPolicy(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class NameCascadeTest {
|
|||||||
|
|
||||||
private String mask(NameCascade cascade, String payloadId) {
|
private String mask(NameCascade cascade, String payloadId) {
|
||||||
Pipeline pipeline =
|
Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30), cascade);
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30), cascade);
|
||||||
return pipeline.process(TEXT, payloadId, SystemPolicy.DEFAULT);
|
return pipeline.process(TEXT, payloadId, SystemPolicy.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
|||||||
class NormalisedDigitsTest {
|
class NormalisedDigitsTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private void assertHidden(String text, String secret) {
|
private void assertHidden(String text, String secret) {
|
||||||
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
String masked = pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class OrganisationNamesTest {
|
class OrganisationNamesTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class PayloadCipherTest {
|
|||||||
void storeStoresEncryptedButReturnsPlaintext() {
|
void storeStoresEncryptedButReturnsPlaintext() {
|
||||||
PayloadCipher cipher = new PayloadCipher(KEY);
|
PayloadCipher cipher = new PayloadCipher(KEY);
|
||||||
PayloadStore store =
|
PayloadStore store =
|
||||||
new PayloadStore(1_000_000L, 30, ru.pdguard.core.SharedIndex.disabled(), cipher);
|
new PayloadStore(30, ru.pdguard.core.SharedIndex.disabled(), cipher);
|
||||||
|
|
||||||
String original = "Клиент Иванов Иван Иванович, паспорт 4509 123456";
|
String original = "Клиент Иванов Иван Иванович, паспорт 4509 123456";
|
||||||
String masked = "Клиент И. И. И., паспорт 45** ****56";
|
String masked = "Клиент И. И. И., паспорт 45** ****56";
|
||||||
|
|||||||
@@ -3,19 +3,18 @@ package ru.pdguard;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import ru.pdguard.core.PayloadStore;
|
import ru.pdguard.core.PayloadStore;
|
||||||
|
|
||||||
/** Ограничения хранилища соответствий: объём, срок жизни и разделение по системам. */
|
/** Ограничения хранилища соответствий: срок жизни и разделение по системам. */
|
||||||
class PayloadStoreTest {
|
class PayloadStoreTest {
|
||||||
|
|
||||||
private static final String SYSTEM = "crm";
|
private static final String SYSTEM = "crm";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void returnsWhatWasStored() {
|
void returnsWhatWasStored() {
|
||||||
PayloadStore store = new PayloadStore(1_000_000L, 30);
|
PayloadStore store = new PayloadStore(30);
|
||||||
store.put(SYSTEM, "id", "исходный текст", "маска");
|
store.put(SYSTEM, "id", "исходный текст", "маска");
|
||||||
|
|
||||||
PayloadStore.Entry entry = store.byId(SYSTEM, "id");
|
PayloadStore.Entry entry = store.byId(SYSTEM, "id");
|
||||||
@@ -27,28 +26,16 @@ class PayloadStoreTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void forgetsEntriesAfterTheirLifetime() {
|
void forgetsEntriesAfterTheirLifetime() {
|
||||||
PayloadStore store = new PayloadStore(1_000_000L, 0);
|
PayloadStore store = new PayloadStore(0);
|
||||||
store.put(SYSTEM, "id", "исходный текст", "маска");
|
store.put(SYSTEM, "id", "исходный текст", "маска");
|
||||||
|
|
||||||
assertNull(store.byId(SYSTEM, "id"), "запись с истёкшим сроком жизни не должна отдаваться");
|
assertNull(store.byId(SYSTEM, "id"), "запись с истёкшим сроком жизни не должна отдаваться");
|
||||||
assertNull(store.originalForMask(SYSTEM, "маска"));
|
assertNull(store.originalForMask(SYSTEM, "маска"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void evictsOldestWhenOverSizeLimit() {
|
|
||||||
PayloadStore store = new PayloadStore(100L, 30);
|
|
||||||
for (int i = 0; i < 50; i++) {
|
|
||||||
store.put(SYSTEM, "id" + i, "текст номер " + i, "маска номер " + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(store.charsHeld() <= 100, "объём хранилища вышел за предел: " + store.charsHeld());
|
|
||||||
assertNull(store.byId(SYSTEM, "id0"), "самая старая запись должна быть вытеснена");
|
|
||||||
assertNotNull(store.byId(SYSTEM, "id49"), "последняя запись должна остаться");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void unknownKeysReturnNothing() {
|
void unknownKeysReturnNothing() {
|
||||||
PayloadStore store = new PayloadStore(1_000_000L, 30);
|
PayloadStore store = new PayloadStore(30);
|
||||||
assertNull(store.byId(SYSTEM, "нет такого"));
|
assertNull(store.byId(SYSTEM, "нет такого"));
|
||||||
assertNull(store.originalForMask(SYSTEM, "нет такой маски"));
|
assertNull(store.originalForMask(SYSTEM, "нет такой маски"));
|
||||||
}
|
}
|
||||||
@@ -60,7 +47,7 @@ class PayloadStoreTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void oneSystemCannotReadAnotherSystemData() {
|
void oneSystemCannotReadAnotherSystemData() {
|
||||||
PayloadStore store = new PayloadStore(1_000_000L, 30);
|
PayloadStore store = new PayloadStore(30);
|
||||||
store.put("crm", "общий-id", "Иванов Иван Иванович", "И. И. И.");
|
store.put("crm", "общий-id", "Иванов Иван Иванович", "И. И. И.");
|
||||||
|
|
||||||
assertNull(
|
assertNull(
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class PdnTypeEfficiencyTest {
|
class PdnTypeEfficiencyTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(10_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
/** Накопитель посимвольных совпадений по одному типу. */
|
/** Накопитель посимвольных совпадений по одному типу. */
|
||||||
private static final class Score {
|
private static final class Score {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class PerformanceBenchmarkTest {
|
|||||||
private static final int MEASURE = 50_000;
|
private static final int MEASURE = 50_000;
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(10_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private void warmup() {
|
private void warmup() {
|
||||||
for (int i = 0; i < WARMUP; i++) {
|
for (int i = 0; i < WARMUP; i++) {
|
||||||
@@ -184,7 +184,7 @@ class PerformanceBenchmarkTest {
|
|||||||
new Pipeline(
|
new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(
|
new NameCascade(
|
||||||
"rubert", Optional.of(model.toString()), "off", Optional.empty(), 16, 4, meters));
|
"rubert", Optional.of(model.toString()), "off", Optional.empty(), 16, 4, meters));
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class PipelineTest {
|
|||||||
private static final String VALID_SNILS = "112-233-445 95";
|
private static final String VALID_SNILS = "112-233-445 95";
|
||||||
|
|
||||||
private Pipeline pipeline() {
|
private Pipeline pipeline() {
|
||||||
return new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
return new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String mask(Pipeline pipeline, String text) {
|
private String mask(Pipeline pipeline, String text) {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class PlacementVariantsTest {
|
|||||||
|
|
||||||
/** Демаскирование обязано восстановить исходный текст всегда, независимо от утечек. */
|
/** Демаскирование обязано восстановить исходный текст всегда, независимо от утечек. */
|
||||||
private void runRoundTrip(BenchmarkFixtures.Sample sample, int index) {
|
private void runRoundTrip(BenchmarkFixtures.Sample sample, int index) {
|
||||||
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(1_000_000L, 30), CASCADE);
|
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(30), CASCADE);
|
||||||
String payloadId = "placement-" + index;
|
String payloadId = "placement-" + index;
|
||||||
|
|
||||||
String masked = pipeline.process(sample.text(), payloadId, SystemPolicy.DEFAULT);
|
String masked = pipeline.process(sample.text(), payloadId, SystemPolicy.DEFAULT);
|
||||||
@@ -90,7 +90,7 @@ class PlacementVariantsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void leakSummary() {
|
void leakSummary() {
|
||||||
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(10_000_000L, 30), CASCADE);
|
Pipeline pipeline = new Pipeline(REGISTRY, MASKER, new PayloadStore(30), CASCADE);
|
||||||
int leaked = 0;
|
int leaked = 0;
|
||||||
int checked = 0;
|
int checked = 0;
|
||||||
java.util.Map<String, Integer> byType = new java.util.LinkedHashMap<>();
|
java.util.Map<String, Integer> byType = new java.util.LinkedHashMap<>();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class SettlementTest {
|
class SettlementTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ru.pdguard.mask.Masker;
|
|||||||
class StreetDenylistTest {
|
class StreetDenylistTest {
|
||||||
|
|
||||||
private final Pipeline pipeline =
|
private final Pipeline pipeline =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30));
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30));
|
||||||
|
|
||||||
private String mask(String text) {
|
private String mask(String text) {
|
||||||
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
return pipeline.process(text, UUID.randomUUID().toString(), SystemPolicy.DEFAULT);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class TwoModelBenchmarkTest {
|
|||||||
new Pipeline(
|
new Pipeline(
|
||||||
new RuleRegistry(),
|
new RuleRegistry(),
|
||||||
new Masker(),
|
new Masker(),
|
||||||
new PayloadStore(10_000_000L, 30),
|
new PayloadStore(30),
|
||||||
new NameCascade(
|
new NameCascade(
|
||||||
new NameCascade.EngineConfig(
|
new NameCascade.EngineConfig(
|
||||||
"wikineural", Optional.of("models/wikineural-ner"),
|
"wikineural", Optional.of("models/wikineural-ner"),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class TwoModelCascadeTest {
|
|||||||
16,
|
16,
|
||||||
4);
|
4);
|
||||||
Pipeline p =
|
Pipeline p =
|
||||||
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(1_000_000L, 30), cascade);
|
new Pipeline(new RuleRegistry(), new Masker(), new PayloadStore(30), cascade);
|
||||||
return p.findPersonalData(text, SystemPolicy.DEFAULT);
|
return p.findPersonalData(text, SystemPolicy.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user