def setup_bond_self_test(test_instance, spy_groups=None): """ Setup Bond for self-tests :param spy_groups: :return: """ # Since we use Bond both as a system-under-test and as a testing library, we # have to be careful with mocking. We want to mock the reconcile prompts in the # system under test, but not in the testing Bond. # We keep a variable that is set whether we are running the test. In that case, # the mocking works. Once the test ends, then Bond becomes the testing one. test_instance.during_test = True bond_observations_dir = os.environ.get('BOND_OBSERVATION_DIR', os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'tests', 'test_observations')) spy_groups = 'bond_self_test' if spy_groups is None else spy_groups bond.start_test(test_instance, spy_groups=spy_groups, observation_directory=bond_observations_dir, reconcile=os.environ.get('BOND_RECONCILE', 'abort')) # By default we abort the test if it fails. No user-interface # Still even the abort reconcile wants to run a quick diff. We let it do it bond.deploy_agent('bond_reconcile._invoke_command', cmd__startswith='diff', result=bond.AGENT_RESULT_CONTINUE) # if we ever get to the read_console, it means that there is a problem with the test. # continue bond.deploy_agent('bond_reconcile._read_console', result=bond.AGENT_RESULT_CONTINUE)
def test_mock_only(self): bond.spy('unmocked_return', val=self.mock_only_method()) bond.deploy_agent('AnnotationTests.mock_only_method', result='mocked value') bond.spy('mocked_return', val=self.mock_only_method()) bond.deploy_agent('AnnotationTests.mock_only_method', skip_save_observation=False, result='mocked value') bond.spy('mocked_return', val=self.mock_only_method())
def deploy_time_mock(self): "Helper function to setup the time mocks and agents" self.time_mocker = TimeMocker() bond.deploy_agent('HeatWatcher.get_current_time', result=self.time_mocker.time) bond.deploy_agent('HeatWatcher.sleep', result=self.time_mocker.sleep)
def test_with_formatter(self): "Test the standard annotation with a formatter" def my_format(obs): obs['arg1'] += 1000 bond.deploy_agent('AnnotationTests.annotated_standard_method', formatter=my_format) self.annotated_standard_method(8, 9)
def test_formatter(self): "Apply the formatter" def my_formatter(obs): obs['new_key'] = 'new_value' bond.deploy_agent('fun1', cmd__contains="fun", formatter=my_formatter) bond.deploy_agent('fun1', cmd__startswith="myfun", result=lambda obs: obs) # Now the spying. The result should be the modified observation bond.spy('spy result', res=bond.spy('fun1', cmd="myfun3"))
def test_result(self): "Test the result aspect of the bond mocking" def my_formatter(obs): obs['cmd'] += ' : formatted' # The formatter is processed after the result is computed bond.deploy_agent('fun1', cmd__contains="fun", formatter=my_formatter, result=lambda obs: obs['cmd'] + ' here') bond.deploy_agent('fun1', cmd__startswith="myfun", result=123) # Now the spying self.assertEquals('a ton of fun here', bond.spy(spy_point_name='fun1', cmd="a ton of fun")) self.assertEquals(bond.AGENT_RESULT_NONE, bond.spy(spy_point_name='nofun', cmd="myfun2")) self.assertEquals(123, bond.spy('fun1', cmd="myfun3"))
def test_ok_warning(self): """ A test where the higher-level functions get_temperature and send_alert are mocked out to return specified temperatures and do nothing, respectively. """ self.deploy_time_mock() temp_rates = [(0, 0.5), (60, 1.2), (110, 0.12)] self.temp_mocker = TemperatureMocker(time_mocker=self.time_mocker, temp_start=70, temp_rates=temp_rates) bond.deploy_agent('HeatWatcher.get_temperature', result=self.temp_mocker.get_temperature) bond.deploy_agent('HeatWatcher.send_alert', result=None) HeatWatcher().monitor_loop(self.time_mocker.current_time + 400)
def test_exception(self): "A test that throws exceptions" def my_formatter(obs): obs['cmd'] += ' : formatted' bond.deploy_agent('fun1', cmd__startswith="myfun", result=1, formatter=my_formatter, exception=Exception("some exception")) self.assertRaises(Exception, lambda : bond.spy('fun1', cmd="myfun1")) bond.deploy_agent('fun1', cmd="myfun2", result=1, formatter=my_formatter, exception=lambda obs: Exception("some exception: "+obs['cmd'])) self.assertRaises(Exception, lambda : bond.spy(spy_point_name='fun1', cmd="myfun2"))
def setup_bond_self_tests(test_instance, spy_groups=None): """ Setup Bond for self-tests :param spy_groups: :return: """ bond_observations_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'tests', 'test_observations') spy_groups = 'bond_self_test' if spy_groups is None else spy_groups bond.start_test(test_instance, spy_groups=spy_groups, observation_directory=bond_observations_dir, reconcile=os.environ.get('BOND_RECONCILE', 'abort')) # By default we abort the test if it fails. No user-interface # Still even the abort reconcile wants to run a quick diff bond.deploy_agent('bond_reconcile._invoke_command', cmd__startswith='diff', result=0)
def test_doers(self): "Test the doer aspect of the bond mocking" results = [] def my_formatter(obs): obs['cmd'] += ' : formatted' bond.deploy_agent('fun1', cmd__startswith="myfun", formatter=my_formatter, do=(lambda args: results.append("1: " + args['cmd']))) bond.deploy_agent('fun1', cmd__contains="fun1", do=(lambda args: results.append("2: " + args['cmd']))) # Now the spying bond.spy(spy_point_name='fun1', cmd="myfun1") # agent 2: only bond.spy(spy_point_name='nofun', cmd="myfun2") # no agent bond.spy(spy_point_name='fun1', cmd="myfun3") # agent 1: only self.assertSequenceEqual(['2: myfun1', '1: myfun3'], results)
def test_critical(self): """ A test where make_request is mocked out, and returns different responses depending on the URL that is passed in. This can allow you to test that the parsing logic in get_temperature is working correctly. """ self.deploy_time_mock() temp_rates = [(0, 0.5), (60, 2.5), (120, 3), (140, 0.5)] self.temp_mocker = TemperatureMocker(time_mocker=self.time_mocker, temp_start=70, temp_rates=temp_rates) bond.deploy_agent('HeatWatcher.make_request', url__contains='messages', result=None) bond.deploy_agent('HeatWatcher.make_request', url__contains='temperature', result=lambda obs: (200, '<temperature>{}</temperature>' .format(self.temp_mocker.get_temperature()))) HeatWatcher().monitor_loop(self.time_mocker.time() + 210)
def test_skip_save_observation(self): "Test the ability to specify skipping saving observations and overriding it" bond.spy('skipped_spy_point', skip_save_observation=True, key='val') bond.deploy_agent('skipped_spy_point', result='Mock Value') ret = bond.spy('skipped_spy_point', skip_save_observation=True, key='val') bond.spy('skipped_return_value', val=ret) bond.deploy_agent('normal_spy_point', skip_save_observation=False, result='Mock Value') ret = bond.spy('normal_spy_point', skip_save_observation=True, key='val') bond.spy('not_skipped_return_value', val=ret) bond.deploy_agent('skipped_spy_point', skip_save_observation=True, result='Mock Value') ret = bond.spy('skipped_spy_point', key='val') bond.spy('skipped_return_value', val=ret)
def test_with_mocking(self): bond.deploy_agent("AnnotationTests.annotated_standard_method", result="mocked value") self.assertEquals("mocked value", self.annotated_standard_method(arg1=1, arg2=2))
def setUp(self): self.testing_observation_dir = '/tmp/bondObservations Dir' # Intentionally put a space in the path self.reference_file = os.path.join(self.testing_observation_dir, 'reference.json') self.reference_file_content = """ [ { "__spy_point__" : "point 1", val" : 12345 } ] """ self.reference_file_content_lines = map(lambda s: s + '\n', self.reference_file_content.split('\n')[0:-1]) setup_bond_self_test(self) def format_diff_join_lists(obs): obs['current_lines'] = ''.join(obs['current_lines']) obs['reference_lines'] = ''.join(obs['reference_lines']) bond.deploy_agent('bond_reconcile._compute_diff', formatter=format_diff_join_lists, result=bond.AGENT_RESULT_CONTINUE) bond.deploy_agent('bond_reconcile._random_string', result='random') self.console_reply = [] # List of strings to reply when we try to read from console bond.deploy_agent('bond_reconcile._get_user_input', result=lambda obs: self.console_reply.pop(0) if self.console_reply else bond.AGENT_RESULT_CONTINUE) self.kdiff3_result = 0 def mock_kdiff3(obs): "Mock call to kdiff3" if not self.during_test: return bond.AGENT_RESULT_CONTINUE if self.kdiff3_result == 0: # Success, create the merged file # First, get the file name from the command line m = re.search(r'-o\s*"([^"]+)"', obs['cmd']) if m: with open(m.group(1), 'w') as f: f.write("The merge result") return self.kdiff3_result bond.deploy_agent('bond_reconcile._invoke_command', cmd__startswith='kdiff3 ', result=mock_kdiff3) # A special formatter for the printing of diffs def _print_formatter(obs): # We want to observe each line individually res = [] for l in obs['what'].split('\n'): res.append(l) obs['what'] = res bond.deploy_agent('bond_reconcile._print', what__contains='@@', formatter=_print_formatter)
def test_with_mocking(self): bond.deploy_agent('AnnotationTests.annotated_standard_method', result='mocked value') self.assertEquals('mocked value', self.annotated_standard_method(arg1=1, arg2=2))
def test_with_return_none(self): arr = [0] bond.deploy_agent('AnnotationTests.annotated_with_side_effects', result=None) ret = self.annotated_with_side_effects(arr) bond.spy('return value', ret=ret, arr_value=arr[0])
def test_with_mocking_mandatory_applied(self): bond.deploy_agent('AnnotationTests.annotated_with_mocking_mandatory', result='mocked value') self.assertEqual('mocked value', self.annotated_with_mocking_mandatory())
def test_with_mocking_mandatory_applied(self): bond.deploy_agent("AnnotationTests.annotated_with_mocking_mandatory", result="mocked value") self.assertEqual("mocked value", self.annotated_with_mocking_mandatory())