def test_that_signing_service_should_reconnect_when_expected_socket_error_was_caught(self): with mock.patch('socket.socket.connect', side_effect=socket.error()) as mock_socket_connect: with mock.patch('signing_service.signing_service.SigningService._was_sigterm_caught', side_effect=[False, False, True]): signing_service = SigningService(*self.parameters) signing_service.run() assertpy.assert_that(mock_socket_connect.call_count).is_equal_to(2)
def test_that_signing_service_should_run_full_loop_when_instantiated_with_all_parameters( self): with mock.patch('socket.socket.connect') as mock_socket_connect: with mock.patch( 'signing_service.signing_service.SigningService._authenticate' ) as mock___authenticate: with mock.patch( 'signing_service.signing_service.SigningService._get_signing_service_daily_transaction_sum_so_far' ) as mock_daily_transaction_sum: with mock.patch( 'signing_service.signing_service.SigningService._handle_connection' ) as mock__handle_connection: with mock.patch( 'socket.socket.close') as mock_socket_close: with mock.patch( 'signing_service.signing_service.SigningService._was_sigterm_caught', side_effect=[False, True]): signing_service = SigningService( *self.parameters) signing_service.run() mock_socket_connect.assert_called_once_with(('127.0.0.1', self.port)) mock_socket_close.assert_called_once() mock___authenticate.assert_called_once() mock_daily_transaction_sum.assert_called_once() mock__handle_connection.assert_called_once()
def test_that_signing_service_should_exit_gracefully_on_keyboard_interrupt(self): with mock.patch('socket.socket.connect', side_effect=KeyboardInterrupt()) as mock_socket_connect: with mock.patch('socket.socket.close') as mock_socket_close: signing_service = SigningService(*self.parameters) signing_service.run() mock_socket_connect.assert_called_once_with(('127.0.0.1', self.port)) mock_socket_close.assert_called_once()
def test_that_signing_service_should_reraise_unrecognized_exception(self): with mock.patch('socket.socket.connect', side_effect=Exception()) as mock_socket_connect: with mock.patch('socket.socket.close') as mock_socket_close: signing_service = SigningService(*self.parameters) with pytest.raises(Exception): signing_service.run() mock_socket_connect.assert_called_once_with(('127.0.0.1', self.port)) mock_socket_close.assert_called_once()
def _prepare_and_execute_handle_connection( self, raw_message, handle_connection_wrapper=None, expect_response_from_scoket=True): def mocked_generator(): yield raw_message raise SigningServiceValidationError() with mock.patch('signing_service.signing_service.SigningService.run'): with closing(socket.socket( socket.AF_INET, socket.SOCK_STREAM)) as signing_service_socket: signing_service_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) with closing(socket.socket( socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) # For test purposes we reverse roles, so signing service works as server. signing_service_socket.bind( ('127.0.0.1', self.signing_service_port)) signing_service_socket.listen(1) client_socket.connect( ('127.0.0.1', self.signing_service_port)) (connection, _address) = signing_service_socket.accept() client_socket.setblocking(False) with pytest.raises(SigningServiceValidationError): if handle_connection_wrapper is not None: handle_connection_wrapper(signing_service, connection, mocked_generator()) else: signing_service._handle_connection( mocked_generator(), connection) if expect_response_from_scoket: response = next( unescape_stream(connection=client_socket)) else: # We do not expect to get anything from the socket, dummy response is returned. response = mock.sentinel.no_response return response
def test_that_signing_service_will_reconnect_after_authentication_fails(self): with mock.patch('socket.socket.connect') as mock_socket_connect: with mock.patch('socket.socket.close') as mock_socket_close: with mock.patch('signing_service.signing_service.SigningService._authenticate', side_effect=socket.error()) as mock___authenticate: with mock.patch('signing_service.signing_service.sleep'): signing_service = SigningService(*self.parameters) signing_service.run() assertpy.assert_that(mock_socket_connect.call_count).is_equal_to(SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1) assertpy.assert_that(mock_socket_close.call_count).is_equal_to(SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1) assertpy.assert_that(mock___authenticate.call_count).is_equal_to(SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1)
class SigningServiceValidateArgumentsTestCase(TestCase): def setUp(self): super().setUp() self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_signing_service__validate_arguments_should_raise_exception_on_port_number_below_or_above_range( self): for wrong_port in [0, 65535 + 1]: self.signing_service.port = wrong_port with self.assertRaises(SigningServiceValidationError): self.signing_service._validate_arguments() def test_that_signing_service__validate_arguments_should_raise_exception_on_initial_reconnect_delay_lower_than_zero( self): self.signing_service.initial_reconnect_delay = -1 with self.assertRaises(SigningServiceValidationError): self.signing_service._validate_arguments() def test_that_signing_service__validate_arguments_should_raise_exception_on_wrong_length_of_concent_public_key( self): self.signing_service.concent_public_key = CONCENT_PUBLIC_KEY[:-1] with self.assertRaises(SigningServiceValidationError): self.signing_service._validate_arguments() def test_that_signing_service__validate_arguments_should_raise_exception_on_wrong_length_of_ethereum_private_key( self): self.signing_service.ethereum_private_key = TEST_ETHEREUM_PRIVATE_KEY[: -1] with self.assertRaises(SigningServiceValidationError): self.signing_service._validate_arguments() def test_that_signing_service__validate_arguments_should_raise_exception_on_wrong_characters_in_ethereum_private_key( self): self.signing_service.ethereum_private_key = self.signing_service.ethereum_private_key[: -1] + 'g' with self.assertRaises(SigningServiceValidationError): self.signing_service._validate_arguments()
def setUp(self, unused_tcp_port_factory): self.signing_service = SigningService( '127.0.0.1', unused_tcp_port_factory(), 2, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), )
class SigningServiceGetSignedTransactionTestCase(SigningServiceIntegrationTestCase, TestCase): def setUp(self): self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 with mock.patch('signing_service.signing_service.SigningService.run'): self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_get_signed_transaction_should_return_transaction_signed_if_transaction_was_signed_correctly(self): transaction_signing_request = self._get_deserialized_transaction_signing_request() transaction_signed = self.signing_service._get_signed_transaction(transaction_signing_request) self.assertIsInstance(transaction_signed, SignedTransaction) self.assertEqual(transaction_signed.nonce, transaction_signing_request.nonce) # pylint: disable=no-member self.assertEqual(transaction_signed.gasprice, transaction_signing_request.gasprice) # pylint: disable=no-member self.assertEqual(transaction_signed.startgas, transaction_signing_request.startgas) # pylint: disable=no-member self.assertEqual(transaction_signed.to, transaction_signing_request.to) # pylint: disable=no-member self.assertEqual(transaction_signed.value, transaction_signing_request.value) # pylint: disable=no-member self.assertEqual(transaction_signed.data, transaction_signing_request.data) # pylint: disable=no-member self.assertEqual(transaction_signed.v, 27) # pylint: disable=no-member self.assertEqual(transaction_signed.r, 30388804072119173430692318653717116791007045427887199775992056799290419449340) # pylint: disable=no-member self.assertEqual(transaction_signed.s, 12415095341641447952516229207372622127096123813439844824954905697584046077123) # pylint: disable=no-member def test_that_get_signed_transaction_should_return_transaction_rejected_if_transaction_cannot_be_recreated_from_received_transaction_signing_request(self): transaction_signing_request = self._get_deserialized_transaction_signing_request() transaction_signing_request.nonce = 'invalid_nonce' transaction_rejected = self.signing_service._get_signed_transaction(transaction_signing_request) self.assertIsInstance(transaction_rejected, TransactionRejected) self.assertEqual(transaction_rejected.reason, TransactionRejected.REASON.InvalidTransaction) # pylint: disable=no-member def test_that_get_signed_transaction_should_return_transaction_rejected_if_transaction_cannot_be_signed(self): transaction_signing_request = self._get_deserialized_transaction_signing_request() self.signing_service.ethereum_private_key = b'\x00' transaction_rejected = self.signing_service._get_signed_transaction(transaction_signing_request) self.assertIsInstance(transaction_rejected, TransactionRejected) self.assertEqual(transaction_rejected.reason, TransactionRejected.REASON.UnauthorizedAccount) # pylint: disable=no-member
class SigningServiceDailyThresholdTestCase(TestCase): def setUp(self): self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 with mock.patch('signing_service.signing_service.SigningService.run'): self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_signing_service_get_daily_transaction_threshold_file_directory_should_return_existing_file( self): threshold_file = self.signing_service._get_daily_transaction_threshold_file_path( ) self.assertTrue(threshold_file.exists()) # pylint: disable=no-member self.assertTrue(threshold_file.is_file()) # pylint: disable=no-member threshold_file.unlink() # pylint: disable=no-member def test_that_add_payload_value_to_daily_transactions_sum_write_int_and_get_signing_service_daily_transaction_sum_so_far_returns_correct_value( self): threshold_file = self.signing_service._get_daily_transaction_threshold_file_path( ) self.signing_service._add_payload_value_to_daily_transactions_sum(1337) transaction_sum = self.signing_service._get_signing_service_daily_transaction_sum_so_far( ) self.assertEqual(transaction_sum, 1337) threshold_file.unlink() # pylint: disable=no-member def test_that_signing_service_get_signing_service_daily_transaction_sum_so_far_returns_zero_in_case_of_value_error( self): threshold_file = self.signing_service._get_daily_transaction_threshold_file_path( ) threshold_file.write_text('GolemConcent') # pylint: disable=no-member transaction_sum = self.signing_service._get_signing_service_daily_transaction_sum_so_far( ) self.assertEqual(transaction_sum, 0) threshold_file.unlink() # pylint: disable=no-member def test_that_signing_service_update_daily_transactions_limit_file_name_overwrite_old_value( self): self.signing_service.daily_transactions_limit_file_name = '1970-01-01' self.signing_service.signing_service_daily_transaction_sum_so_far = 10000 self.signing_service._update_daily_transactions_limit_file_name() self.assertEqual( self.signing_service.daily_transactions_limit_file_name, datetime.datetime.now().strftime('%Y-%m-%d')) self.assertEqual( self.signing_service.signing_service_daily_transaction_sum_so_far, 0)
def test_that_signing_service_will_reconnect_on_socket_errors_and_exit_gracefully_when_exceeds_maximum_number_of_reconnection_attempts(self): with mock.patch('socket.socket.connect', side_effect=socket.error()) as mock_socket_connect: with mock.patch('socket.socket.close') as mock_socket_close: with mock.patch('signing_service.signing_service.sleep'): signing_service = SigningService(*self.parameters) with mock.patch('signing_service.signing_service.logger.error') as mock_logger_error: signing_service.run() assertpy.assert_that(mock_socket_connect.call_count).is_equal_to(SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1) assertpy.assert_that(mock_socket_close.call_count).is_equal_to(SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1) assertpy.assert_that( mock_logger_error.call_args_list[mock_logger_error.call_count - 1], ['Maximum number of reconnection exceeded.'], )
def test_that_signing_service_will_reconnect_on_socket_errors_and_raise_exception_when_exceeds_maxium_number_of_reconnection_attempts( self): with mock.patch('socket.socket.connect', side_effect=socket.error()) as mock_socket_connect: with mock.patch('socket.socket.close') as mock_socket_close: with mock.patch('signing_service.signing_service.sleep'): signing_service = SigningService(*self.parameters) with pytest.raises( SigningServiceMaximumReconnectionAttemptsExceeded): signing_service.run() assertpy.assert_that(mock_socket_connect.call_count).is_equal_to( SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1) assertpy.assert_that(mock_socket_close.call_count).is_equal_to( SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS + 1)
def setUp(self): self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 with mock.patch('signing_service.signing_service.SigningService.run'): self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), )
class SigningServiceGetAuthenticationChallengeSignatureTestCase(SigningServiceIntegrationTestCase, TestCase): def setUp(self): self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 with mock.patch('signing_service.signing_service.SigningService.run'): self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_get_authentication_challenge_signature_should_return_signature_of_passed_bytes(self): authentication_challenge = bytes(os.urandom(1000)) signature = self.signing_service._get_authentication_challenge_signature(authentication_challenge) self.assertIsInstance(signature, bytes) self.assertTrue( ecdsa_verify( self.signing_service.signing_service_public_key, signature, authentication_challenge, ) )
def test_that_signing_service_should_be_instantiated_correctly_with_all_parameters(self): signing_service = SigningService(*self.parameters) assertpy.assert_that(signing_service).is_instance_of(SigningService) assertpy.assert_that(signing_service.host).is_equal_to(self.host) assertpy.assert_that(signing_service.port).is_equal_to(self.port) assertpy.assert_that(signing_service.initial_reconnect_delay).is_equal_to(self.initial_reconnect_delay)
class TestSigningServiceIncreaseDelay: @pytest.fixture(autouse=True) def setUp(self, unused_tcp_port_factory): self.signing_service = SigningService( '127.0.0.1', unused_tcp_port_factory(), 2, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_initial_reconnect_delay_should_be_set_to_passed_value(self): assertpy.assert_that(self.signing_service.current_reconnect_delay).is_equal_to(None) assertpy.assert_that(self.signing_service.initial_reconnect_delay).is_equal_to(2) def test_that_current_reconnect_delay_should_be_set_to_reconnect_delay_after_first_call_to__increase_delay(self): self.signing_service._increase_delay() assertpy.assert_that(self.signing_service.current_reconnect_delay).is_equal_to(2) def test_that_current_reconnect_delay_should_be_doubled_after_next_call_to__increase_delay(self): self.signing_service._increase_delay() self.signing_service._increase_delay() assertpy.assert_that(self.signing_service.current_reconnect_delay).is_equal_to(2 * 2) def test_that_current_reconnect_delay_should_be_set_to_allowed_maximum_after_it_extends_it(self): self.signing_service.current_reconnect_delay = SIGNING_SERVICE_MAXIMUM_RECONNECT_TIME - 1 self.signing_service._increase_delay() assertpy.assert_that(self.signing_service.current_reconnect_delay).is_equal_to(SIGNING_SERVICE_MAXIMUM_RECONNECT_TIME)
def _prepare_and_execute_handle_connection(self, raw_message): def mocked_generator(): yield raw_message with mock.patch('signing_service.signing_service.SigningService.run'): with closing(socket.socket( socket.AF_INET, socket.SOCK_STREAM)) as signing_service_socket: signing_service_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) with closing(socket.socket( socket.AF_INET, socket.SOCK_STREAM)) as client_socket: client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) # For test purposes we reverse roles, so signing service works as server. signing_service_socket.bind( ('127.0.0.1', self.signing_service_port)) signing_service_socket.listen(1) client_socket.connect( ('127.0.0.1', self.signing_service_port)) (connection, _address) = signing_service_socket.accept() signing_service._authenticate(mocked_generator(), connection) raw_message_received = next( unescape_stream(connection=client_socket)) return raw_message_received
class SigningServiceSetSigtermTestCase(TestCase): def setUp(self): self.host = '127.0.0.1' self.port = 8000 self.initial_reconnect_delay = 2 with mock.patch('signing_service.signing_service.SigningService.run'): self.signing_service = SigningService( self.host, self.port, self.initial_reconnect_delay, CONCENT_PUBLIC_KEY, SIGNING_SERVICE_PRIVATE_KEY, TEST_ETHEREUM_PRIVATE_KEY, SIGNING_SERVICE_DEFAULT_RECONNECT_ATTEMPTS, ConsoleNotifier(), ) def test_that_calling_set_was_sigterm_caught_sets_was_sigterm_caught_to_true(self): self.signing_service._set_was_sigterm_caught_true(mock.Mock(), mock.Mock()) self.assertTrue(self.signing_service.was_sigterm_caught)
if __name__ == '__main__': logging.config.fileConfig( os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'logging.ini')) # Parse required arguments. args = _parse_arguments() raven_client = Client( dsn=args.sentry_dsn, environment=args.sentry_environment, tags={ 'component': 'signing-service', }, ) crash_logger.handlers[0].client = raven_client # type: ignore notifier = get_notifier(args) SigningService( args.concent_cluster_host, args.concent_cluster_port, args.initial_reconnect_delay, args.concent_public_key, args.signing_service_private_key, args.ethereum_private_key, args.max_reconnect_attempts, notifier, ).run()