def acquire_resources_and_run(self, node, func, func_type=TestFunctionType.TEST): """ Tries to acquire resources for a function and run it, reporting appropriately to the TestLogger. Takes care of returning nodes to the work provider if resources cannot be locked. :param node: The WorkNode containing the function you wish to run. :param func: The function you wish to execute :param func_type: The TestFunctionType of the function :return: True if the function was successfully run, False otherwise """ instance = node.get_test_class_instance() # Check for failed execution groups if WorkerThread.has_failed_ex_groups(node.test_class, func, node.test_env, self.work_provider): self.logger.skippingTestFunction(instance, func, func_type, thread_num=self.thread_num) #AB - still want to call teardown when threads has failed if func_type == TestFunctionType.TEARDOWN: func(instance) node.test_class_is_torndown = True return True # Try to lock this function's resources func_resources = getattr(func, 'resources', []) func_resources_locked = self.work_provider.lock_resources(func_resources) if not func_resources_locked: self.work_provider.release_resources(node.class_resources) self.work_provider.add_nodes(node) return False # Execute the function self.logger.runningTestFunction(instance, func, func_type, thread_num=self.thread_num) try: func(instance) except: e = sys.exc_info()[0] tb = traceback.format_exc() self.work_provider.add_failed_ex_groups( WorkerThread.get_ex_groups(node.test_class, func), node.test_env ) self.logger.foundException(instance, func, e, tb, func_type, thread_num=self.thread_num) #AB - additional logging options if instance.details != None: self.logger.logDetails(instance, func, instance.details, thread_num=self.thread_num) instance.clearLog() # Cleanup if func_type == TestFunctionType.SETUP: node.test_class_is_setup = True elif func_type == TestFunctionType.TEARDOWN: node.test_class_is_torndown = True else: node.test_funcs.remove(func) self.logger.finishedTestFunction(instance, func, func_type, thread_num=self.thread_num) self.work_provider.release_resources(func_resources) return True
def run_tests(self): """Runs the tests that have been added to this TestRunner and reports the results to the given TestLogger.""" self.logger.startingTests() workers = [] for i in range(len(self.work_providers)): work_provider = self.work_providers[i] worker = WorkerThread(work_provider, self.logger, thread_num=i) worker.start() workers.append(worker) for worker in workers: worker.join() return self.logger.finishedTests()
def run_tests_for_node(self, node): """Takes a WorkNode and runs the tests it contains. If some of the node's resources are in use, the node may be returned to the work_provider.""" # Try to get a lock on the class resources resources_locked = self.work_provider.lock_resources( node.class_resources) if not resources_locked: self.work_provider.add_nodes(node) return cls = node.test_class instance = node.get_test_class_instance() # if this node contains only one function, check for failed execution groups # and don't instatiate the class or call setup if len(node.test_funcs) == 1: func = node.test_funcs[0] if WorkerThread.has_failed_ex_groups(cls, func, node.test_env, self.work_provider): self.logger.skippingTestFunction(instance, func, thread_num=self.thread_num) self.work_provider.release_resources(node.class_resources) return # Try to call the class's setup method if not node.test_class_is_setup: if hasattr(cls, 'setup') and callable(cls.setup): success = self.acquire_resources_and_run( node, cls.setup, TestFunctionType.SETUP) if not success: return # Run all the test functions for func in list( node.test_funcs ): # copy the list so we don't remove items while iterating success = self.acquire_resources_and_run(node, func) if not success: return # Try to call the class's teardown method if not node.test_class_is_torndown: if hasattr(cls, 'teardown') and callable(cls.teardown): success = self.acquire_resources_and_run( node, cls.teardown, TestFunctionType.TEARDOWN) if not success: return self.work_provider.release_resources(node.class_resources)
def test_has_failed_ex_groups(self): wp = WorkProvider() env = {'env': 'env'} # Same class, no failed ex groups self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp)) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp)) # Same class, with failed class ex groups wp.add_failed_ex_groups([1], env) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp)) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp)) # Same class, no ex groups, with wp.failed_ex_groups reset wp = WorkProvider() self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp)) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp)) # Same class, with one method having a failed ex_group wp.add_failed_ex_groups([2], env) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture2, Fixture2.meth1, env, wp)) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture2, Fixture2.meth2, env, wp))
def test_has_failed_ex_groups(self): wp = WorkProvider() env = { 'env': 'env' } # Same class, no failed ex groups self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp) ) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp) ) # Same class, with failed class ex groups wp.add_failed_ex_groups([1], env) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp) ) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp) ) # Same class, no ex groups, with wp.failed_ex_groups reset wp = WorkProvider() self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth1, env, wp) ) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture1, Fixture1.meth2, env, wp) ) # Same class, with one method having a failed ex_group wp.add_failed_ex_groups([2], env) self.assertTrue( WorkerThread.has_failed_ex_groups(Fixture2, Fixture2.meth1, env, wp) ) self.assertFalse( WorkerThread.has_failed_ex_groups(Fixture2, Fixture2.meth2, env, wp) )
def run_tests_for_node(self, node): """Takes a WorkNode and runs the tests it contains. If some of the node's resources are in use, the node may be returned to the work_provider.""" # Try to get a lock on the class resources resources_locked = self.work_provider.lock_resources(node.class_resources) if not resources_locked: self.work_provider.add_nodes(node) return cls = node.test_class instance = node.get_test_class_instance() # if this node contains only one function, check for failed execution groups # and don't instatiate the class or call setup if len(node.test_funcs) == 1: func = node.test_funcs[0] if WorkerThread.has_failed_ex_groups(cls, func, node.test_env, self.work_provider): self.logger.skippingTestFunction(instance, func, thread_num=self.thread_num) self.work_provider.release_resources(node.class_resources) return # Try to call the class's setup method if not node.test_class_is_setup: if hasattr(cls, 'setup') and callable(cls.setup): success = self.acquire_resources_and_run(node, cls.setup, TestFunctionType.SETUP) if not success: return # Run all the test functions for func in list(node.test_funcs): # copy the list so we don't remove items while iterating success = self.acquire_resources_and_run(node, func) if not success: return # Try to call the class's teardown method if not node.test_class_is_torndown: if hasattr(cls, 'teardown') and callable(cls.teardown): success = self.acquire_resources_and_run(node, cls.teardown, TestFunctionType.TEARDOWN) if not success: return self.work_provider.release_resources(node.class_resources)
def test_get_ex_groups(self): self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture1.meth1)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture1.meth2)) self.assertEqual([2], WorkerThread.get_ex_groups(Fixture1.meth3)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture2)) self.assertEqual([2], WorkerThread.get_ex_groups(Fixture2.meth1)) self.assertEqual([3, 4], sorted(WorkerThread.get_ex_groups(Fixture2.meth2))) self.assertEqual([], WorkerThread.get_ex_groups(Fixture2.meth3)) # class and method self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1, Fixture1.meth1)) # class and method, each have an execution group self.assertEqual( [1, 2], sorted(WorkerThread.get_ex_groups(Fixture1, Fixture1.meth3))) # two methods self.assertEqual([2], WorkerThread.get_ex_groups(Fixture1.meth2, Fixture1.meth3)) # two classes self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1, Fixture2)) # class and method with multiple groups self.assertEqual( [1, 3, 4], sorted(WorkerThread.get_ex_groups(Fixture1, Fixture2.meth2)))
def test_get_ex_groups(self): self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture1.meth1)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture1.meth2)) self.assertEqual([2], WorkerThread.get_ex_groups(Fixture1.meth3)) self.assertEqual([], WorkerThread.get_ex_groups(Fixture2)) self.assertEqual([2], WorkerThread.get_ex_groups(Fixture2.meth1)) self.assertEqual([3, 4], sorted(WorkerThread.get_ex_groups(Fixture2.meth2))) self.assertEqual([], WorkerThread.get_ex_groups(Fixture2.meth3)) # class and method self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1, Fixture1.meth1)) # class and method, each have an execution group self.assertEqual( [1, 2], sorted(WorkerThread.get_ex_groups(Fixture1, Fixture1.meth3)) ) # two methods self.assertEqual( [2], WorkerThread.get_ex_groups(Fixture1.meth2, Fixture1.meth3) ) # two classes self.assertEqual([1], WorkerThread.get_ex_groups(Fixture1, Fixture2)) # class and method with multiple groups self.assertEqual( [1, 3, 4], sorted(WorkerThread.get_ex_groups(Fixture1, Fixture2.meth2)) )
def acquire_resources_and_run(self, node, func, func_type=TestFunctionType.TEST): """ Tries to acquire resources for a function and run it, reporting appropriately to the TestLogger. Takes care of returning nodes to the work provider if resources cannot be locked. :param node: The WorkNode containing the function you wish to run. :param func: The function you wish to execute :param func_type: The TestFunctionType of the function :return: True if the function was successfully run, False otherwise """ instance = node.get_test_class_instance() # Check for failed execution groups if WorkerThread.has_failed_ex_groups(node.test_class, func, node.test_env, self.work_provider): self.logger.skippingTestFunction(instance, func, func_type, thread_num=self.thread_num) #AB - still want to call teardown when threads has failed if func_type == TestFunctionType.TEARDOWN: func(instance) node.test_class_is_torndown = True return True # Try to lock this function's resources func_resources = getattr(func, 'resources', []) func_resources_locked = self.work_provider.lock_resources( func_resources) if not func_resources_locked: self.work_provider.release_resources(node.class_resources) self.work_provider.add_nodes(node) return False # Execute the function self.logger.runningTestFunction(instance, func, func_type, thread_num=self.thread_num) try: func(instance) except: e = sys.exc_info()[0] tb = traceback.format_exc() self.work_provider.add_failed_ex_groups( WorkerThread.get_ex_groups(node.test_class, func), node.test_env) self.logger.foundException(instance, func, e, tb, func_type, thread_num=self.thread_num) #AB - additional logging options if instance.details != None: self.logger.logDetails(instance, func, instance.details, thread_num=self.thread_num) instance.clearLog() # Cleanup if func_type == TestFunctionType.SETUP: node.test_class_is_setup = True elif func_type == TestFunctionType.TEARDOWN: node.test_class_is_torndown = True else: node.test_funcs.remove(func) self.logger.finishedTestFunction(instance, func, func_type, thread_num=self.thread_num) self.work_provider.release_resources(func_resources) return True