Cybersecurity-Projects/PROJECTS/advanced/ai-threat-detection/backend/tests/test_synthetic.py

180 lines
5.5 KiB
Python

"""
©AngelaMos | 2026
test_synthetic.py
"""
import numpy as np
from app.core.features.encoder import encode_for_inference
from app.core.features.extractor import extract_request_features
from app.core.features.mappings import WINDOWED_FEATURE_NAMES
from app.core.ingestion.parsers import ParsedLogEntry
from ml.synthetic import (
generate_log4shell_requests,
generate_mixed_dataset,
generate_normal_requests,
generate_scanner_requests,
generate_sqli_requests,
generate_ssrf_requests,
generate_traversal_requests,
generate_xss_requests,
)
class TestGenerators:
"""
Test individual attack and normal traffic generators
"""
def test_sqli_returns_correct_count(self, ) -> None:
"""
generate_sqli_requests returns the requested count
"""
results = generate_sqli_requests(10)
assert len(results) == 10
def test_xss_returns_correct_count(self, ) -> None:
"""
generate_xss_requests returns the requested count
"""
results = generate_xss_requests(10)
assert len(results) == 10
def test_traversal_returns_correct_count(self, ) -> None:
"""
generate_traversal_requests returns the requested count
"""
results = generate_traversal_requests(10)
assert len(results) == 10
def test_log4shell_returns_correct_count(self, ) -> None:
"""
generate_log4shell_requests returns the requested count
"""
results = generate_log4shell_requests(10)
assert len(results) == 10
def test_ssrf_returns_correct_count(self, ) -> None:
"""
generate_ssrf_requests returns the requested count
"""
results = generate_ssrf_requests(10)
assert len(results) == 10
def test_scanner_returns_correct_count(self, ) -> None:
"""
generate_scanner_requests returns the requested count
"""
results = generate_scanner_requests(10)
assert len(results) == 10
def test_normal_returns_correct_count(self, ) -> None:
"""
generate_normal_requests returns the requested count
"""
results = generate_normal_requests(20)
assert len(results) == 20
def test_sqli_has_attack_payloads(self, ) -> None:
"""
SQLi entries contain injection patterns in query string
"""
results = generate_sqli_requests(20)
has_sqli = any("OR" in e.query_string or "UNION" in e.query_string
or "DROP" in e.query_string or "SLEEP" in e.query_string
for e in results)
assert has_sqli
def test_xss_has_script_patterns(self, ) -> None:
"""
XSS entries contain script-related patterns
"""
results = generate_xss_requests(20)
has_xss = any(
"script" in e.query_string.lower() or "alert" in
e.query_string.lower() or "onerror" in e.query_string.lower()
for e in results)
assert has_xss
def test_traversal_has_dotdot(self) -> None:
"""
Traversal entries contain ../ in path
"""
results = generate_traversal_requests(20)
has_traversal = any(".." in e.path or "%2e" in e.path.lower()
for e in results)
assert has_traversal
def test_all_entries_are_parsed_log_entry(self, ) -> None:
"""
All generators return ParsedLogEntry instances
"""
generators = [
generate_sqli_requests,
generate_xss_requests,
generate_traversal_requests,
generate_log4shell_requests,
generate_ssrf_requests,
generate_scanner_requests,
generate_normal_requests,
]
for gen in generators:
results = gen(5)
assert all(isinstance(e, ParsedLogEntry) for e in results)
def test_entries_pass_feature_extraction(self, ) -> None:
"""
All generated entries extract and encode without error
"""
generators = [
generate_sqli_requests,
generate_xss_requests,
generate_traversal_requests,
generate_log4shell_requests,
generate_ssrf_requests,
generate_scanner_requests,
generate_normal_requests,
]
for gen in generators:
for entry in gen(5):
features = extract_request_features(entry)
for name in WINDOWED_FEATURE_NAMES:
features[name] = 0.0
vector = encode_for_inference(features)
assert len(vector) == 35
class TestMixedDataset:
"""
Test end-to-end mixed dataset generation
"""
def test_returns_correct_shape(self) -> None:
"""
generate_mixed_dataset returns X with 35 columns
"""
X, y = generate_mixed_dataset(100, 60)
assert X.shape == (160, 35)
def test_contains_both_labels(self) -> None:
"""
y array contains both 0 and 1
"""
_, y = generate_mixed_dataset(100, 60)
assert 0 in y
assert 1 in y
def test_label_counts_match(self) -> None:
"""
Label counts match requested normal and attack counts
"""
_, y = generate_mixed_dataset(100, 60)
assert np.sum(y == 0) == 100
assert np.sum(y == 1) == 60
def test_values_are_finite(self) -> None:
"""
All feature values are finite
"""
X, _ = generate_mixed_dataset(50, 30)
assert np.all(np.isfinite(X))