"""Tests for ALL module categories — import, BaseModule subclass, and attribute validation. Covers: passive (17), active (9), intel (9), connectivity (8). Stealth modules are already covered by test_stealth_modules.py. """ import importlib import pytest from modules.base import BaseModule # --------------------------------------------------------------------------- # Passive modules (17) # --------------------------------------------------------------------------- PASSIVE_MODULE_DOTTED = [ "modules.passive.packet_capture", "modules.passive.dns_logger", "modules.passive.tls_sni_extractor", "modules.passive.credential_sniffer", "modules.passive.kerberos_harvester", "modules.passive.host_discovery", "modules.passive.os_fingerprint", "modules.passive.traffic_analyzer", "modules.passive.vlan_discovery", "modules.passive.network_mapper", "modules.passive.auth_flow_tracker", "modules.passive.smb_monitor", "modules.passive.cloud_token_harvester", "modules.passive.ldap_harvester", "modules.passive.rdp_monitor", "modules.passive.quic_analyzer", "modules.passive.db_interceptor", ] PASSIVE_CLASS_NAMES = [ "PacketCapture", "DNSLogger", "TLSSNIExtractor", "CredentialSniffer", "KerberosHarvester", "HostDiscovery", "OSFingerprint", "TrafficAnalyzer", "VLANDiscovery", "NetworkMapper", "AuthFlowTracker", "SMBMonitor", "CloudTokenHarvester", "LDAPHarvester", "RDPMonitor", "QUICAnalyzer", "DBInterceptor", ] class TestPassiveModulesImportable: @pytest.mark.parametrize("dotted_path", PASSIVE_MODULE_DOTTED) def test_passive_module_importable(self, dotted_path): """Each passive module file can be imported without errors.""" mod = importlib.import_module(dotted_path) assert mod is not None class TestPassiveModulesAreBaseModule: @pytest.mark.parametrize("class_name", PASSIVE_CLASS_NAMES) def test_passive_modules_are_base_module(self, class_name): """Each passive module class is a subclass of BaseModule.""" import modules.passive as passive_pkg cls = getattr(passive_pkg, class_name) assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass" class TestPassiveModuleAttributes: @pytest.mark.parametrize("class_name", PASSIVE_CLASS_NAMES) def test_passive_module_attributes(self, class_name): """Each passive module has required class attributes.""" import modules.passive as passive_pkg cls = getattr(passive_pkg, class_name) assert hasattr(cls, "name") and cls.name != "unnamed" assert hasattr(cls, "module_type") and cls.module_type == "passive" assert hasattr(cls, "priority") and isinstance(cls.priority, int) assert hasattr(cls, "dependencies") and isinstance(cls.dependencies, list) assert hasattr(cls, "requires_root") for method_name in ("start", "stop", "status", "configure"): assert callable(getattr(cls, method_name, None)) class TestPassiveModuleInstantiate: @pytest.mark.parametrize("class_name", PASSIVE_CLASS_NAMES) def test_passive_module_instantiate(self, class_name, mock_bus, mock_state, mock_config): """Each passive module can be instantiated with mock bus/state/config.""" import modules.passive as passive_pkg cls = getattr(passive_pkg, class_name) instance = cls(bus=mock_bus, state=mock_state, config=mock_config) assert instance is not None assert instance._running is False # --------------------------------------------------------------------------- # Active modules (9) # --------------------------------------------------------------------------- ACTIVE_MODULE_DOTTED = [ "modules.active.bettercap_mgr", "modules.active.arp_spoof", "modules.active.dns_poison", "modules.active.dhcp_spoof", "modules.active.evil_twin", "modules.active.ipv6_slaac", "modules.active.responder_mgr", "modules.active.mitmproxy_mgr", "modules.active.ntlm_relay", ] ACTIVE_CLASS_NAMES = [ "BettercapManager", "ARPSpoof", "DNSPoison", "DHCPSpoof", "EvilTwin", "IPv6SLAAC", "ResponderManager", "MitmproxyManager", "NTLMRelay", ] class TestActiveModulesImportable: @pytest.mark.parametrize("dotted_path", ACTIVE_MODULE_DOTTED) def test_active_module_importable(self, dotted_path): """Each active module file can be imported without errors.""" mod = importlib.import_module(dotted_path) assert mod is not None class TestActiveModulesAreBaseModule: @pytest.mark.parametrize("class_name", ACTIVE_CLASS_NAMES) def test_active_modules_are_base_module(self, class_name): """Each active module class is a subclass of BaseModule.""" import modules.active as active_pkg cls = getattr(active_pkg, class_name) assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass" class TestActiveModuleAttributes: @pytest.mark.parametrize("class_name", ACTIVE_CLASS_NAMES) def test_active_module_attributes(self, class_name): """Each active module has required class attributes.""" import modules.active as active_pkg cls = getattr(active_pkg, class_name) assert hasattr(cls, "name") and cls.name != "unnamed" assert hasattr(cls, "module_type") and cls.module_type == "active" assert hasattr(cls, "priority") and isinstance(cls.priority, int) assert hasattr(cls, "dependencies") and isinstance(cls.dependencies, list) assert hasattr(cls, "requires_root") for method_name in ("start", "stop", "status", "configure"): assert callable(getattr(cls, method_name, None)) class TestActiveModuleInstantiate: @pytest.mark.parametrize("class_name", ACTIVE_CLASS_NAMES) def test_active_module_instantiate(self, class_name, mock_bus, mock_state, mock_config): """Each active module can be instantiated with mock bus/state/config.""" import modules.active as active_pkg cls = getattr(active_pkg, class_name) instance = cls(bus=mock_bus, state=mock_state, config=mock_config) assert instance is not None assert instance._running is False # --------------------------------------------------------------------------- # Intel modules (9) # --------------------------------------------------------------------------- INTEL_MODULE_DOTTED = [ "modules.intel.credential_db", "modules.intel.topology_mapper", "modules.intel.net_intel", "modules.intel.user_timeline", "modules.intel.supply_chain_detect", "modules.intel.change_detector", "modules.intel.security_posture", "modules.intel.operator_audit", "modules.intel.tool_output_parser", ] INTEL_CLASS_NAMES = [ "CredentialDB", "TopologyMapper", "NetIntel", "UserTimeline", "SupplyChainDetect", "ChangeDetector", "SecurityPosture", "OperatorAudit", "ToolOutputParser", ] class TestIntelModulesImportable: @pytest.mark.parametrize("dotted_path", INTEL_MODULE_DOTTED) def test_intel_module_importable(self, dotted_path): """Each intel module file can be imported without errors.""" mod = importlib.import_module(dotted_path) assert mod is not None class TestIntelModulesAreBaseModule: @pytest.mark.parametrize("class_name", INTEL_CLASS_NAMES) def test_intel_modules_are_base_module(self, class_name): """Each intel module class is a subclass of BaseModule.""" import modules.intel as intel_pkg cls = getattr(intel_pkg, class_name) assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass" class TestIntelModuleAttributes: @pytest.mark.parametrize("class_name", INTEL_CLASS_NAMES) def test_intel_module_attributes(self, class_name): """Each intel module has required class attributes.""" import modules.intel as intel_pkg cls = getattr(intel_pkg, class_name) assert hasattr(cls, "name") and cls.name != "unnamed" assert hasattr(cls, "module_type") and cls.module_type == "intel" assert hasattr(cls, "priority") and isinstance(cls.priority, int) assert hasattr(cls, "dependencies") and isinstance(cls.dependencies, list) assert hasattr(cls, "requires_root") for method_name in ("start", "stop", "status", "configure"): assert callable(getattr(cls, method_name, None)) class TestIntelModuleInstantiate: @pytest.mark.parametrize("class_name", INTEL_CLASS_NAMES) def test_intel_module_instantiate(self, class_name, mock_bus, mock_state, mock_config): """Each intel module can be instantiated with mock bus/state/config.""" import modules.intel as intel_pkg cls = getattr(intel_pkg, class_name) instance = cls(bus=mock_bus, state=mock_state, config=mock_config) assert instance is not None assert instance._running is False # --------------------------------------------------------------------------- # Connectivity modules (8) # --------------------------------------------------------------------------- CONNECTIVITY_MODULE_DOTTED = [ "modules.connectivity.wireguard", "modules.connectivity.tailscale", "modules.connectivity.bridge", "modules.connectivity.wifi_client", "modules.connectivity.cellular_backup", "modules.connectivity.ble_emergency", "modules.connectivity.data_exfil", ] CONNECTIVITY_CLASS_NAMES = [ "WireGuard", "Tailscale", "Bridge", "WiFiClient", "CellularBackup", "BLEEmergency", "DataExfil", ] class TestConnectivityModulesImportable: @pytest.mark.parametrize("dotted_path", CONNECTIVITY_MODULE_DOTTED) def test_connectivity_module_importable(self, dotted_path): """Each connectivity module file can be imported without errors.""" mod = importlib.import_module(dotted_path) assert mod is not None class TestConnectivityModulesAreBaseModule: @pytest.mark.parametrize("class_name", CONNECTIVITY_CLASS_NAMES) def test_connectivity_modules_are_base_module(self, class_name): """Each connectivity module class is a subclass of BaseModule.""" import modules.connectivity as conn_pkg cls = getattr(conn_pkg, class_name) assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass" class TestConnectivityModuleAttributes: @pytest.mark.parametrize("class_name", CONNECTIVITY_CLASS_NAMES) def test_connectivity_module_attributes(self, class_name): """Each connectivity module has required class attributes.""" import modules.connectivity as conn_pkg cls = getattr(conn_pkg, class_name) assert hasattr(cls, "name") and cls.name != "unnamed" assert hasattr(cls, "module_type") and cls.module_type == "connectivity" assert hasattr(cls, "priority") and isinstance(cls.priority, int) assert hasattr(cls, "dependencies") and isinstance(cls.dependencies, list) assert hasattr(cls, "requires_root") for method_name in ("start", "stop", "status", "configure"): assert callable(getattr(cls, method_name, None)) class TestConnectivityModuleInstantiate: @pytest.mark.parametrize("class_name", CONNECTIVITY_CLASS_NAMES) def test_connectivity_module_instantiate(self, class_name, mock_bus, mock_state, mock_config): """Each connectivity module can be instantiated with mock bus/state/config.""" import modules.connectivity as conn_pkg cls = getattr(conn_pkg, class_name) instance = cls(bus=mock_bus, state=mock_state, config=mock_config) assert instance is not None assert instance._running is False # --------------------------------------------------------------------------- # Cross-category: package __init__.py exports # --------------------------------------------------------------------------- class TestPackageExports: def test_passive_init_exports_all(self): """modules.passive.__init__.py exports all 17 classes.""" import modules.passive as pkg assert len(pkg.__all__) == 17 for name in pkg.__all__: cls = getattr(pkg, name) assert issubclass(cls, BaseModule) def test_active_init_exports_all(self): """modules.active.__init__.py exports all 9 classes.""" import modules.active as pkg assert len(pkg.__all__) == 9 for name in pkg.__all__: cls = getattr(pkg, name) assert issubclass(cls, BaseModule) def test_intel_init_exports_all(self): """modules.intel.__init__.py exports all 9 classes.""" import modules.intel as pkg assert len(pkg.__all__) == 9 for name in pkg.__all__: cls = getattr(pkg, name) assert issubclass(cls, BaseModule) def test_connectivity_init_exports_all(self): """modules.connectivity.__init__.py exports all 7 classes.""" import modules.connectivity as pkg assert len(pkg.__all__) == 7 for name in pkg.__all__: cls = getattr(pkg, name) assert issubclass(cls, BaseModule) def test_stealth_init_exports_all(self): """modules.stealth.__init__.py exports all 12 classes.""" import modules.stealth as pkg assert len(pkg.__all__) == 12 for name in pkg.__all__: cls = getattr(pkg, name) assert issubclass(cls, BaseModule) # --------------------------------------------------------------------------- # Discovery function test # --------------------------------------------------------------------------- class TestModuleDiscovery: def test_discover_all_modules(self): """discover_all_modules() finds all 55 modules across 5 categories.""" from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from bigbrother import discover_all_modules, discover_modules_in_category all_mods = discover_all_modules() # Stealth: 12, Passive: 17, Active: 9, Intel: 9, Connectivity: 7 = 54 assert len(all_mods) == 54, f"Expected 54 modules, found {len(all_mods)}" # Verify per-category counts assert len(discover_modules_in_category("stealth")) == 12 assert len(discover_modules_in_category("passive")) == 17 assert len(discover_modules_in_category("active")) == 9 assert len(discover_modules_in_category("intel")) == 9 assert len(discover_modules_in_category("connectivity")) == 7 def test_all_discovered_are_base_module(self): """Every discovered module is a BaseModule subclass.""" from bigbrother import discover_all_modules for name, cls in discover_all_modules().items(): assert issubclass(cls, BaseModule), f"{name} ({cls}) is not a BaseModule subclass"