إن تركيبات live_server
محددة بالجلسة بينما يتم تحديد نطاق الوظيفة transactional_db
(الذي يمكّنه live_server
ضمنيًا).
نتيجة لذلك ، يمكن أن يتعامل live_server
مع الطلبات خلال كامل مدة مجموعة الاختبار. يمكن أن تتعارض هذه الطلبات مع عمليات تدفق قاعدة البيانات التي يؤديها transactional_db
بعد كل اختبار أو مع الفترات التي يتم فيها تعطيل الوصول إلى قاعدة البيانات بين اختبارين.
إليك ما يبدو عليه تسلسل الأحداث:
live_server
بدأت المباراة بـ LiveServerThread
transactional_db
تشغيلات التثبيت (يتم تشغيلها بواسطة الوظيفة ذات النطاق ، autouse _live_server_helper
fixture) وتضيف TransactionTestCase._post_teardown
إلى Finalizerstransactional_db
ومحاولات مسح قاعدة البيانات ، بما يتعارض مع الطلبات التي لا يزال الخادم المباشر يعالجهاlive_server
finalizer ينتظر LiveServerThread
للإنهاءيمكن أن يتسبب التعارض في حالات توقف تام بين أي استعلام SQL من طلب HTTP يتم التعامل معه بواسطة الخادم المباشر والاستعلام الذي يمسح قاعدة البيانات ، والذي يبدو كالتالي:
Exception Database test_xxxxxxxx couldn't be flushed. Possible reasons:
* The database isn't running or isn't configured correctly.
* At least one of the expected database tables doesn't exist.
* The SQL was invalid.
Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run.
The full error: deadlock detected
DETAIL: Process 37253 waits for AccessExclusiveLock on relation 131803 of database 131722; blocked by process 37250.
Process 37250 waits for AccessShareLock on relation 132659 of database 131722; blocked by process 37253.
HINT: See server log for query details.
يعد وضع الفشل هذا مزعجًا بشكل خاص لأن قاعدة البيانات لا يتم مسحها ، مما يتطلب التشغيل التجريبي التالي لإعادة إنشاء قاعدة البيانات وبالتالي إبطال فوائد --reuse-db
.
إذا لم يتم تمكين إعادة استخدام قاعدة البيانات ، فقد يفشل إتلاف قاعدة بيانات الاختبار مع:
django.db.utils.OperationalError: database "test_xxxxxxxx" is being accessed by other users
DETAIL: There is 1 other session using the database.
لقد رأيت أيضًا استعلامات SQL من طلبات HTTP التي يعالجها الخادم المباشر والتي تفشل مع:
Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.
لأن أداة Finalizer transactional_db
قامت بمسح قاعدة البيانات وحظر الوصول حتى الاختبار التالي.
أخطط للبحث عن حلول وسأحدث هذه التذكرة بالنتائج التي توصلت إليها.
يجري في هذا أيضا. هل وجدت أي شيء؟
لا.
سأبلغ نتائجي هنا إذا وجدت وقتًا للعمل على حل. إنه ليس بالقرب من أعلى قائمة TODO الخاصة بي.
أواجه نفس المشكلة (؟) ، لا يرى live_server fixture التغييرات التي تم إجراؤها على قاعدة البيانات ، والتي تعمل في معاملتها الخاصة. aaugustin ، هل يبدو ذلك محتملًا بالنسبة لك؟
كنت أتساءل ... ربما يجب أن أتخلى عن تركيبات الخادم المباشر تمامًا وأكتب بديلي. سيتكون من تشغيل "manager.py runserver" في موضوع. باستثناء توجيهه إلى قاعدة بيانات اختبارية ، لن أقوم بتحديث إعدادات المشروع. في مرحلة ما قد أحتاج ذلك. أيضًا ، لا يدعم LiveServerTestCase STATICFILES_FINDERS المخصص باستثناء نظام الملفات الأول ...
أنا أيضًا أواجه هذه المشكلة. الحل الحالي الذي أستخدمه هو تجاوز تركيبات live_server
بحيث يتم تحديد نطاق الوظيفة. على وجه التحديد ، يحتوي ملف conftest.py
على ما يلي:
from pytest_django.fixtures import live_server as orig_live_server
@pytest.fixture(scope='function')
def live_server(request):
"""
Workaround inspired by https://github.com/mozilla/addons-server/pull/4875/files#diff-0223c02758be2ac7967ea22c6fa4b361R96
"""
return orig_live_server(request)
يبدو أن هذا يعمل ، على الرغم من أنه من المسلم به أنه يبطئ جميع حالات الاختبار التي تستخدمه _way_ إلى أسفل. إذا رأى أي شخص مشكلة في هذا النهج ، فيرجى إبلاغي بذلك.
لدي مشكلة مماثلة: live_server
لا يعمل ، إنه يطبع الخطأ no such table: django_session
.
لقد أصلح حل
RemovedInPytest4Warning: يسمى Fixture "live_server" مباشرة. لا يُقصد باستدعاء التركيبات مباشرة ، بل يتم إنشاؤها تلقائيًا عندما تطلبها وظائف الاختبار كمعلمات.
هل هناك أي طريقة أخرى لاستخدام live_server
مع قاعدة بيانات؟
يثير حل Helumpago خطأً بدلاً من التحذير منذ pytest 4.0 (2018-11-13) :(
محدث: يبدو أنه يعمل (لكن هذا قبيح)
from pytest_django.fixtures import live_server as orig_live_server
live_server = pytest.fixture(scope='function')(orig_live_server.__wrapped__)
لقد حققت بعض النجاح مع الكود أدناه ، ولكن (YMMV)
@pytest.fixture(name='live_server', scope='function')
def _live_server(live_server):
# This rescopes the live_server fixture to function scope
# See https://github.com/pytest-dev/pytest-django/issues/454
return live_server
scope='function'
غير مطلوب تقنيًا لأن النطاق الافتراضي هو function
ولكن تمت إضافته للتوضيح
أنا أواجه هذا أيضًا. لا شك أن جميع المتغيرات المذكورة أعلاه من الإصلاح ستعمل.
لكني أتساءل: ما هو السلوك الصحيح هنا؟ يبدو مثل جذور المشكلة هي في الواقع تلك الطلبات AJAX يزال يحدث بعد انتهاء الاختبار. بحق ، يجب عليهم منع قاعدة البيانات من التنظيف.
فكر في الأمر في الحياة الواقعية وليس في الاختبار. إذا كان لديك قاعدة بيانات وأردت تشغيل أمر تدفق ، وكان لديك الكثير من الطلبات النشطة تجاه هذا الجدول ، فلن تتوقع حدوث خطأ أو يتعين عليك التعامل معه ، بدلاً من مجرد العمل وقضاء جميع الطلبات المعلقة بطريقة سحرية ؟
يمكنني التفكير في بعض الخيارات:
psql postgres -c 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid <> EVERYTHING_BUT_PYTEST_PID';
التعليق الأكثر فائدة
لقد حققت بعض النجاح مع الكود أدناه ، ولكن (YMMV)
scope='function'
غير مطلوب تقنيًا لأن النطاق الافتراضي هوfunction
ولكن تمت إضافته للتوضيح