Ejemplo n.º 1
0
def test_multifirst():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver(wait_value):
        value = yield tap.Receive('key', lambda x: x == wait_value)
        return value

    def fn():
        strand_1 = yield tap.CallFork(receiver, (1, ))
        strand_2 = yield tap.CallFork(receiver, (2, ))
        strand_3 = yield tap.CallFork(receiver, (3, ))
        results = yield tap.Fork([
            tap.First([strand_1, strand_2, strand_3]),
            tap.First([strand_2, strand_1]),
        ])
        yield tap.Call(broadcaster, (5, ))
        yield tap.Call(broadcaster, (3, ))
        yield tap.Call(broadcaster, (1, ))
        value = yield tap.Join(results)
        return value

    # the first race resolves first, thus cancelling strands 1 and 2, preventing the second from ever finishing
    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    assert str(x.value).startswith("Hanging strands")
Ejemplo n.º 2
0
def test_lock_cancel_mid_acquire():
    a = 0

    lock = tap.Lock()

    def acquire():
        release = yield lock.Acquire()
        nonlocal a
        a += 5
        yield tap.Receive("unlock")
        yield release

    def fn():
        yield tap.CallFork(acquire)
        t = yield tap.CallFork(acquire)
        yield tap.CallFork(acquire)
        yield tap.Sleep(0)
        assert a == 5

        yield tap.Cancel(t)
        yield tap.Broadcast("unlock")
        yield tap.Sleep(0.01)
        assert a == 10

        yield tap.Broadcast("unlock")
        yield tap.Sleep(0.001)
        assert a == 10

    tap.run(fn)
Ejemplo n.º 3
0
def test_call_thread():
    a = 0

    cv = threading.Condition()

    def thread_fn():
        nonlocal a
        for _ in range(2):
            with cv:
                cv.wait()
            a += 1
            with cv:
                cv.notify()
        return "done"

    def fn():
        t = yield tap.Fork(tap.CallThread(thread_fn))
        yield tap.Sleep(0.01)
        assert a == 0
        with cv:
            cv.notify()
            cv.wait()
        assert a == 1
        with cv:
            cv.notify()
            cv.wait()
        assert a == 2
        with cv:
            cv.notify()
        assert a == 2

        assert (yield tap.Join(t)) == "done"

    tap.run(fn)
Ejemplo n.º 4
0
def test_multifirst_canceled():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver(wait_value):
        value = yield tap.Receive('key', lambda x: x == wait_value)
        return value

    def fn():
        strand_1 = yield tap.CallFork(receiver, (1, ))
        strand_2 = yield tap.CallFork(receiver, (2, ))
        strand_3 = yield tap.CallFork(receiver, (3, ))
        results = yield tap.Fork([
            tap.First([strand_1, strand_2], name="1v2"),
            tap.First([strand_2, strand_3], name="2v3"),
        ])
        yield tap.Call(broadcaster, (5, ))
        yield tap.Call(broadcaster, (1, ))
        yield tap.Call(broadcaster, (3, ))
        value = yield tap.Join(results, name="joinfork")
        yield tap.Join(strand_2, name="joincanceled")
        return value

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    # TODO: always do the child strand
    assert str(x.value).startswith(
        "Hanging strands detected waiting for Race(Join(joincanceled))"
    ) or str(x.value).startswith("Hanging strands detected waiting for Join")
Ejemplo n.º 5
0
def test_intercept_nontest():
    def fn():
        yield tap.Intercept()

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    assert str(x.value).startswith("Cannot intercept outside of test mode")
Ejemplo n.º 6
0
def test_race_threads():
    def fn():
        winner, r = yield tap.Race(
            dict(long=tap.Sleep(0.03), short=tap.Sleep(0.02)))
        assert winner == "short"

    tap.run(fn)
