def test_manual_enter_and_exit_out_of_order_exit_raises_assertion(cxn):
    t1, t2 = Transaction(cxn), Transaction(cxn)
    t1.__enter__()
    t2.__enter__()
    with pytest.raises(
            AssertionError,
            match=re.escape(
                'Out-of-order Transaction context exits. Are you calling '
                '__exit__() manually and getting it wrong?')):
        t1.__exit__(None, None, None)
def test_explicit_rollback_required_after_handling_sql_exception_otherwise_exception_is_raised(
        cxn):
    txn = Transaction(cxn)
    txn.__enter__()
    with pytest.raises(psycopg2.ProgrammingError):
        cxn.cursor().execute('SELECT * FROM this_table_does_not_exist')
    with pytest.raises(
            Exception,
            match=re.escape(
                'SQL error occurred within current transaction. '
                'Transaction.rollback() must be called before exiting '
                'transaction context.')):
        txn.__exit__(None, None, None)
def test_manual_transaction_management_inside_context_explicit_commit(
        cxn, other_cxn):
    def classic_method(cxn):
        assert cxn.autocommit is False
        insert_row(cxn, 'inner')
        cxn.commit()

    txn = Transaction(cxn).__enter__()
    insert_row(cxn, 'outer')
    classic_method(cxn)
    # All changes are committed and visible immediately :-(
    assert_rows(other_cxn, {'inner', 'outer'})

    # Context exit fails :-((
    with pytest.raises(psycopg2.InternalError, match='no such savepoint'):
        txn.__exit__(None, None, None)
def test_manual_transaction_management_inside_context_implicit_rollback(
        cxn, other_cxn):
    def method(cxn):
        # This method implicitly rolls back the current transaction :-(
        # See: https://github.com/psycopg/psycopg2/issues/950
        cxn.set_client_encoding('LATIN1')

    txn = Transaction(cxn).__enter__()
    insert_row(cxn, 'outer')
    assert_in_transaction(cxn)
    method(cxn)
    assert_not_in_transaction(cxn)

    # Context exit fails :-(
    with pytest.raises(psycopg2.InternalError, match='no such savepoint'):
        txn.__exit__(None, None, None)

    # All changes are discarded :-((
    assert_rows(other_cxn, set())
def test_manual_transaction_management_inside_context_explicit_rollback(
        cxn, other_cxn):
    def classic_method(cxn):
        assert cxn.autocommit is False
        insert_row(cxn, 'inner')
        cxn.rollback()

    txn = Transaction(cxn).__enter__()
    insert_row(cxn, 'outer')
    assert_in_transaction(cxn)
    classic_method(cxn)
    assert_not_in_transaction(cxn)

    # Context exit fails :-(
    with pytest.raises(psycopg2.InternalError, match='no such savepoint'):
        txn.__exit__(None, None, None)

    # All changes are discarded :-((
    assert_rows(other_cxn, set())