Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
395 lines
14 KiB
Python
395 lines
14 KiB
Python
"""
|
|
Test IT Audit Collaboration Matching
|
|
====================================
|
|
|
|
Tests for the collaboration matching functionality in IT Audit Service.
|
|
|
|
Test cases:
|
|
1. Backup replication matching (Proxmox PBS)
|
|
2. Shared licensing matching (M365)
|
|
3. Teams federation matching (Azure AD)
|
|
4. Shared monitoring matching (Zabbix)
|
|
5. Collective purchasing matching (similar size)
|
|
6. Knowledge sharing matching (similar tech stack)
|
|
|
|
Author: Maciej Pienczyn, InPi sp. z o.o.
|
|
Created: 2026-01-09
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
from dataclasses import dataclass
|
|
|
|
# Add parent directory (worktree root) to path for imports
|
|
WORKTREE_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, WORKTREE_ROOT)
|
|
|
|
# Mock database module before importing it_audit_service
|
|
# This prevents database connection errors during import
|
|
sys.modules['database'] = MagicMock()
|
|
|
|
# Now we can safely import it_audit_service
|
|
from it_audit_service import ITAuditService, CollaborationMatch
|
|
|
|
|
|
class MockCompany:
|
|
"""Mock Company object for testing"""
|
|
def __init__(self, id: int, name: str, slug: str):
|
|
self.id = id
|
|
self.name = name
|
|
self.slug = slug
|
|
|
|
|
|
class MockITAudit:
|
|
"""Mock ITAudit object for testing"""
|
|
def __init__(self, **kwargs):
|
|
self.company_id = kwargs.get('company_id', 1)
|
|
|
|
# Collaboration flags
|
|
self.open_to_shared_licensing = kwargs.get('open_to_shared_licensing', False)
|
|
self.open_to_backup_replication = kwargs.get('open_to_backup_replication', False)
|
|
self.open_to_teams_federation = kwargs.get('open_to_teams_federation', False)
|
|
self.open_to_shared_monitoring = kwargs.get('open_to_shared_monitoring', False)
|
|
self.open_to_collective_purchasing = kwargs.get('open_to_collective_purchasing', False)
|
|
self.open_to_knowledge_sharing = kwargs.get('open_to_knowledge_sharing', False)
|
|
|
|
# Technology flags
|
|
self.has_azure_ad = kwargs.get('has_azure_ad', False)
|
|
self.azure_tenant_name = kwargs.get('azure_tenant_name', None)
|
|
self.has_m365 = kwargs.get('has_m365', False)
|
|
self.m365_plans = kwargs.get('m365_plans', [])
|
|
self.has_proxmox_pbs = kwargs.get('has_proxmox_pbs', False)
|
|
self.monitoring_solution = kwargs.get('monitoring_solution', None)
|
|
|
|
# Size info
|
|
self.employee_count = kwargs.get('employee_count', None)
|
|
|
|
# Tech stack
|
|
self.virtualization_platform = kwargs.get('virtualization_platform', None)
|
|
self.backup_solution = kwargs.get('backup_solution', None)
|
|
self.network_firewall_brand = kwargs.get('network_firewall_brand', None)
|
|
self.erp_system = kwargs.get('erp_system', None)
|
|
|
|
|
|
class TestCollaborationMatching(unittest.TestCase):
|
|
"""Test collaboration matching logic without database"""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures"""
|
|
# Create service without database (we'll test internal methods)
|
|
self.service = ITAuditService.__new__(ITAuditService)
|
|
|
|
def test_backup_replication_match_both_have_pbs_and_open(self):
|
|
"""Test backup replication match when both companies have PBS and are open"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_proxmox_pbs=True,
|
|
open_to_backup_replication=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_proxmox_pbs=True,
|
|
open_to_backup_replication=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
# Should have exactly 1 match for backup_replication
|
|
backup_matches = [m for m in matches if m.match_type == 'backup_replication']
|
|
self.assertEqual(len(backup_matches), 1)
|
|
|
|
match = backup_matches[0]
|
|
self.assertEqual(match.company_a_id, 1)
|
|
self.assertEqual(match.company_b_id, 2)
|
|
self.assertEqual(match.match_type, 'backup_replication')
|
|
self.assertEqual(match.match_score, 90)
|
|
self.assertIn('Proxmox PBS', match.match_reason)
|
|
|
|
def test_backup_replication_no_match_only_one_has_pbs(self):
|
|
"""Test no backup match when only one company has PBS"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_proxmox_pbs=True,
|
|
open_to_backup_replication=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_proxmox_pbs=False, # Company B doesn't have PBS
|
|
open_to_backup_replication=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
backup_matches = [m for m in matches if m.match_type == 'backup_replication']
|
|
self.assertEqual(len(backup_matches), 0)
|
|
|
|
def test_backup_replication_no_match_not_open(self):
|
|
"""Test no backup match when one company is not open"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_proxmox_pbs=True,
|
|
open_to_backup_replication=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_proxmox_pbs=True,
|
|
open_to_backup_replication=False # Company B not open
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
backup_matches = [m for m in matches if m.match_type == 'backup_replication']
|
|
self.assertEqual(len(backup_matches), 0)
|
|
|
|
def test_shared_licensing_match_both_have_m365_and_open(self):
|
|
"""Test shared licensing match when both have M365 and are open"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_m365=True,
|
|
m365_plans=['Business Basic', 'E3'],
|
|
open_to_shared_licensing=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_m365=True,
|
|
m365_plans=['E3', 'E5'],
|
|
open_to_shared_licensing=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
licensing_matches = [m for m in matches if m.match_type == 'shared_licensing']
|
|
self.assertEqual(len(licensing_matches), 1)
|
|
|
|
match = licensing_matches[0]
|
|
self.assertEqual(match.match_score, 80)
|
|
self.assertIn('Microsoft 365', match.match_reason)
|
|
|
|
def test_teams_federation_match_both_have_azure_ad_and_open(self):
|
|
"""Test Teams federation match when both have Azure AD and are open"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_azure_ad=True,
|
|
azure_tenant_name='firmaa.onmicrosoft.com',
|
|
open_to_teams_federation=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_azure_ad=True,
|
|
azure_tenant_name='firmab.onmicrosoft.com',
|
|
open_to_teams_federation=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
teams_matches = [m for m in matches if m.match_type == 'teams_federation']
|
|
self.assertEqual(len(teams_matches), 1)
|
|
|
|
match = teams_matches[0]
|
|
self.assertEqual(match.match_score, 85)
|
|
self.assertIn('Azure AD', match.match_reason)
|
|
|
|
def test_shared_monitoring_match_both_use_zabbix(self):
|
|
"""Test shared monitoring match when both use Zabbix"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
monitoring_solution='Zabbix',
|
|
open_to_shared_monitoring=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
monitoring_solution='Zabbix 6.0',
|
|
open_to_shared_monitoring=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
monitoring_matches = [m for m in matches if m.match_type == 'shared_monitoring']
|
|
self.assertEqual(len(monitoring_matches), 1)
|
|
|
|
match = monitoring_matches[0]
|
|
self.assertEqual(match.match_score, 75)
|
|
self.assertIn('Zabbix', match.match_reason)
|
|
|
|
def test_collective_purchasing_match_similar_size(self):
|
|
"""Test collective purchasing match for similar company sizes"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
employee_count='11-50',
|
|
open_to_collective_purchasing=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
employee_count='51-100', # Similar size (within 3x ratio)
|
|
open_to_collective_purchasing=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
purchasing_matches = [m for m in matches if m.match_type == 'collective_purchasing']
|
|
self.assertEqual(len(purchasing_matches), 1)
|
|
|
|
match = purchasing_matches[0]
|
|
self.assertEqual(match.match_score, 70)
|
|
|
|
def test_knowledge_sharing_match_similar_tech_stack(self):
|
|
"""Test knowledge sharing match for similar tech stack"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
virtualization_platform='Proxmox',
|
|
backup_solution='Veeam',
|
|
has_azure_ad=True,
|
|
has_m365=True,
|
|
open_to_knowledge_sharing=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
virtualization_platform='Proxmox',
|
|
backup_solution='Veeam',
|
|
has_azure_ad=True,
|
|
has_m365=True,
|
|
open_to_knowledge_sharing=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
knowledge_matches = [m for m in matches if m.match_type == 'knowledge_sharing']
|
|
self.assertEqual(len(knowledge_matches), 1)
|
|
|
|
match = knowledge_matches[0]
|
|
self.assertEqual(match.match_score, 65)
|
|
# Should have at least 2 common technologies
|
|
self.assertIn('common_tech', match.shared_attributes)
|
|
self.assertGreaterEqual(len(match.shared_attributes['common_tech']), 2)
|
|
|
|
def test_multiple_matches_for_same_companies(self):
|
|
"""Test that multiple match types can be found for the same company pair"""
|
|
company_a = MockCompany(1, "Firma A", "firma-a")
|
|
company_b = MockCompany(2, "Firma B", "firma-b")
|
|
|
|
# Both companies have multiple collaboration opportunities
|
|
audit_a = MockITAudit(
|
|
company_id=1,
|
|
has_proxmox_pbs=True,
|
|
has_azure_ad=True,
|
|
has_m365=True,
|
|
open_to_backup_replication=True,
|
|
open_to_teams_federation=True,
|
|
open_to_shared_licensing=True
|
|
)
|
|
audit_b = MockITAudit(
|
|
company_id=2,
|
|
has_proxmox_pbs=True,
|
|
has_azure_ad=True,
|
|
has_m365=True,
|
|
open_to_backup_replication=True,
|
|
open_to_teams_federation=True,
|
|
open_to_shared_licensing=True
|
|
)
|
|
|
|
matches = self.service._check_all_match_types(
|
|
company_a, audit_a, company_b, audit_b
|
|
)
|
|
|
|
# Should have matches for backup_replication, teams_federation, and shared_licensing
|
|
match_types = {m.match_type for m in matches}
|
|
self.assertIn('backup_replication', match_types)
|
|
self.assertIn('teams_federation', match_types)
|
|
self.assertIn('shared_licensing', match_types)
|
|
self.assertEqual(len(matches), 3)
|
|
|
|
def test_parse_count_range(self):
|
|
"""Test employee count range parsing"""
|
|
self.assertEqual(self.service._parse_count_range('1-10'), 5)
|
|
self.assertEqual(self.service._parse_count_range('11-50'), 30)
|
|
self.assertEqual(self.service._parse_count_range('51-100'), 75)
|
|
self.assertEqual(self.service._parse_count_range('101-250'), 175)
|
|
self.assertEqual(self.service._parse_count_range('251-500'), 375)
|
|
self.assertEqual(self.service._parse_count_range('500+'), 750)
|
|
self.assertIsNone(self.service._parse_count_range(None))
|
|
self.assertIsNone(self.service._parse_count_range('unknown'))
|
|
|
|
def test_sizes_similar(self):
|
|
"""Test company size similarity check"""
|
|
# Within 3x ratio should be similar
|
|
self.assertTrue(self.service._sizes_similar(30, 75)) # 2.5x
|
|
self.assertTrue(self.service._sizes_similar(30, 30)) # 1x
|
|
self.assertTrue(self.service._sizes_similar(30, 50)) # 1.67x
|
|
|
|
# More than 3x ratio should not be similar
|
|
self.assertFalse(self.service._sizes_similar(5, 175)) # 35x
|
|
self.assertFalse(self.service._sizes_similar(5, 750)) # 150x
|
|
|
|
# Zero handling
|
|
self.assertFalse(self.service._sizes_similar(0, 50))
|
|
self.assertFalse(self.service._sizes_similar(50, 0))
|
|
|
|
|
|
class TestCollaborationMatchDataclass(unittest.TestCase):
|
|
"""Test CollaborationMatch dataclass"""
|
|
|
|
def test_collaboration_match_creation(self):
|
|
"""Test creating a CollaborationMatch"""
|
|
match = CollaborationMatch(
|
|
company_a_id=1,
|
|
company_b_id=2,
|
|
company_a_name="Firma A",
|
|
company_b_name="Firma B",
|
|
match_type="backup_replication",
|
|
match_reason="Obie firmy używają Proxmox PBS",
|
|
match_score=90,
|
|
shared_attributes={"pbs": True}
|
|
)
|
|
|
|
self.assertEqual(match.company_a_id, 1)
|
|
self.assertEqual(match.company_b_id, 2)
|
|
self.assertEqual(match.match_type, "backup_replication")
|
|
self.assertEqual(match.match_score, 90)
|
|
self.assertEqual(match.shared_attributes["pbs"], True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main(verbosity=2)
|