async def test_replay_ending_cancels_timeouts(event_loop, replay_deps): mock_merger, mock_sender, _ = replay_deps conf = MockReplayConfig(15, 100) replay = Replay(*replay_deps, conf, 1) exhaust_callbacks(event_loop) replay.close() mock_merger.stop_accepting_connections.assert_called() mock_sender.stop_accepting_connections.assert_called() mock_merger.stop_accepting_connections.reset_mock() mock_sender.stop_accepting_connections.reset_mock() # Replay expects these to end after calling close mock_merger.wait_for_ended._lock.set() mock_sender.wait_for_ended._lock.set() await replay.wait_for_ended() # Did replay stop waiting until merger says there aren't more connections? await asyncio.sleep(1) mock_merger.no_connections_for._lock.set() # Did replay stop waiting for its own timeout? await asyncio.sleep(19) exhaust_callbacks(event_loop) mock_merger.stop_accepting_connections.assert_not_called() mock_sender.stop_accepting_connections.assert_not_called()
async def test_replay_forwarding_connections(event_loop, mock_merger, mock_sender, mock_bookkeeper, mock_conn_plus_head): reader = mock_conn_plus_head(ConnectionHeader.Type.READER, 1) writer = mock_conn_plus_head(ConnectionHeader.Type.WRITER, 1) invalid = mock_conn_plus_head(17, 1) timeout = 15 replay = Replay(mock_merger, mock_sender, mock_bookkeeper, timeout, 1) await replay.handle_connection(*reader) mock_merger.handle_connection.assert_not_awaited() mock_sender.handle_connection.assert_awaited_with(reader[1]) mock_sender.handle_connection.reset_mock() await replay.handle_connection(*writer) mock_sender.handle_connection.assert_not_awaited() mock_merger.handle_connection.assert_awaited_with(writer[1]) mock_merger.handle_connection.reset_mock() with pytest.raises(MalformedDataError): await replay.handle_connection(*invalid) mock_sender.handle_connection.assert_not_awaited() mock_merger.handle_connection.assert_not_awaited() mock_merger._manual_end.set() mock_sender._manual_end.set() await replay.wait_for_ended()
async def test_replay_forwarding_connections(event_loop, replay_deps, mock_conn_plus_head): mock_merger, mock_sender, _ = replay_deps reader = mock_conn_plus_head(ConnectionHeader.Type.READER, 1) writer = mock_conn_plus_head(ConnectionHeader.Type.WRITER, 1) invalid = mock_conn_plus_head(17, 1) conf = MockReplayConfig(15, 100) replay = Replay(*replay_deps, conf, 1) mock_sender.handle_connection._lock.set() mock_merger.handle_connection._lock.set() await replay.handle_connection(*reader) mock_merger.handle_connection.assert_not_awaited() mock_sender.handle_connection.assert_awaited_with(reader[1]) mock_sender.handle_connection.reset_mock() await replay.handle_connection(*writer) mock_sender.handle_connection.assert_not_awaited() mock_merger.handle_connection.assert_awaited_with(writer[1]) mock_merger.handle_connection.reset_mock() with pytest.raises(MalformedDataError): await replay.handle_connection(*invalid) mock_sender.handle_connection.assert_not_awaited() mock_merger.handle_connection.assert_not_awaited() mock_merger.wait_for_ended._lock.set() mock_sender.wait_for_ended._lock.set() await replay.wait_for_ended()
async def test_replay_diverging_replay(event_loop, mock_bookkeeper, controlled_connections): r = Replay.build(1, mock_bookkeeper, replay_config(config_dict)) conns = [controlled_connections() for _ in range(0, 6)] conn_work = [do_write(c, div, 4000) for c, div in zip(conns, diverging_1)] read_conn = controlled_connections() head = ConnectionHeader(ConnectionHeader.Type.WRITER, 1, "foo") read_head = ConnectionHeader(ConnectionHeader.Type.READER, 1, "foo") r_work = [r.handle_connection(head, c) for c in conns] w_work = [r.handle_connection(read_head, read_conn)] # Version 5 is the best for this replay. # We don't require picking a specific header, its dicts have unspecified # order :/ def check_saved(_, s): body_offset = diverging_1[5].header_size assert s.data.bytes() == diverging_1[5].data[body_offset:] mock_bookkeeper.save_replay.side_effect = check_saved await asyncio.gather(*(conn_work + r_work + w_work)) await r.wait_for_ended() # Our current strategy should find replay 5, ignoring header. read_data = read_conn._get_mock_write_data()[diverging_1[5].header_size:] assert read_data == diverging_1[5].main_data
async def test_replay_timeouts_while_ending_dont_explode( event_loop, replay_deps): mock_merger, mock_sender, _ = replay_deps conf = MockReplayConfig(15, 100) replay = Replay(*replay_deps, conf, 1) exhaust_callbacks(event_loop) # Won't finish until we tell mock merger & sender to end f = asyncio.ensure_future(replay.wait_for_ended()) await asyncio.sleep(1) mock_merger.no_connections_for._lock.set() await asyncio.sleep(19) exhaust_callbacks(event_loop) mock_merger.wait_for_ended._lock.set() mock_sender.wait_for_ended._lock.set() await f
async def test_replay_closes_after_timeout(event_loop, replay_deps, mock_conn_plus_head): mock_merger, mock_sender, _ = replay_deps conf = MockReplayConfig(15, 100) replay = Replay(*replay_deps, conf, 1) mock_merger.stop_accepting_connections.assert_not_called() mock_sender.stop_accepting_connections.assert_not_called() writer = mock_conn_plus_head(ConnectionHeader.Type.WRITER, 1) wf = asyncio.ensure_future(replay.handle_connection(*writer)) await asyncio.sleep(20) exhaust_callbacks(event_loop) mock_merger.stop_accepting_connections.assert_called() mock_sender.stop_accepting_connections.assert_called() writer[1].close.assert_called() mock_merger.handle_connection._lock.set() mock_merger.wait_for_ended._lock.set() mock_sender.wait_for_ended._lock.set() await wf await replay.wait_for_ended()
async def test_replay_close_cancels_timeout( event_loop, mock_merger, mock_sender, mock_bookkeeper): timeout = 15 replay = Replay(mock_merger, mock_sender, mock_bookkeeper, timeout, 1) exhaust_callbacks(event_loop) replay.close() mock_merger.close.assert_called() mock_sender.close.assert_called() mock_merger.close.reset_mock() mock_sender.close.reset_mock() # Replay expects these to end after calling close mock_merger._manual_end.set() mock_sender._manual_end.set() await asyncio.sleep(20) exhaust_callbacks(event_loop) mock_merger.close.assert_not_called() mock_sender.close.assert_not_called() mock_merger._manual_end.set() mock_sender._manual_end.set() await replay.wait_for_ended()
async def test_replay_closes_after_timeout( event_loop, mock_merger, mock_sender, mock_bookkeeper): timeout = 15 replay = Replay(mock_merger, mock_sender, mock_bookkeeper, timeout, 1) mock_merger.close.assert_not_called() mock_sender.close.assert_not_called() await asyncio.sleep(20) exhaust_callbacks(event_loop) mock_merger.close.assert_called() mock_sender.close.assert_called() mock_merger._manual_end.set() mock_sender._manual_end.set() await replay.wait_for_ended()
async def test_replay_keeps_proper_event_order( event_loop, mock_merger, mock_sender, mock_bookkeeper): async def bookkeeper_check(*args, **kwargs): # Merging has to end before bookkeeping starts mock_merger.wait_for_ended.assert_awaited() # We shall not wait for stream sending to end before bookkeeping mock_sender.wait_for_ended.assert_not_awaited() return mock_bookkeeper.save_replay.side_effect = bookkeeper_check timeout = 0.1 replay = Replay(mock_merger, mock_sender, mock_bookkeeper, timeout, 1) await exhaust_callbacks(event_loop) mock_merger._manual_end.set() await exhaust_callbacks(event_loop) mock_sender._manual_end.set() await replay.wait_for_ended()
async def test_replay_keeps_proper_event_order(event_loop, mocker, replay_deps): merger, sender, bookkeeper = replay_deps async def bookkeeper_check(game_id, stream): assert stream is merger.canonical_stream # Merging has to end before bookkeeping starts merger.wait_for_ended.assert_awaited() # We shall not wait for stream sending to end before bookkeeping sender.wait_for_ended.assert_not_awaited() return bookkeeper.save_replay.side_effect = bookkeeper_check conf = MockReplayConfig(0.1, 100) replay = Replay(*replay_deps, conf, 1) await exhaust_callbacks(event_loop) merger.wait_for_ended._lock.set() await exhaust_callbacks(event_loop) sender.wait_for_ended._lock.set() await replay.wait_for_ended()
def build(cls, bookkeeper, config): return cls(lambda game_id: Replay.build(game_id, bookkeeper, config))
def test_replay_init(mock_bookkeeper): Replay.build(1, mock_bookkeeper, replay_config(config_dict))
def test_replay_init(mock_bookkeeper): Replay.build(1, mock_bookkeeper, **config)
def build(cls, bookkeeper, **kwargs): return cls(lambda game_id: Replay.build(game_id, bookkeeper, **kwargs))