Exemplo n.º 1
0
    def test_multiple_connections(self):
        """
        Test multiple connections with pipelined requests.
        """
        conns = [self.get_connection() for i in range(5)]
        events = [Event() for i in range(5)]
        query = "SELECT keyspace_name FROM system.schema_keyspaces LIMIT 1"

        def cb(event, conn, count, *args, **kwargs):
            count += 1
            if count >= 10:
                conn.close()
                event.set()
            else:
                conn.send_msg(
                    QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
                    request_id=count,
                    cb=partial(cb, event, conn, count))

        for event, conn in zip(events, conns):
            conn.send_msg(
                QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
                request_id=0,
                cb=partial(cb, event, conn, 0))

        for event in events:
            event.wait()
Exemplo n.º 2
0
        def send_msgs(conn, event):
            thread_responses = [False] * num_requests_per_conn
            for i in range(num_requests_per_conn):
                qmsg = QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE)
                with conn.lock:
                    request_id = conn.get_request_id()
                conn.send_msg(qmsg, request_id, cb=partial(cb, conn, event, thread_responses, i))

            event.wait()
Exemplo n.º 3
0
    def test_retry_policy_says_retry(self):
        session = self.make_session()
        pool = session._pools.get.return_value

        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.QUORUM)

        connection = Mock(spec=Connection)
        pool.borrow_connection.return_value = (connection, 1)

        retry_policy = Mock()
        retry_policy.on_unavailable.return_value = (RetryPolicy.RETRY,
                                                    ConsistencyLevel.ONE)

        rf = ResponseFuture(session,
                            message,
                            query,
                            1,
                            retry_policy=retry_policy)
        rf.send_request()

        rf.session._pools.get.assert_called_once_with('ip1')
        pool.borrow_connection.assert_called_once_with(timeout=ANY)
        connection.send_msg.assert_called_once_with(
            rf.message,
            1,
            cb=ANY,
            encoder=ProtocolHandler.encode_message,
            decoder=ProtocolHandler.decode_message,
            result_metadata=[])

        result = Mock(spec=UnavailableErrorMessage, info={})
        host = Mock()
        rf._set_result(host, None, None, result)

        session.submit.assert_called_once_with(rf._retry_task, True, host)
        self.assertEqual(1, rf._query_retries)

        connection = Mock(spec=Connection)
        pool.borrow_connection.return_value = (connection, 2)

        # simulate the executor running this
        rf._retry_task(True, host)

        # it should try again with the same host since this was
        # an UnavailableException
        rf.session._pools.get.assert_called_with(host)
        pool.borrow_connection.assert_called_with(timeout=ANY)
        connection.send_msg.assert_called_with(
            rf.message,
            2,
            cb=ANY,
            encoder=ProtocolHandler.encode_message,
            decoder=ProtocolHandler.decode_message,
            result_metadata=[])
Exemplo n.º 4
0
 def cb(event, conn, count, *args, **kwargs):
     count += 1
     if count >= 10:
         conn.close()
         event.set()
     else:
         conn.send_msg(
             QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
             request_id=count,
             cb=partial(cb, event, conn, count))
 def send_msgs(all_responses, thread_responses):
     for i in range(num_requests_per_conn):
         qmsg = QueryMessage(query=query,
                             consistency_level=ConsistencyLevel.ONE)
         with conn.lock:
             request_id = conn.get_request_id()
         conn.send_msg(qmsg,
                       request_id,
                       cb=partial(cb, all_responses, thread_responses,
                                  i))
    def set_keyspace_async(self, keyspace, callback):
        """
        Use this in order to avoid deadlocking the event loop thread.
        When the operation completes, `callback` will be called with
        two arguments: this connection and an Exception if an error
        occurred, otherwise :const:`None`.

        This method will always increment :attr:`.in_flight` attribute, even if
        it doesn't need to make a request, just to maintain an
        ":attr:`.in_flight` is incremented" invariant.
        """
        # Here we increment in_flight unconditionally, whether we need to issue
        # a request or not. This is bad, but allows callers -- specifically
        # _set_keyspace_for_all_conns -- to assume that we increment
        # self.in_flight during this call. This allows the passed callback to
        # safely call HostConnection{Pool,}.return_connection on this
        # Connection.
        #
        # We use a busy wait on the lock here because:
        # - we'll only spin if the connection is at max capacity, which is very
        #   unlikely for a set_keyspace call
        # - it allows us to avoid signaling a condition every time a request completes
        while True:
            with self.lock:
                if self.in_flight < self.max_request_id:
                    self.in_flight += 1
                    break
            time.sleep(0.001)

        if not keyspace or keyspace == self.keyspace:
            callback(self, None)
            return

        query = QueryMessage(query='USE "%s"' % (keyspace, ),
                             consistency_level=ConsistencyLevel.ONE)

        def process_result(result):
            if isinstance(result, ResultMessage):
                self.keyspace = keyspace
                callback(self, None)
            elif isinstance(result, InvalidRequestException):
                callback(self, result.to_exception())
            else:
                callback(
                    self,
                    self.defunct(
                        ConnectionException(
                            "Problem while setting keyspace: %r" % (result, ),
                            self.host)))

        # We've incremented self.in_flight above, so we "have permission" to
        # acquire a new request id
        request_id = self.get_request_id()

        self.send_msg(query, request_id, process_result)
