Co-authored-by: Perplexity Computer <perplexity@tower.local> Co-committed-by: Perplexity Computer <perplexity@tower.local>
This commit was merged in pull request #1348.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Tests for the Nexus conversational awareness routes."""
|
||||
"""Tests for the Nexus v2 conversational awareness routes."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -24,6 +24,41 @@ def test_nexus_page_contains_teach_form(client):
|
||||
assert "/nexus/teach" in response.text
|
||||
|
||||
|
||||
def test_nexus_page_contains_cognitive_panel(client):
|
||||
"""Nexus v2 page must include the cognitive state panel."""
|
||||
response = client.get("/nexus")
|
||||
assert response.status_code == 200
|
||||
assert "COGNITIVE STATE" in response.text
|
||||
|
||||
|
||||
def test_nexus_page_contains_thought_stream(client):
|
||||
"""Nexus v2 page must include the thought stream panel."""
|
||||
response = client.get("/nexus")
|
||||
assert response.status_code == 200
|
||||
assert "THOUGHT STREAM" in response.text
|
||||
|
||||
|
||||
def test_nexus_page_contains_sovereignty_pulse(client):
|
||||
"""Nexus v2 page must include the sovereignty pulse panel."""
|
||||
response = client.get("/nexus")
|
||||
assert response.status_code == 200
|
||||
assert "SOVEREIGNTY PULSE" in response.text
|
||||
|
||||
|
||||
def test_nexus_page_contains_session_analytics(client):
|
||||
"""Nexus v2 page must include the session analytics panel."""
|
||||
response = client.get("/nexus")
|
||||
assert response.status_code == 200
|
||||
assert "SESSION ANALYTICS" in response.text
|
||||
|
||||
|
||||
def test_nexus_page_contains_websocket_script(client):
|
||||
"""Nexus v2 page must include the WebSocket connection script."""
|
||||
response = client.get("/nexus")
|
||||
assert response.status_code == 200
|
||||
assert "/nexus/ws" in response.text
|
||||
|
||||
|
||||
def test_nexus_chat_empty_message_returns_empty(client):
|
||||
"""POST /nexus/chat with blank message returns empty response."""
|
||||
response = client.post("/nexus/chat", data={"message": " "})
|
||||
@@ -72,3 +107,17 @@ def test_nexus_clear_history(client):
|
||||
response = client.request("DELETE", "/nexus/history")
|
||||
assert response.status_code == 200
|
||||
assert "cleared" in response.text.lower()
|
||||
|
||||
|
||||
def test_nexus_introspect_api(client):
|
||||
"""GET /nexus/introspect should return JSON introspection snapshot."""
|
||||
response = client.get("/nexus/introspect")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "introspection" in data
|
||||
assert "sovereignty_pulse" in data
|
||||
assert "cognitive" in data["introspection"]
|
||||
assert "recent_thoughts" in data["introspection"]
|
||||
assert "analytics" in data["introspection"]
|
||||
assert "overall_pct" in data["sovereignty_pulse"]
|
||||
assert "health" in data["sovereignty_pulse"]
|
||||
|
||||
0
tests/timmy/nexus/__init__.py
Normal file
0
tests/timmy/nexus/__init__.py
Normal file
199
tests/timmy/nexus/test_introspection.py
Normal file
199
tests/timmy/nexus/test_introspection.py
Normal file
@@ -0,0 +1,199 @@
|
||||
"""Tests for the Nexus Introspection Engine."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from timmy.nexus.introspection import (
|
||||
CognitiveSummary,
|
||||
IntrospectionSnapshot,
|
||||
NexusIntrospector,
|
||||
SessionAnalytics,
|
||||
ThoughtSummary,
|
||||
)
|
||||
|
||||
# ── Data model tests ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestCognitiveSummary:
|
||||
def test_defaults(self):
|
||||
s = CognitiveSummary()
|
||||
assert s.mood == "settled"
|
||||
assert s.engagement == "idle"
|
||||
assert s.focus_topic is None
|
||||
|
||||
def test_to_dict(self):
|
||||
s = CognitiveSummary(mood="curious", engagement="deep", focus_topic="architecture")
|
||||
d = s.to_dict()
|
||||
assert d["mood"] == "curious"
|
||||
assert d["engagement"] == "deep"
|
||||
assert d["focus_topic"] == "architecture"
|
||||
|
||||
|
||||
class TestThoughtSummary:
|
||||
def test_to_dict(self):
|
||||
t = ThoughtSummary(
|
||||
id="t1", content="Hello world", seed_type="freeform", created_at="2026-01-01"
|
||||
)
|
||||
d = t.to_dict()
|
||||
assert d["id"] == "t1"
|
||||
assert d["seed_type"] == "freeform"
|
||||
assert d["parent_id"] is None
|
||||
|
||||
|
||||
class TestSessionAnalytics:
|
||||
def test_defaults(self):
|
||||
a = SessionAnalytics()
|
||||
assert a.total_messages == 0
|
||||
assert a.avg_response_length == 0.0
|
||||
assert a.topics_discussed == []
|
||||
|
||||
|
||||
class TestIntrospectionSnapshot:
|
||||
def test_to_dict_structure(self):
|
||||
snap = IntrospectionSnapshot()
|
||||
d = snap.to_dict()
|
||||
assert "cognitive" in d
|
||||
assert "recent_thoughts" in d
|
||||
assert "analytics" in d
|
||||
assert "timestamp" in d
|
||||
|
||||
def test_to_dict_with_data(self):
|
||||
snap = IntrospectionSnapshot(
|
||||
cognitive=CognitiveSummary(mood="energized"),
|
||||
recent_thoughts=[
|
||||
ThoughtSummary(id="x", content="test", seed_type="s", created_at="now"),
|
||||
],
|
||||
)
|
||||
d = snap.to_dict()
|
||||
assert d["cognitive"]["mood"] == "energized"
|
||||
assert len(d["recent_thoughts"]) == 1
|
||||
|
||||
|
||||
# ── Introspector tests ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestNexusIntrospector:
|
||||
def test_snapshot_empty_log(self):
|
||||
intro = NexusIntrospector()
|
||||
snap = intro.snapshot(conversation_log=[])
|
||||
assert isinstance(snap, IntrospectionSnapshot)
|
||||
assert snap.analytics.total_messages == 0
|
||||
|
||||
def test_snapshot_with_messages(self):
|
||||
intro = NexusIntrospector()
|
||||
log = [
|
||||
{"role": "user", "content": "hello", "timestamp": "10:00:00"},
|
||||
{"role": "assistant", "content": "Hi there!", "timestamp": "10:00:01"},
|
||||
{"role": "user", "content": "architecture question", "timestamp": "10:00:02"},
|
||||
]
|
||||
snap = intro.snapshot(conversation_log=log)
|
||||
assert snap.analytics.total_messages == 3
|
||||
assert snap.analytics.user_messages == 2
|
||||
assert snap.analytics.assistant_messages == 1
|
||||
assert snap.analytics.avg_response_length > 0
|
||||
|
||||
def test_record_memory_hits(self):
|
||||
intro = NexusIntrospector()
|
||||
intro.record_memory_hits(3)
|
||||
intro.record_memory_hits(2)
|
||||
snap = intro.snapshot(
|
||||
conversation_log=[{"role": "user", "content": "x", "timestamp": "t"}]
|
||||
)
|
||||
assert snap.analytics.memory_hits_total == 5
|
||||
|
||||
def test_reset_clears_state(self):
|
||||
intro = NexusIntrospector()
|
||||
intro.record_memory_hits(10)
|
||||
intro.reset()
|
||||
snap = intro.snapshot(
|
||||
conversation_log=[{"role": "user", "content": "x", "timestamp": "t"}]
|
||||
)
|
||||
assert snap.analytics.memory_hits_total == 0
|
||||
|
||||
def test_topics_deduplication(self):
|
||||
intro = NexusIntrospector()
|
||||
log = [
|
||||
{"role": "user", "content": "hello", "timestamp": "t"},
|
||||
{"role": "user", "content": "hello", "timestamp": "t"},
|
||||
{"role": "user", "content": "different topic", "timestamp": "t"},
|
||||
]
|
||||
snap = intro.snapshot(conversation_log=log)
|
||||
assert len(snap.analytics.topics_discussed) == 2
|
||||
|
||||
def test_topics_capped_at_8(self):
|
||||
intro = NexusIntrospector()
|
||||
log = [{"role": "user", "content": f"topic {i}", "timestamp": "t"} for i in range(15)]
|
||||
snap = intro.snapshot(conversation_log=log)
|
||||
assert len(snap.analytics.topics_discussed) <= 8
|
||||
|
||||
def test_cognitive_read_fallback(self):
|
||||
"""If cognitive read fails, snapshot still works with defaults."""
|
||||
intro = NexusIntrospector()
|
||||
# Patch the module-level import inside _read_cognitive
|
||||
with patch.dict("sys.modules", {"timmy.cognitive_state": None}):
|
||||
snap = intro.snapshot(conversation_log=[])
|
||||
# Should not raise — fallback to default
|
||||
assert snap.cognitive.mood == "settled"
|
||||
|
||||
def test_thoughts_read_fallback(self):
|
||||
"""If thought read fails, snapshot still works with empty list."""
|
||||
intro = NexusIntrospector()
|
||||
with patch.dict("sys.modules", {"timmy.thinking": None}):
|
||||
snap = intro.snapshot(conversation_log=[])
|
||||
assert snap.recent_thoughts == []
|
||||
|
||||
def test_read_cognitive_from_tracker(self):
|
||||
intro = NexusIntrospector()
|
||||
mock_state = MagicMock()
|
||||
mock_state.mood = "curious"
|
||||
mock_state.engagement = "deep"
|
||||
mock_state.focus_topic = "sovereignty"
|
||||
mock_state.conversation_depth = 5
|
||||
mock_state.active_commitments = ["build something"]
|
||||
mock_state.last_initiative = "build something"
|
||||
|
||||
mock_tracker = MagicMock()
|
||||
mock_tracker.get_state.return_value = mock_state
|
||||
|
||||
with patch("timmy.cognitive_state.cognitive_tracker", mock_tracker):
|
||||
summary = intro._read_cognitive()
|
||||
|
||||
assert summary.mood == "curious"
|
||||
assert summary.engagement == "deep"
|
||||
assert summary.focus_topic == "sovereignty"
|
||||
assert summary.conversation_depth == 5
|
||||
|
||||
def test_read_thoughts_from_engine(self):
|
||||
intro = NexusIntrospector()
|
||||
mock_thought = MagicMock()
|
||||
mock_thought.id = "t1"
|
||||
mock_thought.content = "Deep thought about sovereignty"
|
||||
mock_thought.seed_type = "existential"
|
||||
mock_thought.created_at = "2026-03-23T10:00:00"
|
||||
mock_thought.parent_id = None
|
||||
|
||||
mock_engine = MagicMock()
|
||||
mock_engine.get_recent_thoughts.return_value = [mock_thought]
|
||||
|
||||
with patch("timmy.thinking.thinking_engine", mock_engine):
|
||||
thoughts = intro._read_thoughts(limit=5)
|
||||
|
||||
assert len(thoughts) == 1
|
||||
assert thoughts[0].id == "t1"
|
||||
assert thoughts[0].seed_type == "existential"
|
||||
|
||||
def test_read_thoughts_truncates_long_content(self):
|
||||
intro = NexusIntrospector()
|
||||
mock_thought = MagicMock()
|
||||
mock_thought.id = "t2"
|
||||
mock_thought.content = "x" * 300
|
||||
mock_thought.seed_type = "freeform"
|
||||
mock_thought.created_at = "2026-03-23"
|
||||
mock_thought.parent_id = None
|
||||
|
||||
mock_engine = MagicMock()
|
||||
mock_engine.get_recent_thoughts.return_value = [mock_thought]
|
||||
|
||||
with patch("timmy.thinking.thinking_engine", mock_engine):
|
||||
thoughts = intro._read_thoughts(limit=5)
|
||||
|
||||
assert len(thoughts[0].content) <= 201 # 200 + "…"
|
||||
144
tests/timmy/nexus/test_persistence.py
Normal file
144
tests/timmy/nexus/test_persistence.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""Tests for the Nexus Session Persistence store."""
|
||||
|
||||
import pytest
|
||||
|
||||
from timmy.nexus.persistence import MAX_MESSAGES, NexusStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path):
|
||||
"""Provide a NexusStore backed by a temp database."""
|
||||
db = tmp_path / "test_nexus.db"
|
||||
s = NexusStore(db_path=db)
|
||||
yield s
|
||||
s.close()
|
||||
|
||||
|
||||
class TestNexusStoreBasic:
|
||||
def test_append_and_retrieve(self, store):
|
||||
store.append("user", "hello")
|
||||
store.append("assistant", "hi there")
|
||||
history = store.get_history()
|
||||
assert len(history) == 2
|
||||
assert history[0]["role"] == "user"
|
||||
assert history[0]["content"] == "hello"
|
||||
assert history[1]["role"] == "assistant"
|
||||
|
||||
def test_message_count(self, store):
|
||||
assert store.message_count() == 0
|
||||
store.append("user", "a")
|
||||
store.append("user", "b")
|
||||
assert store.message_count() == 2
|
||||
|
||||
def test_custom_timestamp(self, store):
|
||||
store.append("user", "msg", timestamp="12:34:56")
|
||||
history = store.get_history()
|
||||
assert history[0]["timestamp"] == "12:34:56"
|
||||
|
||||
def test_clear_session(self, store):
|
||||
store.append("user", "a")
|
||||
store.append("assistant", "b")
|
||||
deleted = store.clear()
|
||||
assert deleted == 2
|
||||
assert store.message_count() == 0
|
||||
|
||||
def test_clear_empty_session(self, store):
|
||||
deleted = store.clear()
|
||||
assert deleted == 0
|
||||
|
||||
def test_clear_all(self, store):
|
||||
store.append("user", "a", session_tag="s1")
|
||||
store.append("user", "b", session_tag="s2")
|
||||
deleted = store.clear_all()
|
||||
assert deleted == 2
|
||||
assert store.message_count(session_tag="s1") == 0
|
||||
assert store.message_count(session_tag="s2") == 0
|
||||
|
||||
|
||||
class TestNexusStoreOrdering:
|
||||
def test_chronological_order(self, store):
|
||||
for i in range(5):
|
||||
store.append("user", f"msg-{i}")
|
||||
history = store.get_history()
|
||||
contents = [m["content"] for m in history]
|
||||
assert contents == ["msg-0", "msg-1", "msg-2", "msg-3", "msg-4"]
|
||||
|
||||
def test_limit_parameter(self, store):
|
||||
for i in range(10):
|
||||
store.append("user", f"msg-{i}")
|
||||
history = store.get_history(limit=3)
|
||||
assert len(history) == 3
|
||||
# Should be the 3 most recent
|
||||
assert history[0]["content"] == "msg-7"
|
||||
assert history[2]["content"] == "msg-9"
|
||||
|
||||
|
||||
class TestNexusStoreSessionTags:
|
||||
def test_session_isolation(self, store):
|
||||
store.append("user", "nexus-msg", session_tag="nexus")
|
||||
store.append("user", "other-msg", session_tag="other")
|
||||
nexus_history = store.get_history(session_tag="nexus")
|
||||
other_history = store.get_history(session_tag="other")
|
||||
assert len(nexus_history) == 1
|
||||
assert len(other_history) == 1
|
||||
assert nexus_history[0]["content"] == "nexus-msg"
|
||||
|
||||
def test_clear_only_affects_target_session(self, store):
|
||||
store.append("user", "a", session_tag="s1")
|
||||
store.append("user", "b", session_tag="s2")
|
||||
store.clear(session_tag="s1")
|
||||
assert store.message_count(session_tag="s1") == 0
|
||||
assert store.message_count(session_tag="s2") == 1
|
||||
|
||||
|
||||
class TestNexusStorePruning:
|
||||
def test_prune_excess_messages(self, tmp_path):
|
||||
"""Inserting beyond MAX_MESSAGES should prune oldest."""
|
||||
db = tmp_path / "prune_test.db"
|
||||
s = NexusStore(db_path=db)
|
||||
# Insert MAX_MESSAGES + 5 to trigger pruning
|
||||
for i in range(MAX_MESSAGES + 5):
|
||||
s.append("user", f"msg-{i}")
|
||||
assert s.message_count() == MAX_MESSAGES
|
||||
# Get full history — oldest remaining should be msg-5
|
||||
history = s.get_history(limit=MAX_MESSAGES)
|
||||
assert history[0]["content"] == "msg-5"
|
||||
s.close()
|
||||
|
||||
|
||||
class TestNexusStoreReopen:
|
||||
def test_data_survives_close_reopen(self, tmp_path):
|
||||
"""Data persists across store instances (simulates process restart)."""
|
||||
db = tmp_path / "reopen.db"
|
||||
|
||||
s1 = NexusStore(db_path=db)
|
||||
s1.append("user", "persistent message")
|
||||
s1.close()
|
||||
|
||||
s2 = NexusStore(db_path=db)
|
||||
history = s2.get_history()
|
||||
assert len(history) == 1
|
||||
assert history[0]["content"] == "persistent message"
|
||||
s2.close()
|
||||
|
||||
|
||||
class TestNexusStoreReturnedId:
|
||||
def test_append_returns_row_id(self, store):
|
||||
id1 = store.append("user", "first")
|
||||
id2 = store.append("user", "second")
|
||||
assert isinstance(id1, int)
|
||||
assert id2 > id1
|
||||
|
||||
|
||||
class TestNexusStoreClose:
|
||||
def test_close_is_idempotent(self, store):
|
||||
store.close()
|
||||
store.close() # Should not raise
|
||||
|
||||
def test_operations_after_close_reconnect(self, store):
|
||||
"""After close, next operation should reconnect automatically."""
|
||||
store.append("user", "before close")
|
||||
store.close()
|
||||
# Should auto-reconnect
|
||||
store.append("user", "after close")
|
||||
assert store.message_count() == 2
|
||||
151
tests/timmy/nexus/test_sovereignty_pulse.py
Normal file
151
tests/timmy/nexus/test_sovereignty_pulse.py
Normal file
@@ -0,0 +1,151 @@
|
||||
"""Tests for the Sovereignty Pulse module."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from timmy.nexus.sovereignty_pulse import (
|
||||
LayerPulse,
|
||||
SovereigntyPulse,
|
||||
SovereigntyPulseSnapshot,
|
||||
_classify_health,
|
||||
)
|
||||
|
||||
|
||||
class TestClassifyHealth:
|
||||
def test_sovereign(self):
|
||||
assert _classify_health(95.0) == "sovereign"
|
||||
assert _classify_health(80.0) == "sovereign"
|
||||
|
||||
def test_degraded(self):
|
||||
assert _classify_health(79.9) == "degraded"
|
||||
assert _classify_health(50.0) == "degraded"
|
||||
|
||||
def test_dependent(self):
|
||||
assert _classify_health(49.9) == "dependent"
|
||||
assert _classify_health(0.1) == "dependent"
|
||||
|
||||
def test_unknown(self):
|
||||
assert _classify_health(0.0) == "unknown"
|
||||
|
||||
|
||||
class TestLayerPulse:
|
||||
def test_to_dict(self):
|
||||
lp = LayerPulse(name="perception", sovereign_pct=75.0, cache_hits=15, model_calls=5)
|
||||
d = lp.to_dict()
|
||||
assert d["name"] == "perception"
|
||||
assert d["sovereign_pct"] == 75.0
|
||||
assert d["cache_hits"] == 15
|
||||
|
||||
|
||||
class TestSovereigntyPulseSnapshot:
|
||||
def test_defaults(self):
|
||||
snap = SovereigntyPulseSnapshot()
|
||||
assert snap.overall_pct == 0.0
|
||||
assert snap.health == "unknown"
|
||||
assert snap.layers == []
|
||||
|
||||
def test_to_dict_structure(self):
|
||||
snap = SovereigntyPulseSnapshot(
|
||||
overall_pct=85.0,
|
||||
health="sovereign",
|
||||
layers=[LayerPulse(name="perception", sovereign_pct=90.0)],
|
||||
crystallizations_last_hour=3,
|
||||
api_independence_pct=88.0,
|
||||
total_events=42,
|
||||
)
|
||||
d = snap.to_dict()
|
||||
assert d["overall_pct"] == 85.0
|
||||
assert d["health"] == "sovereign"
|
||||
assert len(d["layers"]) == 1
|
||||
assert d["layers"][0]["name"] == "perception"
|
||||
assert d["crystallizations_last_hour"] == 3
|
||||
assert d["api_independence_pct"] == 88.0
|
||||
assert d["total_events"] == 42
|
||||
assert "timestamp" in d
|
||||
|
||||
|
||||
class TestSovereigntyPulse:
|
||||
def test_snapshot_graceful_degradation(self):
|
||||
"""When metrics are unavailable, should return default snapshot."""
|
||||
pulse = SovereigntyPulse()
|
||||
with patch.object(
|
||||
pulse,
|
||||
"_read_metrics",
|
||||
side_effect=ImportError("no metrics"),
|
||||
):
|
||||
snap = pulse.snapshot()
|
||||
assert isinstance(snap, SovereigntyPulseSnapshot)
|
||||
assert snap.health == "unknown"
|
||||
|
||||
def test_snapshot_with_metrics(self):
|
||||
"""When metrics are available, should read and compute correctly."""
|
||||
pulse = SovereigntyPulse()
|
||||
mock_snapshot = {
|
||||
"perception": {"cache_hits": 8, "model_calls": 2},
|
||||
"decision": {"cache_hits": 6, "model_calls": 4},
|
||||
"narration": {"cache_hits": 10, "model_calls": 0},
|
||||
"crystallizations": 7,
|
||||
"total_events": 100,
|
||||
}
|
||||
mock_store = MagicMock()
|
||||
mock_store.get_snapshot.return_value = mock_snapshot
|
||||
|
||||
with patch(
|
||||
"timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store
|
||||
):
|
||||
snap = pulse.snapshot()
|
||||
|
||||
# Perception: 8/10 = 80%, Decision: 6/10 = 60%, Narration: 10/10 = 100%
|
||||
# Overall: (80 + 60 + 100) / 3 = 80.0
|
||||
assert len(snap.layers) == 3
|
||||
assert snap.layers[0].name == "perception"
|
||||
assert snap.layers[0].sovereign_pct == 80.0
|
||||
assert snap.layers[1].name == "decision"
|
||||
assert snap.layers[1].sovereign_pct == 60.0
|
||||
assert snap.layers[2].name == "narration"
|
||||
assert snap.layers[2].sovereign_pct == 100.0
|
||||
assert snap.overall_pct == 80.0
|
||||
assert snap.health == "sovereign"
|
||||
assert snap.crystallizations_last_hour == 7
|
||||
assert snap.total_events == 100
|
||||
|
||||
def test_api_independence_calculation(self):
|
||||
pulse = SovereigntyPulse()
|
||||
mock_snapshot = {
|
||||
"perception": {"cache_hits": 5, "model_calls": 5},
|
||||
"decision": {"cache_hits": 5, "model_calls": 5},
|
||||
"narration": {"cache_hits": 5, "model_calls": 5},
|
||||
"crystallizations": 0,
|
||||
"total_events": 0,
|
||||
}
|
||||
mock_store = MagicMock()
|
||||
mock_store.get_snapshot.return_value = mock_snapshot
|
||||
|
||||
with patch(
|
||||
"timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store
|
||||
):
|
||||
snap = pulse.snapshot()
|
||||
|
||||
# Total hits: 15, Total calls: 15, Total: 30
|
||||
# Independence: 15/30 = 50%
|
||||
assert snap.api_independence_pct == 50.0
|
||||
|
||||
def test_zero_events_no_division_error(self):
|
||||
pulse = SovereigntyPulse()
|
||||
mock_snapshot = {
|
||||
"perception": {"cache_hits": 0, "model_calls": 0},
|
||||
"decision": {"cache_hits": 0, "model_calls": 0},
|
||||
"narration": {"cache_hits": 0, "model_calls": 0},
|
||||
"crystallizations": 0,
|
||||
"total_events": 0,
|
||||
}
|
||||
mock_store = MagicMock()
|
||||
mock_store.get_snapshot.return_value = mock_snapshot
|
||||
|
||||
with patch(
|
||||
"timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store
|
||||
):
|
||||
snap = pulse.snapshot()
|
||||
|
||||
assert snap.overall_pct == 0.0
|
||||
assert snap.api_independence_pct == 0.0
|
||||
assert snap.health == "unknown"
|
||||
Reference in New Issue
Block a user