2016-12-29 21:35:41 +00:00
|
|
|
import asyncio
|
2020-03-26 04:42:46 +00:00
|
|
|
import os
|
|
|
|
import signal
|
2019-04-23 22:44:42 +01:00
|
|
|
|
2017-01-22 02:26:32 +00:00
|
|
|
from queue import Queue
|
2022-04-17 10:25:41 +01:00
|
|
|
from types import SimpleNamespace
|
2019-04-23 22:44:42 +01:00
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
2020-03-26 04:42:46 +00:00
|
|
|
import pytest
|
|
|
|
|
2021-01-28 07:22:22 +00:00
|
|
|
from sanic_testing.testing import HOST, PORT
|
|
|
|
|
2020-03-26 04:42:46 +00:00
|
|
|
from sanic.compat import ctrlc_workaround_for_windows
|
2022-03-23 13:34:33 +00:00
|
|
|
from sanic.exceptions import InvalidUsage
|
2019-04-23 22:44:42 +01:00
|
|
|
from sanic.response import HTTPResponse
|
2016-12-29 21:35:41 +00:00
|
|
|
|
|
|
|
|
2017-01-22 02:26:32 +00:00
|
|
|
async def stop(app, loop):
|
|
|
|
await asyncio.sleep(0.1)
|
2016-12-29 21:35:41 +00:00
|
|
|
app.stop()
|
|
|
|
|
2018-12-30 11:18:06 +00:00
|
|
|
|
2017-01-22 02:26:32 +00:00
|
|
|
calledq = Queue()
|
|
|
|
|
2018-10-22 21:25:38 +01:00
|
|
|
|
2017-01-22 02:26:32 +00:00
|
|
|
def set_loop(app, loop):
|
2020-03-26 04:42:46 +00:00
|
|
|
global mock
|
|
|
|
mock = MagicMock()
|
|
|
|
if os.name == "nt":
|
|
|
|
signal.signal = mock
|
|
|
|
else:
|
|
|
|
loop.add_signal_handler = mock
|
2017-01-22 02:26:32 +00:00
|
|
|
|
2018-10-22 21:25:38 +01:00
|
|
|
|
2017-01-22 02:26:32 +00:00
|
|
|
def after(app, loop):
|
2020-03-26 04:42:46 +00:00
|
|
|
calledq.put(mock.called)
|
2016-12-29 21:35:41 +00:00
|
|
|
|
2018-10-22 21:25:38 +01:00
|
|
|
|
2020-06-05 15:14:18 +01:00
|
|
|
@pytest.mark.skipif(os.name == "nt", reason="May hang CI on py38/windows")
|
2018-08-26 15:43:14 +01:00
|
|
|
def test_register_system_signals(app):
|
2016-12-29 21:35:41 +00:00
|
|
|
"""Test if sanic register system signals"""
|
|
|
|
|
2018-12-30 11:18:06 +00:00
|
|
|
@app.route("/hello")
|
2016-12-29 21:35:41 +00:00
|
|
|
async def hello_route(request):
|
|
|
|
return HTTPResponse()
|
|
|
|
|
2018-12-30 11:18:06 +00:00
|
|
|
app.listener("after_server_start")(stop)
|
|
|
|
app.listener("before_server_start")(set_loop)
|
|
|
|
app.listener("after_server_stop")(after)
|
2017-02-11 14:30:17 +00:00
|
|
|
|
2018-03-16 04:28:52 +00:00
|
|
|
app.run(HOST, PORT)
|
2018-10-22 21:25:38 +01:00
|
|
|
assert calledq.get() is True
|
2016-12-29 21:35:41 +00:00
|
|
|
|
|
|
|
|
2020-06-05 15:14:18 +01:00
|
|
|
@pytest.mark.skipif(os.name == "nt", reason="May hang CI on py38/windows")
|
2018-08-26 15:43:14 +01:00
|
|
|
def test_dont_register_system_signals(app):
|
2016-12-29 21:35:41 +00:00
|
|
|
"""Test if sanic don't register system signals"""
|
|
|
|
|
2018-12-30 11:18:06 +00:00
|
|
|
@app.route("/hello")
|
2016-12-29 21:35:41 +00:00
|
|
|
async def hello_route(request):
|
|
|
|
return HTTPResponse()
|
|
|
|
|
2018-12-30 11:18:06 +00:00
|
|
|
app.listener("after_server_start")(stop)
|
|
|
|
app.listener("before_server_start")(set_loop)
|
|
|
|
app.listener("after_server_stop")(after)
|
2017-02-11 14:30:17 +00:00
|
|
|
|
2018-03-16 04:28:52 +00:00
|
|
|
app.run(HOST, PORT, register_sys_signals=False)
|
2018-10-22 21:25:38 +01:00
|
|
|
assert calledq.get() is False
|
2020-03-26 04:42:46 +00:00
|
|
|
|
|
|
|
|
2020-06-05 15:14:18 +01:00
|
|
|
@pytest.mark.skipif(os.name == "nt", reason="windows cannot SIGINT processes")
|
2020-03-26 04:42:46 +00:00
|
|
|
def test_windows_workaround():
|
|
|
|
"""Test Windows workaround (on any other OS)"""
|
|
|
|
# At least some code coverage, even though this test doesn't work on
|
|
|
|
# Windows...
|
|
|
|
class MockApp:
|
|
|
|
def __init__(self):
|
2022-04-17 10:25:41 +01:00
|
|
|
self.state = SimpleNamespace()
|
|
|
|
self.state.is_stopping = False
|
2020-03-26 04:42:46 +00:00
|
|
|
|
|
|
|
def stop(self):
|
2022-04-17 10:25:41 +01:00
|
|
|
assert not self.state.is_stopping
|
|
|
|
self.state.is_stopping = True
|
2020-03-26 04:42:46 +00:00
|
|
|
|
|
|
|
def add_task(self, func):
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
self.stay_active_task = loop.create_task(func(self))
|
|
|
|
|
|
|
|
async def atest(stop_first):
|
|
|
|
app = MockApp()
|
|
|
|
ctrlc_workaround_for_windows(app)
|
|
|
|
await asyncio.sleep(0.05)
|
|
|
|
if stop_first:
|
|
|
|
app.stop()
|
|
|
|
await asyncio.sleep(0.2)
|
2022-04-17 10:25:41 +01:00
|
|
|
assert app.state.is_stopping == stop_first
|
2020-03-26 04:42:46 +00:00
|
|
|
# First Ctrl+C: should call app.stop() within 0.1 seconds
|
|
|
|
os.kill(os.getpid(), signal.SIGINT)
|
|
|
|
await asyncio.sleep(0.2)
|
2022-04-17 10:25:41 +01:00
|
|
|
assert app.state.is_stopping
|
2021-09-27 08:22:30 +01:00
|
|
|
assert app.stay_active_task.result() is None
|
2020-03-26 04:42:46 +00:00
|
|
|
# Second Ctrl+C should raise
|
|
|
|
with pytest.raises(KeyboardInterrupt):
|
|
|
|
os.kill(os.getpid(), signal.SIGINT)
|
|
|
|
return "OK"
|
|
|
|
|
|
|
|
# Run in our private loop
|
|
|
|
loop = asyncio.new_event_loop()
|
|
|
|
asyncio.set_event_loop(loop)
|
|
|
|
res = loop.run_until_complete(atest(False))
|
|
|
|
assert res == "OK"
|
|
|
|
res = loop.run_until_complete(atest(True))
|
|
|
|
assert res == "OK"
|
2022-03-23 13:34:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(os.name == "nt", reason="May hang CI on py38/windows")
|
|
|
|
def test_signals_with_invalid_invocation(app):
|
|
|
|
"""Test if sanic register fails with invalid invocation"""
|
|
|
|
|
|
|
|
@app.route("/hello")
|
|
|
|
async def hello_route(request):
|
|
|
|
return HTTPResponse()
|
|
|
|
|
|
|
|
with pytest.raises(
|
|
|
|
InvalidUsage, match="Invalid event registration: Missing event name"
|
|
|
|
):
|
|
|
|
app.listener(stop)
|