Exemplo n.º 7
0
    def test_unavailable_error_message(self):
        session = self.make_session()
        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        query.retry_policy = Mock()
        query.retry_policy.on_unavailable.return_value = (RetryPolicy.RETHROW,
                                                          None)
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        rf = ResponseFuture(session, message, query, 1)
        rf.send_request()

        result = Mock(spec=UnavailableErrorMessage, info={})
        rf._set_result(None, None, None, result)
        self.assertRaises(Exception, rf.result)
    def test_continuous_paging(self):
        """
        Test to check continuous paging throws an Exception if it's not supported and the correct valuesa
        are written to the buffer if the option is enabled.

        @since DSE 2.0b3 GRAPH 1.0b1
        @jira_ticket PYTHON-694
        @expected_result the values are correctly written

        @test_category connection
        """
        max_pages = 4
        max_pages_per_second = 3
        continuous_paging_options = ContinuousPagingOptions(
            max_pages=max_pages, max_pages_per_second=max_pages_per_second)
        message = QueryMessage(
            "a", 3, continuous_paging_options=continuous_paging_options)
        io = Mock()
        for version in [
                version for version in ProtocolVersion.SUPPORTED_VERSIONS
                if version != ProtocolVersion.DSE_V1
        ]:
            self.assertRaises(UnsupportedOperation, message.send_body, io,
                              version)

        io.reset_mock()
        message.send_body(io, ProtocolVersion.DSE_V1)

        # continuous paging adds two write calls to the buffer
        self.assertEqual(len(io.write.mock_calls), 6)
        # Check that the appropriate flag is set to True
        self.assertEqual(
            uint32_unpack(io.write.mock_calls[3][1][0])
            & _WITH_SERIAL_CONSISTENCY_FLAG, 0)
        self.assertEqual(
            uint32_unpack(io.write.mock_calls[3][1][0]) & _PAGE_SIZE_FLAG, 0)
        self.assertEqual(
            uint32_unpack(io.write.mock_calls[3][1][0])
            & _WITH_PAGING_STATE_FLAG, 0)
        self.assertEqual(
            uint32_unpack(io.write.mock_calls[3][1][0]) & _PAGING_OPTIONS_FLAG,
            _PAGING_OPTIONS_FLAG)

        # Test max_pages and max_pages_per_second are correctly written
        self.assertEqual(uint32_unpack(io.write.mock_calls[4][1][0]),
                         max_pages)
        self.assertEqual(uint32_unpack(io.write.mock_calls[5][1][0]),
                         max_pages_per_second)
Exemplo n.º 9
0
    def test_read_timeout_error_message(self):
        session = self.make_session()
        query = SimpleStatement("SELECT * FROM foo")
        query.retry_policy = Mock()
        query.retry_policy.on_read_timeout.return_value = (RetryPolicy.RETHROW,
                                                           None)
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        rf = ResponseFuture(session, message, query, 1)
        rf.send_request()

        result = Mock(spec=ReadTimeoutErrorMessage, info={})
        rf._set_result(None, None, None, result)

        self.assertRaises(Exception, rf.result)
