Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions backend/tests/test_incident_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import pytest
from unittest.mock import MagicMock
import sys
import os

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from backend.services.incident_service import IncidentService, CORRELATION_THRESHOLD, WINDOW_SECONDS


class MockDuplicateService:
def __init__(self):
self.model = None
self._loaded = False

def load(self):
self._loaded = True


class TestIncidentServicePrune:
def test_prune_removes_old_tickets(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
now = 1000.0
service._recent = [
{"ticket_id": "1", "ts": now - 100},
{"ticket_id": "2", "ts": now - WINDOW_SECONDS - 10},
{"ticket_id": "3", "ts": now -50},
]
service._prune(now)
assert len(service._recent) == 2
assert all(t["ts"] >= now - WINDOW_SECONDS for t in service._recent)

def test_prune_keeps_recent_tickets(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
now = 1000.0
service._recent = [
{"ticket_id": "1", "ts": now - 100},
{"ticket_id": "2", "ts": now - 200},
]
service._prune(now)
assert len(service._recent) == 2


class TestIncidentServiceCritical:
def test_is_critical_priority_critical(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
assert service._is_critical("critical", None) is True
assert service._is_critical("CRITICAL", None) is True

def test_is_critical_category_email(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
assert service._is_critical(None, "email") is True
assert service._is_critical(None, "network") is True
assert service._is_critical(None, "authentication") is True
assert service._is_critical(None, "exchange") is True

def test_is_critical_not_critical(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
assert service._is_critical("high", "general") is False
assert service._is_critical(None, None) is False


class TestIncidentServiceCorrelate:
def test_correlate_returns_defaults_when_no_model(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
result = service.correlate("Test ticket text")
assert result["incident_id"] is None
assert result["is_major_incident"] is False
assert result["ticket_count"] == 0
assert result["affected_users"] == 0
assert result["similarity"] == 0.0


class TestIncidentServiceListActive:
def test_list_active_returns_empty_initially(self):
mock_dup = MockDuplicateService()
service = IncidentService(mock_dup)
assert service.list_active() == []
111 changes: 111 additions & 0 deletions backend/tests/test_ner_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import pytest
from unittest.mock import MagicMock, patch
import sys
import os

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

import importlib.util

spec = importlib.util.spec_from_file_location(
"ner_service",
"/home/itsmaestro/gssoc/HELPDESK.AI/backend/services/ner_service.py"
)
ner_module = importlib.util.module_from_spec(spec)
sys.modules['backend.services.ner_service'] = ner_module
spec.loader.exec_module(ner_module)


class TestNERServiceInit:
def test_init_sets_defaults(self):
service = ner_module.NERService()
assert service.model is None
assert service.tokenizer is None
assert service.id2label is None
assert service.label2id is None
assert service._loaded is False


class TestNERServiceCleanLabel:
def test_clean_label_o_tag(self):
service = ner_module.NERService()
bio, entity = service._clean_label("O")
assert bio == "O"
assert entity == ""

def test_clean_label_b_b_entity(self):
service = ner_module.NERService()
bio, entity = service._clean_label("B-B-APP_NAME")
assert bio == "B"
assert entity == "APP_NAME"

def test_clean_label_i_b_entity(self):
service = ner_module.NERService()
bio, entity = service._clean_label("I-B-APP_NAME")
assert bio == "I"
assert entity == "APP_NAME"

def test_clean_label_b_entity(self):
service = ner_module.NERService()
bio, entity = service._clean_label("B-ENTITY")
assert bio == "B"
assert entity == "ENTITY"

def test_clean_label_i_entity(self):
service = ner_module.NERService()
bio, entity = service._clean_label("I-ENTITY")
assert bio == "I"
assert entity == "ENTITY"

def test_clean_label_unknown_returns_o(self):
service = ner_module.NERService()
bio, entity = service._clean_label("UNKNOWN")
assert bio == "O"
assert entity == ""


class TestNERServiceLoad:
def test_load_without_torch(self):
original_has_torch = ner_module._HAS_TORCH
ner_module._HAS_TORCH = False
try:
service = ner_module.NERService()
service.load()
assert service._loaded is False
finally:
ner_module._HAS_TORCH = original_has_torch

def test_load_idempotent(self):
service = ner_module.NERService()
service._loaded = True
service.load()
assert service._loaded is True


class TestNERServiceExtractEntities:
def test_extract_entities_empty_text(self):
service = ner_module.NERService()
service._loaded = True
service._load_failed = True
result = service.extract_entities("")
assert result == []


class TestRegexPatterns:
def test_regex_patterns_exist(self):
assert hasattr(ner_module, 'REGEX_PATTERNS')
patterns = ner_module.REGEX_PATTERNS
assert "IP_ADDRESS" in patterns
assert "HOSTNAME" in patterns
assert "NETWORK_ERROR" in patterns
assert "LOGIN_ISSUE" in patterns
assert "VLAN" in patterns
assert "DATABASE" in patterns
assert "SYSTEM" in patterns
assert "BROWSER" in patterns


class TestNERServiceMaxLen:
def test_max_len_constant(self):
assert hasattr(ner_module, 'MAX_LEN')
assert ner_module.MAX_LEN == 128
Loading