def test_from_dict_response_invalid(self):
     # If: I create an invalid response from a dictionary
     # Then: I should get an exception
     with self.assertRaises(ValueError):
         JSONRPCMessage.from_dictionary({
             'id': '10',
             'error': {},
             'result': {}
         })
 def test_from_dict_invalid_notification(self):
     # If: I create a notification message from a dictionary that is missing a method
     # Then: I should get an exception
     with self.assertRaises(ValueError):
         JSONRPCMessage.from_dictionary({
             'params': {}
             # No ID = Notification
             # No method = Invalid
         })
Beispiel #3
0
    def test_send_message(self):
        with io.BytesIO(b'') as stream:
            # If:
            # ... I create a JSON RPC writer
            writer = JSONRPCWriter(stream, logger=utils.get_mock_logger())

            # ... and I send a message
            message = JSONRPCMessage.create_request('123', 'test/test', {})
            writer.send_message(message)

            # Then:
            # ... The content-length header should be present
            stream.seek(0)
            header = stream.readline().decode('ascii')
            self.assertRegex(
                header,
                re.compile('^Content-Length: [0-9]+\r\n$', re.IGNORECASE))

            # ... There should be a blank line to signify the end of the headers
            blank_line = stream.readline().decode('ascii')
            self.assertEqual(blank_line, '\r\n')

            # ... The JSON message as a dictionary should match the dictionary of the message
            message_str = str.join(
                os.linesep, [x.decode('UTF-8') for x in stream.readlines()])
            message_dict = json.loads(message_str)
            self.assertDictEqual(message_dict, message.dictionary)
    def test_from_dict_request(self):
        # If: I create a request from a dictionary
        message = JSONRPCMessage.from_dictionary({
            'id': '10',
            'method': 'test/test',
            'params': {}
        })

        # Then:
        # ... The message should have all the properties I defined
        self.assertIsNotNone(message)
        self.assertEqual(message.message_id, '10')
        self.assertEqual(message.message_method, "test/test")
        self.assertDictEqual(message.message_params, {})
        self.assertIsNone(message.message_result)
        self.assertIsNone(message.message_error)
        self.assertEqual(message.message_type, JSONRPCMessageType.Request)

        # ... The dictionary should have the same values stored
        dictionary = message.dictionary
        self.assertIsNotNone(dictionary)
        self.assertDictEqual(dictionary, {
            'jsonrpc': '2.0',
            'method': 'test/test',
            'params': {},
            'id': '10'
        })
    def test_read_multiple_messages(self):
        # Setup:
        # ... Create an input stream with two messages
        test_bytes = b'Content-Length: 30\r\n\r\n{"method":"test", "params":{}}'
        input_stream = io.BytesIO(test_bytes + test_bytes)
        output_stream = io.BytesIO()

        # ... Create a server that uses the input and output streams
        server = JSONRPCServer(input_stream, output_stream, logger=utils.get_mock_logger())

        # ... Patch the server to not dispatch a message
        dispatch_mock = mock.MagicMock()
        server._dispatch_message = dispatch_mock

        # If: I start the server, run it for a bit, and stop it
        server.start()
        time.sleep(1)
        server.stop()
        server.wait_for_exit()

        # Then: The dispatch method should have been called twice
        expected_output = JSONRPCMessage.from_dictionary({"method": "test", "params": {}})
        self.assertEqual(len(dispatch_mock.mock_calls), 2)
        self.assertDictEqual(dispatch_mock.mock_calls[0][1][0].dictionary, expected_output.dictionary)
        self.assertDictEqual(dispatch_mock.mock_calls[1][1][0].dictionary, expected_output.dictionary)

        # Teardown: All background threads should be shut down.
        self.assertFalse(server._input_consumer.isAlive())
        self.assertFalse(server._output_consumer.isAlive())
    def test_create_error(self):
        # If: I create an error message
        message = JSONRPCMessage.create_error(10, 20, 'msg', {})

        # Then:
        # ... The message should have all the properties I defined
        self.assertIsNotNone(message)
        self.assertEqual(message.message_id, 10)
        self.assertIsNone(message.message_method)
        self.assertIsNone(message.message_params)
        self.assertIsNone(message.message_result)
        self.assertIsNotNone(message.message_error)
        self.assertEqual(message.message_error['code'], 20)
        self.assertEqual(message.message_error['message'], 'msg')
        self.assertDictEqual(message.message_error['data'], {})
        self.assertEqual(message.message_type,
                         JSONRPCMessageType.ResponseError)

        # ... The dictionary should have the same values stored
        dictionary = message.dictionary
        self.assertIsNotNone(dictionary)
        self.assertDictEqual(
            dictionary, {
                'jsonrpc': '2.0',
                'error': {
                    'code': 20,
                    'message': 'msg',
                    'data': {}
                },
                'id': 10
            })
 def send_response(self, params):
     """
     Sends a successful response to this request
     :param params: Data to send back with the response
     """
     message = JSONRPCMessage.create_response(self._message.message_id,
                                              params)
     self._queue.put(message)
 def send_notification(self, method, params):
     """
     Sends a notification, independent to this request
     :param method: String name of the method for the notification
     :param params: Data to send with the notification
     """
     message = JSONRPCMessage.create_notification(method, params)
     self._queue.put(message)
 def send_notification(self, method, params):
     """
     Sends a new notification over the JSON RPC channel
     :param method: String name of the method of the notification being send
     :param params: Any data to send along with the notification
     """
     message = JSONRPCMessage.create_notification(method, params)
     self._queue.put(message)
Beispiel #10
0
    def test_request_context_init_test(self):
        # If: I create a request context
        queue = Queue()
        message = JSONRPCMessage.from_dictionary({'id': '123', 'method': 'test/text/', 'params': {}})
        rc = RequestContext(message, queue)

        # Then: The internal state should be set up correctly
        self.assertIs(rc._message, message)
        self.assertIs(rc._queue, queue)
Beispiel #11
0
 def test_initialization(self, mockdataeditorsession):
     queue = Queue()
     message = JSONRPCMessage.from_dictionary({
         'id': '123',
         'method': 'edit/initialize',
         'params': {}
     })
     request_context = RequestContext(message, queue)
     self._service_under_test._edit_initialize(
         request_context, self._initialize_edit_request)
     mockdataeditorsession.assert_called()
    def send_error(self, message, data=None, code=0):
        """
        Sends a failure response to this request
        :param message: Concise 1-sentence message explanation of the error
        :param data: Optional data to send back with the error
        :param code: Optional error code to identify the error
        """

        message = JSONRPCMessage.create_error(self._message.message_id, code,
                                              message, data)
        self._queue.put(message)
Beispiel #13
0
    def test_dispatch_notification_no_handler():
        # If: I dispatch a message that has no handler
        logger = utils.get_mock_logger()
        message = JSONRPCMessage.create_notification('non_existent', {})
        server = JSONRPCServer(None, None, logger=logger)
        server._dispatch_message(message)

        # Then:
        # ... Nothing should have happened
        # TODO: Capture that an error was sent
        # ... A warning should have been logged
        logger.warn.assert_called_once()
    def send_notification(self, method, params):
        """
        Sends a notification, independent of any request
        :param method: String name of the method for the notification
        :param params: Data to send with the notification
        """
        # Create the message
        message = JSONRPCMessage.create_notification(method, params)

        # TODO: Add support for handlers for the responses
        # Add the message to the output queue
        self._output_queue.put(message)
    def send_request(self, method, params):
        """
        Add a new request to the output queue
        :param method: Method string of the request
        :param params: Data to send along with the request
        """
        message_id = str(uuid.uuid4())

        # Create the message
        message = JSONRPCMessage.create_request(message_id, method, params)

        # TODO: Add support for handlers for the responses
        # Add the message to the output queue
        self._output_queue.put(message)
Beispiel #16
0
    def read_message(self):
        """
        Read JSON RPC message from buffer
        :raises ValueError: if the body-content cannot be serialized to a JSON object
        :return: JsonRpcMessage that was received
        """
        # Using a mutable list to hold the value since an immutable string passed by reference won't
        # change the value
        content = ['']
        try:
            while not self._needs_more_data or self._read_next_chunk():
                # We should have all the data we need to form a message in the buffer. If we need
                # more data to form the next message, this flag will be reset by an attempt to form
                # a header or content
                self._needs_more_data = False

                # If we can't read a header, read the next chunk
                if self._read_state is self.ReadState.Header and not self._try_read_headers():
                    self._needs_more_data = True
                    continue

                # If we read the header, try the content. If that fails, read the next chunk
                if self._read_state is self.ReadState.Content and not self._try_read_content(content):
                    self._needs_more_data = True
                    continue

                # We have the content
                break

            # Uncomment for verbose logging
            # if self._logger is not None:
            #     self._logger.debug(f'{content[0]}')

            return JSONRPCMessage.from_dictionary(json.loads(content[0]))
        except ValueError as ve:
            # Response has invalid json object
            if self._logger is not None:
                self._logger.warn('JSON RPC reader on read_message() encountered exception: {}'.format(ve))
            raise
        finally:
            # Remove the bytes that have been read
            self._trim_buffer_and_resize(self._read_offset)
Beispiel #17
0
    def test_dispatch_notification_normal(self):
        # Setup: Create a server with a single handler that has none for the deserialization class
        config = IncomingMessageConfiguration('test/test', _TestParams)
        handler = mock.MagicMock()
        server = JSONRPCServer(None, None, logger=utils.get_mock_logger())
        server.set_notification_handler(config, handler)

        # If: I dispatch a message that has none set for the deserialization class
        params = {}
        message = JSONRPCMessage.create_notification('test/test', params)
        server._dispatch_message(message)

        # Then:
        # ... The handler should have been called
        handler.assert_called_once()

        # ... The parameters to the handler should have been a request context and params
        self.assertIsInstance(handler.mock_calls[0][1][0], NotificationContext)
        self.assertIs(handler.mock_calls[0][1][0]._queue, server._output_queue)
        self.assertIsInstance(handler.mock_calls[0][1][1], _TestParams)
Beispiel #18
0
    def test_request_context_send_response(self):
        # Setup: Create a request context
        queue = Queue()
        in_message = JSONRPCMessage.from_dictionary({'id': '123', 'method': 'test/text/', 'params': {}})
        rc = RequestContext(in_message, queue)

        # If: I send a response via the response handler
        params = {}
        rc.send_response(params)

        # Then:
        # ... There should be a message in the outbound queue
        self.assertTrue(queue.not_empty)
        out_message = queue.get_nowait()
        self.assertIsInstance(out_message, JSONRPCMessage)

        # .. The message must be a response with the proper id
        self.assertEqual(out_message.message_type, JSONRPCMessageType.ResponseSuccess)
        self.assertEqual(out_message.message_id, '123')
        self.assertEqual(out_message.message_result, params)
