Skip to content

Deferred constraints in tests #130

@meshy

Description

@meshy

In production, "deferred constraints" will be checked when a transaction commits. In Django tests, because the test's transaction is not committed, this is usually simulated at the end of the test by calling SET CONSTRAINTS ALL IMMEDIATE.

Similarly, production behaviour is usually to be in "autocommit" mode when not in a transaction, meaning that all constraints are immediately checked.

For tests to realistically simulate these two scenarios, all constraints would need to be immediate when we are not in a transaction block, and constraints which are "initially deferred" would need to be set to deferred for the duration of any simulated transaction.

This would be relatively simple if Postgres (etc) had a SET CONSTRAINTS ALL INITIAL command, but this does not exist. (The signature is SET CONSTRAINTS { ALL | name [, ...] } { DEFERRED | IMMEDIATE }.)

As it is, we would need to explicitly set each constraint when opening the transaction, which means we need to discover the initial state of those constraints. Ideally we will be able to determine the initially-deferred constraints from the models, rather than asking the database.

Example expected behaviour (pytest syntax):

def test_deferred_constraint_in_simulated_autocommit_mode():
    with pytest.raises(...):
        # Author doesn't exist.
        # Raised immediately because of autocommit mode.
        models.Book.objects.create(author=1)

def test_deferred_constraint_in_simulated_transaction():
    txn = transaction()
    txn.__enter__()
    # Author doesn't exist.
    models.Book.objects.create(author=1)

    with pytest.raises(...):
        # Exception raised on commit.
        txn.__exit__(...)

Note: I'm not sure if we should/can enable this by default. Perhaps we'll need some kind of context manager to enable this behaviour.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions