def test_new_id_types_can_be_registered(): class MyID: pass ID.register(MyID) assert isinstance(MyID(), ID)
def test_duplicate_ids_are_ignored(data_obj): ir = ImportRecord([ ID(1, 2), ID(1, 2), ID(1, 3), ID(1, 3), ID(2, 3), ID(2, 3), ], data_obj) assert ir.ids == {ID(1, 2), ID(1, 3), ID(2, 3)}
def test_import_failed_called_when_handler_raises(mock_iop_handler): mock_iop_handler.on_record_available.side_effect = ValueError('boom') with pytest.raises(ImportOperationError): perform_import('foo', ImportType.FULL_SYNC, [ ImportRecord([ID(1, 1)], 1) ]) assert mock_iop_handler.on_record_available.call_count == 1 assert mock_iop_handler.on_import_finished.call_count == 0 assert mock_iop_handler.on_import_failed.call_count == 1
def test_handlers_get_call_to_finished_func_after_records(mock_iop_handler): def assert_finished_not_called(iop, record): mock_iop_handler.on_import_finished.assert_not_called() mock_iop_handler.on_record_available.side_effect = \ assert_finished_not_called perform_import('foo', ImportType.FULL_SYNC, [ImportRecord([ID(1, 1)], 1)]) assert mock_iop_handler.on_record_available.call_count == 1 assert mock_iop_handler.on_import_finished.call_count == 1
def records(): yield ImportRecord([ID(1, 1)], 1) raise ValueError('boom')
def test_import_type_must_be_importtype_instances(import_type): with pytest.raises(ValueError) as excinfo: perform_import('foo', import_type, []) assert 'import_type was not an ImportType' in str(excinfo.value) def test_records_must_be_importrecord_instances(): with pytest.raises(ImportOperationError) as exc_info: perform_import('foo', ImportType.FULL_SYNC, [object()]) assert isinstance(exc_info.value.__cause__, ValueError) @pytest.mark.parametrize('records', [ [ImportRecord([ID('foo', 'x-{}'.format(x))], x) for x in [1, 2, 3]], # Generators work too (ImportRecord([ID('foo', 'x-{}'.format(x))], x) for x in [object(), object(), object()]) ]) def test_records_are_provided_to_handlers_registered_with_importop( mock_iop_handler, records): # tee in case it's a one shot generator in_records, expected_records = itertools.tee(records) iop = perform_import('foo', ImportType.FULL_SYNC, in_records) mock_iop_handler.on_record_available.assert_has_calls([ call(iop, record) for record in expected_records])
def record(): return ImportRecord([ID(1, 1)], object())
def test_ids_cant_be_modified(ir): with pytest.raises(Exception): ir.ids.add(ID(2, 3))
def test_ids_field_cant_be_modified(ir): with pytest.raises(AttributeError): ir.ids = {ID(1, 2)}
def ids(): return [ID(1, 1)]
def test_id_has_type_and_value_fields(): ident = ID('abc', '123') assert ident.type == 'abc' assert ident.value == '123'
def test_integration(): # A mock "database" of records db = dict() # The generator which def record_handler(import_operation, records): to_update = dict() to_remove = set() for record in records: fid = get_f_id(record) if record.is_deleted(): to_remove.add(fid) else: to_update[fid] = record.data # Yield is required to allow the next record to be made available # and allow other handlers to run. An exception is rail yield if import_operation.import_type is ImportType.FULL_SYNC: db.clear() else: for fid in to_remove: del db[fid] db.update(to_update) def import_listener(*args, sender=None, **kwargs): import_op = sender # We're handling the all-important foo records if import_op.record_type != 'foo': return handler = GeneratorImportOperationHandler(import_op, record_handler) import_op.attach_handler(handler) # Can use @receiver(import_started) decorator in normal app with import_started_receiver(import_listener): # Not a type we're interested in - these get ignored perform_import('bar', ImportType.FULL_SYNC, [ImportRecord([ID('x', 0)], object())]) assert len(db) == 0 perform_import('foo', ImportType.FULL_SYNC, [ ImportRecord([ID('f', 'a')], 'abc'), ImportRecord([ID('f', 'd')], 'def'), ]) assert db == {'a': 'abc', 'd': 'def'} # Update/delete just what's specified perform_import( 'foo', ImportType.PARTIAL_UPDATE, [ # Delete this ImportRecord([ID('f', 'd')], None), # Add these ImportRecord([ID('f', 'g')], 'ghi'), ImportRecord([ID('f', 'j')], 'jkl'), ]) assert db == {'a': 'abc', 'g': 'ghi', 'j': 'jkl'} # Replace everything perform_import('foo', ImportType.FULL_SYNC, [ ImportRecord([ID('f', 'm')], 'mno'), ImportRecord([ID('f', 'p')], 'pqr'), ]) assert db == {'m': 'mno', 'p': 'pqr'}