예제 #1
0
def test_new_id_types_can_be_registered():
    class MyID:
        pass

    ID.register(MyID)

    assert isinstance(MyID(), ID)
예제 #2
0
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)}
예제 #3
0
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
예제 #4
0
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
예제 #5
0
 def records():
     yield ImportRecord([ID(1, 1)], 1)
     raise ValueError('boom')
예제 #6
0
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())
예제 #8
0
def test_ids_cant_be_modified(ir):
    with pytest.raises(Exception):
        ir.ids.add(ID(2, 3))
예제 #9
0
def test_ids_field_cant_be_modified(ir):
    with pytest.raises(AttributeError):
        ir.ids = {ID(1, 2)}
예제 #10
0
def ids():
    return [ID(1, 1)]
예제 #11
0
def test_id_has_type_and_value_fields():
    ident = ID('abc', '123')

    assert ident.type == 'abc'
    assert ident.value == '123'
예제 #12
0
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'}