class BaseTimeExecutionCase(TestCase): """Base Test case for code execute timeout.""" BASE_TIMEOUT = 0.35 @classmethod def setUpClass(cls) -> None: """Set up.""" if cls is BaseTimeExecutionCase: raise unittest.SkipTest("Skip BaseTest tests, it's a base class") def tearDown(self) -> None: """Tear down.""" self.aea_tool.stop() def prepare(self, function: Callable) -> None: """Prepare aea_tool for testing. :param function: function be called on react handle or/and Behaviour.act :return: None """ agent_name = "MyAgent" builder = AEABuilder() builder.set_name(agent_name) builder.add_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_PATH) self.function_finished = False def handler_func(*args, **kwargs): function() self.function_finished = True skill_context = SkillContext() handler_cls = make_handler_cls_from_funcion(handler_func) behaviour_cls = make_behaviour_cls_from_funcion(handler_func) test_skill = Skill( SkillConfig(name="test_skill", author="fetchai"), skill_context=skill_context, handlers={ "handler1": handler_cls(name="handler1", skill_context=skill_context) }, behaviours={ "behaviour1": behaviour_cls(name="behaviour1", skill_context=skill_context) }, ) skill_context._skill = test_skill # weird hack builder._add_component_to_resources(test_skill) aea = builder.build() self.aea_tool = AeaTool(aea) self.aea_tool.put_inbox(AeaTool.dummy_envelope()) def test_long_handler_cancelled_by_timeout(self): """Test long function terminated by timeout.""" num_sleeps = 10 sleep_time = self.BASE_TIMEOUT function_sleep_time = num_sleeps * sleep_time execution_timeout = self.BASE_TIMEOUT * 2 assert execution_timeout < function_sleep_time self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps)) self.aea_tool.set_execution_timeout(execution_timeout) self.aea_tool.setup() with timeit_context() as timeit: self.aea_action() assert execution_timeout <= timeit.time_passed <= function_sleep_time assert not self.function_finished self.aea_tool.stop() def test_short_handler_not_cancelled_by_timeout(self): """Test short function NOTterminated by timeout.""" num_sleeps = 1 sleep_time = self.BASE_TIMEOUT function_sleep_time = num_sleeps * sleep_time execution_timeout = self.BASE_TIMEOUT * 2 assert function_sleep_time <= execution_timeout self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps)) self.aea_tool.set_execution_timeout(execution_timeout) self.aea_tool.setup() with timeit_context() as timeit: self.aea_action() assert function_sleep_time <= timeit.time_passed <= execution_timeout assert self.function_finished self.aea_tool.stop() def test_no_timeout(self): """Test function NOT terminated by timeout cause timeout == 0.""" num_sleeps = 1 sleep_time = self.BASE_TIMEOUT function_sleep_time = num_sleeps * sleep_time execution_timeout = 0 self.prepare(lambda: sleep_a_bit(sleep_time, num_sleeps)) self.aea_tool.set_execution_timeout(execution_timeout) self.aea_tool.setup() with timeit_context() as timeit: self.aea_action() assert function_sleep_time <= timeit.time_passed assert self.function_finished self.aea_tool.stop()
class TestAeaExceptionPolicy: """Tests for exception policies.""" @staticmethod def raise_exception(*args, **kwargs) -> None: """Raise exception for tests.""" raise ExpectedExcepton("we wait it!") def setup(self) -> None: """Set test cae instance.""" agent_name = "MyAgent" builder = AEABuilder() builder.set_name(agent_name) builder.add_private_key(DEFAULT_LEDGER, COSMOS_PRIVATE_KEY_PATH) self.handler_called = 0 def handler_func(*args, **kwargs): self.handler_called += 1 skill_context = SkillContext() handler_cls = make_handler_cls_from_funcion(handler_func) behaviour_cls = make_behaviour_cls_from_funcion(handler_func) self.handler = handler_cls(name="handler1", skill_context=skill_context) self.behaviour = behaviour_cls(name="behaviour1", skill_context=skill_context) test_skill = Skill( SkillConfig(name="test_skill", author="fetchai"), skill_context=skill_context, handlers={"handler": self.handler}, behaviours={"behaviour": self.behaviour}, ) skill_context._skill = test_skill # weird hack builder.add_component_instance(test_skill) self.aea = builder.build() self.aea_tool = AeaTool(self.aea) def test_no_exceptions(self) -> None: """Test act and handle works if no exception raised.""" t = Thread(target=self.aea.start) t.start() self.aea_tool.put_inbox(self.aea_tool.dummy_envelope()) time.sleep(1) assert self.handler_called >= 2 def test_handle_propagate(self) -> None: """Test propagate policy on message handle.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.propagate self.handler.handle = self.raise_exception # type: ignore # cause error: Cannot assign to a method self.aea_tool.put_inbox(self.aea_tool.dummy_envelope()) with pytest.raises(ExpectedExcepton): self.aea.start() assert not self.aea.is_running def test_handle_stop_and_exit(self) -> None: """Test stop and exit policy on message handle.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.stop_and_exit self.handler.handle = self.raise_exception # type: ignore # cause error: Cannot assign to a method self.aea_tool.put_inbox(self.aea_tool.dummy_envelope()) with pytest.raises(AEAException, match=r"AEA was terminated cause exception .*"): self.aea.start() assert not self.aea.is_running def test_handle_just_log(self) -> None: """Test just log policy on message handle.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log self.handler.handle = self.raise_exception # type: ignore # cause error: Cannot assign to a method with patch.object(logger, "exception") as patched: t = Thread(target=self.aea.start) t.start() self.aea_tool.put_inbox(self.aea_tool.dummy_envelope()) self.aea_tool.put_inbox(self.aea_tool.dummy_envelope()) time.sleep(1) assert self.aea.is_running assert patched.call_count == 2 def test_act_propagate(self) -> None: """Test propagate policy on behaviour act.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.propagate self.behaviour.act = self.raise_exception # type: ignore # cause error: Cannot assign to a method with pytest.raises(ExpectedExcepton): self.aea.start() assert not self.aea.is_running def test_act_stop_and_exit(self) -> None: """Test stop and exit policy on behaviour act.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.stop_and_exit self.behaviour.act = self.raise_exception # type: ignore # cause error: Cannot assign to a method with pytest.raises(AEAException, match=r"AEA was terminated cause exception .*"): self.aea.start() assert not self.aea.is_running def test_act_just_log(self) -> None: """Test just log policy on behaviour act.""" self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log self.behaviour.act = self.raise_exception # type: ignore # cause error: Cannot assign to a method with patch.object(logger, "exception") as patched: t = Thread(target=self.aea.start) t.start() time.sleep(1) assert self.aea.is_running assert patched.call_count > 1 def test_act_bad_policy(self) -> None: """Test propagate policy on behaviour act.""" self.aea._skills_exception_policy = "non exists policy" # type: ignore self.behaviour.act = self.raise_exception # type: ignore # cause error: Cannot assign to a method with pytest.raises(AEAException, match=r"Unsupported exception policy.*"): self.aea.start() assert not self.aea.is_running def teardown(self) -> None: """Stop AEA if not stopped.""" self.aea.stop()