summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorFlorian Zimmermann <flo@chaos-wg.net>2023-06-01 16:39:52 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-08-21 13:44:25 +0200
commitfbd16438f46bc2128926958ad24331da5d1b406f (patch)
tree41994cef67f580af8f52b47b252c1efb92a03d41 /tests
parentbd2ff65fddd0259e37996e904c90ccf49c2cbb9f (diff)
Fixed #33143 -- Raised RuntimeWarning when performing import-time queries.
Diffstat (limited to 'tests')
-rw-r--r--tests/apps/query_performing_app/__init__.py0
-rw-r--r--tests/apps/query_performing_app/apps.py92
-rw-r--r--tests/apps/tests.py85
-rw-r--r--tests/inspectdb/models.py5
4 files changed, 179 insertions, 3 deletions
diff --git a/tests/apps/query_performing_app/__init__.py b/tests/apps/query_performing_app/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/apps/query_performing_app/__init__.py
diff --git a/tests/apps/query_performing_app/apps.py b/tests/apps/query_performing_app/apps.py
new file mode 100644
index 0000000000..f57ccbb7a0
--- /dev/null
+++ b/tests/apps/query_performing_app/apps.py
@@ -0,0 +1,92 @@
+from django.apps import AppConfig
+from django.db import connections
+
+
+class BaseAppConfig(AppConfig):
+ name = "apps.query_performing_app"
+ database = "default"
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.query_results = []
+
+ def ready(self):
+ self.query_results = []
+ self._perform_query()
+
+ def _perform_query(self):
+ raise NotImplementedError
+
+
+class ModelQueryAppConfig(BaseAppConfig):
+ def _perform_query(self):
+ from ..models import TotallyNormal
+
+ queryset = TotallyNormal.objects.using(self.database)
+ queryset.update_or_create(name="new name")
+ self.query_results = list(queryset.values_list("name"))
+
+
+class QueryDefaultDatabaseModelAppConfig(ModelQueryAppConfig):
+ database = "default"
+
+
+class QueryOtherDatabaseModelAppConfig(ModelQueryAppConfig):
+ database = "other"
+
+
+class CursorQueryAppConfig(BaseAppConfig):
+ def _perform_query(self):
+ connection = connections[self.database]
+ with connection.cursor() as cursor:
+ cursor.execute("SELECT 42" + connection.features.bare_select_suffix)
+ self.query_results = cursor.fetchall()
+
+
+class QueryDefaultDatabaseCursorAppConfig(CursorQueryAppConfig):
+ database = "default"
+
+
+class QueryOtherDatabaseCursorAppConfig(CursorQueryAppConfig):
+ database = "other"
+
+
+class CursorQueryManyAppConfig(BaseAppConfig):
+ def _perform_query(self):
+ from ..models import TotallyNormal
+
+ connection = connections[self.database]
+ table_meta = TotallyNormal._meta
+ with connection.cursor() as cursor:
+ cursor.executemany(
+ "INSERT INTO %s (%s) VALUES(%%s)"
+ % (
+ connection.introspection.identifier_converter(table_meta.db_table),
+ connection.ops.quote_name(table_meta.get_field("name").column),
+ ),
+ [("test name 1",), ("test name 2",)],
+ )
+ self.query_results = []
+
+
+class QueryDefaultDatabaseCursorManyAppConfig(CursorQueryManyAppConfig):
+ database = "default"
+
+
+class QueryOtherDatabaseCursorManyAppConfig(CursorQueryManyAppConfig):
+ database = "other"
+
+
+class StoredProcedureQueryAppConfig(BaseAppConfig):
+ def _perform_query(self):
+ with connections[self.database].cursor() as cursor:
+ cursor.callproc("test_procedure")
+ self.query_results = []
+
+
+class QueryDefaultDatabaseStoredProcedureAppConfig(StoredProcedureQueryAppConfig):
+ database = "default"
+
+
+class QueryOtherDatabaseStoredProcedureAppConfig(StoredProcedureQueryAppConfig):
+ database = "other"
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index ecfb70162f..e443e37dc5 100644
--- a/tests/apps/tests.py
+++ b/tests/apps/tests.py
@@ -1,11 +1,18 @@
import os
+from unittest.mock import patch
+import django
from django.apps import AppConfig, apps
from django.apps.registry import Apps
from django.contrib.admin.models import LogEntry
from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured
-from django.db import models
-from django.test import SimpleTestCase, override_settings
+from django.db import connections, models
+from django.test import (
+ SimpleTestCase,
+ TransactionTestCase,
+ override_settings,
+ skipUnlessDBFeature,
+)
from django.test.utils import extend_sys_path, isolate_apps
from .models import SoAlternative, TotallyNormal, new_apps
@@ -539,3 +546,77 @@ class NamespacePackageAppTests(SimpleTestCase):
with self.settings(INSTALLED_APPS=["nsapp.apps.NSAppConfig"]):
app_config = apps.get_app_config("nsapp")
self.assertEqual(app_config.path, self.app_path)
+
+
+class QueryPerformingAppTests(TransactionTestCase):
+ available_apps = ["apps"]
+ databases = {"default", "other"}
+ expected_msg = (
+ "Accessing the database during app initialization is discouraged. To fix this "
+ "warning, avoid executing queries in AppConfig.ready() or when your app "
+ "modules are imported."
+ )
+
+ def test_query_default_database_using_model(self):
+ query_results = self.run_setup("QueryDefaultDatabaseModelAppConfig")
+ self.assertSequenceEqual(query_results, [("new name",)])
+
+ def test_query_other_database_using_model(self):
+ query_results = self.run_setup("QueryOtherDatabaseModelAppConfig")
+ self.assertSequenceEqual(query_results, [("new name",)])
+
+ def test_query_default_database_using_cursor(self):
+ query_results = self.run_setup("QueryDefaultDatabaseCursorAppConfig")
+ self.assertSequenceEqual(query_results, [(42,)])
+
+ def test_query_other_database_using_cursor(self):
+ query_results = self.run_setup("QueryOtherDatabaseCursorAppConfig")
+ self.assertSequenceEqual(query_results, [(42,)])
+
+ def test_query_many_default_database_using_cursor(self):
+ self.run_setup("QueryDefaultDatabaseCursorManyAppConfig")
+
+ def test_query_many_other_database_using_cursor(self):
+ self.run_setup("QueryOtherDatabaseCursorManyAppConfig")
+
+ @skipUnlessDBFeature("create_test_procedure_without_params_sql")
+ def test_query_default_database_using_stored_procedure(self):
+ connection = connections["default"]
+ with connection.cursor() as cursor:
+ cursor.execute(connection.features.create_test_procedure_without_params_sql)
+
+ try:
+ self.run_setup("QueryDefaultDatabaseStoredProcedureAppConfig")
+ finally:
+ with connection.schema_editor() as editor:
+ editor.remove_procedure("test_procedure")
+
+ @skipUnlessDBFeature("create_test_procedure_without_params_sql")
+ def test_query_other_database_using_stored_procedure(self):
+ connection = connections["other"]
+ with connection.cursor() as cursor:
+ cursor.execute(connection.features.create_test_procedure_without_params_sql)
+
+ try:
+ self.run_setup("QueryOtherDatabaseStoredProcedureAppConfig")
+ finally:
+ with connection.schema_editor() as editor:
+ editor.remove_procedure("test_procedure")
+
+ def run_setup(self, app_config_name):
+ custom_settings = override_settings(
+ INSTALLED_APPS=[f"apps.query_performing_app.apps.{app_config_name}"]
+ )
+ # Ignore the RuntimeWarning, as override_settings.enable() calls
+ # AppConfig.ready() which will trigger the warning.
+ with self.assertWarnsMessage(RuntimeWarning, self.expected_msg):
+ custom_settings.enable()
+ try:
+ with patch.multiple(apps, ready=False, loading=False, app_configs={}):
+ with self.assertWarnsMessage(RuntimeWarning, self.expected_msg):
+ django.setup()
+
+ app_config = apps.get_app_config("query_performing_app")
+ return app_config.query_results
+ finally:
+ custom_settings.disable()
diff --git a/tests/inspectdb/models.py b/tests/inspectdb/models.py
index 25714cb086..ad42871644 100644
--- a/tests/inspectdb/models.py
+++ b/tests/inspectdb/models.py
@@ -1,5 +1,6 @@
from django.db import connection, models
from django.db.models.functions import Lower
+from django.utils.functional import SimpleLazyObject
class People(models.Model):
@@ -94,7 +95,9 @@ class JSONFieldColumnType(models.Model):
}
-test_collation = connection.features.test_collations.get("non_default")
+test_collation = SimpleLazyObject(
+ lambda: connection.features.test_collations.get("non_default")
+)
class CharFieldDbCollation(models.Model):