def test_drive_single(self): """Drive a single chain""" driver = self.driver_class() elements = [Adder(val) for val in (2, -2, 1E6, random.randint(-256, 256))] for run_async in (False, True): results = [] self.assertFalse(driver.mounts) with self.subTest(run_async=run_async): for elements in itertools.product(elements, repeat=3): initials = [0, 2, 1E6, -1232527] expected = [initial + sum(element.value for element in elements) for initial in initials] a, b, c = elements buffer = self.buffer_class() chain = produce(initials) >> a >> b >> c >> buffer driver.mount(chain) results.append([expected, buffer]) if run_async: driver.start() driver.start() # starting multiple times is allowed time.sleep(0.05) # let the driver startup while driver.running: time.sleep(0.05) else: driver.run() for expected, buffer in results: self.assertEqual(expected, buffer.buffer)
def test_concurrent(self): """concurrent sleep""" sleep_chain = self.chain_type((Adder(1), sleep(seconds=0.05), sleep(seconds=0.05))) start_time = time.time() result = list(sleep_chain.dispatch(range(5))) end_time = time.time() self.assertEqual(result, list(range(1, 6))) self.assertLess(end_time - start_time, 0.5)
def test_simple(self): """simple bundle as `a >> (b, c)`""" primitives = [Adder(val) for val in (0, -2, 16, -1E6)] for elements in itertools.product(primitives, repeat=3): a, b, c = elements reference_chain = a >> (b, c) concurrent_chain = a >> self.bundle_type((b, c)) for initial in (0, -12, 124, -12234, +1E6): self.assertEqual(reference_chain.send(initial), concurrent_chain.send(initial))
def test_pair(self): """Push single link chain as `parent >> child`""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] for parent, child in itertools.product(elements, repeat=2): for initial in (0, 15, -15, -1E6, +1E6): with self.subTest(parent=parent, child=child, initial=initial): expected = initial + parent.value + child.value chain_a = parent >> child self.assertEqual(chain_a.send(initial), expected)
def test_multi(self): """nested bundle as `a >> (b, c >> (d, e >> ...`""" primitives = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(primitives, repeat=6): a, b, c, d, e, f = elements reference_chain = a >> (b, c >> (d, e >> f)) concurrent_chain = a >> self.bundle_type((b, c >> self.bundle_type((d, e >> f)))) for initial in (0, -12, 124, -12234, +1E6): self.assertEqual(reference_chain.send(initial), concurrent_chain.send(initial))
def test_convert_concurrent(self): """concurrent sleep from converter""" if self.converter is None: raise unittest.SkipTest('no converter for %s' % self.__class__.__name__) sleep_chain = self.converter(Adder(1) >> sleep(seconds=0.05) >> sleep(seconds=0.05)) start_time = time.time() result = list(sleep_chain.dispatch(range(5))) end_time = time.time() self.assertEqual(result, list(range(1, 6))) self.assertLess(end_time - start_time, 0.5)
def test_pair(self): """Subscribe chain[i:j:k] for `a >> b`""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=2): with self.subTest(elements=elements): a, b = elements def factory(): return a >> b self._assert_subscriptable(factory)
def test_multi(self): """Push multi link chain as `a >> b >> c >> ...`""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] for chain in itertools.product(elements, repeat=5): for initial in (0, 15, -15, -1E6, +1E6): with self.subTest(chain=chain, initial=initial): expected = initial + sum(element.value for element in chain) a, b, c, d, e = chain chain_a = a >> b >> c >> d >> e self.assertEqual(chain_a.send(initial), expected)
def test_fork(self): """Subscribe chain[i:j:k] for `a >> (b, c) >> d ...`""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=5): with self.subTest(elements=elements): a, b, c, d, e = elements def factory(): return a >> (b, c) >> MergeLink() >> d >> e self._assert_subscriptable(factory)
def test_fork(self): """Push fork link chain as `a >> (b, c)`""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] for a, b, c in itertools.product(elements, repeat=3): for initial in (0, 15, -15, -1E6, +1E6): with self.subTest(a=a, b=b, c=c, initial=initial): expected = [ initial + a.value + b.value, initial + a.value + c.value ] chain_a = a >> (b, c) self.assertEqual(chain_a.send(initial), expected)
def test_generator(self): """Pull generator link chain as `(a for a in values) >> child >> ...`""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] initials = (0, 15, -15, -1E6, +1E6) for chain in itertools.product(elements, repeat=3): with self.subTest(chain=chain): expected = [ initial + sum(element.value for element in chain) for initial in initials ] a, b, c = chain chain_a = (val for val in initials) >> a >> b >> c self.assertEqual(list(chain_a), expected)
def test_fork(self): """Push fork link chain as `a >> (b, c)` => [[1a, 1b], ...]""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=3): with self.subTest(elements=elements): a, b, c = elements initials = (0, 15, -15, -1E6, +1E6) expected = [[ initial + a.value + b.value, initial + a.value + c.value ] for initial in initials] def factory(): return produce(initials) >> a >> (b, c) self._test_iter(factory, expected, parallel=True)
def test_multi(self): """Push nested fork as `a >> (b, c >> (d, e >> ...`""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=6): for initial in (0, -15, +1E6): with self.subTest(chain=elements, initial=initial): a, b, c, d, e, f = elements chain_a = a >> (b, c >> (d, e >> f)) expected = [ initial + a.value + b.value, initial + a.value + c.value + d.value, initial + a.value + c.value + e.value + f.value, ] self.assertEqual(len(chain_a.send(initial)), 3) # flat result, number of leaf nodes self.assertEqual(chain_a.send(initial), expected)
def test_abort(self): """Abort in nested fork""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=3): with self.subTest(elements=elements): a, b, c = elements initials = (0, 15, -15, -1E6, +1E6, 0) chain_abort_one_swallow = produce(initials) >> a >> (b >> abort_swallow(), c) self.assertEqual( list(chain_abort_one_swallow), [[initial + a.value + c.value] for initial in initials] ) chain_abort_all_swallow = produce(initials) >> a >> (b >> abort_swallow(), c >> abort_swallow()) self.assertEqual( list(chain_abort_all_swallow), [] ) for every in (2, 3): chain_switch_nth = produce(initials) >> a >> either(AbortEvery(every) >> b, c) self.assertEqual( list(chain_switch_nth), [ initial + a.value + b.value if (idx+1) % every else initial + a.value + c.value for idx, initial in enumerate(initials) ] ) chain_abort_nth_return = produce(initials) >> a >> (b >> AbortEvery(every), c) self.assertEqual( list(chain_abort_nth_return), [ [initial + a.value + b.value, initial + a.value + c.value] if (idx+1) % every else [initial + a.value + c.value] for idx, initial in enumerate(initials) ] ) chain_abort_nth_swallow = produce(initials) >> a >> (b >> ReturnEvery(every), c) self.assertEqual( list(chain_abort_nth_swallow), [ [initial + a.value + c.value] if (idx) % every else [initial + a.value + b.value, initial + a.value + c.value] for idx, initial in enumerate(initials) ] )
def test_fork_join(self): """Fork and join as `source >> (child_a, child_b) >> join` => [1, 2, ...]""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] for elements in itertools.product(elements, repeat=2): with self.subTest(elements=elements): initials = (0, 15, -15, 200, -200, -1E6, +1E6) expected = [ 2 * initial + sum(element.value for element in elements) for initial in initials ] a, b = elements def factory(): return produce(initials) >> (a, b) >> MergeLink() self._test_iter(factory, expected, parallel=True)
def test_multi(self): """Iter multi link chain as `a >> b >> c >> ...` => [1, 2, ...]""" elements = [Adder(val) for val in (0, -2, -1E6)] for elements in itertools.product(elements, repeat=5): with self.subTest(elements=elements): initials = (0, 15, -15, -1E6, +1E6) expected = [ initial + sum(element.value for element in elements) for initial in initials ] a, b, c, d, e = elements def factory(): return produce(initials) >> a >> b >> c >> d >> e self._test_iter(factory, expected)
def test_pair(self): """Iter single link chain as `parent >> child` => [1, 2, ...]""" elements = [Adder(val) for val in (0, -2, 2, 1E6, -1E6)] for elements in itertools.product(elements, repeat=2): with self.subTest(elements=elements): initials = (0, 15, -15, 200, -200, -1E6, +1E6) expected = [ initial + sum(element.value for element in elements) for initial in initials ] a, b = elements def factory(): return produce(initials) >> a >> b self._test_iter(factory, expected)
def test_repacking(self): """chained bundles as `a >> (b, c, d) >> (e, f, g) >> ...""" primitives = [Adder(val) for val in (0, -2, -1E6)] delay = 0.00001 # sleep to interleave threads for elements in itertools.product(primitives, repeat=6): a, b, c, d, e, f = elements reference_chain = a >> (b, c, d) >> (MergeLink() >> c, MergeLink() >> d, e) >> f concurrent_chain = a >> self.bundle_type( (sleep(seconds=delay) >> b, sleep(seconds=delay) >> c, sleep(seconds=delay) >> d)) >> self.bundle_type( ( MergeLink() >> sleep(seconds=delay) >> c, MergeLink() >> sleep(seconds=delay) >> d, sleep(seconds=delay) >> e) ) >> f for initial in (0, -12, 124, -12234, +1E6): sequential = reference_chain.send(initial) concurrent = concurrent_chain.send(initial) self.assertEqual(sequential, concurrent)