Opened 4 years ago

Closed 4 years ago

#31065 closed Bug (invalid)

"django.db.utils.InterfaceError: connection already closed" in unittests

Reported by: Harm Verhagen Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Harm Verhagen)

I found a weird bug in Django that causes database errors when running unittesets, this happens when doing nothing special/funky (see small included testcase)

Steps to reproduce

  1. Start a new project myproj, with a new app foo
  2. Edit foo/tests.py
    from django.test import TestCase
    from django.contrib.auth.models import User
    
    
    class A(TestCase):
        """
        We have a tearDownClass() in this class without a matching setUpClass
    
        Removing the tearDownClass, or adding a setUpClass fixes/hides the problem
        """
    
        @classmethod
        def tearDownClass(cls):
            pass
    
        def test_foo(self):
            pass
    
    
    class B(TestCase):
    
        def test_foo(self):
            pass
    
    
    class C(TestCase):
    
        def test_foo(self):
            pass
    
        def setUp(self):
            User.objects.create_user('user', 'myemail@test.com', "123")
    
  1. edit your settings.py to connect to a postgresql server (The problem does _not_ reproduce with the default sqlite config)
  1. ./manage.py test foo.tests.A foo.tests.B foo.tests.C

(NB the order in which the tests are executed is important, in another order the problem does not reproduce)

result

$ ./manage.py test foo.tests.A foo.tests.B foo.tests.C
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..E
======================================================================
ERROR: test_foo (foo.tests.C)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 235, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/venv/lib/python3.5/site-packages/django/db/backends/postgresql/base.py", line 223, in create_cursor
    cursor = self.connection.cursor()
psycopg2.InterfaceError: connection already closed

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "myproj/foo/tests.py", line 39, in setUp
    User.objects.create_user('user', 'myemail@test.com', "123")
  File "/env/lib/python3.5/site-packages/django/contrib/auth/models.py", line 151, in create_user
    return self._create_user(username, email, password, **extra_fields)
  File "/venv/lib/python3.5/site-packages/django/contrib/auth/models.py", line 145, in _create_user
    user.save(using=self._db)
  File "/venv/lib/python3.5/site-packages/django/contrib/auth/base_user.py", line 66, in save
    super().save(*args, **kwargs)
  File "/venv/lib/python3.5/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/venv/lib/python3.5/site-packages/django/db/models/base.py", line 779, in save_base
    force_update, using, update_fields,
  File "/venv/lib/python3.5/site-packages/django/db/models/base.py", line 870, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/venv/lib/python3.5/site-packages/django/db/models/base.py", line 908, in _do_insert
    using=using, raw=raw)
  File "/venv/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/venv/lib/python3.5/site-packages/django/db/models/query.py", line 1186, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/venv/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1366, in execute_sql
    with self.connection.cursor() as cursor:
  File "/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 256, in cursor
    return self._cursor()
  File "/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 235, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/venv/lib/python3.5/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 235, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/venv/lib/python3.5/site-packages/django/db/backends/postgresql/base.py", line 223, in create_cursor
    cursor = self.connection.cursor()
django.db.utils.InterfaceError: connection already closed

----------------------------------------------------------------------

expected result

All tests pass

notes

  • The problem does not reproduce with sqlite
  • The problem goes away if you add a @setUpClass to class A
  • The problem goes away if you remove the @tearDownClass of class A
  • The problem goes away if you change the order in which you execute the testclasses
  • The problem goes away if you don't create the User in class C

version info

Seen on Django 2.2.8 and 2.2.6
psycopg2==2.7.3.1
postgresql 10.10

Change History (2)

comment:1 by Harm Verhagen, 4 years ago

Description: modified (diff)

comment:2 by Mariusz Felisiak, 4 years ago

Resolution: invalid
Status: newclosed
Version: 2.2master

You shouldn't override setUpClass() or tearDownClass() methods without calling super(), see a warning box.

Note: See TracTickets for help on using tickets.
Back to Top