diff --git a/pytest.ini b/pytest.ini index 97ca37ea10..bfd39867c0 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,3 @@ [pytest] DJANGO_SETTINGS_MODULE = tests.integrations.django.myapp.settings -addopts = --boxed --tb=short +addopts = --tb=short diff --git a/tests/conftest.py b/tests/conftest.py index d37c14de0e..7ec667b076 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -91,16 +91,28 @@ def inner(event): @pytest.fixture -def sentry_init(monkeypatch_test_transport): +def sentry_init(monkeypatch_test_transport, monkeypatch): def inner(*a, **kw): hub = sentry_sdk.Hub.current client = sentry_sdk.Client(*a, **kw) - hub.bind_client(client) + monkeypatch.setattr(hub, "_stack", [(client, sentry_sdk.Scope())]) monkeypatch_test_transport(sentry_sdk.Hub.current.client) return inner +@pytest.fixture(autouse=True) +def _assert_no_client(request, monkeypatch): + assert sentry_sdk.Hub.current.client is None + assert sentry_sdk.Hub.main.client is None + + @request.addfinalizer + def _check_no_client(): + monkeypatch.undo() # tear down sentry_init + assert sentry_sdk.Hub.current.client is None + assert sentry_sdk.Hub.main.client is None + + class TestTransport(Transport): def __init__(self, capture_event_callback): Transport.__init__(self) diff --git a/tests/integrations/django/myapp/wsgi.py b/tests/integrations/django/myapp/wsgi.py index 298524a800..8c01991e9f 100644 --- a/tests/integrations/django/myapp/wsgi.py +++ b/tests/integrations/django/myapp/wsgi.py @@ -11,6 +11,8 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings") +os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", "tests.integrations.django.myapp.settings" +) application = get_wsgi_application() diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 55686a0929..8f28586bd5 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -1,8 +1,11 @@ +from __future__ import absolute_import + +import threading + import pytest import json from werkzeug.test import Client -from django.contrib.auth.models import User from django.core.management import execute_from_command_line from django.db.utils import OperationalError, ProgrammingError, DataError @@ -18,6 +21,34 @@ from tests.integrations.django.myapp.wsgi import application +@pytest.fixture +def django_clear_caches(): + """Invalidate the connection caches. + + https://github.com/pytest-dev/pytest-django/issues/587 + """ + from django.db import connections + + connections._connections = threading.local() + # this will clear the cached property + connections.__dict__.pop("databases", None) + + +@pytest.fixture(autouse=True) +def setup_app_tables(request): + if request.node.get_closest_marker("django_db") is None: + return + + # Honestly no idea why pytest-django does not do this + from django import VERSION + from django.core import management + + if VERSION < (2, 0): + management.call_command("migrate", noinput=True) + else: + management.call_command("migrate", no_input=True) + + @pytest.fixture def client(): return Client(application) @@ -80,9 +111,11 @@ def test_transaction_with_class_view(sentry_init, client, capture_events): assert event["message"] == "hi" -@pytest.mark.django_db +@pytest.mark.django_db(transaction=True) def test_user_captured(sentry_init, client, capture_events): + sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) + events = capture_events() content, status, headers = client.get(reverse("mylogin")) assert b"".join(content) == b"ok" @@ -101,9 +134,12 @@ def test_user_captured(sentry_init, client, capture_events): } -@pytest.mark.django_db +@pytest.mark.django_db(transaction=True) def test_queryset_repr(sentry_init, capture_events): + from django.contrib.auth.models import User + sentry_init(integrations=[DjangoIntegration()]) + events = capture_events() User.objects.create_user("john", "lennon@thebeatles.com", "johnpassword") @@ -163,28 +199,30 @@ def test_management_command_raises(): execute_from_command_line(["manage.py", "mycrash"]) -@pytest.mark.django_db -def test_sql_queries(sentry_init, capture_events): - sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) +@pytest.mark.django_db(transaction=True) +def test_sql_queries(request, sentry_init, capture_events): from django.db import connection + from django.db.backends.utils import CursorWrapper - sql = connection.cursor() + sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) events = capture_events() - with pytest.raises(OperationalError): - # table doesn't even exist - sql.execute("""SELECT count(*) FROM people_person WHERE foo = %s""", [123]) + + with connection.cursor() as sql: + assert type(sql) is CursorWrapper + with pytest.raises(OperationalError): + # table doesn't even exist + sql.execute("""SELECT count(*) FROM people_person WHERE foo = %s""", [123]) capture_message("HI") event, = events - + assert event["message"] == "HI" crumb, = event["breadcrumbs"] - assert crumb["message"] == """SELECT count(*) FROM people_person WHERE foo = 123""" -@pytest.mark.django_db +@pytest.mark.django_db(transaction=True) def test_sql_dict_query_params(sentry_init, capture_events): sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) @@ -278,11 +316,12 @@ def test_sql_psycopg2_placeholders(sentry_init, capture_events): ) -@pytest.mark.django_db +@pytest.mark.django_db(transaction=True) def test_sql_queries_large_params(sentry_init, capture_events): - sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) from django.db import connection + sentry_init(integrations=[DjangoIntegration()], send_default_pii=True) + sql = connection.cursor() events = capture_events() diff --git a/tests/test_basics.py b/tests/test_basics.py index 1d5a69b292..421c6491b7 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -205,26 +205,21 @@ def test_breadcrumbs(sentry_init, capture_events): assert len(event["breadcrumbs"]) == 0 -def test_integration_scoping(): +def test_integration_scoping(sentry_init, capture_events): logger = logging.getLogger("test_basics") - events = [] - logging_integration = LoggingIntegration(event_level=logging.WARNING) # This client uses the logging integration - client_with_logging = Client( - transport=events.append, - default_integrations=False, - integrations=[logging_integration], - ) - Hub.current.bind_client(client_with_logging) + logging_integration = LoggingIntegration(event_level=logging.WARNING) + sentry_init(default_integrations=False, integrations=[logging_integration]) + events = capture_events() logger.warning("This is a warning") + assert len(events) == 1 # This client does not - client_without_logging = Client(transport=events.append, default_integrations=False) - Hub.current.bind_client(client_without_logging) + sentry_init(default_integrations=False) + events = capture_events() logger.warning("This is not a warning") - - assert len(events) == 1 + assert not events def test_client_initialized_within_scope(sentry_init, caplog): @@ -233,7 +228,7 @@ def test_client_initialized_within_scope(sentry_init, caplog): sentry_init(debug=True) with push_scope(): - sentry_init() + Hub.current.bind_client(Client()) record, = (x for x in caplog.records if x.levelname == "WARNING") diff --git a/tests/test_client.py b/tests/test_client.py index 9f1637cf9b..e38c00693c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -16,7 +16,6 @@ add_breadcrumb, capture_exception, ) -from sentry_sdk.hub import HubMeta from sentry_sdk.transport import Transport from sentry_sdk._compat import reraise, text_type, PY2 from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS @@ -336,15 +335,8 @@ def callback(scope): assert calls[0] is Hub.current._stack[-1][1] -@pytest.mark.parametrize("no_sdk", (True, False)) -def test_configure_scope_unavailable(no_sdk, monkeypatch): - if no_sdk: - # Emulate minimal without SDK installation: callbacks are not called - monkeypatch.setattr(HubMeta, "current", None) - assert not Hub.current - else: - # Still, no client configured - assert Hub.current +def test_configure_scope_unavailable(monkeypatch): + assert Hub.current calls = []