| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- """Real loopback service control without starting the business API."""
- import json
- from pathlib import Path
- from types import SimpleNamespace
- import socket
- import tempfile
- import threading
- import time
- import unittest
- from unittest.mock import patch
- from step4_web import service_control as control
- class ControlTests(unittest.TestCase):
- def setUp(self):
- self.tmp=tempfile.TemporaryDirectory()
- self.addCleanup(self.tmp.cleanup)
- self.root=Path(self.tmp.name)
- self.patch=patch.object(control,'ROOT',self.root)
- self.patch.start(); self.addCleanup(self.patch.stop)
- def test_stop_waits_for_exit_and_allows_new_instance(self):
- server=SimpleNamespace(should_exit=False)
- ready=threading.Event()
- def worker():
- with control.managed_service(server):
- ready.set()
- while not server.should_exit: time.sleep(.01)
- thread=threading.Thread(target=worker)
- thread.start()
- try:
- self.assertTrue(ready.wait(3))
- self.assertTrue(control.running())
- control.stop_for_restart(timeout=3)
- thread.join(3)
- self.assertFalse(thread.is_alive())
- with control.managed_service(SimpleNamespace(should_exit=False)):
- self.assertTrue(control.running())
- self.assertFalse((self.root/'.runtime/service-control.json').exists())
- finally:
- server.should_exit=True
- thread.join(3)
- def test_wrong_token_cannot_stop_service(self):
- server=SimpleNamespace(should_exit=False)
- with control.managed_service(server):
- data=json.loads((self.root/'.runtime/service-control.json').read_text())
- with socket.create_connection(('127.0.0.1',data['port'])) as conn:
- conn.sendall(b'wrong-token\n')
- self.assertEqual(conn.recv(32).strip(),b'DENIED')
- self.assertFalse(server.should_exit)
- with self.assertRaises(RuntimeError):
- with control.managed_service(server): pass
- def test_timeout_does_not_start_or_force_kill(self):
- server=SimpleNamespace(should_exit=False)
- with control.managed_service(server):
- with self.assertRaisesRegex(RuntimeError,'未启动新实例'):
- control.stop_for_restart(timeout=.01)
- self.assertTrue(server.should_exit)
- def test_stale_state_does_not_signal_any_process(self):
- folder=self.root/'.runtime'; folder.mkdir()
- (folder/'service-control.json').write_text('{}')
- control.stop_for_restart()
- self.assertFalse(control.running())
- if __name__=='__main__': unittest.main()
|