Add terminal TUI and shell completion
This commit is contained in:
parent
a7535cfc56
commit
cab60cd633
11 changed files with 612 additions and 0 deletions
|
|
@ -51,6 +51,8 @@ class TestDocsVersioning(unittest.TestCase):
|
|||
self.assertGreaterEqual(len(commands), 8)
|
||||
for phrase in ("Global options:", "Exit code:", "Expected use:"):
|
||||
self.assertIn(phrase, text)
|
||||
self.assertIn("### `tui` / `enodia-sentinel-tui`", text)
|
||||
self.assertIn("### `completion`", text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -26,5 +26,9 @@ class TestTrayBoundaries(unittest.TestCase):
|
|||
data["project"]["scripts"]["enodia-sentinel-tray"],
|
||||
"enodia_sentinel.tray.app:main",
|
||||
)
|
||||
self.assertEqual(
|
||||
data["project"]["scripts"]["enodia-sentinel-tui"],
|
||||
"enodia_sentinel.tui:main",
|
||||
)
|
||||
# Core runtime deps stay empty.
|
||||
self.assertEqual(data["project"]["dependencies"], [])
|
||||
|
|
|
|||
81
tests/test_tui.py
Normal file
81
tests/test_tui.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import redirect_stdout
|
||||
from pathlib import Path
|
||||
|
||||
from enodia_sentinel.cli import main
|
||||
from enodia_sentinel.config import Config
|
||||
from enodia_sentinel.tui import (
|
||||
TuiState,
|
||||
collect_model,
|
||||
complete_command,
|
||||
render_lines,
|
||||
run_tui_command,
|
||||
)
|
||||
|
||||
|
||||
class TestTuiCore(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.dir = tempfile.TemporaryDirectory()
|
||||
self.tmp = Path(self.dir.name)
|
||||
self.cfg = Config()
|
||||
self.cfg.log_dir = self.tmp
|
||||
|
||||
def tearDown(self):
|
||||
self.dir.cleanup()
|
||||
|
||||
def test_command_completion_unique_and_common_prefix(self):
|
||||
self.assertEqual(complete_command("inc"), "incidents")
|
||||
self.assertEqual(complete_command("r"), "r")
|
||||
self.assertEqual(complete_command("zzz"), "zzz")
|
||||
|
||||
def test_run_tui_command_switches_views_and_filters(self):
|
||||
state = TuiState()
|
||||
run_tui_command(state, "incidents")
|
||||
self.assertEqual(state.view, "incidents")
|
||||
run_tui_command(state, "filter ssh")
|
||||
self.assertEqual(state.filter_text, "ssh")
|
||||
run_tui_command(state, "clear")
|
||||
self.assertEqual(state.filter_text, "")
|
||||
run_tui_command(state, "quit")
|
||||
self.assertTrue(state.should_quit)
|
||||
|
||||
def test_collect_model_and_render_status(self):
|
||||
model = collect_model(self.cfg)
|
||||
state = TuiState(model=model)
|
||||
lines = render_lines(state, width=80)
|
||||
self.assertTrue(any("Daemon:" in line for line in lines))
|
||||
self.assertTrue(any("Heartbeat:" in line for line in lines))
|
||||
|
||||
def test_render_alerts_and_filter(self):
|
||||
(self.tmp / "alert-1.json").write_text(json.dumps({
|
||||
"time": "2026-07-09T01:02:03-07:00",
|
||||
"alerts": [{
|
||||
"severity": "CRITICAL",
|
||||
"sid": 100010,
|
||||
"signature": "reverse_shell",
|
||||
"detail": "bash connected to 8.8.8.8",
|
||||
}],
|
||||
}))
|
||||
state = TuiState(view="alerts", model=collect_model(self.cfg))
|
||||
self.assertTrue(any("reverse_shell" in line for line in render_lines(state)))
|
||||
state.filter_text = "nomatch"
|
||||
self.assertEqual(render_lines(state), ["No rows match filter: nomatch"])
|
||||
|
||||
def test_cli_completion_outputs_scripts(self):
|
||||
for shell in ("bash", "zsh"):
|
||||
with self.subTest(shell=shell):
|
||||
buf = io.StringIO()
|
||||
with redirect_stdout(buf):
|
||||
code = main(["completion", shell])
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("enodia-sentinel", buf.getvalue())
|
||||
self.assertIn("tui", buf.getvalue())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue