def test_that_receiving_wrongly_encoded_message_should_return_none( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY, ) raw_message_encoded = escape_encode_raw_message(raw_message) raw_message_encoded = raw_message_encoded + ESCAPE_CHARACTER + b'\xff' raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy.assert_that(raw_message_received).is_none()
def test_that_receiving_a_series_of_messages_should_be_handled_correctly( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) raw_message = escape_encode_raw_message( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message_with_separator = append_frame_separator(raw_message) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() for _i in range(10): client_socket.send(raw_message_with_separator) split_stream_generator = split_stream(connection=connection) for _i in range(10): raw_message_received = next(split_stream_generator) assertpy.assert_that(raw_message).is_equal_to( raw_message_received)
def test_that_sci_callback_should_raise_exception_when_response_is_not_signed_transaction_golem_message(self): with mock.patch('core.payments.sci_callback.socket.socket.connect'): with mock.patch('core.payments.sci_callback.send_over_stream'): with mock.patch('core.payments.sci_callback.unescape_stream', side_effect=self.frame_iterator): with mock.patch( 'middleman_protocol.message.AbstractFrame.deserialize', return_value=GolemMessageFrame(payload=Ping(), request_id=self.request_id), ): with self.assertRaises(SCICallbackPayloadError): sci_callback(self.transaction)
def test_that_sent_data_is_escaped_and_contains_frame_separator(event_loop): frame = GolemMessageFrame(Ping(), 777) expected_data = append_frame_separator( escape_encode_raw_message(frame.serialize(CONCENT_PRIVATE_KEY))) mocked_writer = prepare_mocked_writer() task = _run_test_in_event_loop(event_loop, send_over_stream_async, frame, mocked_writer, CONCENT_PRIVATE_KEY) assert_that(task.done()).is_true() mocked_writer.write.assert_called_once_with(expected_data) mocked_writer.drain.mock.assert_called_once_with()
def test_that_serializing_different_golem_message_middleman_messages_should_keep_part_of_header_the_same( self): message_1 = GolemMessageFrame( ServiceRefused(reason=ServiceRefused.REASON.InvalidRequest), self.request_id).serialize(private_key=CONCENT_PRIVATE_KEY) message_2 = GolemMessageFrame( Ping(), self.request_id).serialize(private_key=CONCENT_PRIVATE_KEY) assertpy.assert_that( message_1[FRAME_SIGNATURE_BYTES_LENGTH:FRAME_PAYLOAD_STARTING_BYTE] ).is_equal_to( message_2[FRAME_SIGNATURE_BYTES_LENGTH:FRAME_PAYLOAD_STARTING_BYTE] )
def test_that_when_frame_with_escaped_sequence_and_separator_is_received_unescaped_frame_is_returned( event_loop): golem_message_frame = GolemMessageFrame(Ping(), 777) data_to_send = escape_encode_raw_message( golem_message_frame.serialize(CONCENT_PRIVATE_KEY) ) + ESCAPE_SEQUENCES[ESCAPE_CHARACTER] + FRAME_SEPARATOR mocked_reader = prepare_mocked_reader(data_to_send) task = _run_test_in_event_loop(event_loop, handle_frame_receive_async, mocked_reader, CONCENT_PUBLIC_KEY) assert_that(task.done()).is_true() mocked_reader.readuntil.mock.assert_called_once_with(FRAME_SEPARATOR) assert_that(task.result()).is_equal_to(golem_message_frame)
def is_concent_api_running(api_url: str) -> bool: """ Verifies if Concent API server instance is running on given API url. """ try: response = requests.post( api_url, data=Ping().serialize(), headers={ 'Content-Type': 'application/octet-stream', }, verify=False, ) return (response.json()['error'] == 'Unknown message type' and response.json()['error_code'] == 'message.unknown') except requests.ConnectionError: return False
def test_that_exceeding_maximum_frame_length_should_treat_exceeded_frame_as_invalid( self, unused_tcp_port): first_middleman_message = GolemMessageFrame(Ping(), self.request_id) first_raw_message = append_frame_separator( escape_encode_raw_message( first_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) second_middleman_message = AuthenticationChallengeFrame( payload=b'', request_id=100, ) second_raw_message = append_frame_separator( escape_encode_raw_message( second_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) assert len(first_raw_message) > len(second_raw_message) + 10 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(first_raw_message) client_socket.send(second_raw_message) with mock.patch( 'middleman_protocol.stream.MAXIMUM_FRAME_LENGTH', len(first_raw_message) - 10): raw_message_received = next( unescape_stream(connection=connection)) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message.request_id).is_equal_to(100)
def setUp(self, unused_tcp_port_factory, event_loop): golem_message_frame = GolemMessageFrame( Ping(), 777).serialize(CONCENT_PRIVATE_KEY) self.patcher = mock.patch("middleman.middleman_server.crash_logger") self.crash_logger_mock = self.patcher.start() self.internal_port, self.external_port = unused_tcp_port_factory( ), unused_tcp_port_factory() self.data_to_send = append_frame_separator( escape_encode_raw_message(golem_message_frame)) self.timeout = 0.2 self.short_delay = 0.1 self.middleman = MiddleMan(internal_port=self.internal_port, external_port=self.external_port, loop=event_loop) yield self.internal_port, self.external_port self.patcher.stop()
def setUp(self, event_loop): self.mocked_writer = prepare_mocked_writer() self.message_tracker = OrderedDict({}) self.golem_message = Ping() sign_message(self.golem_message, CONCENT_PRIVATE_KEY) self.connection_id = 4 self.request_id = 888 self.queue = Queue(loop=event_loop) self.queue_pool = QueuePool( {self.connection_id: Queue(loop=event_loop)}, loop=event_loop, ) self.signing_service_request_id = 1 self.request_queue_item = RequestQueueItem( self.connection_id, self.request_id, self.golem_message, FROZEN_TIMESTAMP )
def test_that_receiving_a_series_of_messages_should_be_handled_correctly( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() for _i in range(10): send_over_stream(connection=client_socket, raw_message=middleman_message, private_key=CONCENT_PRIVATE_KEY) unescape_stream_generator = unescape_stream( connection=connection) for _i in range(10): raw_message_received = next(unescape_stream_generator) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message).is_instance_of( GolemMessageFrame) assertpy.assert_that( deserialized_message.payload).is_instance_of(Ping) assertpy.assert_that( deserialized_message.payload).is_equal_to(payload)
def setUp(self): super().setUp() self.v = 28 self.r = 43021479287739768723523510158222935518435169120980980279247970098168969365906 self.s = 27167722793113753385347871828548141783025585937756999455305671053201800240244 self.request_id = RequestIDGenerator.generate_request_id() + 1 self.transaction = self._create_unsigned_transaction() self.signed_transaction_golem_message = self._create_signed_transaction() self.signed_transaction_golem_message.sign_message(SIGNING_SERVICE_PRIVATE_KEY) self.frame = GolemMessageFrame( payload=self.signed_transaction_golem_message, request_id=self.request_id, ).serialize(private_key=CONCENT_PRIVATE_KEY) def iterator(connection): # pylint: disable=unused-argument yield self.frame self.frame_iterator = iterator self.middleman_message = GolemMessageFrame(payload=Ping(), request_id=self.request_id)
def test_case_ping_message_send_to_concent_with_malformed_golem_messages_should_get_http400_response_with_bad_request_error( cluster_url: str, cluster_consts: ProtocolConstants, concent_1_golem_messages_version: str, concent_2_golem_messages_version: str, ) -> None: # Sending Ping message to concent with malformed header(Golem Messages version has a wrong, non-semver format). # Expected: ngingx-router will respond with Http400 with error code "bad-request". api_request( cluster_url, 'send', PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY, Ping(), headers={ 'Content-Type': 'application/octet-stream', 'X-Golem-Messages': 'X.X.X' }, expected_status=400, expected_error_code='bad-request', )
def test_case_ping_message_send_to_concent_with_unsupported_golem_messages_should_get_http404_response_with_not_found_error( cluster_url: str, cluster_consts: ProtocolConstants, concent_1_golem_messages_version: str, concent_2_golem_messages_version: str, ) -> None: # Sending Ping message to concent with unsupported version of Golem Messages. # Expected: nginx-router will respond with Http404. api_request( cluster_url, 'send', PROVIDER_PRIVATE_KEY, CONCENT_PUBLIC_KEY, Ping(), headers={ 'Content-Type': 'application/octet-stream', 'X-Golem-Messages': '1.0.0' }, expected_status=404, expected_error_code='not-found', )
def setUp(self, event_loop): self.first_index = 1 self.second_index = 2 ping_message = Ping() resposne_queue_items = [ ResponseQueueItem(ping_message, 777, get_current_utc_timestamp()), ResponseQueueItem(ping_message, 888, get_current_utc_timestamp()), ResponseQueueItem(ping_message, 1001, get_current_utc_timestamp()), ResponseQueueItem(ping_message, 1007, get_current_utc_timestamp()), ] first_queue = asyncio.Queue(loop=event_loop) second_queue = asyncio.Queue(loop=event_loop) self.number_of_items_in_first_queue = 3 event_loop.run_until_complete(self._populate_queues(first_queue, resposne_queue_items, second_queue)) self.initial_dict = { self.first_index: first_queue, self.second_index: second_queue, } self.logger_mock = create_autospec(spec=Logger, spec_set=True) self.queue_pool = QueuePool(self.initial_dict, event_loop, self.logger_mock)
def test_that_receiving_encoded_message_should_decode_on_the_fly( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = append_frame_separator( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message = raw_message[:10] + ESCAPE_CHARACTER + raw_message[ len(ESCAPE_CHARACTER) + 10:] raw_message_encoded = escape_encode_raw_message(raw_message) assert FRAME_SEPARATOR not in raw_message_encoded raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy_bytes_starts_with(raw_message, raw_message_received) assertpy.assert_that( len(raw_message_received)).is_greater_than_or_equal_to( FRAME_PAYLOAD_STARTING_BYTE)
def test_that__handle_connection_should_send_error_frame_if_payload_is_invalid( self): # Prepare frame payload which is not Golem message. middleman_message = GolemMessageFrame( payload=Ping(), request_id=99, ) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) malformed_raw_message = ( raw_message[:FRAME_PAYLOAD_STARTING_BYTE] + AbstractFrame.get_frame_format( ).signed_part_of_the_frame.payload.build(b'\x00' * 100)) # Replace message signature new_signature = ecdsa_sign( CONCENT_PRIVATE_KEY, malformed_raw_message[FRAME_SIGNATURE_BYTES_LENGTH:]) malformed_raw_message_with_new_signature = new_signature + malformed_raw_message[ FRAME_SIGNATURE_BYTES_LENGTH:] raw_message_received = self._prepare_and_execute_handle_connection( malformed_raw_message_with_new_signature) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=SIGNING_SERVICE_PUBLIC_KEY, ) assertpy.assert_that( deserialized_message.payload).is_instance_of(tuple) assertpy.assert_that(deserialized_message.payload).is_length(2) assertpy.assert_that(deserialized_message.payload[0]).is_equal_to( ErrorCode.InvalidPayload) assertpy.assert_that(deserialized_message.request_id).is_equal_to( REQUEST_ID_FOR_RESPONSE_FOR_INVALID_FRAME)
class TestMessageMiddlemanProtocol: request_id = 99 @pytest.mark.parametrize( ('expected_middleman_message_type', 'payload_type', 'payload'), [ (GolemMessageFrame, PayloadType.GOLEM_MESSAGE, Ping()), (ErrorFrame, PayloadType.ERROR, (111, 'error_message')), (AuthenticationChallengeFrame, PayloadType.AUTHENTICATION_CHALLENGE, b'random_bytes'), (AuthenticationResponseFrame, PayloadType.AUTHENTICATION_RESPONSE, b'TODO'), (HeartbeatFrame, PayloadType.HEARTBEAT, None), ]) def test_that_create_middleman_protocol_message_with_various_payload_types_should_create_proper_middleman_message( self, expected_middleman_message_type, payload_type, payload, ): message = create_middleman_protocol_message( payload_type, payload, self.request_id, ) assertpy.assert_that(message).is_instance_of( expected_middleman_message_type) assertpy.assert_that(message.payload_type).is_equal_to(payload_type) def test_that_abstract_middleman_message_instantiation_should_raise_exception( self): with pytest.raises(TypeError): AbstractFrame( # pylint: disable=abstract-class-instantiated Ping(), self.request_id, ) @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), (HeartbeatFrame, None), ]) def test_that_serializing_and_deserializing_message_should_preserve_original_data( self, middleman_message_type, payload, ): middleman_message = middleman_message_type(payload, self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) deserialized_message = AbstractFrame.deserialize( raw_message, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message).is_instance_of( middleman_message_type) assertpy.assert_that(deserialized_message.payload).is_instance_of( type(payload)) assertpy.assert_that(deserialized_message.payload).is_equal_to(payload) @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), (HeartbeatFrame, None), ]) def test_that_sending_message_over_tcp_socket_should_preserve_original_data( self, middleman_message_type, payload, unused_tcp_port, ): middleman_message = middleman_message_type(payload, self.request_id) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() send_over_stream(connection=client_socket, raw_message=middleman_message, private_key=CONCENT_PRIVATE_KEY) raw_message_received = next( unescape_stream(connection=connection)) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message).is_instance_of( middleman_message_type) assertpy.assert_that(deserialized_message.payload).is_instance_of( type(payload)) assertpy.assert_that(deserialized_message.payload).is_equal_to(payload) def test_that_serializing_different_golem_message_middleman_messages_should_keep_part_of_header_the_same( self): message_1 = GolemMessageFrame( ServiceRefused(reason=ServiceRefused.REASON.InvalidRequest), self.request_id).serialize(private_key=CONCENT_PRIVATE_KEY) message_2 = GolemMessageFrame( Ping(), self.request_id).serialize(private_key=CONCENT_PRIVATE_KEY) assertpy.assert_that( message_1[FRAME_SIGNATURE_BYTES_LENGTH:FRAME_PAYLOAD_STARTING_BYTE] ).is_equal_to( message_2[FRAME_SIGNATURE_BYTES_LENGTH:FRAME_PAYLOAD_STARTING_BYTE] ) @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), (HeartbeatFrame, None), ]) def test_that_serializing_and_deserializing_message_with_wrong_signature_should_raise_exception( self, middleman_message_type, payload, ): middleman_message = middleman_message_type(payload, self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) first_byte = 2 if raw_message[0] == 0 else raw_message[0] malformed_raw_message = bytes(bytearray([first_byte - 1 ])) + raw_message[1:] with pytest.raises(SignatureInvalidMiddlemanProtocolError): AbstractFrame.deserialize( malformed_raw_message, CONCENT_PUBLIC_KEY, ) def test_that_serializing_and_deserializing_message_with_wrong_payload_type_should_raise_exception( self): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) payload_type_position = FRAME_SIGNATURE_BYTES_LENGTH + FRAME_REQUEST_ID_BYTES_LENGTH invalid_payload_type = 100 # Sanity check for payload type in this case to be between expected bytes assert raw_message[payload_type_position:payload_type_position + 1] == b'\x00' assert invalid_payload_type not in PAYLOAD_TYPE_TO_MIDDLEMAN_MESSAGE_CLASS # Replace bytes with payload length raw_message = ( raw_message[:payload_type_position] + bytes(bytearray([invalid_payload_type])) + raw_message[payload_type_position + FRAME_PAYLOAD_TYPE_LENGTH:]) # Replace message signature new_signature = ecdsa_sign(CONCENT_PRIVATE_KEY, raw_message[FRAME_SIGNATURE_BYTES_LENGTH:]) raw_message_with_new_signature = new_signature + raw_message[ FRAME_SIGNATURE_BYTES_LENGTH:] with pytest.raises(PayloadTypeInvalidMiddlemanProtocolError): AbstractFrame.deserialize(raw_message_with_new_signature, CONCENT_PUBLIC_KEY) @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), (HeartbeatFrame, None), ]) def test_that_serializing_and_deserializing_message_too_short_should_raise_exception( self, middleman_message_type, payload, ): middleman_message = middleman_message_type(payload, self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY) malformed_raw_message = raw_message[:-1] with pytest.raises(FrameInvalidMiddlemanProtocolError): AbstractFrame.deserialize( malformed_raw_message, CONCENT_PUBLIC_KEY, )
class TestUnescapeStreamHelperMiddlemanProtocol: request_id = 99 @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), ]) def test_that_receiving_any_message_should_be_handled_correctly( self, middleman_message_type, payload, unused_tcp_port, ): middleman_message = middleman_message_type(payload, self.request_id) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() send_over_stream(connection=client_socket, raw_message=middleman_message, private_key=CONCENT_PRIVATE_KEY) raw_message_received = next( unescape_stream(connection=connection)) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message).is_instance_of( middleman_message_type) assertpy.assert_that(deserialized_message.payload).is_equal_to(payload) def test_that_receiving_a_series_of_messages_should_be_handled_correctly( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() for _i in range(10): send_over_stream(connection=client_socket, raw_message=middleman_message, private_key=CONCENT_PRIVATE_KEY) unescape_stream_generator = unescape_stream( connection=connection) for _i in range(10): raw_message_received = next(unescape_stream_generator) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message).is_instance_of( GolemMessageFrame) assertpy.assert_that( deserialized_message.payload).is_instance_of(Ping) assertpy.assert_that( deserialized_message.payload).is_equal_to(payload) def test_that_receiving_encoded_message_should_decode_on_the_fly( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = append_frame_separator( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message = raw_message[:10] + ESCAPE_CHARACTER + raw_message[ len(ESCAPE_CHARACTER) + 10:] raw_message_encoded = escape_encode_raw_message(raw_message) assert FRAME_SEPARATOR not in raw_message_encoded raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy_bytes_starts_with(raw_message, raw_message_received) assertpy.assert_that( len(raw_message_received)).is_greater_than_or_equal_to( FRAME_PAYLOAD_STARTING_BYTE) def test_that_receiving_wrongly_encoded_message_should_return_none( self, unused_tcp_port): middleman_message = GolemMessageFrame(Ping(), self.request_id) raw_message = middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY, ) raw_message_encoded = escape_encode_raw_message(raw_message) raw_message_encoded = raw_message_encoded + ESCAPE_CHARACTER + b'\xff' raw_message_encoded = append_frame_separator(raw_message_encoded) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_encoded) raw_message_received = next( unescape_stream(connection=connection)) assertpy.assert_that(raw_message_received).is_none() def test_that_exceeding_maximum_frame_length_should_treat_exceeded_frame_as_invalid( self, unused_tcp_port): first_middleman_message = GolemMessageFrame(Ping(), self.request_id) first_raw_message = append_frame_separator( escape_encode_raw_message( first_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) second_middleman_message = AuthenticationChallengeFrame( payload=b'', request_id=100, ) second_raw_message = append_frame_separator( escape_encode_raw_message( second_middleman_message.serialize( private_key=CONCENT_PRIVATE_KEY))) assert len(first_raw_message) > len(second_raw_message) + 10 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(first_raw_message) client_socket.send(second_raw_message) with mock.patch( 'middleman_protocol.stream.MAXIMUM_FRAME_LENGTH', len(first_raw_message) - 10): raw_message_received = next( unescape_stream(connection=connection)) deserialized_message = AbstractFrame.deserialize( raw_message=raw_message_received, public_key=CONCENT_PUBLIC_KEY, ) assertpy.assert_that(deserialized_message.request_id).is_equal_to(100)
def setUp(self, event_loop): self.golem_message = Ping() self.connection_id = 1 self.request_id = 777 self.queue = Queue(loop=event_loop) self.response_queue = Queue(loop=event_loop)
class TestSplitStreamHelperMiddlemanProtocol: request_id = 99 @pytest.mark.parametrize(('middleman_message_type', 'payload'), [ (GolemMessageFrame, Ping()), (ErrorFrame, (111, 'error_message')), (AuthenticationChallengeFrame, b'random_bytes'), (AuthenticationResponseFrame, b'TODO'), ]) def test_that_receiving_any_message_should_be_handled_correctly( self, middleman_message_type, payload, unused_tcp_port, ): middleman_message = middleman_message_type(payload, self.request_id) raw_message = escape_encode_raw_message( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message_with_separator = append_frame_separator(raw_message) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() client_socket.send(raw_message_with_separator) raw_message_received = next( split_stream(connection=connection)) assertpy.assert_that(raw_message).is_equal_to(raw_message_received) def test_that_receiving_a_series_of_messages_should_be_handled_correctly( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) raw_message = escape_encode_raw_message( middleman_message.serialize(private_key=CONCENT_PRIVATE_KEY)) raw_message_with_separator = append_frame_separator(raw_message) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() for _i in range(10): client_socket.send(raw_message_with_separator) split_stream_generator = split_stream(connection=connection) for _i in range(10): raw_message_received = next(split_stream_generator) assertpy.assert_that(raw_message).is_equal_to( raw_message_received) def test_that_raising_error_in_generator_should_call_close_on_socket( self, unused_tcp_port): payload = Ping() middleman_message = GolemMessageFrame(payload, self.request_id) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() send_over_stream(connection=client_socket, raw_message=middleman_message, private_key=CONCENT_PRIVATE_KEY) split_stream_generator = split_stream(connection=connection) with mock.patch('middleman_protocol.stream.socket.socket.recv', side_effect=Exception()): with mock.patch( 'middleman_protocol.stream.socket.socket.close' ) as mock_socket_close: with pytest.raises(Exception): next(split_stream_generator) mock_socket_close.assert_called_once() def test_that_when_socket_receives_no_bytes_socket_error_is_raised( self, unused_tcp_port): # pylint: disable=no-self-use with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as server_socket: server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(('127.0.0.1', unused_tcp_port)) server_socket.listen(1) client_socket.connect(('127.0.0.1', unused_tcp_port)) (connection, _address) = server_socket.accept() # Closing client socket will cause that socket.recv() function will read 0 bytes. client_socket.close() with pytest.raises(socket.error): next(split_stream(connection=connection))