Files
deb-python-taskflow/taskflow/tests/unit/test_green_executor.py
Joshua Harlow 8de131502c Move async utils to own file
Instead of mixing eventlet related utility
functionality with async utility functionality
it seems to make sense to seperate those types
into two different files.

Change-Id: I8770fa5163feaa5f3666d36bf55d9aa30ca1b15f
2013-12-20 23:38:34 -08:00

146 lines
4.4 KiB
Python

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import collections
import functools
import testtools
from concurrent import futures
from taskflow import test
from taskflow.utils import async_utils as au
from taskflow.utils import eventlet_utils as eu
@testtools.skipIf(not eu.EVENTLET_AVAILABLE, 'eventlet is not available')
class GreenExecutorTest(test.TestCase):
def make_funcs(self, called, amount):
def store_call(name):
called[name] += 1
for i in range(0, amount):
yield functools.partial(store_call, name=int(i))
def test_func_calls(self):
called = collections.defaultdict(int)
with eu.GreenExecutor(2) as e:
for f in self.make_funcs(called, 2):
e.submit(f)
self.assertEqual(1, called[0])
self.assertEqual(1, called[1])
def test_no_construction(self):
self.assertRaises(AssertionError, eu.GreenExecutor, 0)
self.assertRaises(AssertionError, eu.GreenExecutor, -1)
self.assertRaises(AssertionError, eu.GreenExecutor, "-1")
def test_result_callback(self):
called = collections.defaultdict(int)
def call_back(future):
called[future] += 1
funcs = list(self.make_funcs(called, 1))
with eu.GreenExecutor(2) as e:
f = e.submit(funcs[0])
f.add_done_callback(call_back)
self.assertEqual(2, len(called))
def test_exception_transfer(self):
def blowup():
raise IOError("Broke!")
with eu.GreenExecutor(2) as e:
f = e.submit(blowup)
self.assertRaises(IOError, f.result)
def test_result_transfer(self):
def return_given(given):
return given
create_am = 50
with eu.GreenExecutor(2) as e:
fs = []
for i in range(0, create_am):
fs.append(e.submit(functools.partial(return_given, i)))
self.assertEqual(create_am, len(fs))
for i in range(0, create_am):
result = fs[i].result()
self.assertEqual(i, result)
def test_func_cancellation(self):
called = collections.defaultdict(int)
fs = []
with eu.GreenExecutor(2) as e:
for func in self.make_funcs(called, 2):
fs.append(e.submit(func))
# Greenthreads don't start executing until we wait for them
# to, since nothing here does IO, this will work out correctly.
#
# If something here did a blocking call, then eventlet could swap
# one of the executors threads in, but nothing in this test does.
for f in fs:
self.assertFalse(f.running())
f.cancel()
self.assertEqual(0, len(called))
for f in fs:
self.assertTrue(f.cancelled())
self.assertTrue(f.done())
class WaitForAnyTestCase(test.TestCase):
@testtools.skipIf(not eu.EVENTLET_AVAILABLE, 'eventlet is not available')
def test_green_waits_and_finishes(self):
def foo():
pass
e = eu.GreenExecutor()
f1 = e.submit(foo)
f2 = e.submit(foo)
# this test assumes that our foo will end within 10 seconds
done, not_done = au.wait_for_any([f1, f2], 10)
self.assertIn(len(done), (1, 2))
self.assertTrue(any((f1 in done, f2 in done)))
def test_threaded_waits_and_finishes(self):
def foo():
pass
e = futures.ThreadPoolExecutor(2)
try:
f1 = e.submit(foo)
f2 = e.submit(foo)
# this test assumes that our foo will end within 10 seconds
done, not_done = au.wait_for_any([f1, f2], 10)
self.assertIn(len(done), (1, 2))
self.assertTrue(any((f1 in done, f2 in done)))
finally:
e.shutdown()