mirror of
https://github.com/Quad4-Software/MeshChatX.git
synced 2026-08-18 09:49:09 -04:00
158 lines
5.1 KiB
Python
158 lines
5.1 KiB
Python
# SPDX-License-Identifier: 0BSD
|
|
|
|
import shutil
|
|
import tempfile
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
import RNS
|
|
|
|
from meshchatx.meshchat import ReticulumMeshChat, main
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_dir():
|
|
dir_path = tempfile.mkdtemp()
|
|
yield dir_path
|
|
shutil.rmtree(dir_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_rns():
|
|
# Save the real identity class to use as base for our mock class
|
|
real_identity_class = RNS.Identity
|
|
|
|
class MockIdentityClass(real_identity_class):
|
|
def __init__(self, *args, **kwargs):
|
|
self.hash = b"test_hash_32_bytes_long_01234567"
|
|
self.hexhash = self.hash.hex()
|
|
|
|
def get_private_key(self):
|
|
return b"test_private_key"
|
|
|
|
def load(self, *args, **kwargs):
|
|
pass
|
|
|
|
def load_private_key(self, *args, **kwargs):
|
|
pass
|
|
|
|
with (
|
|
patch("RNS.Reticulum") as mock_reticulum,
|
|
patch("RNS.Transport") as mock_transport,
|
|
patch("RNS.Identity", MockIdentityClass),
|
|
patch("threading.Thread"),
|
|
patch("LXMF.LXMRouter"),
|
|
patch.object(ReticulumMeshChat, "announce_loop", return_value=None),
|
|
patch.object(
|
|
ReticulumMeshChat,
|
|
"announce_sync_propagation_nodes",
|
|
return_value=None,
|
|
),
|
|
patch.object(ReticulumMeshChat, "crawler_loop", return_value=None),
|
|
patch.object(ReticulumMeshChat, "auto_backup_loop", return_value=None),
|
|
patch.object(
|
|
ReticulumMeshChat,
|
|
"send_config_to_websocket_clients",
|
|
return_value=None,
|
|
),
|
|
):
|
|
mock_id_instance = MockIdentityClass()
|
|
|
|
with (
|
|
patch.object(MockIdentityClass, "from_file", return_value=mock_id_instance),
|
|
patch.object(MockIdentityClass, "recall", return_value=mock_id_instance),
|
|
patch.object(
|
|
MockIdentityClass,
|
|
"from_bytes",
|
|
return_value=mock_id_instance,
|
|
),
|
|
):
|
|
yield {
|
|
"Reticulum": mock_reticulum,
|
|
"Transport": mock_transport,
|
|
"Identity": MockIdentityClass,
|
|
"id_instance": mock_id_instance,
|
|
}
|
|
|
|
|
|
def _ok_results():
|
|
from meshchatx.src.backend.self_check import SELF_CHECK_LABELS
|
|
|
|
return {key: {"status": "ok", "reason": ""} for key in SELF_CHECK_LABELS}
|
|
|
|
|
|
def test_self_check_cli_success(mock_rns, temp_dir):
|
|
"""Test that self-check CLI argument prints results and exits with 0 on success."""
|
|
mock_results = _ok_results()
|
|
|
|
with (
|
|
patch("meshchatx.meshchat.ReticulumMeshChat") as mock_app_class,
|
|
patch("meshchatx.src.backend.identity_context.Database"),
|
|
patch("meshchatx.src.backend.identity_context.ConfigManager"),
|
|
patch("aiohttp.web.run_app"),
|
|
patch("sys.argv", ["meshchat.py", "--storage-dir", temp_dir, "--self-check"]),
|
|
):
|
|
mock_app_instance = mock_app_class.return_value
|
|
mock_app_instance.run_self_test = MagicMock(return_value=mock_results)
|
|
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
main()
|
|
|
|
assert excinfo.value.code == 0
|
|
mock_app_instance.run_self_test.assert_called_once()
|
|
|
|
|
|
def test_self_check_cli_failure(mock_rns, temp_dir):
|
|
"""Test that self-check CLI argument prints results and exits with 1 on failure."""
|
|
mock_results = _ok_results()
|
|
mock_results["stack_up"] = {
|
|
"status": "failed",
|
|
"reason": "Reticulum stack is not initialized",
|
|
}
|
|
mock_results["db_good"] = {
|
|
"status": "failed",
|
|
"reason": "Database check failed",
|
|
}
|
|
|
|
with (
|
|
patch("meshchatx.meshchat.ReticulumMeshChat") as mock_app_class,
|
|
patch("meshchatx.src.backend.identity_context.Database"),
|
|
patch("meshchatx.src.backend.identity_context.ConfigManager"),
|
|
patch("aiohttp.web.run_app"),
|
|
patch("sys.argv", ["meshchat.py", "--storage-dir", temp_dir, "--self-check"]),
|
|
):
|
|
mock_app_instance = mock_app_class.return_value
|
|
mock_app_instance.run_self_test = MagicMock(return_value=mock_results)
|
|
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
main()
|
|
|
|
assert excinfo.value.code == 1
|
|
mock_app_instance.run_self_test.assert_called_once()
|
|
|
|
|
|
def test_self_check_env_var_success(mock_rns, temp_dir):
|
|
"""Test that MESHCHAT_SELF_CHECK env var triggers self-check and exits with 0 on success."""
|
|
mock_results = _ok_results()
|
|
|
|
env = {
|
|
"MESHCHAT_SELF_CHECK": "true",
|
|
"MESHCHAT_STORAGE_DIR": temp_dir,
|
|
}
|
|
|
|
with (
|
|
patch("meshchatx.meshchat.ReticulumMeshChat") as mock_app_class,
|
|
patch("meshchatx.src.backend.identity_context.Database"),
|
|
patch("meshchatx.src.backend.identity_context.ConfigManager"),
|
|
patch("aiohttp.web.run_app"),
|
|
patch.dict("os.environ", env),
|
|
patch("sys.argv", ["meshchat.py"]),
|
|
):
|
|
mock_app_instance = mock_app_class.return_value
|
|
mock_app_instance.run_self_test = MagicMock(return_value=mock_results)
|
|
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
main()
|
|
|
|
assert excinfo.value.code == 0
|
|
mock_app_instance.run_self_test.assert_called_once()
|