Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sqlite database table is locked on tests

I am trying to migrate an application from django 1.11.1 to django 2.0.1 Tests are set up to run with sqlite in memory database. But every test is failing, because sqlite3.OperationalError: database table is locked for every table. How can I find out why is it locked? Icreasing timeout setting does not help.

I am using LiveServerTestCase, so I suppose the tests must be running in a different thread than the in memory database, and it for some reason does not get shared.

like image 652
Euphorbium Avatar asked Jan 20 '18 05:01

Euphorbium


People also ask

When sqlite database is locked?

A locked SQLite database stops the user from writing more transactions, and the tables are not updated or altered anymore. If you are facing the same problem, then you will get some simple solutions to remove error 5 and make the SQLite database functional.

How do you unlock a locked database?

If you want to remove a "database is locked" error then follow these steps: Copy your database file to some other location. Replace the database with the copied database. This will dereference all processes which were accessing your database file.

Why database is locked?

A database lock is used to “lock” some data in a database so that only one database user/session may update that particular data. So, database locks exist to prevent two or more database users from updating the same exact piece of data at the same exact time.


3 Answers

I hit this, too. The LiveServerTestCase is multi-threaded since this got merged.

It becomes a problem for me when my app under test issues multiple requests. Then, so my speculation, the LiveServer spawns threads to handle those requests. Those requests then cause a write to the SQLite db. That in turn does not like multiple writing threads.

Funnily enough, runserver knows about --nothreading. But such an option seems to be missing for the test server.

The following snippet brought me a single-threaded test server:

class LiveServerSingleThread(LiveServerThread):
    """Runs a single threaded server rather than multi threaded. Reverts https://github.com/django/django/pull/7832"""

    def _create_server(self):

        """
        the keep-alive fixes introduced in Django 2.1.4 (934acf1126995f6e6ccba5947ec8f7561633c27f)
        cause problems when serving the static files in a stream.
        We disable the helper handle method that calls handle_one_request multiple times.
        """
        QuietWSGIRequestHandler.handle = QuietWSGIRequestHandler.handle_one_request

        return WSGIServer((self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False)


class LiveServerSingleThreadedTestCase(LiveServerTestCase):
    "A thin sub-class which only sets the single-threaded server as a class"
    server_thread_class = LiveServerSingleThread

Then, derive your test class from LiveServerSingleThreadedTestCase instead of LiveServerTestCase.

like image 154
Frederick Nord Avatar answered Oct 15 '22 20:10

Frederick Nord


It was caused by this django bug.

like image 24
Euphorbium Avatar answered Oct 15 '22 22:10

Euphorbium


Using a file-based database during testing fixes the "table is locked" error. To make Django use a file-based database, specify it's filename as test database name:

DATABASES = {
    'default': {
        ...
        'TEST': {
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3.test'),
       },
    }
}

I suppose that the timeout setting is ignored in case of in-memory database, see this comment for additional info.

like image 26
don_vanchos Avatar answered Oct 15 '22 20:10

don_vanchos