playwright-python/tests/common/test_signals.py

146 lines
4.5 KiB
Python

# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import asyncio
import multiprocessing
import os
import signal
import sys
from typing import Any, Dict
import pytest
from playwright.async_api import async_playwright
from playwright.sync_api import sync_playwright
def _test_signals_async(
browser_name: str, launch_arguments: Dict, wait_queue: "multiprocessing.Queue[str]"
) -> None:
# On Windows, hint to mypy and pyright that they shouldn't check this function
if sys.platform == "win32":
return
os.setpgrp()
sigint_received = False
def my_sig_handler(signum: int, frame: Any) -> None:
nonlocal sigint_received
sigint_received = True
signal.signal(signal.SIGINT, my_sig_handler)
async def main() -> None:
playwright = await async_playwright().start()
browser = await playwright[browser_name].launch(
**launch_arguments,
handle_sigint=False,
)
context = await browser.new_context()
page = await context.new_page()
notified = False
try:
while not sigint_received:
if not notified:
wait_queue.put("ready")
notified = True
await page.wait_for_timeout(100)
finally:
wait_queue.put("close context")
await context.close()
wait_queue.put("close browser")
await browser.close()
wait_queue.put("close playwright")
await playwright.stop()
wait_queue.put("all done")
asyncio.run(main())
def _test_signals_sync(
browser_name: str, launch_arguments: Dict, wait_queue: "multiprocessing.Queue[str]"
) -> None:
# On Windows, hint to mypy and pyright that they shouldn't check this function
if sys.platform == "win32":
return
os.setpgrp()
sigint_received = False
def my_sig_handler(signum: int, frame: Any) -> None:
nonlocal sigint_received
sigint_received = True
signal.signal(signal.SIGINT, my_sig_handler)
playwright = sync_playwright().start()
browser = playwright[browser_name].launch(
**launch_arguments,
handle_sigint=False,
)
context = browser.new_context()
page = context.new_page()
notified = False
try:
while not sigint_received:
if not notified:
wait_queue.put("ready")
notified = True
page.wait_for_timeout(100)
finally:
wait_queue.put("close context")
context.close()
wait_queue.put("close browser")
browser.close()
wait_queue.put("close playwright")
playwright.stop()
wait_queue.put("all done")
def _create_signals_test(
target: Any, browser_name: str, launch_arguments: Dict
) -> None:
# On Windows, hint to mypy and pyright that they shouldn't check this function
if sys.platform == "win32":
return
wait_queue: "multiprocessing.Queue[str]" = multiprocessing.Queue()
process = multiprocessing.Process(
target=target, args=[browser_name, launch_arguments, wait_queue]
)
process.start()
assert process.pid is not None
logs = [wait_queue.get()]
os.killpg(os.getpgid(process.pid), signal.SIGINT)
process.join()
while not wait_queue.empty():
logs.append(wait_queue.get())
assert logs == [
"ready",
"close context",
"close browser",
"close playwright",
"all done",
]
assert process.exitcode == 0
@pytest.mark.skipif(sys.platform == "win32", reason="there is no SIGINT on Windows")
def test_signals_sync(browser_name: str, launch_arguments: Dict) -> None:
_create_signals_test(_test_signals_sync, browser_name, launch_arguments)
@pytest.mark.skipif(sys.platform == "win32", reason="there is no SIGINT on Windows")
def test_signals_async(browser_name: str, launch_arguments: Dict) -> None:
_create_signals_test(_test_signals_async, browser_name, launch_arguments)