Files
Mark-VIII/tests/test_health.py
T
bzuccaro a4285496fb fix: health monitor disables SSID pool immediately on PING failure
Ring-buffer SIGSEGV counts were unreliable for growth detection; the pool
broadcast is the only known crash cause, so disable it on first failure.
2026-08-18 19:32:49 -05:00

99 lines
3.8 KiB
Python

import os
import sys
import unittest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'payload', 'user', 'remote_access', 'pager-webui'))
import server
def setUpModule():
__import__('importlib').reload(server)
class HealthCheckTest(unittest.TestCase):
def setUp(self):
self.runs = []
self.ping_ok = True
self.sigsegvs = 0
self.iw_out = 'wlan0mon\nwlan1mon\n'
self.uci_state = {}
server._health.update({
'sigsegv_last': None, 'last_fix': 0.0, 'fixes': 0,
'last_action': None, 'pineap_up': False})
def fake_run(args, timeout=20, input_data=None):
self.runs.append((list(args), timeout))
a = list(args)
if a[0] == '/usr/bin/hak5cmd' and a[1] == 'PING':
if self.ping_ok:
return (0, 'Sending PING...\nGot PONG response\n', '')
return (1, '', 'could not connect to pineap: connection refused')
if a[0] == 'logread':
return (0, 'SIGSEGV\n' * self.sigsegs if hasattr(self, 'sigsegs') else '', '')
if a[0] == 'iw':
return (0, self.iw_out, '')
if a[:2] == ['uci', 'set']:
k, _, v = a[2].partition('=')
self.uci_state[k] = v
if a[:2] == ['uci', 'get']:
return (0, self.uci_state.get(a[2], '') + '\n', '')
return (0, '', '')
server.device_run = fake_run
def test_pineap_up_reports_no_action(self):
result = server.health_check()
self.assertTrue(result['pineap_up'])
self.assertIsNone(result['last_action'])
def test_down_with_growing_sigsegv_disables_pool(self):
self.ping_ok = False
self.sigsegs = 5
result = server.health_check()
self.assertIn('pool broadcast disabled', result['last_action'])
self.assertEqual(self.uci_state['pineapd.@ssidpool[0].disable'], '1')
self.assertIn(['/etc/init.d/pineapd', 'restart'], [r[0] for r in self.runs])
self.assertEqual(result['fixes'], 1)
def test_down_with_pool_already_disabled_restarts_pineapd(self):
self.ping_ok = False
self.uci_state['pineapd.@ssidpool[0].disable'] = '1'
result = server.health_check()
self.assertEqual(result['last_action'], 'pineapd restart')
self.assertIn(['/etc/init.d/pineapd', 'restart'], [r[0] for r in self.runs])
def test_down_without_crash_brings_monitor_up(self):
self.ping_ok = False
self.uci_state['pineapd.@ssidpool[0].disable'] = '1'
self.iw_out = 'wlan0mon\n'
result = server.health_check()
self.assertEqual(result['last_action'], 'wlan1mon brought up')
self.assertIn(['ip', 'link', 'set', 'wlan1mon', 'up'], [r[0] for r in self.runs])
def test_down_with_no_sigsegv_growth_restarts_pineapd(self):
self.ping_ok = False
server._health['sigsegv_last'] = 4
result = server.health_check()
self.assertIn('pineapd restart', result['last_action'])
self.assertIn(['/etc/init.d/pineapd', 'restart'], [r[0] for r in self.runs])
def test_fix_cooldown_prevents_thrash(self):
self.ping_ok = False
server._health['last_fix'] = server.time.time() - 30
server.health_check()
server.health_check()
fixes = [r for r in self.runs if r[0][0] in ('/etc/init.d/pineapd', 'ip', 'uci')]
self.assertEqual(len(fixes), 1, 'cooldown must allow only one fix action')
def test_health_endpoint_shape(self):
server._health['sigsegv_last'] = 7
status, payload = server.h_health(type('C', (), {'query': {}})())
self.assertEqual(status, 200)
self.assertEqual(payload['sigsegv_count'], 7)
self.assertIn('wlan1mon_up', payload)
self.assertIn('pool_disabled', payload)
if __name__ == '__main__':
unittest.main()