Skip to content

Commit

Permalink
Fix asyncio testing setup (#3832)
Browse files Browse the repository at this point in the history
* Fix asyncio testing setup

* default `asyncio_default_fixture_loop_scope` to `function` to get rid
  of deprecation messages
* Change `test_asyncio.py` event loop scopes to `module` to avoid that
  event loop bleeding into all other tests in the same `session`.
* Remove explicit `event_loop`s since `pytest-asyncio` takes care of
  those
* Bump asyncio tests to 3.8 min
  • Loading branch information
sl0thentr0py authored Dec 2, 2024
1 parent c4274a3 commit 6bd7e08
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 46 deletions.
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[pytest]
addopts = -vvv -rfEs -s --durations=5 --cov=./sentry_sdk --cov-branch --cov-report= --tb=short --junitxml=.junitxml
asyncio_mode = strict
asyncio_default_fixture_loop_scope = function
markers =
tests_internal_exceptions: Handle internal exceptions just as the SDK does, to test it. (Otherwise internal exceptions are recorded and reraised.)

Expand Down
57 changes: 23 additions & 34 deletions tests/integrations/asyncio/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
pass # All tests will be skipped with incompatible versions


minimum_python_37 = pytest.mark.skipif(
sys.version_info < (3, 7), reason="Asyncio tests need Python >= 3.7"
minimum_python_38 = pytest.mark.skipif(
sys.version_info < (3, 8), reason="Asyncio tests need Python >= 3.8"
)


Expand All @@ -38,14 +38,6 @@ async def boom():
1 / 0


@pytest.fixture(scope="session")
def event_loop(request):
"""Create an instance of the default event loop for each test case."""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()


def get_sentry_task_factory(mock_get_running_loop):
"""
Patches (mocked) asyncio and gets the sentry_task_factory.
Expand All @@ -57,12 +49,11 @@ def get_sentry_task_factory(mock_get_running_loop):
return patched_factory


@minimum_python_37
@pytest.mark.asyncio
@minimum_python_38
@pytest.mark.asyncio(loop_scope="module")
async def test_create_task(
sentry_init,
capture_events,
event_loop,
):
sentry_init(
traces_sample_rate=1.0,
Expand All @@ -76,10 +67,10 @@ async def test_create_task(

with sentry_sdk.start_transaction(name="test_transaction_for_create_task"):
with sentry_sdk.start_span(op="root", name="not so important"):
tasks = [event_loop.create_task(foo()), event_loop.create_task(bar())]
tasks = [asyncio.create_task(foo()), asyncio.create_task(bar())]
await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)

sentry_sdk.flush()
sentry_sdk.flush()

(transaction_event,) = events

Expand All @@ -101,8 +92,8 @@ async def test_create_task(
)


@minimum_python_37
@pytest.mark.asyncio
@minimum_python_38
@pytest.mark.asyncio(loop_scope="module")
async def test_gather(
sentry_init,
capture_events,
Expand All @@ -121,7 +112,7 @@ async def test_gather(
with sentry_sdk.start_span(op="root", name="not so important"):
await asyncio.gather(foo(), bar(), return_exceptions=True)

sentry_sdk.flush()
sentry_sdk.flush()

(transaction_event,) = events

Expand All @@ -143,12 +134,11 @@ async def test_gather(
)


@minimum_python_37
@pytest.mark.asyncio
@minimum_python_38
@pytest.mark.asyncio(loop_scope="module")
async def test_exception(
sentry_init,
capture_events,
event_loop,
):
sentry_init(
traces_sample_rate=1.0,
Expand All @@ -162,10 +152,10 @@ async def test_exception(

with sentry_sdk.start_transaction(name="test_exception"):
with sentry_sdk.start_span(op="root", name="not so important"):
tasks = [event_loop.create_task(boom()), event_loop.create_task(bar())]
tasks = [asyncio.create_task(boom()), asyncio.create_task(bar())]
await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)

sentry_sdk.flush()
sentry_sdk.flush()

(error_event, _) = events

Expand All @@ -177,8 +167,8 @@ async def test_exception(
assert error_event["exception"]["values"][0]["mechanism"]["type"] == "asyncio"


@minimum_python_37
@pytest.mark.asyncio
@minimum_python_38
@pytest.mark.asyncio(loop_scope="module")
async def test_task_result(sentry_init):
sentry_init(
integrations=[
Expand All @@ -194,7 +184,7 @@ async def add(a, b):


@minimum_python_311
@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="module")
async def test_task_with_context(sentry_init):
"""
Integration test to ensure working context parameter in Python 3.11+
Expand Down Expand Up @@ -223,7 +213,7 @@ async def retrieve_value():
assert retrieve_task.result() == "changed value"


@minimum_python_37
@minimum_python_38
@patch("asyncio.get_running_loop")
def test_patch_asyncio(mock_get_running_loop):
"""
Expand All @@ -242,7 +232,7 @@ def test_patch_asyncio(mock_get_running_loop):
assert callable(sentry_task_factory)


@minimum_python_37
@minimum_python_38
@patch("asyncio.get_running_loop")
@patch("sentry_sdk.integrations.asyncio.Task")
def test_sentry_task_factory_no_factory(MockTask, mock_get_running_loop): # noqa: N803
Expand Down Expand Up @@ -271,7 +261,7 @@ def test_sentry_task_factory_no_factory(MockTask, mock_get_running_loop): # noq
assert task_kwargs["loop"] == mock_loop


@minimum_python_37
@minimum_python_38
@patch("asyncio.get_running_loop")
def test_sentry_task_factory_with_factory(mock_get_running_loop):
mock_loop = mock_get_running_loop.return_value
Expand Down Expand Up @@ -361,12 +351,11 @@ def test_sentry_task_factory_context_with_factory(mock_get_running_loop):
assert task_factory_kwargs["context"] == mock_context


@minimum_python_37
@pytest.mark.asyncio
@minimum_python_38
@pytest.mark.asyncio(loop_scope="module")
async def test_span_origin(
sentry_init,
capture_events,
event_loop,
):
sentry_init(
integrations=[AsyncioIntegration()],
Expand All @@ -377,11 +366,11 @@ async def test_span_origin(

with sentry_sdk.start_transaction(name="something"):
tasks = [
event_loop.create_task(foo()),
asyncio.create_task(foo()),
]
await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)

sentry_sdk.flush()
sentry_sdk.flush()

(event,) = events

Expand Down
16 changes: 4 additions & 12 deletions tests/integrations/grpc/test_grpc_aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,14 @@
AIO_PORT += os.getpid() % 100 # avoid port conflicts when running tests in parallel


@pytest.fixture(scope="function")
def event_loop(request):
"""Create an instance of the default event loop for each test case."""
loop = asyncio.new_event_loop()
yield loop
loop.close()


@pytest_asyncio.fixture(scope="function")
async def grpc_server(sentry_init, event_loop):
async def grpc_server(sentry_init):
sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()])
server = grpc.aio.server()
server.add_insecure_port("[::]:{}".format(AIO_PORT))
add_gRPCTestServiceServicer_to_server(TestService, server)

await event_loop.create_task(server.start())
await asyncio.create_task(server.start())

try:
yield server
Expand All @@ -45,12 +37,12 @@ async def grpc_server(sentry_init, event_loop):


@pytest.mark.asyncio
async def test_noop_for_unimplemented_method(event_loop, sentry_init, capture_events):
async def test_noop_for_unimplemented_method(sentry_init, capture_events):
sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()])
server = grpc.aio.server()
server.add_insecure_port("[::]:{}".format(AIO_PORT))

await event_loop.create_task(server.start())
await asyncio.create_task(server.start())

events = capture_events()
try:
Expand Down

0 comments on commit 6bd7e08

Please sign in to comment.