Files
instagram-bot/tests/conftest.py
Marc Mintel 2c6404f387 feat: stabilize autonomous instagram bot suite (100% green)
Summary of work:
- Resolved mass SystemExit: 2 failures by hardening Config against pytest CLI args.
- Fixed state leakage in test suite by implementing aggressive cache wiping in conftest.py.
- Fixed TypeErrors and UnboundLocalErrors in TelepathicEngine and bot_flow.
- Aligned MockTelepathicEngine signatures to resolve Mock Drift.
- Achieved 100% pass rate across 498 tests.
2026-04-20 15:11:49 +02:00

179 lines
5.7 KiB
Python

import pytest
import logging
import os
from unittest.mock import MagicMock
MagicMock.app_id = "com.instagram.android"
MagicMock._get_current_app = MagicMock(return_value="com.instagram.android")
class MockArgs:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
class MockConfigs:
def __init__(self, args):
self.args = args
class MockDeviceV2:
def __init__(self):
self.clicks = []
self.shells = []
self.double_clicks = []
self.presses = []
self.xml_dump = "<hierarchy><node resource-id='com.instagram.android:id/row_comment_imageview' bounds='[10,10][20,20]' content-desc='Story' text='following' /><node resource-id='com.instagram.android:id/button_like' bounds='[50,50][60,60]' /><node resource-id='com.instagram.android:id/reel_viewer' /></hierarchy>"
def click(self, x, y):
self.clicks.append((x, y))
self.xml_dump += f"<node new='true' x='{x}' y='{y}' />"
def shell(self, cmd):
self.shells.append(cmd)
def double_click(self, x, y, duration=0):
self.double_clicks.append((x, y))
def press(self, key):
self.presses.append(key)
def dump_hierarchy(self):
return self.xml_dump
class MockDevice:
def __init__(self):
self.deviceV2 = MockDeviceV2()
self.app_id = "com.instagram.android"
def _get_current_app(self):
return "com.instagram.android"
def get_info(self):
return {"displayWidth": 1080, "displayHeight": 2400}
def cm_to_pixels(self, cm):
return cm * 10
def dump_hierarchy(self):
return self.deviceV2.dump_hierarchy()
def click(self, x=None, y=None, obj=None):
if obj:
x, y = obj.get("x", 0), obj.get("y", 0)
self.deviceV2.click(x, y)
class MockTelepathicEngine:
def find_best_node(self, xml, intent_description, device=None, **kwargs):
description = intent_description.lower()
if "story ring" in description:
return {"x": 100, "y": 100, "description": "Story Ring", "score": 1.0}
if "follow" in description or "folgen" in description:
return {"x": 200, "y": 200, "text": "Follow", "description": "Follow Button", "score": 1.0}
if "first image" in description or "profile grid" in description:
return {"x": 300, "y": 300, "description": "Grid Image", "score": 1.0}
return None
def _extract_semantic_nodes(self, xml, intent=None, threshold=0.0):
return [{"x": 10, "y": 10, "semantic_string": "mock node", "area": 100}]
def _keyword_match_score(self, intent, nodes):
if nodes:
return {"semantic": nodes[0].get("semantic_string"), "score": 0.9, "node": nodes[0]}
return None
def _cosine_similarity(self, v1, v2):
return 0.9
def verify_success(self, intent_description, post_click_xml, previous_state_xml=None):
return True
def confirm_click(self, *args, **kwargs):
pass
def reject_click(self, *args, **kwargs):
pass
def classify_screen_content(self, xml, target_class):
# Default mock behavior: assume it matches if it's not obviously trash
return "organic"
def get_active_engagement(self):
return {"type": "like", "confidence": 0.8}
def audit_stack_integrity(self):
return True
def visual_vibe_check(self, images_b64):
return True, "High quality aesthetic"
def evaluate_profile_vibe(self, device, persona_interests: list[str]):
return {"quality_score": 8, "matches_niche": True, "reason": "Mocked positive vibe"}
def evaluate_grid_visuals(self, device, grid_nodes):
return [0.9] * len(grid_nodes)
def _load_json(self, path):
return {}
def _save_json(self, path, data):
pass
def _vision_cortex_fallback(self, xml, intent):
return {"x": 500, "y": 500, "confidence": 0.7}
@classmethod
def get_instance(cls):
return cls()
@pytest.fixture
def mock_logger():
return logging.getLogger("test")
@pytest.fixture
def device():
return MockDevice()
@pytest.fixture(autouse=True)
def reset_singletons():
"""Ensure all core engine singletons are fresh for each test."""
from GramAddict.core.telepathic_engine import TelepathicEngine
from GramAddict.core.goap import GoalExecutor
from GramAddict.core.situational_awareness import SituationalAwarenessEngine
TelepathicEngine.reset()
GoalExecutor.reset()
SituationalAwarenessEngine.reset()
# Aggressively wipe on-disk session files to prevent state leakage in tests
for f in ["telepathic_memory.json", "telepathic_blacklist.json", "growth_brain_memory.json", "gramaddict_nav_map.json", "l2_channels_cache.json"]:
if os.path.exists(f):
try:
os.remove(f)
except Exception:
pass
yield
@pytest.fixture(autouse=True)
def telepathic_mock(monkeypatch):
import GramAddict.core.telepathic_engine
engine = MockTelepathicEngine()
monkeypatch.setattr(GramAddict.core.telepathic_engine.TelepathicEngine, "get_instance", lambda: engine)
return engine
@pytest.fixture
def mock_cognitive_stack():
stack = {
"dopamine": MagicMock(),
"darwin": MagicMock(),
"resonance": MagicMock(),
"active_inference": MagicMock(),
"growth_brain": MagicMock(),
"swarm": MagicMock(),
"radome": MagicMock(),
"nav_graph": MagicMock(),
"zero_engine": MagicMock(),
"crm": MagicMock(),
"telepathic": MockTelepathicEngine()
}
stack["radome"].sanitize_xml.side_effect = lambda x: x
return stack