Ejemplo n.º 1
0
    async def test_proto_executescript_02(self):
        # Test ReadyForCommand.transaction_state

        await self.con.connect()

        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='START TRANSACTION; SELECT 1/0'
            )
        )
        await self.con.recv_match(
            protocol.ErrorResponse,
            message='division by zero'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.IN_FAILED_TRANSACTION,
        )

        # Test that the protocol is still in a failed transaction

        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='SELECT 1/0'
            )
        )
        await self.con.recv_match(
            protocol.ErrorResponse,
            message='current transaction is aborted'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.IN_FAILED_TRANSACTION,
        )

        # Test recovery

        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='ROLLBACK'
            )
        )
        await self.con.recv_match(
            protocol.CommandComplete,
            status='ROLLBACK'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.NOT_IN_TRANSACTION,
        )
Ejemplo n.º 2
0
 async def test_proto_gh3170_connection_lost_error(self):
     async with tb.start_edgedb_server(
         security=srv_args.ServerSecurityMode.InsecureDevMode,
     ) as sd:
         self.assertNotIn(
             'edgedb_server_background_errors_total'
             '{source="release_pgcon"}',
             sd.fetch_metrics(),
         )
         con = await sd.connect_test_protocol()
         try:
             await con.send(
                 protocol.ExecuteScript(
                     headers=[],
                     script='START TRANSACTION'
                 )
             )
             await con.recv_match(
                 protocol.CommandComplete,
                 status='START TRANSACTION'
             )
             await con.recv_match(
                 protocol.ReadyForCommand,
                 transaction_state=protocol.TransactionState.IN_TRANSACTION,
             )
             await con.aclose()
             self.assertNotIn(
                 'edgedb_server_background_errors_total'
                 '{source="release_pgcon"}',
                 sd.fetch_metrics(),
             )
         except Exception:
             await con.aclose()
             raise
Ejemplo n.º 3
0
 async def _test_connection(self, con):
     await con.send(protocol.ExecuteScript(headers=[], script='SELECT 1'))
     await con.recv_match(protocol.CommandComplete, status='SELECT')
     await con.recv_match(
         protocol.ReadyForCommand,
         transaction_state=protocol.TransactionState.NOT_IN_TRANSACTION,
     )
Ejemplo n.º 4
0
    async def test_proto_flush_01(self):

        await self.con.connect()

        await self.con.send(
            protocol.Prepare(
                headers=[],
                io_format=protocol.IOFormat.BINARY,
                expected_cardinality=compiler.Cardinality.AT_MOST_ONE,
                statement_name=b'',
                command='SEL ECT 1',
            )
        )
        # Should come through even without an explicit 'flush'
        await self.con.recv_match(
            protocol.ErrorResponse,
            message="Unexpected 'SEL'"
        )

        # Recover the protocol state from the error
        self.assertEqual(
            await self.con.sync(),
            protocol.TransactionState.NOT_IN_TRANSACTION)

        # This Prepare should be handled alright
        await self.con.send(
            protocol.Prepare(
                headers=[],
                io_format=protocol.IOFormat.BINARY,
                expected_cardinality=compiler.Cardinality.AT_MOST_ONE,
                statement_name=b'',
                command='SELECT 1',
            ),
            protocol.Flush()
        )
        await self.con.recv_match(
            protocol.PrepareComplete,
            cardinality=compiler.Cardinality.AT_MOST_ONE,
        )

        # Test that Flush has completed successfully -- the
        # command should be executed and no exception should
        # be received.
        # While at it, rogue ROLLBACK should be allowed.
        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='ROLLBACK'
            )
        )
        await self.con.recv_match(
            protocol.CommandComplete,
            status='ROLLBACK'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.NOT_IN_TRANSACTION,
        )
Ejemplo n.º 5
0
    async def test_proto_connection_lost_cancel_query(self):
        async with self._fixture() as (con1, con2, conn_args):
            # Use an implicit transaction in the nested connection: lock
            # the row with an UPDATE, and then hold the transaction for 10
            # seconds, which is long enough for the upcoming cancellation
            await con1.send(
                protocol.ExecuteScript(
                    headers=[],
                    script="""\
                    UPDATE tclcq SET { p := 'inner' };
                    SELECT sys::_sleep(10);
                    """,
                )
            )

            # Take up all free backend connections
            other_conns = []
            for _ in range(2):
                con = await tconn.async_connect_test_client(**conn_args)
                other_conns.append(con)
                self.loop.create_task(
                    con.execute("SELECT sys::_sleep(60)")
                ).add_done_callback(lambda f: f.exception())
            await asyncio.sleep(0.1)

            try:
                # Close the nested connection without waiting for the result;
                # the server is supposed to cancel the pending query.
                self.loop.call_later(0.5, self.loop.create_task, con1.aclose())

                # In the outer connection, let's wait until the lock is
                # released by either an expected cancellation, or an unexpected
                # commit after 10 seconds.
                tx = con2.transaction()
                await asyncio.wait_for(tx.start(), 2)
                try:
                    await con2.execute("UPDATE tclcq SET { p := 'lock' }")
                except edgedb.TransactionSerializationError:
                    # In case the nested transaction succeeded, we'll meet an
                    # concurrent update error here, which can be safely ignored
                    pass
                finally:
                    await tx.rollback()

                # Let's check what's in the row - if the cancellation didn't
                # happen, the test will fail with value "inner".
                val = await con2.query_single('SELECT tclcq.p LIMIT 1')
                self.assertEqual(val, 'initial')
            finally:
                for con in other_conns:
                    con.terminate()
                for con in other_conns:
                    await con.aclose()
Ejemplo n.º 6
0
    async def test_proto_executescript_01(self):
        # Test that ExecuteScript returns ErrorResponse immediately.

        await self.con.connect()

        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='SELECT 1/0'
            )
        )
        await self.con.recv_match(
            protocol.ErrorResponse,
            message='division by zero'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.NOT_IN_TRANSACTION,
        )

        # Test that the protocol has recovered.

        await self.con.send(
            protocol.ExecuteScript(
                headers=[],
                script='SELECT 1'
            )
        )
        await self.con.recv_match(
            protocol.CommandComplete,
            status='SELECT'
        )
        await self.con.recv_match(
            protocol.ReadyForCommand,
            transaction_state=protocol.TransactionState.NOT_IN_TRANSACTION,
        )