def test_get_state_is_not_the_same_object(self): work_request = WorkRequest({'action_instance_id': 1}) eq_(work_request.__dict__, work_request.__getstate__()) ok_( id(work_request.__dict__) != id(work_request.__getstate__()), "Dict should not be the same memory location, should be a copy.")
def test_prepare_to_send_with_hash_with__grain(self): work_request = WorkRequest() work_request.prepare_to_send({ 'action_instance_id': 1, 'pipeline_instance_id': 2, '_grain': 'foobar' }) eq_(1, work_request.action_instance_id) eq_(2, work_request.pipeline_instance_id) eq_('foobar', work_request.grain)
def test_prepare_to_send_with_obj_with__grain(self): mock_obj = MagicMock(action_instance_id=1, pipeline_instance_id=2, _grain='foobar') del mock_obj.grain work_request = WorkRequest() work_request.prepare_to_send(mock_obj) eq_(1, work_request.action_instance_id) eq_(2, work_request.pipeline_instance_id) eq_('foobar', work_request.grain)
def test_verify_work_request_no_executable(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ work_request = WorkRequest() executor = Executor(work_request, "http") work_request.action_instance_id = 1 with self.assertRaises(Exception) as cm: executor.verify_work_request() self.assertEqual("Executable not set, nothing to run.", str(cm.exception))
def test_verify_work_request_no_pipeline_instance_id(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ work_request = WorkRequest() executor = Executor(work_request, "http") work_request.action_instance_id = 1 work_request.executable = "something" with self.assertRaises(Exception) as cm: executor.verify_work_request() self.assertEqual("No pipline_instance_id set.", str(cm.exception))
def test_generate_from_request_with_grain(self): mock_obj = MagicMock() mock_obj.json = { 'action_instance_id': 1, 'pipeline_instance_id': 2, 'grain': 'foobar' } work_request = WorkRequest() work_request.generate_from_request(mock_obj) eq_(1, work_request.action_instance_id) eq_(2, work_request.pipeline_instance_id) eq_('foobar', work_request.grain)
def test_get_results(self): """ rapid-unit: Rapid Client:Can gather test results :return: :rtype: """ executor = Executor(WorkRequest(), None) file_name = '{}/parsers/*.xml'.format( os.path.dirname(os.path.realpath(__file__))) eq_( { 'JUnitXmlReporter.constructor~should default path to an empty string': { 'status': 'FAILED', 'stacktrace': 'Assertion failed', 'time': '0.006' }, 'JUnitXmlReporter.constructor~should default consolidate to true': { 'status': 'SKIPPED', 'time': '0' }, 'JUnitXmlReporter.constructor~should default useDotNotation to true': { 'status': 'SUCCESS', 'time': '0' }, '__summary__': { 'FAILED': 1, 'SKIPPED': 1, 'SUCCESS': 1, Constants.FAILURES_COUNT: False } }, executor._get_results('/', [file_name]))
def test_get_environment(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ executor = Executor( WorkRequest({ 'action_instance_id': 1, 'pipeline_instance_id': 2, 'environment': { 'Something': 'More' } }), None) environment = os.environ environment.update({ 'Something': 'More', 'action_instance_id': '1', 'pipeline_instance_id': '2', 'PYTHONUNBUFFERED': 'true' }) test = executor.get_environment() eq_('More', executor.get_environment()['Something']) eq_('1', executor.get_environment()['action_instance_id']) eq_('2', executor.get_environment()['pipeline_instance_id']) eq_('true', executor.get_environment()['PYTHONUNBUFFERED'])
def test_dynamic_grain_one_found(self): work_request = WorkRequest({ "environment": { "foo": "cool" }, "grain": '{foo};{bar}' }) eq_("cool;{bar}", work_request.grain)
def test_get_arguments_from_work_request(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ executor = Executor(WorkRequest({'args': "testing arguments"}), "bogus") eq_(["testing", "arguments"], executor.get_arguments())
def test_get_results_FAILURE(self): """ rapid-unit: Rapid Client:Remote Execution:Return codes greater than 0 will result in failure. :return: :rtype: """ executor = Executor(WorkRequest(), None) eq_("FAILED", executor._get_status(1))
def test_get_parameters(self): """ rapid-unit: Rapid Client:Remote Execution:Parameters can be recorded and passed via pipeline_instance :return: :rtype: """ executor = Executor(WorkRequest(), None) eq_(["/tmp/testing.txt", "/tmp/*.txt"], executor._get_parameters_files("{}/tmp/testing.txt,/tmp/*.txt".format(Constants.PARAMETERS)))
def test_dynamic_grain_multiple_found(self): work_request = WorkRequest({ "environment": { "foo": "cool", "bar": "stuff" }, "grain": '{foo};{bar}' }) eq_("cool;stuff", work_request.grain)
def test_get_arguments_empty_work_request(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ executor = Executor(WorkRequest({'args': None}), "bogus") eq_([], executor.get_arguments())
def test_get_stats(self): """ rapid-unit: Rapid Client:Remote Execution:Statistics can be recorded per pipeline_instance :return: :rtype: """ executor = Executor(WorkRequest(), None) eq_(['/tmp/testing.txt', '/tmp/*.txt'], executor._get_stats_files("{}/tmp/testing.txt,/tmp/*.txt".format(Constants.STATS)))
def test_get_results_OVERRIDE(self): """ rapid-unit: Rapid Client:Remote Execution:You can override return codes with different statuses. :return: :rtype: """ executor = Executor(WorkRequest(), None) executor.status_overrides = {4: "GIT_ERROR"} eq_("GIT_ERROR", executor._get_status(4))
def start_work(self): executor = Executor( WorkRequest(request.get_json()), self.app.rapid_config.master_uri, workspace=self.app.rapid_config.workspace, quarantine=self.app.rapid_config.quarantine_directory, verify_certs=self.app.rapid_config.verify_certs, rapid_config=self.app.rapid_config) executor.verify_work_request() executor.start()
def test_jsonify(self): work_request = WorkRequest({ 'action_instance_id': 1, 'pipeline_instance_id': 2 }) eq_( json.loads( '{"executable": null, "environment": {}, "headers": {"content-type": "application/json"}, "cmd": null, "args": null, "slice": null, "workflow_instance_id": null, "action_instance_id": 1, "pipeline_instance_id": 2, "grain": null, "configuration": null}' ), json.loads(json.dumps(work_request, cls=WorkRequestEncoder)))
def test_get_parameters_error(self): """ rapid-unit: Rapid Client:Remote Execution:Parameters can be recorded and passed via pipeline_instance :return: :rtype: """ executor = Executor(WorkRequest(), None) with self.assertRaises(Exception) as cm: executor._get_parameters_files("nothing") self.assertEqual("list index out of range", str(cm.exception))
def test_send_work(self, requests): client = Client(None, None, None, False) work_request = WorkRequest() client.send_work(work_request) eq_(1, requests.post.call_count) requests.post.assert_called_with(client.get_work_uri(), json=work_request.__dict__, headers=client.get_headers(), verify=True, timeout=4)
def test_clean_workspace_valid_dir(self, mock_os, mock_shutil, mock_logger): """ rapid-unit: Rapid Client:Remote Execution:Code will execute in sandboxed workspace :return: :rtype: """ executor = Executor(WorkRequest({'args': "testing arguments"}), "bogus", workspace="boggus", logger=mock_logger) mock_os.sep = '/' executor.clean_workspace() mock_shutil.rmtree.assert_called_with("boggus", ignore_errors=True)
def test_verify_work_request_no_action_instance_id(self): """ rapid-unit: Rapid Client:Remote Execution:Can remotely execute code on client :return: :rtype: """ work_request = WorkRequest() executor = Executor(work_request, "http") with self.assertRaises(Exception) as cm: executor.verify_work_request() self.assertEqual("Invalid action_instance_id", str(cm.exception))
def test_clean_workspace_invalid_dir(self, mock_os): """ rapid-unit: Rapid Client:Remote Execution:Code will execute in sandboxed workspace :return: :rtype: """ executor = Executor(WorkRequest({'args': "testing arguments"}), "bogus", workspace="boggus") mock_os.path.isdir.return_value = False mock_os.sep = '/' executor.clean_workspace() mock_os.makedirs.assert_called_with("boggus")
def test_clean_workspace_valid_dir_exception(self, mock_os, mock_shutil, mock_logger): """ rapid-unit: Rapid Client:Remote Execution:Code will execute in sandboxed workspace :return: :rtype: """ executor = Executor(WorkRequest({'args': "testing arguments"}), "bogus", workspace="boggus", logger=mock_logger) def throw_exception(*args, **kwargs): raise Exception("Should not see this") mock_os.sep = '/' mock_shutil.rmtree = throw_exception executor.clean_workspace()
def test_get_command(self): """ rapid-unit: Rapid Client:Remote Execution:Will download remote file when remote: is used. :return: :rtype: """ work_request = WorkRequest({"action_instance_id": 1, "cmd": "/bin/sh", "executable": "{}trial.sh".format(Communication.REMOTE_FILE), "args": "2>&1"}) executor = Executor(work_request, None) communicator = Mock() communicator.get_downloaded_file_name.return_value = "/tmp/rapidci/workspace/trial.sh" eq_(["/bin/sh", "/tmp/rapidci/workspace/trial.sh"], executor.get_command(communicator))
def test_get_read_process_output_with_exception(self): """ rapid-unit: Rapid Client:Logging:Can read the output from external process :return: :rtype: """ mock_logger = Mock() mock_child_process = Mock() def readline(*args, **kwargs): raise Exception("Shouldn't see this.") mock_child_process.stdout.readline = readline executor = Executor(WorkRequest(), "bogus", mock_logger) executor._read_process_output(mock_logger, mock_child_process) mock_logger.info.assert_called_with("__RCI_{}__ - {} - {}".format(None, os.getpid(), "Shouldn't see this."))
def run_action_instance(self, app, action_instance_id): # type: (Flask, int) -> None communicator = ClientCommunicator( self.client_config.master_uri, self.client_config.quarantine_directory, app, self.client_config.verify_certs) self.client_config.is_single_use = True communicator.register(self.client_config) request_json = communicator.get_work_request_by_action_instance_id( action_instance_id) executor = Executor(WorkRequest(request_json), self.client_config.master_uri, workspace=self.client_config.workspace, quarantine=self.client_config.quarantine_directory, verify_certs=self.client_config.verify_certs, rapid_config=self.client_config) executor.verify_work_request() executor.start(False)
def test_get_read_process_output(self): """ rapid-unit: Rapid Client:Logging:Can read the output from external process :return: :rtype: """ mock_logger = Mock() mock_child_process = Mock() results = ["testing", b''] def readline(*args, **kwargs): return results.pop(0) mock_child_process.stdout.readline = readline executor = Executor(WorkRequest(), "bogus", mock_logger) executor._read_process_output(mock_logger, mock_child_process) mock_logger.info.assert_called_with("__RCI_{}__ - {} - {}".format(None, os.getpid(), "Cleaning up thread."))
def test_clean_workspace_invalid_dir_exception(self, mock_os): """ rapid-unit: Rapid Client:Remote Execution:Code will execute in sandboxed workspace :return: :rtype: """ executor = Executor(WorkRequest({'args': "testing arguments"}), "bogus", workspace="boggus") mock_logger = Mock() executor.logger = mock_logger self_exception = Exception("Should not see this") def throw_exception(*args, **kwargs): raise self_exception mock_os.makedirs = throw_exception mock_os.path.isdir.return_value = False mock_os.sep = '/' executor.clean_workspace() mock_logger.exception.assert_called_with(self_exception)
def configure_work_request(self, action_instance, pipeline_parameters, work_requests, results, include_configuration=True): """ :param action_instance: :type action_instance: ActionInstance :param pipeline_parameters: :type pipeline_parameters: PipelineParameters :param results: :type results: list :return: :rtype: """ work_request = None if action_instance.id not in work_requests: work_request = WorkRequest(action_instance.serialize()) work_request.action_instance_id = action_instance.id work_request.pipeline_instance_id = action_instance.pipeline_instance_id work_request.workflow_instance_id = action_instance.workflow_instance_id work_request.slice = action_instance.slice results.append(work_request) work_requests[action_instance.id] = work_request else: work_request = work_requests[action_instance.id] if pipeline_parameters: work_request.environment[ pipeline_parameters.parameter] = pipeline_parameters.value if include_configuration: try: work_request.configuration = action_instance.configuration.configuration except (TypeError, AttributeError): pass