98 lines
3.9 KiB
Python
98 lines
3.9 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Tray action layer: drives CLI + systemctl through an injectable runner."""
|
|
import json
|
|
import subprocess
|
|
import unittest
|
|
|
|
from enodia_sentinel.config import Config
|
|
from enodia_sentinel.tray import actions
|
|
|
|
|
|
def _proc(rc=0, out="", err=""):
|
|
return subprocess.CompletedProcess(args=[], returncode=rc,
|
|
stdout=out, stderr=err)
|
|
|
|
|
|
class _Recorder:
|
|
"""Runner that returns scripted results and records the commands seen."""
|
|
def __init__(self, results):
|
|
self._results = list(results)
|
|
self.calls = []
|
|
|
|
def __call__(self, cmd, timeout):
|
|
self.calls.append(list(cmd))
|
|
return self._results.pop(0)
|
|
|
|
|
|
class TestActions(unittest.TestCase):
|
|
def test_dashboard_url_is_loopback_with_port(self):
|
|
cfg = Config()
|
|
cfg.web_port = 9999
|
|
self.assertEqual(actions.dashboard_url(cfg), "https://127.0.0.1:9999/")
|
|
|
|
def test_fetch_status_parses_json_even_on_nonzero_exit(self):
|
|
runner = _Recorder([_proc(rc=1, out=json.dumps({"running": True}))])
|
|
self.assertEqual(actions.fetch_status(runner), {"running": True})
|
|
|
|
def test_fetch_status_returns_none_on_garbage(self):
|
|
runner = _Recorder([_proc(out="not json")])
|
|
self.assertIsNone(actions.fetch_status(runner))
|
|
|
|
def test_start_daemon_ok(self):
|
|
runner = _Recorder([_proc(rc=0)])
|
|
res = actions.start_daemon(runner)
|
|
self.assertTrue(res.ok)
|
|
self.assertEqual(runner.calls[0],
|
|
["systemctl", "start", "enodia-sentinel.service"])
|
|
|
|
def test_stop_daemon_failure_carries_stderr_tail(self):
|
|
runner = _Recorder([_proc(rc=1, err="line1\nAccess denied")])
|
|
res = actions.stop_daemon(runner)
|
|
self.assertFalse(res.ok)
|
|
self.assertIn("Access denied", res.message)
|
|
|
|
def test_open_dashboard_starts_web_if_inactive(self):
|
|
# is-active -> inactive, then start -> ok
|
|
runner = _Recorder([_proc(out="inactive"), _proc(rc=0)])
|
|
opened = []
|
|
res = actions.open_dashboard(Config(), runner, opener=opened.append)
|
|
self.assertTrue(res.ok)
|
|
self.assertEqual(runner.calls[0],
|
|
["systemctl", "is-active", "enodia-sentinel-web.service"])
|
|
self.assertEqual(runner.calls[1],
|
|
["systemctl", "start", "enodia-sentinel-web.service"])
|
|
self.assertEqual(opened, ["https://127.0.0.1:8787/"])
|
|
|
|
def test_open_dashboard_skips_start_when_active(self):
|
|
runner = _Recorder([_proc(out="active")])
|
|
opened = []
|
|
res = actions.open_dashboard(Config(), runner, opener=opened.append)
|
|
self.assertTrue(res.ok)
|
|
self.assertEqual(len(runner.calls), 1)
|
|
self.assertEqual(opened, ["https://127.0.0.1:8787/"])
|
|
|
|
def test_open_dashboard_returns_early_when_start_fails(self):
|
|
# is-active -> inactive, then start -> failure
|
|
runner = _Recorder([_proc(out="inactive"),
|
|
_proc(rc=1, err="Access denied")])
|
|
opened = []
|
|
res = actions.open_dashboard(Config(), runner, opener=opened.append)
|
|
self.assertFalse(res.ok)
|
|
self.assertEqual(runner.calls[0],
|
|
["systemctl", "is-active", "enodia-sentinel-web.service"])
|
|
self.assertEqual(runner.calls[1],
|
|
["systemctl", "start", "enodia-sentinel-web.service"])
|
|
self.assertEqual(opened, [])
|
|
|
|
def test_run_check_counts_findings(self):
|
|
runner = _Recorder([_proc(out=json.dumps([{"signature": "rsh"},
|
|
{"signature": "suid"}]))])
|
|
res = actions.run_check(runner)
|
|
self.assertTrue(res.ok)
|
|
self.assertIn("2", res.message)
|
|
|
|
def test_run_check_no_findings(self):
|
|
runner = _Recorder([_proc(out="[]")])
|
|
res = actions.run_check(runner)
|
|
self.assertTrue(res.ok)
|
|
self.assertIn("no findings", res.message.lower())
|