class ExecutionLoggingInitiatorTest(unittest.TestCase): def test_start_logging_on_execution_start(self): execution_id = self.executor_service.start_script( create_config_model('my_script'), {}, 'userX', create_audit_names(ip='localhost')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper.finish(0) entry = self.logging_service.find_history_entry(execution_id, 'userX') self.assertIsNotNone(entry) def test_logging_values(self): param1 = create_script_param_config('p1') param2 = create_script_param_config('p2', param='-x') param3 = create_script_param_config('p3', param='-y', no_value=True) param4 = create_script_param_config('p4', param='-z', type='int') config_model = create_config_model( 'my_script', script_command='echo', parameters=[param1, param2, param3, param4]) execution_id = self.executor_service.start_script( config_model, {'p1': 'abc', 'p3': True, 'p4': 987}, 'userX', create_audit_names(ip='localhost', auth_username='******')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper._write_script_output('some text\n') executor.process_wrapper._write_script_output('another text') executor.process_wrapper.finish(0) wait_observable_close_notification(executor.get_anonymized_output_stream(), 2) entry = self.logging_service.find_history_entry(execution_id, 'userX') self.assertIsNotNone(entry) self.assertEqual('userX', entry.user_id) self.assertEqual('sandy', entry.user_name) self.assertEqual('my_script', entry.script_name) self.assertEqual('echo abc -y -z 987', entry.command) self.assertEqual('my_script', entry.script_name) log = self.logging_service.find_log(execution_id) self.assertEqual('some text\nanother text', log) def test_exit_code(self): config_model = create_config_model( 'my_script', script_command='ls', parameters=[]) execution_id = self.executor_service.start_script( config_model, {}, 'userX', create_audit_names(ip='localhost')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper._write_script_output('some text\n') executor.process_wrapper._write_script_output('another text') executor.process_wrapper.finish(14) wait_observable_close_notification(executor.get_anonymized_output_stream(), 2) entry = self.logging_service.find_history_entry(execution_id, 'userX') self.assertEqual(14, entry.exit_code) def setUp(self): test_utils.setup() executor._process_creator = _MockProcessWrapper authorizer = Authorizer([], [], [], EmptyGroupProvider()) self.logging_service = ExecutionLoggingService(test_utils.temp_folder, LogNameCreator(), authorizer) self.executor_service = ExecutionService(_IdGeneratorMock()) self.controller = ExecutionLoggingController(self.executor_service, self.logging_service) self.controller.start() def tearDown(self): test_utils.cleanup() executions = self.executor_service.get_active_executions('userX') for execution_id in executions: try: self.executor_service.kill_script(execution_id) self.executor_service.cleanup_execution(execution_id) except: traceback.print_exc()
class TestInlineImages(unittest.TestCase): def setUp(self) -> None: test_utils.setup() executor._process_creator = _MockProcessWrapper self.executor_service = ExecutionService(_IdGeneratorMock()) self.file_download_feature = file_download_feature.FileDownloadFeature( UserFileStorage(b'123456'), test_utils.temp_folder) self.file_download_feature.subscribe(self.executor_service) self.images = [] def tearDown(self) -> None: test_utils.cleanup() executions = self.executor_service.get_active_executions('userX') for execution in executions: self.executor_service.kill_script(execution) def _add_image(self, original_path, new_path): self.images.append((original_path, new_path)) def test_single_static_image(self): path = test_utils.create_file('test.png') config = create_config_model('my_script', output_files=[inline_image(path)]) execution_id = self.start_execution(config) self.write_output(execution_id, '123\n456') self.wait_output_chunks(execution_id, chunks_count=1) self.assert_images(path) def test_multiple_static_images(self): path1 = test_utils.create_file('test1.png') path2 = test_utils.create_file('test2.png') path3 = test_utils.create_file('test3.png') config = create_config_model('my_script', output_files=[ inline_image(path1), inline_image(path2), inline_image(path3) ]) execution_id = self.start_execution(config) self.write_output(execution_id, '123\n' + '456') self.wait_output_chunks(execution_id, chunks_count=1) self.assert_images(path1, path2, path3) def test_single_static_image_when_multiple_outputs(self): path = test_utils.create_file('test.png') config = create_config_model('my_script', output_files=[inline_image(path)]) execution_id = self.start_execution(config) self.write_output(execution_id, '123\n456') self.wait_output_chunks(execution_id, chunks_count=1) self.write_output(execution_id, '789\n0') self.wait_output_chunks(execution_id, chunks_count=2) self.assert_images(path) def test_single_dynamic_image(self): path = test_utils.create_file('test.png') config = create_config_model( 'my_script', output_files=[inline_image('##any_path.png#')]) execution_id = self.start_execution(config) full_path = file_utils.normalize_path(path) self.write_output(execution_id, '123\n' + full_path + '\n456') self.wait_output_chunks(execution_id, chunks_count=1) self.assert_images(full_path) def test_single_dynamic_image_when_unnormalized(self): test_utils.create_file('sub/test.png') config = create_config_model( 'my_script', output_files=[inline_image('#([\.\w]+/)+\w+.png#')]) execution_id = self.start_execution(config) unnormalized_path = os.path.join(test_utils.temp_folder, '.', 'sub', '..', 'sub', 'test.png') self.write_output(execution_id, '_ ' + unnormalized_path + ' _\n') self.wait_output_chunks(execution_id, chunks_count=1) image_keys = [img[0] for img in self.images] self.assertEqual([unnormalized_path], image_keys) def test_mixed_images_when_multiple_output(self): path1 = test_utils.create_file('test123.png') path2 = test_utils.create_file('images/test.png') path3 = test_utils.create_file('a.b.c.png') path4 = test_utils.create_file('test456.png') path5 = test_utils.create_file('some/long/path/me.jpg') config = create_config_model( 'my_script', output_files=[ inline_image(test_utils.temp_folder + os_utils.path_sep() + '#test\d+.png#'), inline_image(path2), inline_image(path3), inline_image('##any_path/path/\w+#.jpg') ]) execution_id = self.start_execution(config) paths = [ normalize_path(p) for p in (path1, path2, path3, path4, path5) ] for index, path in enumerate(paths): self.write_output(execution_id, '__ ' + path + ' __\n') self.wait_output_chunks(execution_id, chunks_count=index + 1) self.write_output(execution_id, '__ ' + path2 + ' __\n') self.wait_output_chunks(execution_id, chunks_count=len(paths) + 1) self.assert_images(*paths) def test_find_multiple_images_by_same_pattern(self): path1 = test_utils.create_file('test123.png') test_utils.create_file('images/test.png') path3 = test_utils.create_file('a.b.c.png') path4 = test_utils.create_file('some/sub/folder/test456.png') config = create_config_model( 'my_script', output_files=[inline_image('##any_path.png#')]) execution_id = self.start_execution(config) paths = [normalize_path(p) for p in (path1, path3, path4)] for index, path in enumerate(paths): self.write_output(execution_id, '__ ' + path + ' __\n') self.wait_output_chunks(execution_id, chunks_count=index + 1) self.assert_images(*paths) def test_image_path_split_in_chunks(self): path = test_utils.create_file('test123.png') config = create_config_model( 'my_script', output_files=[inline_image('##any_path.png#')]) execution_id = self.start_execution(config) normalized = normalize_path(path) self.write_output(execution_id, normalized[:4]) self.wait_output_chunks(execution_id, chunks_count=1) self.write_output(execution_id, normalized[4:] + '\n') self.wait_output_chunks(execution_id, chunks_count=2) self.assert_images(path) def test_image_path_split_in_chunks_and_no_newlines(self): path = test_utils.create_file('test123.png') config = create_config_model( 'my_script', output_files=[inline_image('##any_path.png#')]) execution_id = self.start_execution(config) normalized = normalize_path(path) self.write_output(execution_id, normalized[:4]) self.wait_output_chunks(execution_id, chunks_count=1) self.write_output(execution_id, normalized[4:]) self.wait_output_chunks(execution_id, chunks_count=2) self.executor_service.get_active_executor( execution_id).process_wrapper.stop() self.wait_close(execution_id) self.assert_images(path) def wait_output_chunks(self, execution_id, *, chunks_count): waiter = OutputWaiter() self.executor_service.get_anonymized_output_stream( execution_id).subscribe(waiter) waiter.wait_chunks(chunks_count, timeout=0.5) def wait_close(self, execution_id): chunk_condition = threading.Condition() closed = False def waiter(): global closed closed = True with chunk_condition: chunk_condition.notify_all() self.executor_service.get_anonymized_output_stream( execution_id).subscribe_on_close(waiter) with chunk_condition: chunk_condition.wait_for(lambda: closed, 0.5) def write_output(self, execution_id, output): process_wrapper = self.executor_service.get_active_executor( execution_id).process_wrapper process_wrapper.write_output(output) def start_execution(self, config): execution_id = self.executor_service.start_script( config, {}, 'userX', {}) self.file_download_feature.subscribe_on_inline_images( execution_id, self._add_image) return execution_id def assert_images(self, *paths): normalized_paths = [file_utils.normalize_path(p) for p in paths] actual_paths = [ file_utils.normalize_path(image[0]) for image in self.images ] self.assertCountEqual(normalized_paths, actual_paths)
class ExecutionLoggingInitiatorTest(unittest.TestCase): def test_start_logging_on_execution_start(self): execution_id = self.executor_service.start_script( create_config_model('my_script'), {}, 'userX', create_audit_names(ip='localhost')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper.finish(0) entry = self.logging_service.find_history_entry(execution_id) self.assertIsNotNone(entry) def test_logging_values(self): param1 = create_script_param_config('p1') param2 = create_script_param_config('p2', param='-x') param3 = create_script_param_config('p3', param='-y', no_value=True) param4 = create_script_param_config('p4', param='-z', type='int') config_model = create_config_model( 'my_script', script_command='echo', parameters=[param1, param2, param3, param4]) execution_id = self.executor_service.start_script( config_model, {'p1': 'abc', 'p3': True, 'p4': 987}, 'userX', create_audit_names(ip='localhost', auth_username='******')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper._write_script_output('some text\n') executor.process_wrapper._write_script_output('another text') executor.process_wrapper.finish(0) wait_observable_close_notification(executor.get_anonymized_output_stream(), 2) entry = self.logging_service.find_history_entry(execution_id) self.assertIsNotNone(entry) self.assertEqual('userX', entry.user_id) self.assertEqual('sandy', entry.user_name) self.assertEqual('my_script', entry.script_name) self.assertEqual('echo abc -y -z 987', entry.command) self.assertEqual('my_script', entry.script_name) log = self.logging_service.find_log(execution_id) self.assertEqual('some text\nanother text', log) def test_exit_code(self): config_model = create_config_model( 'my_script', script_command='ls', parameters=[]) execution_id = self.executor_service.start_script( config_model, {}, 'userX', create_audit_names(ip='localhost')) executor = self.executor_service.get_active_executor(execution_id) executor.process_wrapper._write_script_output('some text\n') executor.process_wrapper._write_script_output('another text') executor.process_wrapper.finish(14) wait_observable_close_notification(executor.get_anonymized_output_stream(), 2) entry = self.logging_service.find_history_entry(execution_id) self.assertEqual(14, entry.exit_code) def setUp(self): test_utils.setup() executor._process_creator = _MockProcessWrapper self.logging_service = ExecutionLoggingService(test_utils.temp_folder, LogNameCreator()) self.executor_service = ExecutionService(_IdGeneratorMock()) self.controller = ExecutionLoggingController(self.executor_service, self.logging_service) self.controller.start() def tearDown(self): test_utils.cleanup() executions = self.executor_service.get_active_executions('userX') for execution_id in executions: try: self.executor_service.kill_script(execution_id) self.executor_service.cleanup_execution(execution_id) except: traceback.print_exc()