Exemplo n.º 10
0
    def test_retry_policy_says_ignore(self):
        session = self.make_session()
        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        retry_policy = Mock()
        retry_policy.on_unavailable.return_value = (RetryPolicy.IGNORE, None)
        rf = ResponseFuture(session,
                            message,
                            query,
                            1,
                            retry_policy=retry_policy)
        rf.send_request()

        result = Mock(spec=UnavailableErrorMessage, info={})
        rf._set_result(None, None, None, result)
        self.assertFalse(rf.result())
Exemplo n.º 11
0
    def test_add_callbacks(self):
        session = self.make_session()
        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        query.retry_policy = Mock()
        query.retry_policy.on_unavailable.return_value = (RetryPolicy.RETHROW,
                                                          None)
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        # test errback
        rf = ResponseFuture(session, message, query, 1)
        rf.send_request()

        rf.add_callbacks(callback=self.assertEqual,
                         callback_args=([{
                             'col': 'val'
                         }], ),
                         errback=self.assertIsInstance,
                         errback_args=(Exception, ))

        result = Mock(spec=UnavailableErrorMessage, info={})
        rf._set_result(None, None, None, result)
        self.assertRaises(Exception, rf.result)

        # test callback
        rf = ResponseFuture(session, message, query, 1)
        rf.send_request()

        callback = Mock()
        expected_result = (object(), object())
        arg = "positional"
        kwargs = {'one': 1, 'two': 2}
        rf.add_callbacks(callback=callback,
                         callback_args=(arg, ),
                         callback_kwargs=kwargs,
                         errback=self.assertIsInstance,
                         errback_args=(Exception, ))

        rf._set_result(
            None, None, None,
            self.make_mock_response(expected_result[0], expected_result[1]))
        self.assertEqual(rf.result()[0], expected_result)

        callback.assert_called_once_with([expected_result], arg, **kwargs)
Exemplo n.º 12
0
    def set_keyspace_async(self, keyspace, callback):
        """
        Use this in order to avoid deadlocking the event loop thread.
        When the operation completes, `callback` will be called with
        two arguments: this connection and an Exception if an error
        occurred, otherwise :const:`None`.
        """
        if not keyspace or keyspace == self.keyspace:
            callback(self, None)
            return

        query = QueryMessage(query='USE "%s"' % (keyspace, ),
                             consistency_level=ConsistencyLevel.ONE)

        def process_result(result):
            if isinstance(result, ResultMessage):
                self.keyspace = keyspace
                callback(self, None)
            elif isinstance(result, InvalidRequestException):
                callback(self, result.to_exception())
            else:
                callback(
                    self,
                    self.defunct(
                        ConnectionException(
                            "Problem while setting keyspace: %r" % (result, ),
                            self.host)))

        request_id = None
        # we use a busy wait on the lock here because:
        # - we'll only spin if the connection is at max capacity, which is very
        #   unlikely for a set_keyspace call
        # - it allows us to avoid signaling a condition every time a request completes
        while True:
            with self.lock:
                if self.in_flight < self.max_request_id:
                    request_id = self.get_request_id()
                    self.in_flight += 1
                    break

            time.sleep(0.001)

        self.send_msg(query, request_id, process_result)
    def test_query_message(self):
        """
        Test to check the appropriate calls are made

        @since 3.9
        @jira_ticket PYTHON-713
        @expected_result the values are correctly written

        @test_category connection
        """
        message = QueryMessage("a", 3)
        io = Mock()

        message.send_body(io, 4)
        self._check_calls(io, [(b'\x00\x00\x00\x01', ), (b'a', ),
                               (b'\x00\x03', ), (b'\x00', )])

        io.reset_mock()
        message.send_body(io, 5)
        self._check_calls(io, [(b'\x00\x00\x00\x01', ), (b'a', ),
                               (b'\x00\x03', ), (b'\x00\x00\x00\x00', )])
Exemplo n.º 14
0
    def test_single_connection_pipelined_requests(self):
        """
        Test a single connection with pipelined requests.
        """
        conn = self.get_connection()
        query = "SELECT keyspace_name FROM system.schema_keyspaces LIMIT 1"
        responses = [False] * 100
        event = Event()

        def cb(response_list, request_num, *args, **kwargs):
            response_list[request_num] = True
            if all(response_list):
                conn.close()
                event.set()

        for i in range(100):
            conn.send_msg(
                QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
                request_id=i,
                cb=partial(cb, responses, i))

        event.wait()
