def test_deleted_but_different_remote_timestamp(self, local_client, s3_client): utils.set_local_index( local_client, { "chemistry.txt": { "local_timestamp": 4000, "remote_timestamp": 3000 } }, ) utils.set_s3_index( s3_client, { "chemistry.txt": { "local_timestamp": 6000, "remote_timestamp": 6000 } }, ) utils.set_s3_contents(s3_client, "chemistry.txt", timestamp=6000) worker = sync.SyncWorker(local_client, s3_client) resolutions, unhandled_events = worker.get_sync_states() expected_unhandled_events = { "chemistry.txt": ( SyncState(SyncState.DELETED, None, 3000), SyncState(SyncState.NOCHANGES, 6000, 6000), ) } assert resolutions == {} assert unhandled_events == expected_unhandled_events
def test_updated_but_different_remote_timestamp(self, local_client, s3_client): utils.set_local_index(local_client, { 'biology.txt': { 'local_timestamp': 4000, 'remote_timestamp': 3000, } }) utils.set_s3_index(s3_client, { 'biology.txt': { 'local_timestamp': 6000, 'remote_timestamp': 6000, } }) utils.set_local_contents(local_client, 'biology.txt', timestamp=4500) utils.set_s3_contents(s3_client, 'biology.txt', timestamp=6000) worker = sync.SyncWorker(local_client, s3_client) resolutions, unhandled_events = worker.get_sync_states() expected_unhandled_events = { 'biology.txt': ( SyncState(SyncState.UPDATED, 4500, 3000), SyncState(SyncState.NOCHANGES, 6000, 6000) ) } assert resolutions == {} assert unhandled_events == expected_unhandled_events
def test_skip(self, get_input, s3_client, local_client): get_input.return_value = "X" action_1 = SyncState(SyncState.UPDATED, 1111, 2222) action_2 = SyncState(SyncState.DELETED, 3333, 4444) result = handle_conflict("movie", action_1, s3_client, action_2, local_client) assert result is None
def test_second_choice(self, get_input, s3_client, local_client): get_input.return_value = "2" action_1 = SyncState(SyncState.UPDATED, 1111, 2222) action_2 = SyncState(SyncState.DELETED, 3333, 4444) result = handle_conflict("movie", action_1, s3_client, action_2, local_client) assert result.action == Resolution.DELETE
def test_diff(self, show_diff, get_input, s3_client, local_client): get_input.side_effect = ["d", "X"] action_1 = SyncState(SyncState.UPDATED, 1111, 2222) action_2 = SyncState(SyncState.DELETED, 3333, 4444) result = handle_conflict("movie", action_1, s3_client, action_2, local_client) assert result is None assert show_diff.call_count == 1 show_diff.assert_called_with(s3_client, local_client, "movie")
def test_first_choice(self, get_input, s3_client, local_client): get_input.return_value = '1' action_1 = SyncState(SyncState.UPDATED, 1111, 2222) action_2 = SyncState(SyncState.DELETED, 3333, 4444) result = cli.handle_conflict( 'movie', action_1, s3_client, action_2, local_client, ) assert result.action == Resolution.UPDATE
def test_repr(self): action = SyncState(SyncState.UPDATED, 1000, 53434) assert repr( action) == "SyncState<UPDATED, local={}, remote={}>".format( datetime.datetime.utcfromtimestamp(1000), datetime.datetime.utcfromtimestamp(53434), )
def test_conflict(self): actual_state = get_sync_state( index_local=6000, real_local=5000, remote=6000, ) expected_state = SyncState(SyncState.CONFLICT, 6000, 6000) assert actual_state == expected_state
def test_created(self): actual_state = get_sync_state( index_local=None, real_local=6000, remote=None, ) expected_state = SyncState(SyncState.CREATED, 6000, None) assert actual_state == expected_state
def test_updated(self): actual_state = get_sync_state( index_local=5000, real_local=6000, remote=5000, ) expected_state = SyncState(SyncState.UPDATED, 6000, 5000) assert actual_state == expected_state
def test_already_deleted(self): actual_state = get_sync_state( index_local=None, real_local=None, remote=77777, ) expected_state = SyncState(SyncState.DELETED, None, 77777) assert actual_state == expected_state
def test_deleted(self): actual_state = get_sync_state( index_local=90000, real_local=None, remote=90000, ) expected_state = SyncState(SyncState.DELETED, None, 90000) assert actual_state == expected_state
def test_no_changes(self): actual_state = get_sync_state( index_local=8130, real_local=8130, remote=8130, ) expected_state = SyncState(SyncState.NOCHANGES, 8130, 8130) assert actual_state == expected_state
def test_ignores_floating_precision(self): actual_state = get_sync_state( index_local=8000.80, real_local=8000.32, remote=6000, ) expected_state = SyncState(SyncState.NOCHANGES, 8000, 6000) assert actual_state == expected_state
def test_diff(self, show_diff, get_input, s3_client, local_client): get_input.side_effect = FakeInputStream([ 'd', 'X', ]) action_1 = SyncState(SyncState.UPDATED, 1111, 2222) action_2 = SyncState(SyncState.DELETED, 3333, 4444) result = cli.handle_conflict( 'movie', action_1, s3_client, action_2, local_client, ) assert result is None assert show_diff.call_count == 1 show_diff.assert_called_with(s3_client, local_client, 'movie')
def test_non_equality(self): assert SyncState(SyncState.UPDATED, 10, 30) != SyncState( SyncState.DELETED, 10, 30) assert SyncState(SyncState.DELETED, 20, 20) != SyncState( SyncState.DELETED, 40, 20) assert SyncState(SyncState.CONFLICT, 20, 20) != SyncState( SyncState.CONFLICT, 20, 40)
def test_get_resolution_updated(self, state, action, s3_client, local_client): sync_state = SyncState(state, 1234, 4567) resolution = Resolution.get_resolution('foo/bar', sync_state, s3_client, local_client) assert resolution.action == action assert resolution.to_client == s3_client assert resolution.key == 'foo/bar' if state != SyncState.DELETED: assert resolution.timestamp == 1234 assert resolution.from_client == local_client else: assert resolution.timestamp == 4567 assert resolution.from_client is None
def get_states(self, keys=None): client_1_actions = self.client_1.get_all_actions() client_2_actions = self.client_2.get_all_actions() all_keys = set(client_1_actions) | set(client_2_actions) self.logger.debug( '%s keys in total (%s for %s and %s for %s)', len(all_keys), len(client_1_actions), self.client_1.get_uri(), len(client_2_actions), self.client_2.get_uri() ) if keys is None: target_keys = sorted(all_keys) else: target_keys = keys DOES_NOT_EXIST = SyncState(SyncState.DOESNOTEXIST, None, None) for key in target_keys: action_1 = client_1_actions.get(key, DOES_NOT_EXIST) action_2 = client_2_actions.get(key, DOES_NOT_EXIST) yield key, action_1, action_2
def test_correct_output(self, local_client, s3_client): utils.set_local_index( local_client, { "chemistry.txt": { "local_timestamp": 9431, "remote_timestamp": 9431 }, "physics.txt": { "local_timestamp": 10000, "remote_timestamp": 10000 }, "maltese.txt": { "local_timestamp": 7000, "remote_timestamp": 6000 }, }, ) utils.set_s3_index( s3_client, { "chemistry.txt": { "local_timestamp": 10000, "remote_timestamp": 9431 }, "physics.txt": { "local_timestamp": 13000, "remote_timestamp": 12000 }, "maltese.txt": { "local_timestamp": 6000, "remote_timestamp": 6000 }, }, ) utils.set_local_contents(local_client, "history.txt", timestamp=5000) utils.set_s3_contents(s3_client, "art.txt", timestamp=200000) utils.set_local_contents(local_client, "english.txt", timestamp=90000) utils.set_s3_contents(s3_client, "english.txt", timestamp=93000) utils.set_s3_contents(s3_client, "chemistry.txt", timestamp=10000) utils.set_local_contents(local_client, "physics.txt", timestamp=11000) utils.set_s3_contents(s3_client, "physics.txt", timestamp=13000) utils.set_local_contents(local_client, "maltese.txt", timestamp=7000) utils.set_s3_contents(s3_client, "maltese.txt", timestamp=8000) worker = sync.SyncWorker(local_client, s3_client) resolutions, unhandled_events = worker.get_sync_states() expected_unhandled_events = { "english.txt": ( SyncState(SyncState.CREATED, 90000, None), SyncState(SyncState.CREATED, 93000, None), ), "physics.txt": ( SyncState(SyncState.UPDATED, 11000, 10000), SyncState(SyncState.NOCHANGES, 13000, 12000), ), } expected_resolutions = { "maltese.txt": Resolution(Resolution.UPDATE, local_client, s3_client, "maltese.txt", 8000), "chemistry.txt": Resolution(Resolution.DELETE, s3_client, None, "chemistry.txt", 9431), "history.txt": Resolution(Resolution.CREATE, s3_client, local_client, "history.txt", 5000), "art.txt": Resolution(Resolution.CREATE, local_client, s3_client, "art.txt", 200000), } assert unhandled_events == expected_unhandled_events assert resolutions == expected_resolutions
def test_unknown(self, local_client, s3_client): state = SyncState("unkonwn state", None, None) with pytest.raises(ValueError): sync.get_resolution("test", state, local_client, s3_client)
def test_equality_with_wrong_type(self): action = SyncState(SyncState.DELETED, 1000, 3000) assert action != 10 assert action != "hello"
def test_correct_output(self, local_client, s3_client): utils.set_local_index(local_client, { 'chemistry.txt': { 'local_timestamp': 9431, 'remote_timestamp': 9431, }, 'physics.txt': { 'local_timestamp': 10000, 'remote_timestamp': 10000, }, 'maltese.txt': { 'local_timestamp': 7000, 'remote_timestamp': 6000, }, }) utils.set_s3_index(s3_client, { 'chemistry.txt': { 'local_timestamp': 10000, 'remote_timestamp': 9431, }, 'physics.txt': { 'local_timestamp': 13000, 'remote_timestamp': 12000, }, 'maltese.txt': { 'local_timestamp': 6000, 'remote_timestamp': 6000, }, }) utils.set_local_contents(local_client, 'history.txt', timestamp=5000) utils.set_s3_contents(s3_client, 'art.txt', timestamp=200000) utils.set_local_contents(local_client, 'english.txt', timestamp=90000) utils.set_s3_contents(s3_client, 'english.txt', timestamp=93000) utils.set_s3_contents(s3_client, 'chemistry.txt', timestamp=10000) utils.set_local_contents(local_client, 'physics.txt', timestamp=11000) utils.set_s3_contents(s3_client, 'physics.txt', timestamp=13000) utils.set_local_contents(local_client, 'maltese.txt', timestamp=7000) utils.set_s3_contents(s3_client, 'maltese.txt', timestamp=8000) worker = sync.SyncWorker(local_client, s3_client) resolutions, unhandled_events = worker.get_sync_states() expected_unhandled_events = { 'english.txt': ( SyncState(SyncState.CREATED, 90000, None), SyncState(SyncState.CREATED, 93000, None) ), 'physics.txt': ( SyncState(SyncState.UPDATED, 11000, 10000), SyncState(SyncState.NOCHANGES, 13000, 12000), ) } expected_resolutions = { 'maltese.txt': Resolution( Resolution.UPDATE, local_client, s3_client, 'maltese.txt', 8000 ), 'chemistry.txt': Resolution( Resolution.DELETE, s3_client, None, 'chemistry.txt', 9431 ), 'history.txt': Resolution( Resolution.CREATE, s3_client, local_client, 'history.txt', 5000 ), 'art.txt': Resolution( Resolution.CREATE, local_client, s3_client, 'art.txt', 200000 ), } assert unhandled_events == expected_unhandled_events assert resolutions == expected_resolutions
def test_invalid_sync_state(self): with pytest.raises(ValueError) as exc: Resolution.get_resolution('', SyncState('Invalid', None, None), None, None) assert exc.value
def test_equality_with_self(self): action = SyncState(SyncState.UPDATED, 1000, 53434) assert action == action
def test_get_remote_datetime_missing(self): action = SyncState(SyncState.CREATED, None, None) assert action.get_remote_datetime() is None
def test_get_local_datetime_missing(self): action = SyncState(SyncState.UPDATED, None, None) assert action.get_local_datetime() is None
def test_does_not_exist(self): assert get_sync_state(None, None, None) == SyncState(SyncState.DOESNOTEXIST, None, None)