Пример #1
0
def test_all_finished_handlers_called_despite_one_failing():
    handler_a = MagicMock(spec=ImportOperationHandler)
    handler_b = MagicMock(spec=ImportOperationHandler)

    def handle_finished_a(operation):
        # b is called after we are
        handler_b.on_import_finished.assert_not_called()
        # Our handler fails for some reason...
        raise ValueError('boom')

    def handle_finished_b(operation):
        # a has been called before us (and failed)
        assert handler_a.on_import_finished.call_count == 1

    handler_a.on_import_finished.side_effect = handle_finished_a
    handler_b.on_import_finished.side_effect = handle_finished_b

    with handlers_attached(handler_a, handler_b):
        with pytest.raises(ImportOperationError) as excinfo:
            perform_import('foo', ImportType.FULL_SYNC, [])

        assert str(excinfo.value) == 'handler raised from on_import_finished()'

    assert handler_a.on_import_finished.call_count == 1
    assert handler_b.on_import_finished.call_count == 1
Пример #2
0
def test_all_failed_handlers_called_despite_one_failing():
    '''
    When invoking failed handlers, all get invoked, even if a preceding
    failed handler itself raises an error.
    '''

    handler_a = MagicMock(spec=ImportOperationHandler)
    handler_b = MagicMock(spec=ImportOperationHandler)

    def handle_failed_a(operation):
        # b is called after we are
        handler_b.on_import_failed.assert_not_called()
        # Our handler fails for some reason...
        raise ValueError('boom')

    def handle_failed_b(operation):
        # a has been called before us (and failed)
        assert handler_a.on_import_failed.call_count == 1

    handler_a.on_import_failed.side_effect = handle_failed_a
    handler_b.on_import_failed.side_effect = handle_failed_b

    with handlers_attached(handler_a, handler_b):
        with pytest.raises(ImportOperationError) as excinfo:
            perform_import('foo', ImportType.FULL_SYNC,
                           # Fails due to division by zero
                           (1/0 for _ in [1]))

        assert str(excinfo.value) == 'record generator raised exception'

    assert handler_a.on_import_failed.call_count == 1
    assert handler_b.on_import_failed.call_count == 1
Пример #3
0
def test_import_failed_called_when_record_is_invalid(mock_iop_handler):

    with pytest.raises(ImportOperationError):
        perform_import('foo', ImportType.FULL_SYNC, [object()])

    assert mock_iop_handler.on_record_available.call_count == 0
    assert mock_iop_handler.on_import_finished.call_count == 0
    assert mock_iop_handler.on_import_failed.call_count == 1
Пример #4
0
def test_importop_has_record_and_import_types(record_type, import_type):
    with import_started_receiver(MagicMock()) as mock_handler:
        perform_import(record_type, import_type, [])

        _, kwargs = mock_handler.call_args
        iop = kwargs['sender']

        assert iop.record_type is record_type
        assert iop.import_type is import_type
Пример #5
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
Пример #6
0
def test_import_failed_called_when_record_generator_raises(mock_iop_handler):

    def records():
        yield ImportRecord([ID(1, 1)], 1)
        raise ValueError('boom')

    with pytest.raises(ImportOperationError):
        perform_import('foo', ImportType.FULL_SYNC, records())

    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
Пример #7
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
Пример #8
0
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])
Пример #9
0
def test_import_failed_called_when_import_started_receiver_raises(
        mock_iop_handler):
    '''
    Registered handlers get an import failed event when an import_started
    receiver fails.
    '''

    # Register another import_started receiver which will fail
    def failing_receiver(*args, **kwargs):
        raise ValueError('boom')

    with import_started_receiver(failing_receiver):
        with pytest.raises(ImportOperationError) as excinfo:
            perform_import('foo', ImportType.FULL_SYNC, [])

        assert ('import_started signal receiver raised exception'
                in str(excinfo.value))

    assert mock_iop_handler.on_import_failed.call_count == 1
Пример #10
0
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)
Пример #11
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)
Пример #12
0
def test_import_started_receiver_receives_importop_as_sender():
    with import_started_receiver(MagicMock()) as mock_handler:
        iop = perform_import('foo', ImportType.FULL_SYNC, [])

        _, kwargs = mock_handler.call_args
        assert kwargs['sender'] is iop
Пример #13
0
def test_import_started_event_is_fired():
    with import_started_receiver(MagicMock()) as mock_handler:
        perform_import('foo', ImportType.FULL_SYNC, [])

        assert mock_handler.called_once()
Пример #14
0
def test_import_failed_not_called_on_successful_imports(mock_iop_handler):
    perform_import('foo', ImportType.FULL_SYNC, [])

    assert mock_iop_handler.on_import_finished.call_count == 1
    assert mock_iop_handler.on_import_failed.call_count == 0
Пример #15
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'}