A5: Extract config routes into blueprint (app.py 1294 → 579 lines)

Move all /api/config/* routes and pending-restart helpers into
routes/config.py. Re-export helpers from app.py for backward compat:

  from routes.config import _set_pending_restart, _clear_pending_restart,
                           _collect_service_ports, _dedup_changes

Test patches updated:
  app._set_pending_restart     → routes.config._set_pending_restart
  app._clear_pending_restart   → routes.config._clear_pending_restart
  app.threading.Thread         → routes.config.threading.Thread

Remaining in app.py: Flask setup, middleware, health monitor thread,
/health, /api/status, /api/health/history* (use module-level state).

1021 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 06:53:24 -04:00
parent 09138fbc18
commit 5d0238ff3c
3 changed files with 687 additions and 730 deletions
+6 -6
View File
@@ -238,7 +238,7 @@ class TestWireGuardPortPropagation(unittest.TestCase):
app.config['TESTING'] = True
self.client = app.test_client()
@patch('app._set_pending_restart')
@patch('routes.config._set_pending_restart')
@patch('app.wireguard_manager')
@patch('app.config_manager')
def test_wireguard_port_identity_change_calls_apply_config(
@@ -263,7 +263,7 @@ class TestWireGuardPortPropagation(unittest.TestCase):
self.assertEqual(r.status_code, 200)
mock_wg.apply_config.assert_called_once_with({'port': 51821})
@patch('app._set_pending_restart')
@patch('routes.config._set_pending_restart')
@patch('app.wireguard_manager')
@patch('app.config_manager')
def test_wireguard_port_same_value_does_not_call_apply_config(
@@ -305,7 +305,7 @@ class TestApplyPendingConfigForceRecreate(unittest.TestCase):
app.config['TESTING'] = True
self.client = app.test_client()
@patch('app._clear_pending_restart')
@patch('routes.config._clear_pending_restart')
@patch('app.config_manager')
def test_apply_pending_uses_force_recreate(self, mock_cm, mock_clear):
"""apply_pending_config for specific containers must include --force-recreate."""
@@ -325,7 +325,7 @@ class TestApplyPendingConfigForceRecreate(unittest.TestCase):
t.start = lambda: None
return t
with patch('app.threading.Thread', side_effect=patched_thread):
with patch('routes.config.threading.Thread', side_effect=patched_thread):
r = self.client.post('/api/config/apply')
self.assertEqual(r.status_code, 200)
@@ -344,7 +344,7 @@ class TestApplyPendingConfigForceRecreate(unittest.TestCase):
f'--force-recreate missing from docker compose command: {cmd}')
self.assertIn('wireguard', cmd)
@patch('app._clear_pending_restart')
@patch('routes.config._clear_pending_restart')
@patch('app.config_manager')
def test_apply_pending_all_services_no_force_recreate(self, mock_cm, mock_clear):
"""All-services restart ('*') uses a helper container (Popen), not subprocess.run."""
@@ -364,7 +364,7 @@ class TestApplyPendingConfigForceRecreate(unittest.TestCase):
t.start = lambda: None
return t
with patch('app.threading.Thread', side_effect=patched_thread):
with patch('routes.config.threading.Thread', side_effect=patched_thread):
r = self.client.post('/api/config/apply')
self.assertEqual(r.status_code, 200)