Exemple #1
0
def test_synchronization_coordinator_with_multiobject_exception():
    mo = MultiObject(range(3))

    executed = []

    class MyException(Exception):
        pass

    def foo(i, _sync=SYNC):
        def execute(caption):
            executed.append((i, caption))

        _sync.wait_for_everyone()
        execute('after wait')

        if i == 2:
            raise MyException

        _sync.wait_for_everyone()
        execute('after wait/abandon')

    with pytest.raises(MultiException) as exc:
        mo.call(foo)
    assert exc.value.count == 1
    assert exc.value.common_type is MyException

    verify_concurrent_order(executed, {(i, 'after wait')
                                       for i in range(3)},
                            {(i, 'after wait/abandon')
                             for i in range(2)})
Exemple #2
0
def test_synchronization_coordinator_abandon():
    mo = MultiObject(range(3))

    sync = SynchronizationCoordinator(len(mo))
    executed = []

    def foo(i):
        def execute(caption):
            executed.append((i, caption))

        sync.wait_for_everyone()
        execute('after wait 1')

        if i == 2:
            sync.abandon()
            return
        # Only two waiters should reach here
        sync.wait_for_everyone()
        execute('after wait 2')

        # Even without explicit call to abandon, sync should only wait for two waiters
        sync.wait_for_everyone()
        execute('after wait 3')

    mo.call(foo)
    verify_concurrent_order(executed, {(i, 'after wait 1')
                                       for i in range(3)}, {(i, 'after wait 2')
                                                            for i in range(2)},
                            {(i, 'after wait 3')
                             for i in range(2)})
Exemple #3
0
def test_synchronization_coordinator_with_multiobject():
    mo = MultiObject(range(3))

    executed = []

    def foo(i, _sync=SYNC):
        def execute(caption):
            executed.append((i, caption))

        sleep(i / 10)
        _sync.wait_for_everyone()
        execute('after wait')

        def func_to_call_once(param):
            executed.append('params = %s' % sorted(param))
            return sum(param)

        result = _sync.collect_and_call_once(i + 1, func_to_call_once)
        execute('result is %s' % result)

    foo(10)
    assert executed == [(10, 'after wait'), 'params = [11]',
                        (10, 'result is 11')]
    executed.clear()

    mo.call(foo)
    verify_concurrent_order(executed, {(i, 'after wait')
                                       for i in range(3)},
                            {'params = [1, 2, 3]'}, {(i, 'result is 6')
                                                     for i in range(3)})
Exemple #4
0
def test_synchronization_coordinator_collect_and_call_once():
    mo = MultiObject(range(3))

    sync = SynchronizationCoordinator(len(mo))
    executed = []

    def foo(i):
        def execute(caption):
            executed.append((i, caption))

        sleep(i / 10)

        def func_to_call_once(param):
            executed.append('params = %s' % sorted(param))
            return sum(param)

        result = sync.collect_and_call_once(i + 1, func_to_call_once)
        execute('result is %s' % result)

        assert sync.collect_and_call_once(
            i, len) == 3, 'parameters remain from previous call'

    mo.call(foo)
    verify_concurrent_order(executed, {'params = [1, 2, 3]'},
                            {(i, 'result is 6')
                             for i in range(3)})
Exemple #5
0
def test_synchronization_coordinator_wait_for_everyone():
    mo = MultiObject(range(3))

    sync = SynchronizationCoordinator(len(mo))
    executed = []

    def foo(i):
        def execute(caption):
            executed.append((i, caption))

        sleep(i / 10)
        execute('after sleep')
        sync.wait_for_everyone()
        execute('after wait')
        sync.wait_for_everyone()

        sleep(i / 10)
        execute('after sleep 2')
        sync.wait_for_everyone()
        execute('after wait 2')

    mo.call(foo)
    verify_concurrent_order(executed, {(i, 'after sleep')
                                       for i in range(3)}, {(i, 'after wait')
                                                            for i in range(3)},
                            {(i, 'after sleep 2')
                             for i in range(3)}, {(i, 'after wait 2')
                                                  for i in range(3)})
Exemple #6
0
def test_synchronization_coordinator_timeout():
    mo = MultiObject(range(3))

    def foo(i, _sync=SYNC):
        sleep(i / 10)
        _sync.wait_for_everyone(timeout=0.1)

    with pytest.raises(MultiException) as exc:
        mo.call(foo)
    assert exc.value.count == len(mo)
    assert exc.value.common_type is threading.BrokenBarrierError
Exemple #7
0
def test_multiobject_logging():
    m = MultiObject(range(4), log_ctx="abcd", initial_log_interval=0.1)

    def check(i):
        sleep(.2)

    # we'll mock the logger so we can ensure it logged
    with patch("easypy.concurrency._logger") as _logger:
        m.call(check)

    args_list = (c[0] for c in _logger.info.call_args_list)
    for args in args_list:
        assert "test_multiobject_logging.<locals>.check" == args[2]
        assert "easypy/tests/test_concurrency.py" in args[4]
Exemple #8
0
def test_synchronization_coordinator_with_context_manager():
    mo = MultiObject(range(3))

    executed = []

    @contextmanager
    def foo(i, _sync=SYNC):
        def execute(caption):
            executed.append((i, caption))

        sleep(i / 10)
        execute('after sleep')
        _sync.wait_for_everyone()
        execute('before yield')
        yield
        _sync.wait_for_everyone()
        execute('after yield')

    with mo.call(foo):
        executed.append('with body')

    verify_concurrent_order(executed, {(i, 'after sleep')
                                       for i in range(3)}, {(i, 'before yield')
                                                            for i in range(3)},
                            {'with body'}, {(i, 'after yield')
                                            for i in range(3)})
Exemple #9
0
def test_multiobject_1():
    m = MultiObject(range(10))

    def mul(a, b, *c):
        return a * b + sum(c)

    assert sum(m.call(mul, 2)) == 90
    assert sum(m.call(mul, b=10)) == 450
    assert sum(m.call(mul, 1, 1, 1)) == 65

    assert m.filter(None).T == (1, 2, 3, 4, 5, 6, 7, 8, 9)
    assert sum(m.denominator) == 10
    with pytest.raises(MultiException) as info:
        m.call(lambda i: 1 / (i % 2))

    assert info.value.count == 5
    assert info.value.common_type == ZeroDivisionError
    assert not info.value.complete
Exemple #10
0
def test_synchronization_coordinator_exception_in_collect_and_call_once():
    mo = MultiObject(range(3))

    sync = SynchronizationCoordinator(len(mo))
    times_called = 0

    class MyException(Exception):
        pass

    def foo(i):
        def func_to_call_once(_):
            nonlocal times_called
            times_called += 1
            raise MyException

        with pytest.raises(MyException):
            sync.collect_and_call_once(i, func_to_call_once)

        assert sync.collect_and_call_once(i + 1, sum) == 6

    mo.call(foo)
    assert times_called == 1, 'collect_and_call_once with exception called the function more than once'
Exemple #11
0
def test_synchronization_coordinator_with_multiobject_early_return():
    mo = MultiObject(range(3))

    executed = []

    def foo(i, _sync=SYNC):
        def execute(caption):
            executed.append((i, caption))

        _sync.wait_for_everyone()
        execute('after wait')

        if i == 2:
            return

        _sync.wait_for_everyone()
        execute('after wait/abandon')

    mo.call(foo)

    verify_concurrent_order(executed, {(i, 'after wait')
                                       for i in range(3)},
                            {(i, 'after wait/abandon')
                             for i in range(2)})