async def test_explicit_rollback_discards_changes(aconn, svcconn):
    """
    Raising a Rollback exception in the middle of a block exits the block and
    discards all changes made within that block.

    You can raise any of the following:
     - Rollback (type)
     - Rollback() (instance)
     - Rollback(tx) (instance initialised with reference to the transaction)
    All of these are equivalent.
    """
    async def assert_no_rows():
        assert not await inserted(aconn)
        assert not inserted(svcconn)

    async with aconn.transaction():
        await insert_row(aconn, "foo")
        raise Rollback
    await assert_no_rows()

    async with aconn.transaction():
        await insert_row(aconn, "foo")
        raise Rollback()
    await assert_no_rows()

    async with aconn.transaction() as tx:
        await insert_row(aconn, "foo")
        raise Rollback(tx)
    await assert_no_rows()
async def test_explicit_rollback_of_outer_transaction(aconn):
    """
    Raising a Rollback exception that references an outer transaction will
    discard all changes from both inner and outer transaction blocks.
    """
    async with aconn.transaction() as outer_tx:
        await insert_row(aconn, "outer")
        async with aconn.transaction():
            await insert_row(aconn, "inner")
            raise Rollback(outer_tx)
        assert False, "This line of code should be unreachable."
    assert not await inserted(aconn)
async def test_named_savepoints_with_repeated_names_works(aconn):
    """
    Using the same savepoint name repeatedly works correctly, but bypasses
    some sanity checks.
    """
    # Works correctly if no inner transactions are rolled back
    async with aconn.transaction(force_rollback=True):
        async with aconn.transaction("sp"):
            await insert_row(aconn, "tx1")
            async with aconn.transaction("sp"):
                await insert_row(aconn, "tx2")
                async with aconn.transaction("sp"):
                    await insert_row(aconn, "tx3")
        assert await inserted(aconn) == {"tx1", "tx2", "tx3"}

    # Works correctly if one level of inner transaction is rolled back
    async with aconn.transaction(force_rollback=True):
        async with aconn.transaction("s1"):
            await insert_row(aconn, "tx1")
            async with aconn.transaction("s1", force_rollback=True):
                await insert_row(aconn, "tx2")
                async with aconn.transaction("s1"):
                    await insert_row(aconn, "tx3")
            assert await inserted(aconn) == {"tx1"}
        assert await inserted(aconn) == {"tx1"}

    # Works correctly if multiple inner transactions are rolled back
    # (This scenario mandates releasing savepoints after rolling back to them.)
    async with aconn.transaction(force_rollback=True):
        async with aconn.transaction("s1"):
            await insert_row(aconn, "tx1")
            async with aconn.transaction("s1") as tx2:
                await insert_row(aconn, "tx2")
                async with aconn.transaction("s1"):
                    await insert_row(aconn, "tx3")
                    raise Rollback(tx2)
            assert await inserted(aconn) == {"tx1"}
        assert await inserted(aconn) == {"tx1"}

    # Will not (always) catch out-of-order exits
    async with aconn.transaction(force_rollback=True):
        tx1 = aconn.transaction("s1")
        tx2 = aconn.transaction("s1")
        await tx1.__aenter__()
        await tx2.__aenter__()
        await tx1.__aexit__(None, None, None)
        await tx2.__aexit__(None, None, None)
Esempio n. 4
0
def test_explicit_rollback_of_enclosing_tx_outer_tx_unaffected(conn, svcconn):
    """
    Rolling-back an enclosing transaction does not impact an outer transaction.
    """
    with conn.transaction():
        insert_row(conn, "outer-before")
        with conn.transaction() as tx_enclosing:
            insert_row(conn, "enclosing")
            with conn.transaction():
                insert_row(conn, "inner")
                raise Rollback(tx_enclosing)
        insert_row(conn, "outer-after")

        assert inserted(conn) == {"outer-before", "outer-after"}
        assert not inserted(svcconn)  # Not yet committed
    # Changes committed
    assert inserted(svcconn) == {"outer-before", "outer-after"}