mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-02 18:51:31 +08:00
test(companion): Add control command tests
Wire ControlServer.handle_line to a real CompanionManager.handle_command and assert the full decode/dispatch/encode round trip: status returns the companion list, start routes through and reports a message, and unknown command, missing name, and reread without a loader each return an error envelope. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e15dd583b9
commit
4d554c2fac
@ -697,7 +697,7 @@ No per-companion logic in Arbiter.
|
|||||||
- [x] Add lifecycle logs.
|
- [x] Add lifecycle logs.
|
||||||
- [x] Add tests for config validation.
|
- [x] Add tests for config validation.
|
||||||
- [x] Add tests for state transitions.
|
- [x] Add tests for state transitions.
|
||||||
- [ ] Add tests for control commands.
|
- [x] Add tests for control commands.
|
||||||
- [ ] Add tests for transactional reread.
|
- [ ] Add tests for transactional reread.
|
||||||
- [ ] Add tests that HTTP worker behavior is unchanged.
|
- [ ] Add tests that HTTP worker behavior is unchanged.
|
||||||
|
|
||||||
|
|||||||
@ -7,12 +7,23 @@ from unittest import mock
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from gunicorn.companion.config import CompanionConfig
|
||||||
from gunicorn.companion.control import (
|
from gunicorn.companion.control import (
|
||||||
CommandError,
|
CommandError,
|
||||||
ControlServer,
|
ControlServer,
|
||||||
decode_command,
|
decode_command,
|
||||||
encode_response,
|
encode_response,
|
||||||
)
|
)
|
||||||
|
from gunicorn.companion.manager import CompanionManager
|
||||||
|
|
||||||
|
|
||||||
|
def make_manager(*names):
|
||||||
|
configs = [CompanionConfig(name=name, target=lambda: None) for name in names]
|
||||||
|
return CompanionManager(configs, log=mock.Mock())
|
||||||
|
|
||||||
|
|
||||||
|
def server_for(manager):
|
||||||
|
return ControlServer(dispatch=manager.handle_command, path="/tmp/x.sock")
|
||||||
|
|
||||||
|
|
||||||
def test_decode_command_valid():
|
def test_decode_command_valid():
|
||||||
@ -85,3 +96,41 @@ def test_close_unlinks():
|
|||||||
server.close()
|
server.close()
|
||||||
unlink.assert_called_once_with("/tmp/x.sock")
|
unlink.assert_called_once_with("/tmp/x.sock")
|
||||||
assert server.listener is None
|
assert server.listener is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_control_status_command_end_to_end():
|
||||||
|
manager = make_manager("rq")
|
||||||
|
response = json.loads(server_for(manager).handle_line('{"cmd": "status"}'))
|
||||||
|
assert response["ok"] is True
|
||||||
|
assert response["companions"][0]["name"] == "rq"
|
||||||
|
|
||||||
|
|
||||||
|
def test_control_start_command_end_to_end():
|
||||||
|
manager = make_manager("rq")
|
||||||
|
with mock.patch("os.fork", return_value=10):
|
||||||
|
response = json.loads(
|
||||||
|
server_for(manager).handle_line('{"cmd": "start", "name": "rq"}'))
|
||||||
|
assert response["ok"] is True
|
||||||
|
assert "rq" in response["message"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_control_unknown_command_error_envelope():
|
||||||
|
manager = make_manager("rq")
|
||||||
|
response = json.loads(
|
||||||
|
server_for(manager).handle_line('{"cmd": "bogus", "name": "rq"}'))
|
||||||
|
assert response["ok"] is False
|
||||||
|
assert "unknown" in response["error"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_control_missing_name_error_envelope():
|
||||||
|
manager = make_manager("rq")
|
||||||
|
response = json.loads(server_for(manager).handle_line('{"cmd": "start"}'))
|
||||||
|
assert response["ok"] is False
|
||||||
|
assert "name" in response["error"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_control_reread_without_loader_error_envelope():
|
||||||
|
manager = make_manager("rq")
|
||||||
|
response = json.loads(server_for(manager).handle_line('{"cmd": "reread"}'))
|
||||||
|
assert response["ok"] is False
|
||||||
|
assert "reread" in response["error"]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user