Ejemplo n.º 7
0
def test_intercept_cancel_too_late():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver():
        value = yield tap.Receive('key')
        return value

    def intercepter():
        (effect,
         inject) = yield tap.Intercept(lambda e: isinstance(e, tap.Receive))
        assert effect.key == "key"
        yield inject("real")

    def fn():
        intercept_strand = yield tap.CallFork(intercepter)
        yield tap.Cancel(intercept_strand)
        recv_strand = yield tap.CallFork(receiver)
        # even though this is forked, it doesn't end up hanging
        yield tap.Call(broadcaster, (5, ))
        # this gets intercepted and never gets injected
        yield tap.Join(recv_strand)

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn, test_mode=True)
    # print(x.value)
    assert str(x.value).startswith(
        "Hanging strands detected waiting for Race(Join") or str(
            x.value
        ).startswith("Hanging strands detected waiting for Join") or str(
            x.value).startswith("Hanging strands detected waiting for Receive")
Ejemplo n.º 8
0
def test_error_stack():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver():
        value = yield tap.Receive('key')
        if value < 10:
            broadcast_strand = yield tap.CallFork(broadcaster, (value + 1, ))
            receive_strand = yield tap.CallFork(receiver)
            yield tap.Join([broadcast_strand, receive_strand])
        raise Exception("too large")
        return value

    def fn():
        # fork in apparently wrong order!
        broadcast_strand = yield tap.CallFork(broadcaster, (5, ))
        recv_strand = yield tap.CallFork(receiver)
        yield tap.Join(broadcast_strand)
        value = yield tap.Join(recv_strand)
        return value

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    # print(x.value)
    assert str(x.value).startswith("Exception caught at")
    assert str(x.value).count(", in receiver\n") == 6
Ejemplo n.º 9
0
def test_queues_get_then_put():
    q = tap.Queue(buffer_size=1)
    a = 0

    def pop_and_add():
        nonlocal a
        b = yield q.Get()
        a += b

    def fn():
        assert not q.has_work()
        t1 = yield tap.CallFork(pop_and_add)
        t2 = yield tap.CallFork(pop_and_add)
        t3 = yield tap.CallFork(pop_and_add)
        yield tap.Sleep(0)
        assert a == 0
        yield q.Put(3)
        assert a == 3

        yield tap.Cancel(t2)
        yield q.Put(5)
        assert a == 8

        yield q.Put(5)
        assert a == 8

        t4 = yield tap.CallFork(pop_and_add)
        yield tap.Sleep(0)
        assert a == 13

        yield tap.Join([t1, t3, t4])

    tap.run(fn)
Ejemplo n.º 10
0
def test_bad_yield():
    def fn():
        yield 3

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    assert str(x.value).startswith("Strand yielded non-effect")
Ejemplo n.º 11
0
def test_immediate_thread():
    def fn():
        def fast():
            pass

        yield tap.Race([tap.CallThread(fast)])

    tap.run(fn)
Ejemplo n.º 12
0
def test_sleep():
    def fn():
        t = time.time()
        yield tap.Sleep(0.01)
        assert time.time() - t > 0.01
        t = time.time()
        yield tap.Sleep(0)
        assert time.time() - t < 0.01

    tap.run(fn)
Ejemplo n.º 13
0
def test_no_arg():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def fn():
        yield tap.CallFork(broadcaster)
        return

    with pytest.raises(TypeError):
        tap.run(fn)
Ejemplo n.º 14
0
def test_tricky_cancel():
    def wake_and_fork():
        yield tap.Fork(tap.Broadcast("wake"))
        yield tap.Fork(tap.Receive("hmm"))

    def fn():
        task = yield tap.CallFork(wake_and_fork)
        yield tap.Receive("wake")
        yield tap.Cancel(task)

    tap.run(fn)
Ejemplo n.º 15
0
def test_lock_hang():
    lock = tap.Lock()

    def fn():
        yield lock.Acquire()
        yield lock.Acquire()

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    # TODO fix
    assert str(x.value).startswith("Hanging strands detected waiting for Receive(lock") or \
        str(x.value).startswith("Hanging strands detected waiting for Call(Acquire")
Ejemplo n.º 16
0
def test_queues_put_then_get_no_buffer():
    q = tap.Queue(buffer_size=0)

    def fn():
        assert not q.has_work()
        t = yield tap.Fork(q.Put(3))
        yield tap.Sleep(0.01)
        assert q.has_work()
        assert (yield q.Get()) == 3
        yield tap.Join(t)

    tap.run(fn)
