def test_backend_connection_connect_connection_exception( mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module ): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now ) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader, ) connection.connect() # run state methods during "connected": mock_async_reader.queue_.put("This is the JEP service, listening on port 4711.") assert TIMEOUT_BACKEND_STARTUP > datetime.timedelta(seconds=0) decorate_connection_state_dispatch(connection, 1, mock_datetime_module) # fail connection return value: mock_socket_module.create_connection = mock.MagicMock(side_effect=NotImplementedError) # nothing happens within allowed timeout period: connection.run(datetime.timedelta(seconds=2)) assert connection.state is State.Disconnected assert mock_process.kill.call_count == 1 assert mock_async_reader.join.call_count == 1 assert not connection._process assert not connection._process_output_reader
def test_backend_connection_send_message_send_failed(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock(return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock(NotImplementedError) connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket connection.state = State.Connected # no message is sent if serialization fails, but no exception surfaces either: connection.send_message(mock.sentinel.MESSAGE)
def test_backend_connection_send_message_serialization_failed(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock(side_effect=NotImplementedError) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock() connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket connection.state = State.Connected # no message is sent if serialization fails: connection.send_message(mock.sentinel.MESSAGE) assert not mock_socket.send.called
def test_backend_connection_connect_no_port_announcement( mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader) connection.connect() # run state methods during "connected": mock_async_reader.queue_.put('Nothing special to say.') mock_async_reader.queue_.put('No port announcement whatsoever.') assert TIMEOUT_BACKEND_STARTUP > datetime.timedelta(seconds=0) decorate_connection_state_dispatch(connection, 1, mock_datetime_module) # nothing happens within allowed timeout period: connection.run(TIMEOUT_BACKEND_STARTUP) assert connection.state is State.Connecting # rollback of connection after timeout has expired: connection.run(datetime.timedelta(seconds=2)) assert connection.state is State.Disconnected assert mock_process.kill.call_count == 1 assert mock_async_reader.join.call_count == 1 assert not connection._process assert not connection._process_output_reader
def test_backend_connection_send_message_wrong_state(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock(return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock() connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket # no message is sent in any state that is not connected: for state in {State.Disconnected, State.Connecting, State.Disconnecting}: connection.state = state connection.send_message(mock.sentinel.MESSAGE) assert not mock_serializer.serialize.called assert not mock_socket.send.called
def test_backend_connection_send_message_ok(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock(return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock() connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket connection.state = State.Connected # we have a socket and are connected, so sending the message must go through just fine: connection.send_message(mock.sentinel.MESSAGE) mock_serializer.serialize.assert_called_once_with(mock.sentinel.MESSAGE) mock_socket.send.assert_called_once_with(mock.sentinel.SERIALIZED)
def test_backend_connection_connect(mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now) # reset to unpatched module: mock_os_module.path = path mock_listener = mock.MagicMock() connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [mock_listener], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader) connection.connect() # process and reader thread were started and state is adapted: assert mock_subprocess_module.Popen.call_args[0][0][ 0] == 'folder/somecommand.ext' assert mock_subprocess_module.Popen.call_args[1]['cwd'] == path.abspath( 'somedir') assert mock_async_reader.start.call_count == 1 assert connection.state is State.Connecting assert connection._process is mock_process # no more actions if called again: mock_subprocess_module.Popen.reset_mock() mock_provide_async_reader.reset_mock() connection.connect() assert not mock_subprocess_module.Popen.called assert not mock_provide_async_reader.called assert connection._process is mock_process # run state methods during "connected": mock_async_reader.queue_.put('Nothing special to say.') mock_async_reader.queue_.put( 'This is the JEP service, listening on port 4711. Yes really!') # single step as allowed duration is less than time spent in call: decorate_connection_state_dispatch(connection, 0.6, mock_datetime_module) connection.run(datetime.timedelta(seconds=0.5)) # connection must have been created to port announced before: assert mock_socket_module.create_connection.called assert mock_socket_module.create_connection.call_args[0][0] == ( 'localhost', 4711) assert connection.state is State.Connected mock_listener.on_connection_state_changed.assert_has_calls([ mock.call(State.Disconnected, State.Connecting, connection), mock.call(State.Connecting, State.Connected, connection) ])
def test_backend_connection_connect_connection_exception( mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader) connection.connect() # run state methods during "connected": mock_async_reader.queue_.put( 'This is the JEP service, listening on port 4711.') assert TIMEOUT_BACKEND_STARTUP > datetime.timedelta(seconds=0) decorate_connection_state_dispatch(connection, 1, mock_datetime_module) # fail connection return value: mock_socket_module.create_connection = mock.MagicMock( side_effect=NotImplementedError) # nothing happens within allowed timeout period: connection.run(datetime.timedelta(seconds=2)) assert connection.state is State.Disconnected assert mock_process.kill.call_count == 1 assert mock_async_reader.join.call_count == 1 assert not connection._process assert not connection._process_output_reader
def prepare_connected_mocks(mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now ) mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock(return_value=mock.sentinel.SERIALIZED_SHUTDOWN) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock_serializer, provide_async_reader=mock_provide_async_reader, ) connection.connect() mock_async_reader.queue_.put("This is the JEP service, listening on port 4711") mock_socket = mock.MagicMock() mock_socket_module.create_connection.return_value = mock_socket decorate_connection_state_dispatch(connection, 0.5, mock_datetime_module) connection.run(datetime.timedelta(seconds=0.4)) assert connection.state is State.Connected return connection, mock_process, mock_serializer, mock_socket
def test_backend_connection_connect(mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now ) # reset to unpatched module: mock_os_module.path = path mock_listener = mock.MagicMock() connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [mock_listener], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader, ) connection.connect() # process and reader thread were started and state is adapted: assert mock_subprocess_module.Popen.call_args[0][0][0] == "folder/somecommand.ext" assert mock_subprocess_module.Popen.call_args[1]["cwd"] == path.abspath("somedir") assert mock_async_reader.start.call_count == 1 assert connection.state is State.Connecting assert connection._process is mock_process # no more actions if called again: mock_subprocess_module.Popen.reset_mock() mock_provide_async_reader.reset_mock() connection.connect() assert not mock_subprocess_module.Popen.called assert not mock_provide_async_reader.called assert connection._process is mock_process # run state methods during "connected": mock_async_reader.queue_.put("Nothing special to say.") mock_async_reader.queue_.put("This is the JEP service, listening on port 4711. Yes really!") # single step as allowed duration is less than time spent in call: decorate_connection_state_dispatch(connection, 0.6, mock_datetime_module) connection.run(datetime.timedelta(seconds=0.5)) # connection must have been created to port announced before: assert mock_socket_module.create_connection.called assert mock_socket_module.create_connection.call_args[0][0] == ("localhost", 4711) assert connection.state is State.Connected mock_listener.on_connection_state_changed.assert_has_calls( [ mock.call(State.Disconnected, State.Connecting, connection), mock.call(State.Connecting, State.Connected, connection), ] )
def test_backend_connection_send_message_send_failed(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock( return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock(NotImplementedError) connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket connection.state = State.Connected # no message is sent if serialization fails, but no exception surfaces either: connection.send_message(mock.sentinel.MESSAGE)
def test_backend_connection_send_message_wrong_state(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock( return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock() connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket # no message is sent in any state that is not connected: for state in {State.Disconnected, State.Connecting, State.Disconnecting}: connection.state = state connection.send_message(mock.sentinel.MESSAGE) assert not mock_serializer.serialize.called assert not mock_socket.send.called
def test_backend_connection_send_message_ok(): mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock( return_value=mock.sentinel.SERIALIZED) mock_socket = mock.MagicMock() mock_socket.send = mock.MagicMock() connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, [], serializer=mock_serializer) connection._socket = mock_socket connection.state = State.Connected # we have a socket and are connected, so sending the message must go through just fine: connection.send_message(mock.sentinel.MESSAGE) mock_serializer.serialize.assert_called_once_with(mock.sentinel.MESSAGE) mock_socket.send.assert_called_once_with(mock.sentinel.SERIALIZED)
def test_backend_connection_connect_no_port_announcement( mock_os_module, mock_datetime_module, mock_socket_module, mock_subprocess_module ): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now ) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock.sentinel.SERIALIZER, provide_async_reader=mock_provide_async_reader, ) connection.connect() # run state methods during "connected": mock_async_reader.queue_.put("Nothing special to say.") mock_async_reader.queue_.put("No port announcement whatsoever.") assert TIMEOUT_BACKEND_STARTUP > datetime.timedelta(seconds=0) decorate_connection_state_dispatch(connection, 1, mock_datetime_module) # nothing happens within allowed timeout period: connection.run(TIMEOUT_BACKEND_STARTUP) assert connection.state is State.Connecting # rollback of connection after timeout has expired: connection.run(datetime.timedelta(seconds=2)) assert connection.state is State.Disconnected assert mock_process.kill.call_count == 1 assert mock_async_reader.join.call_count == 1 assert not connection._process assert not connection._process_output_reader
def prepare_connected_mocks(mock_datetime_module, mock_socket_module, mock_subprocess_module): now = datetime.datetime.now() mock_async_reader, mock_process, mock_provide_async_reader, mock_service_config = prepare_connecting_mocks( mock_datetime_module, mock_socket_module, mock_subprocess_module, now) mock_serializer = mock.MagicMock() mock_serializer.serialize = mock.MagicMock( return_value=mock.sentinel.SERIALIZED_SHUTDOWN) connection = BackendConnection( mock.sentinel.FRONTEND, mock_service_config, [], serializer=mock_serializer, provide_async_reader=mock_provide_async_reader) connection.connect() mock_async_reader.queue_.put( 'This is the JEP service, listening on port 4711') mock_socket = mock.MagicMock() mock_socket_module.create_connection.return_value = mock_socket decorate_connection_state_dispatch(connection, 0.5, mock_datetime_module) connection.run(datetime.timedelta(seconds=0.4)) assert connection.state is State.Connected return connection, mock_process, mock_serializer, mock_socket
def test_backend_connection_request_message_no_token_attribute(): connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, []) connection.state = State.Connected with pytest.raises(AttributeError): connection.request_message(Shutdown(), mock.sentinel.DURATION)
def test_backend_connection_initial_state(): connection = BackendConnection(mock.sentinel.FRONTEND, mock.sentinel.SERVICE_CONFIG, mock.sentinel.LISTENERS) assert connection.state is State.Disconnected