Exemplo n.º 15
0
    def test_multiple_errbacks(self):
        session = self.make_session()
        pool = session._pools.get.return_value
        connection = Mock(spec=Connection)
        pool.borrow_connection.return_value = (connection, 1)

        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        retry_policy = Mock()
        retry_policy.on_unavailable.return_value = (RetryPolicy.RETHROW, None)
        rf = ResponseFuture(session,
                            message,
                            query,
                            1,
                            retry_policy=retry_policy)
        rf.send_request()

        callback = Mock()
        arg = "positional"
        kwargs = {'one': 1, 'two': 2}
        rf.add_errback(callback, arg, **kwargs)

        callback2 = Mock()
        arg2 = "another"
        kwargs2 = {'three': 3, 'four': 4}
        rf.add_errback(callback2, arg2, **kwargs2)

        expected_exception = Unavailable("message", 1, 2, 3)
        result = Mock(spec=UnavailableErrorMessage, info={'something': 'here'})
        result.to_exception.return_value = expected_exception
        rf._set_result(None, None, None, result)
        self.assertRaises(Exception, rf.result)

        callback.assert_called_once_with(expected_exception, arg, **kwargs)
        callback2.assert_called_once_with(expected_exception, arg2, **kwargs2)
Exemplo n.º 16
0
    def set_keyspace_blocking(self, keyspace):
        if not keyspace or keyspace == self.keyspace:
            return

        query = QueryMessage(query='USE "%s"' % (keyspace, ),
                             consistency_level=ConsistencyLevel.ONE)
        try:
            result = self.wait_for_response(query)
        except InvalidRequestException as ire:
            # the keyspace probably doesn't exist
            raise ire.to_exception()
        except Exception as exc:
            conn_exc = ConnectionException(
                "Problem while setting keyspace: %r" % (exc, ), self.host)
            self.defunct(conn_exc)
            raise conn_exc

        if isinstance(result, ResultMessage):
            self.keyspace = keyspace
        else:
            conn_exc = ConnectionException(
                "Problem while setting keyspace: %r" % (result, ), self.host)
            self.defunct(conn_exc)
            raise conn_exc
Exemplo n.º 17
0
    def test_errback(self):
        session = self.make_session()
        pool = session._pools.get.return_value
        connection = Mock(spec=Connection)
        pool.borrow_connection.return_value = (connection, 1)

        query = SimpleStatement("INSERT INFO foo (a, b) VALUES (1, 2)")
        query.retry_policy = Mock()
        query.retry_policy.on_unavailable.return_value = (RetryPolicy.RETHROW,
                                                          None)
        message = QueryMessage(query=query,
                               consistency_level=ConsistencyLevel.ONE)

        rf = ResponseFuture(session, message, query, 1)
        rf.send_request()

        rf.add_errback(self.assertIsInstance, Exception)

        result = Mock(spec=UnavailableErrorMessage, info={})
        rf._set_result(None, None, None, result)
        self.assertRaises(Exception, rf.result)

        # this should get called immediately now that the error is set
        rf.add_errback(self.assertIsInstance, Exception)
Exemplo n.º 18
0
    def test_single_connection(self):
        """
        Test a single connection with sequential requests.
        """
        conn = self.get_connection()
        query = "SELECT keyspace_name FROM system.schema_keyspaces LIMIT 1"
        event = Event()

        def cb(count, *args, **kwargs):
            count += 1
            if count >= 10:
                conn.close()
                event.set()
            else:
                conn.send_msg(
                    QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
                    request_id=0,
                    cb=partial(cb, count))

        conn.send_msg(
            QueryMessage(query=query, consistency_level=ConsistencyLevel.ONE),
            request_id=0,
            cb=partial(cb, 0))
        event.wait()
Exemplo n.º 19
0
 def make_response_future(self, session):
     query = SimpleStatement("SELECT * FROM foo")
     message = QueryMessage(query=query,
                            consistency_level=ConsistencyLevel.ONE)
     return ResponseFuture(session, message, query, 1)
 def _send_query_message(self, session, timeout, **kwargs):
     query = "SELECT * FROM test3rf.test"
     message = QueryMessage(query=query, **kwargs)
     future = ResponseFuture(session, message, query=None, timeout=timeout)
     future.send_request()
     return future