Ejemplo n.º 17
0
def test_create_acquires_out_of_order():
    lock = tap.Lock()

    def fn():
        a1 = lock.Acquire()
        a2 = lock.Acquire()
        r2 = yield a2
        yield r2
        r1 = yield a1
        yield r1

    tap.run(fn)
Ejemplo n.º 18
0
def test_queues_put_then_get():
    q = tap.Queue(buffer_size=2)

    def fn():
        assert not q.has_work()
        # we have buffer so a put is fine
        yield q.Put(3)
        yield q.Put(5)
        assert q.has_work()
        assert (yield q.Get()) == 3
        assert (yield q.Get()) == 5
        yield q.Put(3)
        yield q.Put(5)

    tap.run(fn)
Ejemplo n.º 19
0
def test_call_trivial():
    def random(value):
        return 10

    def fn():
        x = yield tap.Call(random, (5, ))
        return x

    def fork_fn():
        strand = yield tap.CallFork(random, (5, ))
        x = yield tap.Join(strand)
        return x

    assert tap.run(fn) == 10
    assert tap.run(fork_fn) == 10
    assert tap.run(random, args=(5, )) == 10
Ejemplo n.º 20
0
def test_intercept_cancel():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver():
        value = yield tap.Receive('key')
        return value

    def intercepter():
        (effect, inject) = yield tap.Intercept(lambda e: False)
        (effect,
         inject) = yield tap.Intercept(lambda e: isinstance(e, tap.Receive))
        assert effect.key == "key"
        yield inject("real")

    def fn():
        intercept_strand = yield tap.CallFork(intercepter)
        yield tap.Cancel(intercept_strand)
        recv_strand = yield tap.CallFork(receiver)
        # even though this is forked, it doesn't end up hanging
        yield tap.Call(broadcaster, (5, ))
        value = yield tap.Join(recv_strand)
        assert value == 5  # did *not* get intercepted
        return value

    assert tap.run(fn, test_mode=True) == 5  # got intercepted
Ejemplo n.º 21
0
def test_immediate_return():
    def fn():
        if False:
            yield
        return 3

    assert tap.run(fn) == 3
Ejemplo n.º 22
0
def test_multifirst_no_cancel():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver(wait_value):
        value = yield tap.Receive('key', lambda x: x == wait_value)
        return value

    def fn():
        strand_1 = yield tap.CallFork(receiver, (1, ))
        strand_2 = yield tap.CallFork(receiver, (2, ))
        strand_3 = yield tap.CallFork(receiver, (3, ))
        results = yield tap.Fork([
            tap.First([strand_1, strand_2], name="1v2", cancel_losers=False),
            tap.First([strand_2, strand_3], name="2v3", cancel_losers=False),
        ])
        yield tap.Call(broadcaster, (5, ))
        yield tap.Call(broadcaster, (1, ))
        yield tap.Call(broadcaster, (3, ))
        value = yield tap.Join(results, name="joinfork")
        yield tap.Call(broadcaster, (2, ))
        yield tap.Join(strand_2, name="joincanceled")
        return value

    assert tap.run(fn) == [
        (0, 1),
        (1, 3),
    ]
Ejemplo n.º 23
0
def test_yield_from():
    def fn1(value):
        yield tap.Broadcast('key1', value)
        yield tap.Broadcast('key2', value)
        return 1

    def fn2(value):
        yield tap.Broadcast('key3', value)
        yield tap.Broadcast('key4', value)
        return 2

    def fn():
        v1 = yield from fn1(3)
        v2 = yield from fn2(4)
        assert v1 == 1
        assert v2 == 2

    tap.run(fn)
Ejemplo n.º 24
0
def test_release_twice():
    lock = tap.Lock()

    def dummy(eff):
        yield eff

    def fn():
        release = yield lock.Acquire()
        yield tap.Call(dummy, (release, ))
        yield release

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    # print(x.value)
    assert str(x.value).startswith("Exception caught at")
    assert str(x.value).count("in test_release_twice\n") == 1
    assert str(x.value).count("in Acquire\n") == 1
    assert str(x.value).count("Yielded same lock release multiple times?") == 1
