|
|
@@ -1,329 +0,0 @@
|
|
|
-package cz.senslog.analytics.utils;
|
|
|
-
|
|
|
-import cz.senslog.analytics.domain.*;
|
|
|
-import cz.senslog.analytics.domain.ComparisonOperator;
|
|
|
-import cz.senslog.analytics.utils.validator.NotifyTrigger;
|
|
|
-import cz.senslog.analytics.utils.validator.ThresholdChecker;
|
|
|
-import cz.senslog.analytics.utils.validator.Validator;
|
|
|
-import cz.senslog.analytics.utils.validator.domain.ValidationResult;
|
|
|
-import org.junit.jupiter.api.BeforeAll;
|
|
|
-import org.junit.jupiter.api.Test;
|
|
|
-
|
|
|
-import java.time.OffsetDateTime;
|
|
|
-import java.time.ZoneOffset;
|
|
|
-import java.util.List;
|
|
|
-import java.util.concurrent.atomic.AtomicInteger;
|
|
|
-import java.util.stream.Stream;
|
|
|
-
|
|
|
-import static cz.senslog.analytics.domain.AttributeType.TIME;
|
|
|
-import static cz.senslog.analytics.domain.AttributeType.VAL;
|
|
|
-import static cz.senslog.analytics.domain.ComparisonOperator.*;
|
|
|
-import static cz.senslog.analytics.utils.validator.NotifyTrigger.Mode.INSTANT;
|
|
|
-import static cz.senslog.analytics.utils.validator.NotifyTrigger.Mode.ON_CHANGE;
|
|
|
-import static org.junit.jupiter.api.Assertions.*;
|
|
|
-
|
|
|
-class ThresholdCheckerTest {
|
|
|
-
|
|
|
- private static final Sensor SENSOR = new Sensor(100L, 1000L, 1001L);
|
|
|
-
|
|
|
- private static Validator<Observation> validator;
|
|
|
-
|
|
|
- @BeforeAll
|
|
|
- static void setUp() {
|
|
|
- validator = Validator.<Observation>create()
|
|
|
- .addMapping(VAL, o -> o::value)
|
|
|
- .addMapping(AttributeType.TIME, o -> () -> (double) o.timestamp().toLocalTime().toSecondOfDay());
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void test_1() {
|
|
|
-
|
|
|
- final OffsetDateTime startInterval = OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
- final OffsetDateTime endInterval = OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
-
|
|
|
-
|
|
|
- ThresholdChecker<Observation> checker = ThresholdChecker.create(
|
|
|
- List.of(
|
|
|
- Threshold.of(1, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, INSTANT, VAL, List.of(
|
|
|
- ThresholdDimensionRule.of(GT, 25)
|
|
|
- )
|
|
|
- ),
|
|
|
- ThresholdDimension.of(2, INSTANT, TIME, List.of(
|
|
|
- ThresholdDimensionRule.of(GE, 43200),
|
|
|
- ThresholdDimensionRule.of(LE, 54000)
|
|
|
- )
|
|
|
- )
|
|
|
- ))
|
|
|
- ),
|
|
|
- validator,
|
|
|
- (alert) -> {
|
|
|
- assertEquals(SENSOR.id(), alert.datasourceId());
|
|
|
- assertFalse(alert.timestamp().isBefore(startInterval) || alert.timestamp().isAfter(endInterval));
|
|
|
- assertEquals(2, alert.violatedData().length);
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- List<Observation> passedObservations = Stream.of(
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 11, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 1, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 14, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 1, 0, ZoneOffset.ofHours(2))))
|
|
|
- ).filter(checker::check).toList();
|
|
|
-
|
|
|
- assertEquals(2, passedObservations.size());
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void test_2() {
|
|
|
-
|
|
|
- final OffsetDateTime startInterval = OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
- final OffsetDateTime endInterval = OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
-
|
|
|
-
|
|
|
- ThresholdChecker<Observation> checker = ThresholdChecker.create(
|
|
|
- List.of(
|
|
|
- Threshold.of(1, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, ON_CHANGE, VAL, List.of(
|
|
|
- ThresholdDimensionRule.of(GT, 25)
|
|
|
- )
|
|
|
- ),
|
|
|
- ThresholdDimension.of(2, INSTANT, TIME, List.of(
|
|
|
- ThresholdDimensionRule.of(GE, 43200),
|
|
|
- ThresholdDimensionRule.of(LE, 54000)
|
|
|
- )
|
|
|
- )
|
|
|
- )),
|
|
|
- Threshold.of(2, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(3, INSTANT, VAL, List.of(
|
|
|
- ThresholdDimensionRule.of(GT, 25)
|
|
|
- )
|
|
|
- ),
|
|
|
- ThresholdDimension.of(4, ON_CHANGE, TIME, List.of(
|
|
|
- ThresholdDimensionRule.of(GE, 43200),
|
|
|
- ThresholdDimensionRule.of(LE, 54000)
|
|
|
- )
|
|
|
- )
|
|
|
- ))
|
|
|
- ),
|
|
|
- validator,
|
|
|
- (alert) -> {
|
|
|
- assertEquals(SENSOR.id(), alert.datasourceId());
|
|
|
- assertTrue(alert.timestamp().isEqual(startInterval.plusSeconds(1)) || alert.timestamp().isEqual(endInterval));
|
|
|
- assertEquals(2, alert.violatedData().length);
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- List<Observation> passedObservations = Stream.of(
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 24.3, OffsetDateTime.of(2024, 1, 1, 11, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 24.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 1, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 14, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 24.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 1, 0, ZoneOffset.ofHours(2))))
|
|
|
- ).filter(checker::check).toList();
|
|
|
-
|
|
|
- assertEquals(4, passedObservations.size());
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void test_3() {
|
|
|
-
|
|
|
- final OffsetDateTime startInterval = OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
- final OffsetDateTime endInterval = OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2));
|
|
|
-
|
|
|
-
|
|
|
- ThresholdChecker<Observation> checker = ThresholdChecker.create(
|
|
|
- List.of(
|
|
|
- Threshold.of(1, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, ON_CHANGE, VAL, List.of(
|
|
|
- ThresholdDimensionRule.of(GT, 25)
|
|
|
- )
|
|
|
- ),
|
|
|
- ThresholdDimension.of(2, INSTANT, TIME, List.of(
|
|
|
- ThresholdDimensionRule.of(GE, 43200),
|
|
|
- ThresholdDimensionRule.of(LE, 54000)
|
|
|
- )
|
|
|
- )
|
|
|
- )),
|
|
|
- Threshold.of(2, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(3, INSTANT, VAL, List.of(
|
|
|
- ThresholdDimensionRule.of(GT, 25)
|
|
|
- )
|
|
|
- ),
|
|
|
- ThresholdDimension.of(4, ON_CHANGE, TIME, List.of(
|
|
|
- ThresholdDimensionRule.of(GE, 43200),
|
|
|
- ThresholdDimensionRule.of(LE, 54000)
|
|
|
- )
|
|
|
- )
|
|
|
- ))
|
|
|
- ),
|
|
|
- validator,
|
|
|
- (alert) -> {
|
|
|
- assertEquals(SENSOR.id(), alert.datasourceId());
|
|
|
- assertTrue(alert.timestamp().isEqual(startInterval) || alert.timestamp().isEqual(endInterval));
|
|
|
- assertEquals(2, alert.violatedData().length);
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- List<Observation> passedObservations = Stream.of(
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 11, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 12, 0, 1, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* fail | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.of(2024, 1, 1, 14, 59, 59, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | alert */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 24.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 0, 0, ZoneOffset.ofHours(2)))),
|
|
|
- /* pass | none */ Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 24.3, OffsetDateTime.of(2024, 1, 1, 15, 0, 1, 0, ZoneOffset.ofHours(2))))
|
|
|
- ).filter(checker::check).toList();
|
|
|
-
|
|
|
- assertEquals(3, passedObservations.size());
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void check_size_1_INSTANT() {
|
|
|
-
|
|
|
- ThresholdChecker<Observation> checker = new ThresholdChecker<>(
|
|
|
- List.of(
|
|
|
- new Threshold(1, SENSOR.id(), true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, INSTANT, VAL, List.of(ThresholdDimensionRule.of(GT, 10.0)))
|
|
|
- ))
|
|
|
- ),
|
|
|
- Validator.<Observation>create()
|
|
|
- .addMapping(VAL, o -> o::value),
|
|
|
- (report) -> {
|
|
|
- assertEquals(SENSOR.id(), report.datasourceId());
|
|
|
- assertEquals(1, report.violatedData().length);
|
|
|
- ValidationResult valResult = report.violatedData()[0];
|
|
|
- assertEquals(VAL, valResult.attributeType());
|
|
|
- assertEquals(23.3, valResult.validatedValue());
|
|
|
- assertEquals(1, valResult.records().size());
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- long count = Stream.of(
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 23.3, OffsetDateTime.now()))
|
|
|
- ).filter(checker::check).count();
|
|
|
- assertEquals(1, count);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void check_size_3_ON_CHANGE() {
|
|
|
-
|
|
|
- ThresholdChecker<Observation> checker = new ThresholdChecker<>(
|
|
|
- List.of(
|
|
|
- new Threshold(1, SENSOR.id(), true,false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, NotifyTrigger.Mode.ON_CHANGE, VAL, List.of(ThresholdDimensionRule.of(GT, 10.0)))
|
|
|
- ))
|
|
|
- ),
|
|
|
- Validator.<Observation>create()
|
|
|
- .addMapping(VAL, o -> o::value),
|
|
|
- (report) -> {
|
|
|
- assertEquals(SENSOR.id(), report.datasourceId());
|
|
|
- assertEquals(1, report.violatedData().length);
|
|
|
- ValidationResult valResult = report.violatedData()[0];
|
|
|
- assertEquals(VAL, valResult.attributeType());
|
|
|
- assertEquals(25.3, valResult.validatedValue());
|
|
|
- assertEquals(1, valResult.records().size());
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- long count = Stream.of(
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(),9.9, OffsetDateTime.now())),
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(),25.3, OffsetDateTime.now())),
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(),30.5, OffsetDateTime.now()))
|
|
|
- ).filter(checker::check).count();
|
|
|
- assertEquals(3, count);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void check_size_4_ON_CHANGE() {
|
|
|
- AtomicInteger reportStep = new AtomicInteger(1);
|
|
|
- ThresholdChecker<Observation> checker = new ThresholdChecker<>(
|
|
|
- List.of(
|
|
|
- new Threshold(1, SENSOR.id(), true,false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, NotifyTrigger.Mode.ON_CHANGE, VAL, List.of(ThresholdDimensionRule.of(GT, 10.0)))
|
|
|
- ))
|
|
|
- ),
|
|
|
- Validator.<Observation>create()
|
|
|
- .addMapping(VAL, o -> o::value),
|
|
|
- (report) -> {
|
|
|
- assertEquals(SENSOR.id(), report.datasourceId());
|
|
|
- assertEquals(1, report.violatedData().length);
|
|
|
- ValidationResult valResult = report.violatedData()[0];
|
|
|
- assertEquals(VAL, valResult.attributeType());
|
|
|
-
|
|
|
- if (reportStep.compareAndSet(1, 2)) {
|
|
|
- assertEquals(25.3, valResult.validatedValue());
|
|
|
- assertTrue(valResult.isNotValid());
|
|
|
- assertEquals(1, valResult.records().size());
|
|
|
-
|
|
|
- } else if (reportStep.compareAndSet(2, 3)) {
|
|
|
- assertEquals(8.5, valResult.validatedValue());
|
|
|
- assertTrue(valResult.isValid());
|
|
|
- assertEquals(0, valResult.records().size());
|
|
|
- }
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- long count = Stream.of(
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 9.9, OffsetDateTime.now())),
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 25.3, OffsetDateTime.now())),
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(),30.5, OffsetDateTime.now())),
|
|
|
- Observation.of(SENSOR, RawObservation.of(SENSOR.unitId(), SENSOR.sensorId(), 8.5, OffsetDateTime.now()))
|
|
|
- ).filter(checker::check).count();
|
|
|
- assertEquals(4, count);
|
|
|
- }
|
|
|
-
|
|
|
- @Test
|
|
|
- void check_doubleStatistics_INSTANT() {
|
|
|
- long datasourceId = SENSOR.id();
|
|
|
-
|
|
|
- ThresholdChecker<DoubleStatistics> checker = new ThresholdChecker<>(
|
|
|
- List.of(
|
|
|
- new Threshold(1, -1, true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(1, INSTANT, AttributeType.MIN, List.of(ThresholdDimensionRule.of( ComparisonOperator.LT, 0.0))))
|
|
|
- ),
|
|
|
- new Threshold(1, -1, true, false, true, null, List.of(
|
|
|
- ThresholdDimension.of(2, INSTANT, AttributeType.MAX, List.of(ThresholdDimensionRule.of(GT, 5.0))))
|
|
|
- )
|
|
|
- ),
|
|
|
- Validator.<DoubleStatistics>create()
|
|
|
- .addMapping(AttributeType.MIN, s -> s::min)
|
|
|
- .addMapping(AttributeType.MAX, s -> s::max)
|
|
|
- .addMapping(AttributeType.AVG, s -> s::average),
|
|
|
- (report) -> {
|
|
|
- assertEquals(datasourceId, report.datasourceId());
|
|
|
- assertEquals(2, report.violatedData().length);
|
|
|
- ValidationResult[] violatedData = report.violatedData();
|
|
|
- ValidationResult minResult = violatedData[0].attributeType().equals(AttributeType.MIN) ? violatedData[0] : violatedData[1];
|
|
|
- ValidationResult maxResult = violatedData[0].attributeType().equals(AttributeType.MAX) ? violatedData[0] : violatedData[1];
|
|
|
-
|
|
|
- assertEquals(AttributeType.MIN, minResult.attributeType());
|
|
|
- assertEquals(-1.5, minResult.validatedValue());
|
|
|
- assertEquals(1, minResult.records().size());
|
|
|
-
|
|
|
- assertEquals(AttributeType.MAX, maxResult.attributeType());
|
|
|
- assertEquals(5.2, maxResult.validatedValue());
|
|
|
- assertEquals(1, maxResult.records().size());
|
|
|
- },
|
|
|
- true
|
|
|
- );
|
|
|
-
|
|
|
- DoubleStatistics ds = DoubleStatistics.init(datasourceId, OffsetDateTime.now());
|
|
|
- ds.accept(datasourceId, -1.5);
|
|
|
- ds.accept(datasourceId, 3.3);
|
|
|
- ds.accept(datasourceId, 5.2);
|
|
|
-
|
|
|
-
|
|
|
- long count = Stream.of(ds)
|
|
|
- .filter(checker::check).count();
|
|
|
- assertEquals(1, count);
|
|
|
- }
|
|
|
-}
|