mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-04-30 12:30:03 +00:00
172 lines
6 KiB
Python
172 lines
6 KiB
Python
"""Edge case tests for messaging/session.py SessionStore."""
|
|
|
|
import json
|
|
import os
|
|
import pytest
|
|
from unittest.mock import patch
|
|
|
|
from messaging.session import SessionStore
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_store(tmp_path):
|
|
"""Create a SessionStore using a temp file."""
|
|
path = str(tmp_path / "sessions.json")
|
|
return SessionStore(storage_path=path)
|
|
|
|
|
|
class TestSessionStoreLoadEdgeCases:
|
|
"""Tests for loading corrupted/malformed data."""
|
|
|
|
def test_load_corrupted_json(self, tmp_path):
|
|
"""Corrupted JSON file is handled gracefully (logs error, starts empty)."""
|
|
path = str(tmp_path / "sessions.json")
|
|
with open(path, "w") as f:
|
|
f.write("{invalid json")
|
|
|
|
store = SessionStore(storage_path=path)
|
|
assert len(store._sessions) == 0
|
|
assert len(store._trees) == 0
|
|
|
|
def test_load_truncated_json(self, tmp_path):
|
|
"""Truncated JSON file is handled gracefully."""
|
|
path = str(tmp_path / "sessions.json")
|
|
with open(path, "w") as f:
|
|
f.write('{"sessions": {"s1": {"session_id": "s1"')
|
|
|
|
store = SessionStore(storage_path=path)
|
|
assert len(store._sessions) == 0
|
|
|
|
def test_load_empty_file(self, tmp_path):
|
|
"""Empty file is handled gracefully."""
|
|
path = str(tmp_path / "sessions.json")
|
|
with open(path, "w") as f:
|
|
f.write("")
|
|
|
|
store = SessionStore(storage_path=path)
|
|
assert len(store._sessions) == 0
|
|
|
|
def test_load_nonexistent_file(self, tmp_path):
|
|
"""Non-existent file starts with empty state."""
|
|
path = str(tmp_path / "nonexistent.json")
|
|
store = SessionStore(storage_path=path)
|
|
assert len(store._sessions) == 0
|
|
|
|
def test_load_legacy_int_fields(self, tmp_path):
|
|
"""Legacy format with int chat_id/msg_id is converted to string."""
|
|
path = str(tmp_path / "sessions.json")
|
|
data = {
|
|
"sessions": {
|
|
"s1": {
|
|
"session_id": "s1",
|
|
"chat_id": 12345,
|
|
"initial_msg_id": 100,
|
|
"last_msg_id": 200,
|
|
"platform": "telegram",
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"updated_at": "2025-01-01T00:00:00+00:00",
|
|
}
|
|
},
|
|
"trees": {},
|
|
"node_to_tree": {},
|
|
}
|
|
with open(path, "w") as f:
|
|
json.dump(data, f)
|
|
|
|
store = SessionStore(storage_path=path)
|
|
record = store._sessions["s1"]
|
|
assert record.chat_id == "12345"
|
|
assert record.initial_msg_id == "100"
|
|
assert record.last_msg_id == "200"
|
|
|
|
|
|
class TestSessionStoreSaveEdgeCases:
|
|
"""Tests for save failure handling."""
|
|
|
|
def test_save_io_error_handled(self, tmp_store):
|
|
"""Write failure in _save() is logged but doesn't raise."""
|
|
tmp_store.save_tree("r1", {"root_id": "r1", "nodes": {"r1": {}}})
|
|
with patch("builtins.open", side_effect=IOError("disk full")):
|
|
tmp_store._save()
|
|
# Should not raise
|
|
|
|
|
|
class TestSessionStoreClearAll:
|
|
def test_clear_all_wipes_state_and_persists(self, tmp_path):
|
|
path = str(tmp_path / "sessions.json")
|
|
store = SessionStore(storage_path=path)
|
|
|
|
store.save_tree(
|
|
"root1",
|
|
{
|
|
"root_id": "root1",
|
|
"nodes": {
|
|
"root1": {
|
|
"node_id": "root1",
|
|
"incoming": {
|
|
"text": "hello",
|
|
"chat_id": "c1",
|
|
"user_id": "u1",
|
|
"message_id": "m1",
|
|
"platform": "telegram",
|
|
"reply_to_message_id": None,
|
|
"username": None,
|
|
},
|
|
"status_message_id": "status1",
|
|
"state": "pending",
|
|
"parent_id": None,
|
|
"session_id": None,
|
|
"children_ids": [],
|
|
"created_at": "2025-01-01T00:00:00+00:00",
|
|
"completed_at": None,
|
|
"error_message": None,
|
|
}
|
|
},
|
|
},
|
|
)
|
|
|
|
store.clear_all()
|
|
|
|
assert store.get_all_trees() == {}
|
|
assert store.get_node_mapping() == {}
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
assert data["sessions"] == {}
|
|
assert data["trees"] == {}
|
|
assert data["node_to_tree"] == {}
|
|
assert data["message_log"] == {}
|
|
|
|
store2 = SessionStore(storage_path=path)
|
|
assert len(store2._sessions) == 0
|
|
assert len(store2._trees) == 0
|
|
|
|
def test_message_log_persists_and_dedups(self, tmp_path):
|
|
path = str(tmp_path / "sessions.json")
|
|
store = SessionStore(storage_path=path)
|
|
|
|
store.record_message_id("telegram", "c1", "1", direction="in", kind="command")
|
|
store.record_message_id("telegram", "c1", "2", direction="out", kind="command")
|
|
store.record_message_id("telegram", "c1", "2", direction="out", kind="command")
|
|
|
|
ids = store.get_message_ids_for_chat("telegram", "c1")
|
|
assert ids == ["1", "2"]
|
|
|
|
store2 = SessionStore(storage_path=path)
|
|
assert store2.get_message_ids_for_chat("telegram", "c1") == ["1", "2"]
|
|
|
|
|
|
class TestSessionStoreCleanupEdgeCases:
|
|
"""Tests for cleanup with malformed data."""
|
|
|
|
def test_cleanup_trees_malformed_timestamp(self, tmp_store):
|
|
"""Malformed created_at in cleanup_old_trees doesn't crash."""
|
|
tmp_store._trees["root1"] = {"nodes": {"root1": {"created_at": "bad-date"}}}
|
|
removed = tmp_store.cleanup_old_trees(max_age_days=0)
|
|
assert removed == 0 # Skipped due to parse error
|
|
|
|
def test_cleanup_trees_missing_created_at(self, tmp_store):
|
|
"""Tree node without created_at is not cleaned up."""
|
|
tmp_store._trees["root1"] = {"nodes": {"root1": {}}}
|
|
removed = tmp_store.cleanup_old_trees(max_age_days=0)
|
|
assert removed == 0
|