Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 0 additions & 119 deletions tests/tracing/test_misc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import gc
import os
import uuid
from unittest import mock
from unittest.mock import MagicMock

Expand Down Expand Up @@ -263,122 +260,6 @@ def test_finds_non_orphan_span_on_scope_span_streaming(sentry_init):
assert scope._span.name == "sniffing"


def test_circular_references(monkeypatch, sentry_init, request):
# TODO: We discovered while writing this test about transaction/span
# reference cycles that there's actually also a circular reference in
# `serializer.py`, between the functions `_serialize_node` and
# `_serialize_node_impl`, both of which are defined inside of the main
# `serialize` function, and each of which calls the other one. For now, in
# order to avoid having those ref cycles give us a false positive here, we
# can mock out `serialize`. In the long run, though, we should probably fix
# that. (Whenever we do work on fixing it, it may be useful to add
#
# gc.set_debug(gc.DEBUG_LEAK)
# request.addfinalizer(lambda: gc.set_debug(~gc.DEBUG_LEAK))
#
# immediately after the initial collection below, so we can see what new
# objects the garbage collector has to clean up once `transaction.finish` is
# called and the serializer runs.)
monkeypatch.setattr(
sentry_sdk.client,
"serialize",
mock.Mock(
return_value=None,
),
)

# In certain versions of python, in some environments (specifically, python
# 3.4 when run in GH Actions), we run into a `ctypes` bug which creates
# circular references when `uuid4()` is called, as happens when we're
# generating event ids. Mocking it with an implementation which doesn't use
# the `ctypes` function lets us avoid having false positives when garbage
# collecting. See https://bugs.python.org/issue20519.
monkeypatch.setattr(
uuid,
"uuid4",
mock.Mock(
return_value=uuid.UUID(bytes=os.urandom(16)),
),
)

gc.disable()
request.addfinalizer(gc.enable)

sentry_init(traces_sample_rate=1.0)

# Make sure that we're starting with a clean slate before we start creating
# transaction/span reference cycles
gc.collect()

dogpark_transaction = start_transaction(name="dogpark")
sniffing_span = dogpark_transaction.start_child(op="sniffing")
wagging_span = dogpark_transaction.start_child(op="wagging")

# At some point, you have to stop sniffing - there are balls to chase! - so finish
# this span while the dogpark transaction is still open
sniffing_span.finish()

# The wagging, however, continues long past the dogpark, so that span will
# NOT finish before the transaction ends. (Doing it in this order proves
# that both finished and unfinished spans get their cycles broken.)
dogpark_transaction.finish()

# Eventually you gotta sleep...
wagging_span.finish()

# assuming there are no cycles by this point, these should all be able to go
# out of scope and get their memory deallocated without the garbage
# collector having anything to do
del sniffing_span
del wagging_span
del dogpark_transaction

assert gc.collect() == 0


def test_circular_references_span_streaming(monkeypatch, sentry_init, request):
gc.disable()
request.addfinalizer(gc.enable)

sentry_init(
traces_sample_rate=1.0,
trace_lifecycle="stream",
)

# Make sure that we're starting with a clean slate before we start creating
# transaction/span reference cycles
gc.collect()

dogpark_segment = sentry_sdk.traces.start_span(name="dogpark")
sniffing_span = sentry_sdk.traces.start_span(
name="sniffing", parent_span=dogpark_segment
)
wagging_span = sentry_sdk.traces.start_span(
name="wagging", parent_span=dogpark_segment
)

# At some point, you have to stop sniffing - there are balls to chase! - so finish
# this span while the dogpark transaction is still open
sniffing_span.end()

# The wagging, however, continues long past the dogpark, so that span will
# NOT finish before the transaction ends. (Doing it in this order proves
# that both finished and unfinished spans get their cycles broken.)
dogpark_segment.end()

# Eventually you gotta sleep...
wagging_span.end()

# assuming there are no cycles by this point, these should all be able to go
# out of scope and get their memory deallocated without the garbage
# collector having anything to do
del sniffing_span
del wagging_span
del dogpark_segment

assert gc.collect() == 0


def test_set_measurement(sentry_init, capture_events):
sentry_init(traces_sample_rate=1.0)

Expand Down
Loading