Beispiel #19
0
    def test_request_context_send_notification(self):
        # Setup: Create a request context
        queue = Queue()
        in_message = JSONRPCMessage.from_dictionary({'id': '123', 'method': 'test/text/', 'params': {}})
        rc = RequestContext(in_message, queue)

        # If: I send a notification
        params = {}
        method = 'test/test'
        rc.send_notification(method, params)

        # Then:
        # ... There should be a message in the outbound queue
        self.assertTrue(queue.not_empty)
        out_message = queue.get_nowait()
        self.assertIsInstance(out_message, JSONRPCMessage)

        # .. The message must be a response with the proper id
        self.assertEqual(out_message.message_type, JSONRPCMessageType.Notification)
        self.assertIsNone(out_message.message_id)
        self.assertEqual(out_message.message_params, params)
    def test_create_notification(self):
        # If: I create a notification
        message = JSONRPCMessage.create_notification("test/test", {})

        # Then:
        # ... The message should have all the properties I defined
        self.assertIsNotNone(message)
        self.assertIsNone(message.message_id)
        self.assertEqual(message.message_method, "test/test")
        self.assertDictEqual(message.message_params, {})
        self.assertIsNone(message.message_result)
        self.assertIsNone(message.message_error)
        self.assertEqual(message.message_type, JSONRPCMessageType.Notification)

        # ... The dictionary should have the same values stored
        dictionary = message.dictionary
        self.assertIsNotNone(dictionary)
        self.assertDictEqual(dictionary, {
            'jsonrpc': '2.0',
            'method': 'test/test',
            'params': {}
        })
    def test_create_response(self):
        # If: I create a response
        message = JSONRPCMessage.create_response(10, {})

        # Then:
        # ... The message should have all the properties I defined
        self.assertIsNotNone(message)
        self.assertEqual(message.message_id, 10)
        self.assertIsNone(message.message_method)
        self.assertIsNone(message.message_params)
        self.assertIsNotNone(message.message_result)
        self.assertDictEqual(message.message_result, {})
        self.assertIsNone(message.message_error)
        self.assertEqual(message.message_type,
                         JSONRPCMessageType.ResponseSuccess)

        # ... The dictionary should have the same values stored
        dictionary = message.dictionary
        self.assertIsNotNone(dictionary)
        self.assertDictEqual(dictionary, {
            'jsonrpc': '2.0',
            'result': {},
            'id': 10
        })
 def test_from_dict_request_invalid(self):
     # If: I create an invalid request from a dictionary
     # Then: I should get an exception
     with self.assertRaises(ValueError):
         JSONRPCMessage.from_dictionary({'id': '10', 'params': {}})
Beispiel #23
0
 def test_dispatch_response_success():
     # TODO: Replace with robust logic once response routing is implemented
     # If: I dispatch a response message
     message = JSONRPCMessage.create_response('123', {})
     server = JSONRPCServer(None, None, logger=utils.get_mock_logger())
     server._dispatch_message(message)
Beispiel #24
0
 def test_dispatch_response_error():
     # TODO: Replace with robust logic once error routing is implemented
     # If: I dispatch an error message
     message = JSONRPCMessage.create_error('123', 0, message='', data={})
     server = JSONRPCServer(None, None, logger=utils.get_mock_logger())
     server._dispatch_message(message)
 def _received_response_callback(self, params: any):
     rpc_message = JSONRPCMessage.create_response(0, params)
     received_message = ReceivedMessage(JSONRPCMessageType.ResponseSuccess, None, params, type(params), rpc_message)
     self._received_messages.append(received_message)
 def _received_notification_callback(self, method: str, params: any):
     rpc_message = JSONRPCMessage.create_notification(method, params)
     received_message = ReceivedMessage(JSONRPCMessageType.Notification, method, params, type(params), rpc_message)
     self._received_messages.append(received_message)
 def _received_error_callback(self, message: str, data: any = None, code: int = 0):
     error = ReceivedError(code, message, data)
     rpc_message = JSONRPCMessage.create_error(0, code, message, data)
     received_message = ReceivedMessage(JSONRPCMessageType.ResponseError, None, error, type(data), rpc_message)
     self._received_messages.append(received_message)
Beispiel #28
0
 def test_dispatch_invalid():
     # If: I dispatch an invalid message
     message = JSONRPCMessage('invalidType')
     server = JSONRPCServer(None, None, logger=utils.get_mock_logger())
     server._dispatch_message(message)