Ejemplo n.º 25
0
def test_never_receive():
    def broadcaster(value):
        yield tap.Broadcast('key', value)

    def receiver():
        value = yield tap.Receive('key2')
        return value

    def fn():
        recv_strand = yield tap.CallFork(receiver)
        broadcast_strand = yield tap.CallFork(broadcaster, (5, ))
        yield tap.Join(broadcast_strand)
        value = yield tap.Join(recv_strand)
        return value

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    assert str(x.value).startswith("Hanging strands")
Ejemplo n.º 26
0
def test_call():
    def random(value):
        yield tap.Broadcast('key', value)
        return 10

    def fn():
        x = yield tap.Call(random, (5, ))
        return x

    assert tap.run(fn) == 10
Ejemplo n.º 27
0
def test_never_join():
    def broadcaster(value):
        yield tap.Broadcast('key', value)
        yield tap.Broadcast('key2', value)

    def fn():
        yield tap.CallFork(broadcaster, (5, ))
        return

    assert tap.run(fn) is None
Ejemplo n.º 28
0
def test_lock_cancel_after_acquire():
    lock = tap.Lock()

    def acquire():
        release = yield lock.Acquire()
        yield tap.Receive("unlock")
        yield release

    def fn():
        t = yield tap.CallFork(acquire)
        yield tap.Sleep(0.001)
        yield tap.Cancel(t)
        t = yield tap.CallFork(acquire)
        yield tap.Sleep(0.001)

    with pytest.raises(tap.TapystryError) as x:
        tap.run(fn)
    # TODO fix
    assert str(x.value).startswith("Hanging strands detected waiting for Receive(lock") or \
        str(x.value).startswith("Hanging strands detected waiting for Call(Acquire")
Ejemplo n.º 29
0
def test_lock():
    a = 0

    lock = tap.Lock()

    def waits():
        yield tap.Receive("msg")
        nonlocal a
        a += 1
        release = yield lock.Acquire()
        a += 2
        yield release

    def nowaits():
        release = yield lock.Acquire()
        nonlocal a
        a += 5
        yield tap.Receive("unlock")
        yield release

    def fn():
        yield tap.CallFork(waits)
        yield tap.CallFork(nowaits)
        yield tap.CallFork(nowaits)
        yield tap.Sleep(0)
        assert a == 5

        # the waiting strand finally gets to acquire lock, but it is the latest
        yield tap.Broadcast("msg")
        yield tap.Sleep(0)
        assert a == 6

        yield tap.Broadcast("unlock")
        yield tap.Sleep(0.01)
        assert a == 11

        yield tap.Broadcast("unlock")
        yield tap.Sleep(0.01)
        assert a == 13

    tap.run(fn)
Ejemplo n.º 30
0
def test_lock_cancel_mid_acquire_trickier():
    a = 0

    lock = tap.Lock()

    def acquire(x, to_cancel):
        yield tap.Receive(str(x))
        release = yield lock.Acquire()
        nonlocal a
        a += 5
        yield tap.Sequence([
            tap.Receive(str(x)),
            tap.Sequence([
                tap.Cancel(to_cancel),
                release,
            ]) if to_cancel is not None else release
        ])

    def fn():
        t1 = yield tap.CallFork(acquire, (1, None))
        t2 = yield tap.CallFork(acquire, (2, t1))
        t3 = yield tap.CallFork(acquire, (3, None))
        yield tap.Broadcast("2")
        yield tap.Broadcast("1")
        yield tap.Sleep(0.001)
        assert a == 5
        yield tap.Broadcast("3")
        yield tap.Broadcast(
            "2")  # this simultaneously tries to cancel 1 and unlocks

        yield tap.Sleep(0.01)
        assert a == 10

        yield tap.Broadcast("1")
        # 1 gets canceled after the acquire, so it's too late to release
        yield tap.Sleep(0.001)
        assert a == 10
        # yield tap.Join([t1, t2, t3])
        yield tap.Cancel(t3)

    tap.run(fn)