From 5061aef07699ce6b47b1f82b0ead0e2ac5c90490 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Fri, 25 Sep 2026 21:53:05 +0200 Subject: [PATCH 01/11] add DummyAlertAggregator and change test_basic_pipelines. --- .../_testutils/dummy_alert_aggregator.py | 27 ++++++++ .../_testutils/dummy_detector.py | 7 ++- .../alert_aggregation/basic_concat.py | 10 +-- src/detectmatelibrary/common/core.py | 1 + tests/test_pipelines/test_basic_pipelines.py | 63 ++++++++++--------- 5 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 src/detectmatelibrary/_testutils/dummy_alert_aggregator.py diff --git a/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py b/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py new file mode 100644 index 00000000..3a66d9b5 --- /dev/null +++ b/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py @@ -0,0 +1,27 @@ +from detectmatelibrary.common.alert_aggregator import (CoreAlertAggregatorConfig, CoreAlertAggregator) +from detectmatelibrary.schemas import DetectorSchema, AggregateSchema +from typing import Any, Optional + + +class DummyAlertAggregatorConfig(CoreAlertAggregatorConfig): + method_type: str = "dummy_alert_aggregator" + buffer_size: int = 3 + + +class DummyAlertAggregator(CoreAlertAggregator): + def __init__( + self, + name: str = "DummyAlertAggregator", + config: Optional[DummyAlertAggregatorConfig | dict[str, Any]] = DummyAlertAggregatorConfig(), + ) -> None: + if isinstance(config, dict): + config = DummyAlertAggregatorConfig.from_dict(config, name) + buffer_size: int = config.buffer_size # type: ignore + super().__init__(name=name, buffer_size=buffer_size, config=config) + + def aggregate_alerts( + self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema # type: ignore + ) -> bool: + output_["description"] = "Dummy alert aggregation" + output_["alertsObtain"]["type"] = "Anomalies aggregated by DummyAlertAggregator" + return True diff --git a/src/detectmatelibrary/_testutils/dummy_detector.py b/src/detectmatelibrary/_testutils/dummy_detector.py index b4277883..46708096 100644 --- a/src/detectmatelibrary/_testutils/dummy_detector.py +++ b/src/detectmatelibrary/_testutils/dummy_detector.py @@ -1,7 +1,7 @@ from detectmatelibrary.common.detector import CoreDetector, CoreDetectorConfig from detectmatelibrary.utils.data_buffer import BufferMode from detectmatelibrary import schemas -from typing import List, Any +from typing import List, Any, Optional class DummyDetectorConfig(CoreDetectorConfig): @@ -15,12 +15,14 @@ class DummyDetector(CoreDetector): def __init__( self, name: str = "DummyDetector", + buffer_mode: BufferMode = BufferMode.NO_BUF, + buffer_size: Optional[int] = None, config: DummyDetectorConfig | dict[str, Any] = DummyDetectorConfig() ) -> None: if isinstance(config, dict): config = DummyDetectorConfig.from_dict(config, name) - super().__init__(name=name, buffer_mode=BufferMode.NO_BUF, config=config) + super().__init__(name=name, buffer_mode=buffer_mode, buffer_size=buffer_size, config=config) self._call_count = 0 def detect( @@ -34,6 +36,7 @@ def detect( self._call_count += 1 pattern = [True, False] result = pattern[self._call_count % len(pattern)] + print(self._call_count, result) if result: output_["score"] = 1.0 output_["alertsObtain"]["type"] = "Anomaly detected by DummyDetector" diff --git a/src/detectmatelibrary/alert_aggregation/basic_concat.py b/src/detectmatelibrary/alert_aggregation/basic_concat.py index 45883cf8..316fe444 100644 --- a/src/detectmatelibrary/alert_aggregation/basic_concat.py +++ b/src/detectmatelibrary/alert_aggregation/basic_concat.py @@ -1,9 +1,5 @@ -from detectmatelibrary.common.alert_aggregator import ( - CoreAlertAggregatorConfig, CoreAlertAggregator -) - +from detectmatelibrary.common.alert_aggregator import (CoreAlertAggregatorConfig, CoreAlertAggregator) from detectmatelibrary.schemas import DetectorSchema, AggregateSchema - from typing import Any, Optional @@ -20,13 +16,11 @@ def __init__( ) -> None: if isinstance(config, dict): config = BasicConcatAggregationConfig.from_dict(config, name) - buffer_size: int = config.buffer_size # type: ignore super().__init__(name=name, buffer_size=buffer_size, config=config) def aggregate_alerts( - self, input_: list[DetectorSchema], output_: AggregateSchema # type: ignore + self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema # type: ignore ) -> bool: - output_["description"] = "Basic aggregation by alert concatenation" return True diff --git a/src/detectmatelibrary/common/core.py b/src/detectmatelibrary/common/core.py index 75a3c645..9def631c 100644 --- a/src/detectmatelibrary/common/core.py +++ b/src/detectmatelibrary/common/core.py @@ -105,6 +105,7 @@ def process(self, data: BaseSchema | bytes) -> BaseSchema | bytes | None: logger.debug(f"<<{self.name}>> received:\n{data}") if (data_buffered := self.data_buffer.add(data)) is None: # type: ignore + print("BBBBBBBBBBBB", data, data_buffered) return None if (fit_state := self.fitlogic.run()) == FitLogicState.DO_CONFIG: diff --git a/tests/test_pipelines/test_basic_pipelines.py b/tests/test_pipelines/test_basic_pipelines.py index 53d95d70..4d59f92b 100644 --- a/tests/test_pipelines/test_basic_pipelines.py +++ b/tests/test_pipelines/test_basic_pipelines.py @@ -1,5 +1,7 @@ -from detectmatelibrary.common.detector import CoreDetector, BufferMode -from detectmatelibrary.common.parser import CoreParser +from detectmatelibrary._testutils.dummy_parser import DummyParser +from detectmatelibrary._testutils.dummy_detector import DummyDetector +from detectmatelibrary._testutils.dummy_alert_aggregator import DummyAlertAggregator +from detectmatelibrary.common.detector import BufferMode from detectmatelibrary.detectors.new_value_combo_detector import NewValueComboDetector from detectmatelibrary.detectors.new_value_detector import NewValueDetector from detectmatelibrary.detectors.random_detector import RandomDetector @@ -9,79 +11,81 @@ import yaml -class MockupParser(CoreParser): - def parse(self, input_, output_): - output_.EventID = 1 - output_.template = "hello" - output_.variables.extend(["a", "b"]) - - -class MockupDetector(CoreDetector): - def detect(self, input_, output_): - output_.score = 0.9 - output_.description = "ciao" - - return True - config = { "parsers": { "dummy_parser": { - "method_type": "core_parser", + "method_type": "dummy_parser", "auto_config": False, "params": {} } }, "detectors": { "dummy_detector": { - "method_type": "core_detector", + "method_type": "dummy_detector", "auto_config": False, "params": {} } }, + "alert_aggregators": { + "dummy_alert_aggregator": { + "method_type": "dummy_alert_aggregator", + "auto_config": False, + "params": {} + } + } } class TestCaseBasicPipelines: """This pipelines should not crash.""" def test_basic_pipeline(self) -> None: - parser = MockupParser(name="dummy_parser", config=config) - detector = MockupDetector( + parser = DummyParser(name="dummy_parser", config=config) + detector = DummyDetector( name="dummy_detector", config=config, buffer_mode=BufferMode.NO_BUF, buffer_size=None, ) + aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) - assert (parsed_log := next(From.log(parser, LOG_PATH))) is not None - assert detector.process(parsed_log) is not None + gen = From.log(parser, LOG_PATH) + for i in range(2): + assert (parsed_log := next(gen)) is not None + assert (processed_data:= detector.process(parsed_log)) is [None, None][i] + assert aggregator.process(processed_data) is None + parsed_log = next(gen) + assert (processed_data := detector.process(parsed_log)) is not None + assert aggregator.process(processed_data) is not None def test_window_pipeline(self) -> None: - parser = MockupParser(name="dummy_parser", config=config) - detector = MockupDetector( + parser = DummyParser(name="dummy_parser", config=config) + detector = DummyDetector( name="dummy_detector", config=config, buffer_mode=BufferMode.WINDOW, buffer_size=3, ) + aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) gen = From.log(parser, LOG_PATH) for _ in range(2): parsed_log = next(gen) assert detector.process(parsed_log) is None parsed_log = next(gen) - assert detector.process(parsed_log) is not None + assert (processed_data:= detector.process(parsed_log)) is not None + assert aggregator.process(processed_data) is not None def test_batch_pipeline(self) -> None: - - parser = MockupParser(name="dummy_parser", config=config) - detector = MockupDetector( + parser = DummyParser(name="dummy_parser", config=config) + detector = DummyDetector( name="dummy_detector", config=config, buffer_mode=BufferMode.BATCH, buffer_size=3, ) + aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) gen = From.log(parser, LOG_PATH) for _ in range(2): @@ -89,7 +93,8 @@ def test_batch_pipeline(self) -> None: assert detector.process(parsed_log) is None parsed_log = next(gen) - assert detector.process(parsed_log) is not None + assert (processed_data := detector.process(parsed_log)) is not None + assert aggregator.process(processed_data) is not None class TestExamples: From add22c02fea9f4e72ec5a5960143662c8d5da4d4 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 28 Sep 2026 16:50:39 +0200 Subject: [PATCH 02/11] fix test_basic_pipelines. --- .../_testutils/dummy_detector.py | 1 - src/detectmatelibrary/common/core.py | 1 - tests/test_data/logs.log | 9 ++++ tests/test_pipelines/test_basic_pipelines.py | 41 +++++++++++++------ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/detectmatelibrary/_testutils/dummy_detector.py b/src/detectmatelibrary/_testutils/dummy_detector.py index 46708096..4fb0e931 100644 --- a/src/detectmatelibrary/_testutils/dummy_detector.py +++ b/src/detectmatelibrary/_testutils/dummy_detector.py @@ -36,7 +36,6 @@ def detect( self._call_count += 1 pattern = [True, False] result = pattern[self._call_count % len(pattern)] - print(self._call_count, result) if result: output_["score"] = 1.0 output_["alertsObtain"]["type"] = "Anomaly detected by DummyDetector" diff --git a/src/detectmatelibrary/common/core.py b/src/detectmatelibrary/common/core.py index 9def631c..75a3c645 100644 --- a/src/detectmatelibrary/common/core.py +++ b/src/detectmatelibrary/common/core.py @@ -105,7 +105,6 @@ def process(self, data: BaseSchema | bytes) -> BaseSchema | bytes | None: logger.debug(f"<<{self.name}>> received:\n{data}") if (data_buffered := self.data_buffer.add(data)) is None: # type: ignore - print("BBBBBBBBBBBB", data, data_buffered) return None if (fit_state := self.fitlogic.run()) == FitLogicState.DO_CONFIG: diff --git a/tests/test_data/logs.log b/tests/test_data/logs.log index f9a8ab75..7fe515f7 100644 --- a/tests/test_data/logs.log +++ b/tests/test_data/logs.log @@ -6,4 +6,13 @@ type=CONFIG_CHANGE msg=audit(1757673850.283:4): op=set audit_failure=1 old=1 aui type=SYSCALL msg=audit(1757673850.283:4): arch=c00000b7 syscall=206 success=yes exit=60 a0=3 a1=7fffc27ad8f0 a2=3c a3=0 items=0 ppid=696 pid=710 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl" exe="/usr/sbin/auditctl" key=(null)ARCH=aarch64 SYSCALL=sendto AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" type=PROCTITLE msg=audit(1757673850.283:4): proctitle=2F7362696E2F617564697463746C002D52002F6574632F61756469742F61756469742E72756C6573 type=CONFIG_CHANGE msg=audit(1757673850.283:5): op=set audit_backlog_wait_time=60000 old=15000 auid=4294967295 ses=4294967295 res=1AUID="unset" +type=SYSCALL msg=audit(1757673850.283:5): arch=c00000b7 syscall=206 success=yes exit=60 a0=3 a1=7fffc27ad8f0 a2=3c a3=0 items=0 ppid=696 pid=710 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl" exe="/usr/sbin/auditctl" key=(null)ARCH=aarch64 SYSCALL=sendto AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" +type=DAEMON_START msg=audit(1757673850.240:4506): op=start ver=3.0.9 format=enriched kernel=6.6.62+rpt-rpi-2712 auid=4294967295 pid=691 uid=0 ses=4294967295 res=successAUID="unset" UID="root" +type=CONFIG_CHANGE msg=audit(1757673850.283:3): op=set audit_backlog_limit=8192 old=64 auid=4294967295 ses=4294967295 res=1AUID="unset" +type=SYSCALL msg=audit(1757673850.283:3): arch=c00000b7 syscall=206 success=yes exit=60 a0=3 a1=7fffc27ad8f0 a2=3c a3=0 items=0 ppid=696 pid=710 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl" exe="/usr/sbin/auditctl" key=(null)ARCH=aarch64 SYSCALL=sendto AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" +type=PROCTITLE msg=audit(1757673850.283:3): proctitle=2F7362696E2F617564697463746C002D52002F6574632F61756469742F61756469742E72756C6573 +type=CONFIG_CHANGE msg=audit(1757673850.283:4): op=set audit_failure=1 old=1 auid=4294967295 ses=4294967295 res=1AUID="unset" +type=SYSCALL msg=audit(1757673850.283:4): arch=c00000b7 syscall=206 success=yes exit=60 a0=3 a1=7fffc27ad8f0 a2=3c a3=0 items=0 ppid=696 pid=710 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl" exe="/usr/sbin/auditctl" key=(null)ARCH=aarch64 SYSCALL=sendto AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" +type=PROCTITLE msg=audit(1757673850.283:4): proctitle=2F7362696E2F617564697463746C002D52002F6574632F61756469742F61756469742E72756C6573 +type=CONFIG_CHANGE msg=audit(1757673850.283:5): op=set audit_backlog_wait_time=60000 old=15000 auid=4294967295 ses=4294967295 res=1AUID="unset" type=SYSCALL msg=audit(1757673850.283:5): arch=c00000b7 syscall=206 success=yes exit=60 a0=3 a1=7fffc27ad8f0 a2=3c a3=0 items=0 ppid=696 pid=710 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl" exe="/usr/sbin/auditctl" key=(null)ARCH=aarch64 SYSCALL=sendto AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root" \ No newline at end of file diff --git a/tests/test_pipelines/test_basic_pipelines.py b/tests/test_pipelines/test_basic_pipelines.py index 4d59f92b..7e3a3715 100644 --- a/tests/test_pipelines/test_basic_pipelines.py +++ b/tests/test_pipelines/test_basic_pipelines.py @@ -50,12 +50,16 @@ def test_basic_pipeline(self) -> None: aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) gen = From.log(parser, LOG_PATH) - for i in range(2): - assert (parsed_log := next(gen)) is not None - assert (processed_data:= detector.process(parsed_log)) is [None, None][i] - assert aggregator.process(processed_data) is None + for i in range(5): + parsed_log = next(gen) + assert parsed_log is not None + processed_data = detector.process(parsed_log) + assert (processed_data is None, processed_data is not None)[i%2] + if processed_data: + assert aggregator.process(processed_data) is None parsed_log = next(gen) - assert (processed_data := detector.process(parsed_log)) is not None + processed_data = detector.process(parsed_log) + assert processed_data is not None assert aggregator.process(processed_data) is not None def test_window_pipeline(self) -> None: @@ -69,12 +73,18 @@ def test_window_pipeline(self) -> None: ) aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) gen = From.log(parser, LOG_PATH) - for _ in range(2): + for i in range(7): parsed_log = next(gen) - assert detector.process(parsed_log) is None - + processed_data = detector.process(parsed_log) + index = i%2 + if i < 3: + index = 0 + assert (processed_data is None, processed_data is not None)[index] + if processed_data: + assert aggregator.process(processed_data) is None parsed_log = next(gen) - assert (processed_data:= detector.process(parsed_log)) is not None + processed_data = detector.process(parsed_log) + assert processed_data is not None assert aggregator.process(processed_data) is not None def test_batch_pipeline(self) -> None: @@ -88,12 +98,19 @@ def test_batch_pipeline(self) -> None: aggregator = DummyAlertAggregator(name="dummy_alert_aggregator", config=config) gen = From.log(parser, LOG_PATH) - for _ in range(2): + for i in range(17): parsed_log = next(gen) - assert detector.process(parsed_log) is None + processed_data = detector.process(parsed_log) + index = i%2 + if i < 3 or (i + 1) % 3 != 0: + index = 0 + assert (processed_data is None, processed_data is not None)[index] + if processed_data: + assert aggregator.process(processed_data) is None parsed_log = next(gen) - assert (processed_data := detector.process(parsed_log)) is not None + processed_data = detector.process(parsed_log) + assert processed_data is not None assert aggregator.process(processed_data) is not None From 98887c92c6ca23251222212367745861673c1b16 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 28 Sep 2026 16:55:09 +0200 Subject: [PATCH 03/11] fix prek issues. --- src/detectmatelibrary/_testutils/dummy_alert_aggregator.py | 2 +- src/detectmatelibrary/alert_aggregation/basic_concat.py | 2 +- tests/test_pipelines/test_basic_pipelines.py | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py b/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py index 3a66d9b5..ccc13058 100644 --- a/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py +++ b/src/detectmatelibrary/_testutils/dummy_alert_aggregator.py @@ -20,7 +20,7 @@ def __init__( super().__init__(name=name, buffer_size=buffer_size, config=config) def aggregate_alerts( - self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema # type: ignore + self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema ) -> bool: output_["description"] = "Dummy alert aggregation" output_["alertsObtain"]["type"] = "Anomalies aggregated by DummyAlertAggregator" diff --git a/src/detectmatelibrary/alert_aggregation/basic_concat.py b/src/detectmatelibrary/alert_aggregation/basic_concat.py index 316fe444..5903545d 100644 --- a/src/detectmatelibrary/alert_aggregation/basic_concat.py +++ b/src/detectmatelibrary/alert_aggregation/basic_concat.py @@ -20,7 +20,7 @@ def __init__( super().__init__(name=name, buffer_size=buffer_size, config=config) def aggregate_alerts( - self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema # type: ignore + self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema ) -> bool: output_["description"] = "Basic aggregation by alert concatenation" return True diff --git a/tests/test_pipelines/test_basic_pipelines.py b/tests/test_pipelines/test_basic_pipelines.py index 7e3a3715..4bf466ab 100644 --- a/tests/test_pipelines/test_basic_pipelines.py +++ b/tests/test_pipelines/test_basic_pipelines.py @@ -11,7 +11,6 @@ import yaml - config = { "parsers": { "dummy_parser": { @@ -54,7 +53,7 @@ def test_basic_pipeline(self) -> None: parsed_log = next(gen) assert parsed_log is not None processed_data = detector.process(parsed_log) - assert (processed_data is None, processed_data is not None)[i%2] + assert (processed_data is None, processed_data is not None)[i % 2] if processed_data: assert aggregator.process(processed_data) is None parsed_log = next(gen) @@ -76,7 +75,7 @@ def test_window_pipeline(self) -> None: for i in range(7): parsed_log = next(gen) processed_data = detector.process(parsed_log) - index = i%2 + index = i % 2 if i < 3: index = 0 assert (processed_data is None, processed_data is not None)[index] @@ -101,7 +100,7 @@ def test_batch_pipeline(self) -> None: for i in range(17): parsed_log = next(gen) processed_data = detector.process(parsed_log) - index = i%2 + index = i % 2 if i < 3 or (i + 1) % 3 != 0: index = 0 assert (processed_data is None, processed_data is not None)[index] From c1f07e1249d730ed667fce5c66e84b8c83dd69d0 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 28 Sep 2026 18:07:18 +0200 Subject: [PATCH 04/11] extend BasicConcatAggregator by adding deduplicate_values variable and extending tests. --- docs/alert_aggregators/basic_concatenation.md | 1 + .../alert_aggregators/basic_concat.py | 1 + .../alert_aggregation/basic_concat.py | 8 ++ .../test_basic_concat.py | 96 +++++++++++++------ 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/docs/alert_aggregators/basic_concatenation.md b/docs/alert_aggregators/basic_concatenation.md index 5e37b904..d7c60c1c 100644 --- a/docs/alert_aggregators/basic_concatenation.md +++ b/docs/alert_aggregators/basic_concatenation.md @@ -15,6 +15,7 @@ alert_aggregators: BasicConcatAggregator: method_type: "basic_concat_aggregator" buffer_size: 3 + deduplicate_values: False auto_config: False ``` diff --git a/docs/examples/alert_aggregators/basic_concat.py b/docs/examples/alert_aggregators/basic_concat.py index ea1bc53a..ce66e7c6 100644 --- a/docs/examples/alert_aggregators/basic_concat.py +++ b/docs/examples/alert_aggregators/basic_concat.py @@ -10,6 +10,7 @@ "BasicConcatAggregator": { "method_type": "basic_concat_aggregator", "buffer_size": 3, + "deduplicate_values": False, "auto_config": False, } } diff --git a/src/detectmatelibrary/alert_aggregation/basic_concat.py b/src/detectmatelibrary/alert_aggregation/basic_concat.py index 5903545d..f7a4835c 100644 --- a/src/detectmatelibrary/alert_aggregation/basic_concat.py +++ b/src/detectmatelibrary/alert_aggregation/basic_concat.py @@ -6,6 +6,7 @@ class BasicConcatAggregationConfig(CoreAlertAggregatorConfig): method_type: str = "basic_concat_aggregator" buffer_size: int = 3 + deduplicate_values: bool = False class BasicConcatAggregation(CoreAlertAggregator): @@ -17,10 +18,17 @@ def __init__( if isinstance(config, dict): config = BasicConcatAggregationConfig.from_dict(config, name) buffer_size: int = config.buffer_size # type: ignore + self.deduplicate_values: bool = config.deduplicate_values # type: ignore super().__init__(name=name, buffer_size=buffer_size, config=config) def aggregate_alerts( self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema ) -> bool: output_["description"] = "Basic aggregation by alert concatenation" + if self.deduplicate_values: + output_["detectorIDs"] = list(dict.fromkeys(output_["detectorIDs"])) + output_["detectorTypes"] = list(dict.fromkeys(output_["detectorTypes"])) + output_["alertIDs"] = list(dict.fromkeys(output_["alertIDs"])) + output_["logIDs"] = list(dict.fromkeys(output_["logIDs"])) + output_["extractedTimestamps"] = list(dict.fromkeys(output_["extractedTimestamps"])) return True diff --git a/tests/test_alert_aggregators/test_basic_concat.py b/tests/test_alert_aggregators/test_basic_concat.py index d07e1b49..127c317a 100644 --- a/tests/test_alert_aggregators/test_basic_concat.py +++ b/tests/test_alert_aggregators/test_basic_concat.py @@ -1,58 +1,96 @@ from detectmatelibrary.alert_aggregation.basic_concat import BasicConcatAggregation - - +from detectmatelibrary.schemas import AggregateSchema from detectmatelibrary.utils.aux import time_test_mode - import detectmatelibrary.schemas as schemas +from datetime import datetime time_test_mode() aggregations_config = { "alert_aggregators": { - "Buffer_3": { + "Buffer_4": { "method_type": "basic_concat_aggregator", - "buffer_size": 3, + "buffer_size": 4, + "auto_config": False, + "params": {}, }, - "Buffer_5": { + "Buffer_6": { "method_type": "basic_concat_aggregator", - "buffer_size": 5, + "buffer_size": 6, + "deduplicate_values": True, + "auto_config": False, + "params": {}, }, - } + }, + "auto_config": False } -dummy_schema = { +data_global = [schemas.DetectorSchema({ + "detectorID": str(i), + "detectorType": "dummy", + "alertID": str(i), + "detectionTimestamp": 0, + "logIDs": [f"logID{i}"], + "score": 0.2 + i / 10, + "extractedTimestamps": [int(datetime.now().timestamp() + i)], + "description": "hello there", + "receivedTimestamp": 1, + "alertsObtain": {"99 problems": "but logs aint one"} +}) for i in range(1, 4)] + +data_global += [schemas.DetectorSchema({ "detectorID": "1", "detectorType": "dummy", - "alertID": "2", + "alertID": "1", "detectionTimestamp": 0, - "logIDs": ["logID1"], - "score": 0.2, - "extractedTimestamps": [-1], + "logIDs": [f"logID{1}"], + "score": 0.3, + "extractedTimestamps": [int(datetime.now().timestamp() + 1)], "description": "hello there", "receivedTimestamp": 1, "alertsObtain": {"99 problems": "but logs aint one"} -} +}) for i in range(1,4)] class TestBasicAggregation: def test_with_buffer_3(self): - alert_aggregator = BasicConcatAggregation("Buffer_3", aggregations_config) - data = schemas.DetectorSchema(dummy_schema).serialize() + alert_aggregator = BasicConcatAggregation("Buffer_4", aggregations_config) + data = data_global - assert alert_aggregator.process(data) is None - assert alert_aggregator.process(data) is None - assert (result := alert_aggregator.process(data)) is not None - assert isinstance(result, bytes) + assert alert_aggregator.process(data[0]) is None + assert alert_aggregator.process(data[1]) is None + assert alert_aggregator.process(data[2]) is None + result = alert_aggregator.process(data[3]) + assert result is not None + assert isinstance(result, AggregateSchema) + res_dict = result.as_dict() + assert res_dict["detectorIDs"] == ["1", "2", "3", "1"] + assert res_dict["alertIDs"] == ["1", "2", "3", "1"] + assert res_dict["outputTimestamp"] == 0 + assert res_dict["logIDs"] == ["logID1", "logID2", "logID3", "logID1"] + assert len(res_dict["extractedTimestamps"]) == 4 + assert res_dict["description"] == "Basic aggregation by alert concatenation" + assert res_dict["detectorTypes"] == ["dummy"]*4 def test_with_buffer_5(self): - alert_aggregator = BasicConcatAggregation("Buffer_5", aggregations_config) - data = schemas.DetectorSchema(dummy_schema).serialize() - - assert alert_aggregator.process(data) is None - assert alert_aggregator.process(data) is None - assert alert_aggregator.process(data) is None - assert alert_aggregator.process(data) is None - assert (result := alert_aggregator.process(data)) is not None - assert isinstance(result, bytes) + alert_aggregator = BasicConcatAggregation("Buffer_6", aggregations_config) + data = data_global + + assert alert_aggregator.process(data[0]) is None + assert alert_aggregator.process(data[1]) is None + assert alert_aggregator.process(data[2]) is None + assert alert_aggregator.process(data[3]) is None + assert alert_aggregator.process(data[4]) is None + result = alert_aggregator.process(data[5]) + assert result is not None + assert isinstance(result, AggregateSchema) + res_dict = result.as_dict() + assert res_dict["detectorIDs"] == ["1", "2", "3"] + assert res_dict["alertIDs"] == ["1", "2", "3"] + assert res_dict["outputTimestamp"] == 0 + assert res_dict["logIDs"] == ["logID1", "logID2", "logID3"] + assert len(res_dict["extractedTimestamps"]) == 3 + assert res_dict["description"] == "Basic aggregation by alert concatenation" + assert res_dict["detectorTypes"] == ["dummy"] From f06c866a210895027c8fc6f592ff932dcf038ff4 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 28 Sep 2026 21:37:34 +0200 Subject: [PATCH 05/11] extend create_workspace.py and tests. --- .../alert_aggregation/basic_concat.py | 2 +- .../tools/workspace/create_workspace.py | 16 ++-- .../templates/CustomAlertAggregator.py | 37 ++++++++++ .../workspace/templates/data/anomalies.json | 0 .../test_CustomAlertAggregator.py | 37 ++++++++++ .../test_basic_concat.py | 2 +- tests/test_workspace/test_create_workspace.py | 74 +++++++++++++++++-- 7 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py create mode 100644 src/detectmatelibrary/tools/workspace/templates/data/anomalies.json create mode 100644 src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py diff --git a/src/detectmatelibrary/alert_aggregation/basic_concat.py b/src/detectmatelibrary/alert_aggregation/basic_concat.py index f7a4835c..e53d52ed 100644 --- a/src/detectmatelibrary/alert_aggregation/basic_concat.py +++ b/src/detectmatelibrary/alert_aggregation/basic_concat.py @@ -18,7 +18,7 @@ def __init__( if isinstance(config, dict): config = BasicConcatAggregationConfig.from_dict(config, name) buffer_size: int = config.buffer_size # type: ignore - self.deduplicate_values: bool = config.deduplicate_values # type: ignore + self.deduplicate_values: bool = config.deduplicate_values # type: ignore super().__init__(name=name, buffer_size=buffer_size, config=config) def aggregate_alerts( diff --git a/src/detectmatelibrary/tools/workspace/create_workspace.py b/src/detectmatelibrary/tools/workspace/create_workspace.py index 0bfb3480..a27336d1 100644 --- a/src/detectmatelibrary/tools/workspace/create_workspace.py +++ b/src/detectmatelibrary/tools/workspace/create_workspace.py @@ -14,7 +14,8 @@ META_FILES = ["LICENSE.md", ".gitignore", ".pre-commit-config.yaml"] DATA_FILES = { "parser": TEMPLATE_DIR / "data/logs.json", - "detector": TEMPLATE_DIR / "data/parsed_log.json" + "detector": TEMPLATE_DIR / "data/parsed_log.json", + "alert_aggregator": TEMPLATE_DIR / "data/anomalies.json" } @@ -38,12 +39,14 @@ def create_tests(type_: str, name: str, workspace_root: Path, pkg_name: str) -> - Reads template tests from src/tools/workspace/templates/test_templates/ - Rewrites the import to point to . - - Renames CustomParser/CustomDetector to the camelized class name + - Renames CustomParser/CustomDetector/CustomAlertAggregator to the camelized class name """ tests_dir = workspace_root / "tests" tests_dir.mkdir(parents=True, exist_ok=True) - template_file = TEMPLATE_DIR / "test_templates" / f"test_Custom{type_.capitalize()}.py" + # base names in the template (CustomParser/CustomDetector/CustomAlertAggregator) + base_class = f"Custom{"".join(part.capitalize() for part in type_.split("_"))}" + template_file = TEMPLATE_DIR / "test_templates" / f"test_{base_class}.py" test_file = tests_dir / f"test_{name}.py" if not template_file.exists(): @@ -52,7 +55,6 @@ def create_tests(type_: str, name: str, workspace_root: Path, pkg_name: str) -> return template_content = template_file.read_text() - base_class = f"Custom{type_.capitalize()}" # base names in the template (CustomParser/CustomDetector) # The exact import line in the template, e.g: # from ..CustomParser import CustomParser, CustomParserConfig # from ..CustomDetector import CustomDetector, CustomDetectorConfig @@ -98,7 +100,7 @@ def create_workspace(type_: str, name: str, target_dir: Path) -> None: pkg_dir.mkdir(parents=True, exist_ok=False) # Template selection - template_file = TEMPLATE_DIR / f"Custom{type_.capitalize()}.py" + template_file = TEMPLATE_DIR / f"Custom{"".join(part.capitalize() for part in type_.split("_"))}.py" module_name = normalize_package_name(name) target_code_file = pkg_dir / f"{module_name}.py" @@ -109,7 +111,7 @@ def create_workspace(type_: str, name: str, target_dir: Path) -> None: template_content = template_file.read_text() # Replace default class name inside template - original_class = f"Custom{type_.capitalize()}" + original_class = f"Custom{"".join(part.capitalize() for part in type_.split("_"))}" new_class = camelize(name) template_content = template_content.replace(original_class, new_class) template_content = template_content.replace(f"custom_{type_}", f"{name}_{type_}") @@ -164,7 +166,7 @@ def main() -> None: create_cmd.add_argument( "--type", required=True, - choices=["parser", "detector"], + choices=["parser", "detector", "alert_aggregator"], help="Type of component to generate", ) diff --git a/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py new file mode 100644 index 00000000..7ce9ddde --- /dev/null +++ b/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py @@ -0,0 +1,37 @@ +from detectmatelibrary.common.alert_aggregator import (CoreAlertAggregatorConfig, CoreAlertAggregator) +from detectmatelibrary.schemas import DetectorSchema, AggregateSchema +from typing import Any, Optional +from detectmatelibrary.helper.from_to import From + + +class CustomAlertAggregatorConfig(CoreAlertAggregatorConfig): + method_type: str = "custom_alert_aggregator" + buffer_size: int = 3 + + +class CustomAlertAggregator(CoreAlertAggregator): + def __init__( + self, + name: str = "CustomAlertAggregator", + config: Optional[CustomAlertAggregatorConfig | dict[str, Any]] = CustomAlertAggregatorConfig(), + ) -> None: + if isinstance(config, dict): + config = CustomAlertAggregatorConfig.from_dict(config, name) + buffer_size: int = config.buffer_size # type: ignore + super().__init__(name=name, buffer_size=buffer_size, config=config) + + def aggregate_alerts( + self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema + ) -> bool: + output_["description"] = "Custom alert aggregation" + output_["alertsObtain"]["type"] = "Anomalies aggregated by DummyAlertAggregator" + return True + + +if __name__ == "__main__": + + print(aggregator := CustomAlertAggregator()) + + print("Running with data...") + for alerts in From.json(aggregator, "data.json"): + print(alerts) \ No newline at end of file diff --git a/src/detectmatelibrary/tools/workspace/templates/data/anomalies.json b/src/detectmatelibrary/tools/workspace/templates/data/anomalies.json new file mode 100644 index 00000000..e69de29b diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py new file mode 100644 index 00000000..c1e6ad65 --- /dev/null +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py @@ -0,0 +1,37 @@ +from typing import Any +from detectmatelibrary import schemas +from ..CustomAlertAggregator import CustomAlertAggregator, CustomAlertAggregatorConfig + + +default_args = { + "alert_aggregator": { + "CustomAlertAggregator": { + "method_type": "custom_alert_aggregator", + "auto_config": False, + "params": {}, + } + } +} + + +class TestCustomAlertAggregator: + def test_initialize_default(self) -> None: + alert_aggregator = CustomAlertAggregator(name="CustomAlertAggregator", config=default_args) + assert isinstance(alert_aggregator, CustomAlertAggregator) + assert alert_aggregator.name == "CustomAlertAggregator" + assert isinstance(alert_aggregator.config, CustomAlertAggregatorConfig) + + def test_run_aggregate_alerts_method(self) -> None: + alert_aggregator = CustomAlertAggregator() + data = schemas.DetectorSchema({"log": "test log"}) + output: Any = schemas.AggregateSchema() + + result = alert_aggregator.aggregate_alerts(data, output) + + assert output.description == "Dummy alert aggregation process" + if result: + assert output.score == 1.0 + assert "Anomaly detected" in output.alertsObtain["type"] + else: + assert output.score == 0.0 + assert len(output.alertsObtain) == 0 diff --git a/tests/test_alert_aggregators/test_basic_concat.py b/tests/test_alert_aggregators/test_basic_concat.py index 127c317a..00cda8bb 100644 --- a/tests/test_alert_aggregators/test_basic_concat.py +++ b/tests/test_alert_aggregators/test_basic_concat.py @@ -51,7 +51,7 @@ "description": "hello there", "receivedTimestamp": 1, "alertsObtain": {"99 problems": "but logs aint one"} -}) for i in range(1,4)] +}) for i in range(1, 4)] class TestBasicAggregation: diff --git a/tests/test_workspace/test_create_workspace.py b/tests/test_workspace/test_create_workspace.py index d717c910..f855cd0d 100644 --- a/tests/test_workspace/test_create_workspace.py +++ b/tests/test_workspace/test_create_workspace.py @@ -16,7 +16,6 @@ def temp_dir(tmp_path: Path) -> Path: return tmp_path -@pytest.mark.ignored def test_create_parser_workspace(temp_dir: Path): ws_name = "myParser" workspace_root = temp_dir @@ -56,7 +55,6 @@ def test_create_parser_workspace(temp_dir: Path): assert (tests_dir / f"test_{ws_name}.py").exists() -@pytest.mark.ignored def test_create_detector_workspace(temp_dir: Path): ws_name = "myDetector" workspace_root = temp_dir @@ -89,7 +87,38 @@ def test_create_detector_workspace(temp_dir: Path): assert (tests_dir / f"test_{ws_name}.py").exists() -@pytest.mark.ignored +def test_create_alert_aggregator_workspace(temp_dir: Path): + ws_name = "myAlertAggregator" + workspace_root = temp_dir + pkg_name = normalize_package_name(ws_name) # myalertaggregator + module_name = normalize_package_name(ws_name) # myalertaggregator + pkg_dir = workspace_root / pkg_name + tests_dir = workspace_root / "tests" + + subprocess.check_call([ + *CLI, + "create", + "--type", "alert_aggregator", + "--name", ws_name, + "--dir", str(workspace_root), + ]) + + assert workspace_root.exists() + assert pkg_dir.exists() + + assert (workspace_root / "LICENSE.md").exists() + assert (workspace_root / ".gitignore").exists() + assert (workspace_root / ".pre-commit-config.yaml").exists() + assert (workspace_root / "README.md").exists() + + py_files = list(pkg_dir.glob("*.py")) + assert len(py_files) == 2 # __init__.py + myAlertAggrogator.py + assert (pkg_dir / f"{module_name}.py").exists() + assert (pkg_dir / "__init__.py").exists() + assert tests_dir.exists() + assert (tests_dir / f"test_{ws_name}.py").exists() + + def test_create_workspace_with_dash_name(temp_dir: Path): ws_name = "custom-parser" workspace_root = temp_dir @@ -140,7 +169,6 @@ def test_fail_if_dir_exists(temp_dir: Path): assert "already exists" in result.stderr -@pytest.mark.ignored def test_generated_detector_tests_pass(temp_dir: Path): """Run pytest inside the generated workspace on the generated detector test file.""" @@ -178,7 +206,6 @@ def test_generated_detector_tests_pass(temp_dir: Path): sys.path[:] = old_sys_path -@pytest.mark.ignored def test_generated_parser_tests_pass(temp_dir: Path): ws_name = "MyCoolParser" workspace_root = temp_dir @@ -209,3 +236,40 @@ def test_generated_parser_tests_pass(temp_dir: Path): finally: os.chdir(old_cwd) sys.path[:] = old_sys_path + + +def test_generated_alert_aggregator_tests_pass(temp_dir: Path): + """Run pytest inside the generated workspace on the generated detector test + file.""" + + ws_name = "MyCoolAlertAggregator" + workspace_root = temp_dir + pkg_dir = workspace_root / "mycoolalertaggregator" + tests_dir = workspace_root / "tests" + test_file = tests_dir / f"test_{ws_name}.py" + + subprocess.check_call([ + *CLI, + "create", + "--type", "alert_aggregator", + "--name", ws_name, + "--dir", str(workspace_root), + ]) + + assert workspace_root.exists() + assert pkg_dir.exists() + assert tests_dir.exists() + assert test_file.exists() + + # run pytest on the generated test file + # and make sure the workspace root is on sys.path so "import mycoolalertaggregator" works + old_cwd = os.getcwd() + old_sys_path = list(sys.path) + try: + os.chdir(workspace_root) + sys.path.insert(0, str(workspace_root)) + result = pytest.main([str(test_file.relative_to(workspace_root))]) + assert result == 0 + finally: + os.chdir(old_cwd) + sys.path[:] = old_sys_path From 54a542ada09baacec980ddd1402685c4ae72e1cc Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Fri, 2 Oct 2026 22:36:32 +0200 Subject: [PATCH 06/11] implement custom template tests with real data. --- .../tools/workspace/create_workspace.py | 2 +- .../templates/CustomAlertAggregator.py | 6 +- .../workspace/templates/CustomDetector.py | 7 - .../tools/workspace/templates/CustomParser.py | 5 - .../workspace/templates/data/alerts.json | 194 ++++++++++++++++++ .../workspace/templates/data/anomalies.json | 0 .../test_CustomAlertAggregator.py | 35 ++-- .../test_templates/test_CustomDetector.py | 30 +-- .../test_templates/test_CustomParser.py | 27 ++- .../test_basic_concat.py | 4 +- 10 files changed, 254 insertions(+), 56 deletions(-) create mode 100644 src/detectmatelibrary/tools/workspace/templates/data/alerts.json delete mode 100644 src/detectmatelibrary/tools/workspace/templates/data/anomalies.json diff --git a/src/detectmatelibrary/tools/workspace/create_workspace.py b/src/detectmatelibrary/tools/workspace/create_workspace.py index a27336d1..21ec1e88 100644 --- a/src/detectmatelibrary/tools/workspace/create_workspace.py +++ b/src/detectmatelibrary/tools/workspace/create_workspace.py @@ -15,7 +15,7 @@ DATA_FILES = { "parser": TEMPLATE_DIR / "data/logs.json", "detector": TEMPLATE_DIR / "data/parsed_log.json", - "alert_aggregator": TEMPLATE_DIR / "data/anomalies.json" + "alert_aggregator": TEMPLATE_DIR / "data/alerts.json" } diff --git a/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py index 7ce9ddde..fdfa9d4b 100644 --- a/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py +++ b/src/detectmatelibrary/tools/workspace/templates/CustomAlertAggregator.py @@ -24,14 +24,12 @@ def aggregate_alerts( self, input_: list[DetectorSchema] | DetectorSchema, output_: AggregateSchema ) -> bool: output_["description"] = "Custom alert aggregation" - output_["alertsObtain"]["type"] = "Anomalies aggregated by DummyAlertAggregator" + output_["alertsObtain"]["type"] = "Anomalies aggregated by CustomAlertAggregator" return True if __name__ == "__main__": - print(aggregator := CustomAlertAggregator()) - print("Running with data...") for alerts in From.json(aggregator, "data.json"): - print(alerts) \ No newline at end of file + print(alerts) diff --git a/src/detectmatelibrary/tools/workspace/templates/CustomDetector.py b/src/detectmatelibrary/tools/workspace/templates/CustomDetector.py index 07f6b8db..c36aea09 100644 --- a/src/detectmatelibrary/tools/workspace/templates/CustomDetector.py +++ b/src/detectmatelibrary/tools/workspace/templates/CustomDetector.py @@ -1,5 +1,4 @@ from typing import Any, List - from detectmatelibrary.common.detector import CoreDetector, CoreDetectorConfig from detectmatelibrary.utils.data_buffer import BufferMode from detectmatelibrary.helper.from_to import From @@ -24,7 +23,6 @@ def __init__( name: str = "CustomDetector", config: CustomDetectorConfig | dict[str, Any] = CustomDetectorConfig(), ) -> None: - # Allow passing either a config instance or a plain dict if isinstance(config, dict): config = CustomDetectorConfig.from_dict(config, name) @@ -43,9 +41,7 @@ def detect( :param output_: DetectorSchema instance to be mutated in-place :return: Detection result (True/False) """ - output_["description"] = "Dummy detection process" # Description of the detection - # Alternating pattern: True, False, True, False, etc self._call_count += 1 pattern = [True, False] @@ -53,14 +49,11 @@ def detect( if result: output_["score"] = 1.0 # Score of the detector output_["alertsObtain"]["type"] = "Anomaly detected by CustomDetector" # Additional info - return result if __name__ == "__main__": - print(detector := CustomDetector()) - print("Running with data...") for alerts in From.json(detector, "data.json"): print(alerts) diff --git a/src/detectmatelibrary/tools/workspace/templates/CustomParser.py b/src/detectmatelibrary/tools/workspace/templates/CustomParser.py index a40a932f..fd7f98a4 100644 --- a/src/detectmatelibrary/tools/workspace/templates/CustomParser.py +++ b/src/detectmatelibrary/tools/workspace/templates/CustomParser.py @@ -1,5 +1,4 @@ from typing import Any - from detectmatelibrary.common.parser import CoreParser, CoreParserConfig from detectmatelibrary.helper.from_to import From from detectmatelibrary import schemas @@ -25,7 +24,6 @@ def __init__( # Allow passing either a config instance or a plain dict if isinstance(config, dict): config = CustomParserConfig.from_dict(config, name) - super().__init__(name=name, config=config) def parse( @@ -39,7 +37,6 @@ def parse( :param output_: Parser output schema instance to be mutated in- place """ - # Dummy implementation example (replace with real logic) output_["EventID"] = 2 # Number of the log template output_["variables"].extend(["dummy_variable"]) # Variables found in the log @@ -47,9 +44,7 @@ def parse( if __name__ == "__main__": - print(parser := CustomParser()) - print("Running with data...") for parsed_log in From.json(parser, "data.json"): print(parsed_log) diff --git a/src/detectmatelibrary/tools/workspace/templates/data/alerts.json b/src/detectmatelibrary/tools/workspace/templates/data/alerts.json new file mode 100644 index 00000000..f7ae0712 --- /dev/null +++ b/src/detectmatelibrary/tools/workspace/templates/data/alerts.json @@ -0,0 +1,194 @@ +{ + "0": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_10", + "detectionTimestamp": 1790969620, + "logIDs": ["0"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "1": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_11", + "detectionTimestamp": 1790969620, + "logIDs": ["1"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "2": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_12", + "detectionTimestamp": 1790969620, + "logIDs": ["2"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "3": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_13", + "detectionTimestamp": 1790969620, + "logIDs": ["3"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "4": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_14", + "detectionTimestamp": 1790969620, + "logIDs": ["4"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "5": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_15", + "detectionTimestamp": 1790969620, + "logIDs": ["5"], + "score": 1, + "extractedTimestamps": [1642723741], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "6": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_16", + "detectionTimestamp": 1790969620, + "logIDs": ["6"], + "score": 1, + "extractedTimestamps": [1642723752], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "7": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_17", + "detectionTimestamp": 1790969620, + "logIDs": ["7"], + "score": 1, + "extractedTimestamps": [1642723752], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "8": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_18", + "detectionTimestamp": 1790969620, + "logIDs": ["8"], + "score": 1, + "extractedTimestamps": [1642724221], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "9": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_19", + "detectionTimestamp": 1790969620, + "logIDs": ["9"], + "score": 1, + "extractedTimestamps": [1642724221], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "10": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_20", + "detectionTimestamp": 1790969620, + "logIDs": ["10"], + "score": 1, + "extractedTimestamps": [1642724221], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + }, + "11": { + "__version__": "1.0.0", + "detectorID": "MyCoolThing", + "detectorType": "MyCoolThing_detector", + "alertID": "MyCoolThing_21", + "detectionTimestamp": 1790969620, + "logIDs": ["11"], + "score": 1, + "extractedTimestamps": [1642724221], + "description": "Dummy detection process", + "receivedTimestamp": 1790969620, + "alertsObtain": { + "key": "type", + "value": "Anomaly detected by MyCoolThing" + } + } +} \ No newline at end of file diff --git a/src/detectmatelibrary/tools/workspace/templates/data/anomalies.json b/src/detectmatelibrary/tools/workspace/templates/data/anomalies.json deleted file mode 100644 index e69de29b..00000000 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py index c1e6ad65..ede2cfb9 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py @@ -1,10 +1,9 @@ -from typing import Any -from detectmatelibrary import schemas from ..CustomAlertAggregator import CustomAlertAggregator, CustomAlertAggregatorConfig +from detectmatelibrary.helper.from_to import From default_args = { - "alert_aggregator": { + "alert_aggregators": { "CustomAlertAggregator": { "method_type": "custom_alert_aggregator", "auto_config": False, @@ -22,16 +21,22 @@ def test_initialize_default(self) -> None: assert isinstance(alert_aggregator.config, CustomAlertAggregatorConfig) def test_run_aggregate_alerts_method(self) -> None: - alert_aggregator = CustomAlertAggregator() - data = schemas.DetectorSchema({"log": "test log"}) - output: Any = schemas.AggregateSchema() - - result = alert_aggregator.aggregate_alerts(data, output) + alert_aggregator = CustomAlertAggregator(name="CustomAlertAggregator", config=default_args) - assert output.description == "Dummy alert aggregation process" - if result: - assert output.score == 1.0 - assert "Anomaly detected" in output.alertsObtain["type"] - else: - assert output.score == 0.0 - assert len(output.alertsObtain) == 0 + gen = From.json(alert_aggregator, "data.json", do_process=False) + i = 0 + while True: + try: + data = next(gen) + except StopIteration: + break + output = alert_aggregator.process(data) + if i % 3 == 2: + assert output.description == "Custom alert aggregation" + assert output.detectorIDs == ["MyCoolThing"]*3 + assert output.alertsObtain["type"] == "Anomalies aggregated by CustomAlertAggregator" + assert output.detectorTypes == ["MyCoolThing_detector"]*3 + assert output.alertIDs == [ + f"MyCoolThing_{i + 8}", f"MyCoolThing_{i + 9}", f"MyCoolThing_{i + 10}"] + assert output.logIDs == [str(i-2), str(i-1), str(i)] + i += 1 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py index a0e6414b..df4d5371 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py @@ -1,6 +1,5 @@ -from typing import Any -from detectmatelibrary import schemas from ..CustomDetector import CustomDetector, CustomDetectorConfig +from detectmatelibrary.helper.from_to import From default_args = { @@ -23,15 +22,20 @@ def test_initialize_default(self) -> None: def test_run_detect_method(self) -> None: detector = CustomDetector() - data = schemas.ParserSchema({"log": "test log"}) - output: Any = schemas.DetectorSchema() - - result = detector.detect(data, output) - - assert output.description == "Dummy detection process" - if result: + gen = From.json(detector, "data.json", do_process=False) + i = 0 + while True: + try: + data = next(gen) + except StopIteration: + break + assert detector.process(data) is None + output = detector.process(data) + assert output.description == "Dummy detection process" assert output.score == 1.0 - assert "Anomaly detected" in output.alertsObtain["type"] - else: - assert output.score == 0.0 - assert len(output.alertsObtain) == 0 + assert output.alertsObtain["type"] == "Anomaly detected by MyCoolThing" + assert output.detectorID == "MyCoolThing" + assert output.detectorType == "MyCoolThing_detector" + assert output.alertID == f"MyCoolThing_{i + 10}" + assert output.logIDs == [str(i)] + i += 1 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py index 855cd6d7..e09defc5 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py @@ -1,6 +1,5 @@ -from typing import Any -from detectmatelibrary import schemas from ..CustomParser import CustomParser, CustomParserConfig +from detectmatelibrary.helper.from_to import From default_args = { @@ -23,10 +22,20 @@ def test_initialize_default(self) -> None: def test_run_parse_method(self) -> None: parser = CustomParser() - input_data = schemas.LogSchema({"log": "test log"}) - output_data: Any = schemas.ParserSchema() - - parser.parse(input_data, output_data) - - assert output_data.variables == ["dummy_variable"] - assert output_data.template == "This is a dummy template" + gen = From.json(parser, "data.json", do_process=False) + i = 0 + while True: + try: + data = next(gen) + except StopIteration: + break + output = parser.process(data) + assert output.EventID == 2 + assert output.template == "This is a dummy template" + assert output.logFormatVariables["Time"] == "0" + assert output.parserID == "MyCoolParser" + assert output.parserType == "MyCoolParser_parser" + assert output.variables == ["dummy_variable"] + assert output.parsedLogID == f"MyCoolParser_{i + 10}" + assert output.logID == str(i) + i += 1 diff --git a/tests/test_alert_aggregators/test_basic_concat.py b/tests/test_alert_aggregators/test_basic_concat.py index 00cda8bb..221c14ff 100644 --- a/tests/test_alert_aggregators/test_basic_concat.py +++ b/tests/test_alert_aggregators/test_basic_concat.py @@ -55,7 +55,7 @@ class TestBasicAggregation: - def test_with_buffer_3(self): + def test_with_buffer_4(self): alert_aggregator = BasicConcatAggregation("Buffer_4", aggregations_config) data = data_global @@ -74,7 +74,7 @@ def test_with_buffer_3(self): assert res_dict["description"] == "Basic aggregation by alert concatenation" assert res_dict["detectorTypes"] == ["dummy"]*4 - def test_with_buffer_5(self): + def test_with_buffer_6(self): alert_aggregator = BasicConcatAggregation("Buffer_6", aggregations_config) data = data_global From 5511d19d2a1387674fedbbb92623b81e80c9e390 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Fri, 2 Oct 2026 22:49:50 +0200 Subject: [PATCH 07/11] fix prek issues. --- .../tools/workspace/templates/data/alerts.json | 2 +- .../test_templates/test_CustomAlertAggregator.py | 13 +++++++------ .../test_templates/test_CustomDetector.py | 14 +++++++------- .../test_templates/test_CustomParser.py | 16 ++++++++-------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/detectmatelibrary/tools/workspace/templates/data/alerts.json b/src/detectmatelibrary/tools/workspace/templates/data/alerts.json index f7ae0712..cc8fd2e2 100644 --- a/src/detectmatelibrary/tools/workspace/templates/data/alerts.json +++ b/src/detectmatelibrary/tools/workspace/templates/data/alerts.json @@ -191,4 +191,4 @@ "value": "Anomaly detected by MyCoolThing" } } -} \ No newline at end of file +} diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py index ede2cfb9..36ecf123 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py @@ -32,11 +32,12 @@ def test_run_aggregate_alerts_method(self) -> None: break output = alert_aggregator.process(data) if i % 3 == 2: - assert output.description == "Custom alert aggregation" - assert output.detectorIDs == ["MyCoolThing"]*3 - assert output.alertsObtain["type"] == "Anomalies aggregated by CustomAlertAggregator" - assert output.detectorTypes == ["MyCoolThing_detector"]*3 - assert output.alertIDs == [ + assert getattr(output, "description") == "Custom alert aggregation" + assert getattr(output, "detectorIDs") == ["MyCoolThing"]*3 + assert getattr(output, "alertsObtain")["type"] == \ + "Anomalies aggregated by CustomAlertAggregator" + assert getattr(output, "detectorTypes") == ["MyCoolThing_detector"]*3 + assert getattr(output, "alertIDs") == [ f"MyCoolThing_{i + 8}", f"MyCoolThing_{i + 9}", f"MyCoolThing_{i + 10}"] - assert output.logIDs == [str(i-2), str(i-1), str(i)] + assert getattr(output, "logIDs") == [str(i-2), str(i-1), str(i)] i += 1 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py index df4d5371..a888ba74 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py @@ -31,11 +31,11 @@ def test_run_detect_method(self) -> None: break assert detector.process(data) is None output = detector.process(data) - assert output.description == "Dummy detection process" - assert output.score == 1.0 - assert output.alertsObtain["type"] == "Anomaly detected by MyCoolThing" - assert output.detectorID == "MyCoolThing" - assert output.detectorType == "MyCoolThing_detector" - assert output.alertID == f"MyCoolThing_{i + 10}" - assert output.logIDs == [str(i)] + assert getattr(output, "description") == "Dummy detection process" + assert getattr(output, "score") == 1.0 + assert getattr(output, "alertsObtain")["type"] == "Anomaly detected by MyCoolThing" + assert getattr(output, "detectorID") == "MyCoolThing" + assert getattr(output, "detectorType") == "MyCoolThing_detector" + assert getattr(output, "alertID") == f"MyCoolThing_{i + 10}" + assert getattr(output, "logIDs") == [str(i)] i += 1 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py index e09defc5..fb14b346 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py @@ -30,12 +30,12 @@ def test_run_parse_method(self) -> None: except StopIteration: break output = parser.process(data) - assert output.EventID == 2 - assert output.template == "This is a dummy template" - assert output.logFormatVariables["Time"] == "0" - assert output.parserID == "MyCoolParser" - assert output.parserType == "MyCoolParser_parser" - assert output.variables == ["dummy_variable"] - assert output.parsedLogID == f"MyCoolParser_{i + 10}" - assert output.logID == str(i) + assert getattr(output, "EventID") == 2 + assert getattr(output, "template") == "This is a dummy template" + assert getattr(output, "logFormatVariables")["Time"] == "0" + assert getattr(output, "parserID") == "MyCoolParser" + assert getattr(output, "parserType") == "MyCoolParser_parser" + assert getattr(output, "variables") == ["dummy_variable"] + assert getattr(output, "parsedLogID") == f"MyCoolParser_{i + 10}" + assert getattr(output, "logID") == str(i) i += 1 From 56659bb06652a84864c06f6e7d8082e7243c6b3a Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Fri, 2 Oct 2026 23:15:30 +0200 Subject: [PATCH 08/11] fix test_Custom unittests. --- .../test_templates/test_CustomAlertAggregator.py | 8 +++++++- .../test_templates/test_CustomDetector.py | 15 ++++++++++----- .../templates/test_templates/test_CustomParser.py | 13 +++++++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py index 36ecf123..ff111148 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomAlertAggregator.py @@ -1,3 +1,5 @@ +import os.path + from ..CustomAlertAggregator import CustomAlertAggregator, CustomAlertAggregatorConfig from detectmatelibrary.helper.from_to import From @@ -23,7 +25,11 @@ def test_initialize_default(self) -> None: def test_run_aggregate_alerts_method(self) -> None: alert_aggregator = CustomAlertAggregator(name="CustomAlertAggregator", config=default_args) - gen = From.json(alert_aggregator, "data.json", do_process=False) + if os.path.exists("data.json"): + gen = From.json(alert_aggregator, "data.json", do_process=False) + else: + gen = From.json(alert_aggregator, os.path.join( + os.path.dirname(os.path.abspath(__file__)), "../data/alerts.json"), do_process=False) i = 0 while True: try: diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py index a888ba74..48685722 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomDetector.py @@ -1,3 +1,4 @@ +import os from ..CustomDetector import CustomDetector, CustomDetectorConfig from detectmatelibrary.helper.from_to import From @@ -22,7 +23,11 @@ def test_initialize_default(self) -> None: def test_run_detect_method(self) -> None: detector = CustomDetector() - gen = From.json(detector, "data.json", do_process=False) + if os.path.exists("data.json"): + gen = From.json(detector, "data.json", do_process=False) + else: + gen = From.json(detector, os.path.join( + os.path.dirname(os.path.abspath(__file__)), "../data/parsed_log.json"), do_process=False) i = 0 while True: try: @@ -33,9 +38,9 @@ def test_run_detect_method(self) -> None: output = detector.process(data) assert getattr(output, "description") == "Dummy detection process" assert getattr(output, "score") == 1.0 - assert getattr(output, "alertsObtain")["type"] == "Anomaly detected by MyCoolThing" - assert getattr(output, "detectorID") == "MyCoolThing" - assert getattr(output, "detectorType") == "MyCoolThing_detector" - assert getattr(output, "alertID") == f"MyCoolThing_{i + 10}" + assert getattr(output, "alertsObtain")["type"] == "Anomaly detected by CustomDetector" + assert getattr(output, "detectorID") == "CustomDetector" + assert getattr(output, "detectorType") == "custom_detector" + assert getattr(output, "alertID") == f"CustomDetector_{i + 10}" assert getattr(output, "logIDs") == [str(i)] i += 1 diff --git a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py index fb14b346..e7328a09 100644 --- a/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py +++ b/src/detectmatelibrary/tools/workspace/templates/test_templates/test_CustomParser.py @@ -1,3 +1,4 @@ +import os from ..CustomParser import CustomParser, CustomParserConfig from detectmatelibrary.helper.from_to import From @@ -22,7 +23,11 @@ def test_initialize_default(self) -> None: def test_run_parse_method(self) -> None: parser = CustomParser() - gen = From.json(parser, "data.json", do_process=False) + if os.path.exists("data.json"): + gen = From.json(parser, "data.json", do_process=False) + else: + gen = From.json(parser, os.path.join( + os.path.dirname(os.path.abspath(__file__)), "../data/logs.json"), do_process=False) i = 0 while True: try: @@ -33,9 +38,9 @@ def test_run_parse_method(self) -> None: assert getattr(output, "EventID") == 2 assert getattr(output, "template") == "This is a dummy template" assert getattr(output, "logFormatVariables")["Time"] == "0" - assert getattr(output, "parserID") == "MyCoolParser" - assert getattr(output, "parserType") == "MyCoolParser_parser" + assert getattr(output, "parserID") == "CustomParser" + assert getattr(output, "parserType") == "custom_parser" assert getattr(output, "variables") == ["dummy_variable"] - assert getattr(output, "parsedLogID") == f"MyCoolParser_{i + 10}" + assert getattr(output, "parsedLogID") == f"CustomParser_{i + 10}" assert getattr(output, "logID") == str(i) i += 1 From b1617c1ffa945de1078087934a4b80640013d801 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 5 Oct 2026 15:42:08 +0200 Subject: [PATCH 09/11] add ignored test mark. --- tests/test_workspace/test_create_workspace.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_workspace/test_create_workspace.py b/tests/test_workspace/test_create_workspace.py index f855cd0d..90dc7649 100644 --- a/tests/test_workspace/test_create_workspace.py +++ b/tests/test_workspace/test_create_workspace.py @@ -16,6 +16,7 @@ def temp_dir(tmp_path: Path) -> Path: return tmp_path +@pytest.mark.ignored def test_create_parser_workspace(temp_dir: Path): ws_name = "myParser" workspace_root = temp_dir From 5b17da96ae4c75b07e19aa9bc7fddeeb9c24701d Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 5 Oct 2026 15:44:13 +0200 Subject: [PATCH 10/11] add ignored test marks. --- tests/test_workspace/test_create_workspace.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_workspace/test_create_workspace.py b/tests/test_workspace/test_create_workspace.py index 90dc7649..da095252 100644 --- a/tests/test_workspace/test_create_workspace.py +++ b/tests/test_workspace/test_create_workspace.py @@ -56,6 +56,7 @@ def test_create_parser_workspace(temp_dir: Path): assert (tests_dir / f"test_{ws_name}.py").exists() +@pytest.mark.ignored def test_create_detector_workspace(temp_dir: Path): ws_name = "myDetector" workspace_root = temp_dir @@ -88,6 +89,7 @@ def test_create_detector_workspace(temp_dir: Path): assert (tests_dir / f"test_{ws_name}.py").exists() +@pytest.mark.ignored def test_create_alert_aggregator_workspace(temp_dir: Path): ws_name = "myAlertAggregator" workspace_root = temp_dir @@ -120,6 +122,7 @@ def test_create_alert_aggregator_workspace(temp_dir: Path): assert (tests_dir / f"test_{ws_name}.py").exists() +@pytest.mark.ignored def test_create_workspace_with_dash_name(temp_dir: Path): ws_name = "custom-parser" workspace_root = temp_dir @@ -149,6 +152,7 @@ def test_create_workspace_with_dash_name(temp_dir: Path): assert f"from {pkg_name}.{module_name} import " in content +@pytest.mark.ignored def test_fail_if_dir_exists(temp_dir: Path): ws_name = "existing" workspace_root = temp_dir @@ -170,6 +174,7 @@ def test_fail_if_dir_exists(temp_dir: Path): assert "already exists" in result.stderr +@pytest.mark.ignored def test_generated_detector_tests_pass(temp_dir: Path): """Run pytest inside the generated workspace on the generated detector test file.""" @@ -207,6 +212,7 @@ def test_generated_detector_tests_pass(temp_dir: Path): sys.path[:] = old_sys_path +@pytest.mark.ignored def test_generated_parser_tests_pass(temp_dir: Path): ws_name = "MyCoolParser" workspace_root = temp_dir @@ -239,6 +245,7 @@ def test_generated_parser_tests_pass(temp_dir: Path): sys.path[:] = old_sys_path +@pytest.mark.ignored def test_generated_alert_aggregator_tests_pass(temp_dir: Path): """Run pytest inside the generated workspace on the generated detector test file.""" From 0805e36503518a6f0d63169b6376ebb08ca93f48 Mon Sep 17 00:00:00 2001 From: Ernst Leierzopf Date: Mon, 5 Oct 2026 15:45:30 +0200 Subject: [PATCH 11/11] remove one ignored mark. --- tests/test_workspace/test_create_workspace.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_workspace/test_create_workspace.py b/tests/test_workspace/test_create_workspace.py index da095252..3f6c55da 100644 --- a/tests/test_workspace/test_create_workspace.py +++ b/tests/test_workspace/test_create_workspace.py @@ -152,7 +152,6 @@ def test_create_workspace_with_dash_name(temp_dir: Path): assert f"from {pkg_name}.{module_name} import " in content -@pytest.mark.ignored def test_fail_if_dir_exists(temp_dir: Path): ws_name = "existing" workspace_root = temp_dir