def test_execute_jobs(): context = Mock() context.args = Mock() context.args.event_handlers = None task_context = Mock() task_context.pkg = Mock() task_context.pkg.name = 'name' jobs = { 'one': Job(identifier='id', dependencies=set(), task=None, task_context=task_context) } event_reactor = Mock() event_reactor.__enter__ = lambda self: self event_reactor.__exit__ = lambda self, *args: None with patch('colcon_core.executor.create_event_reactor', return_value=event_reactor): with EntryPointContext(extension1=Extension1, extension2=Extension2): # no extension selected with pytest.raises(AssertionError): execute_jobs(context, jobs) # execute method not implemented and sending skipped job event context.args.executor = 'extension2' with patch('colcon_core.executor.logger.error') as error: rc = execute_jobs(context, jobs) assert rc == 1 assert error.call_count == 1 assert len(error.call_args[0]) == 1 assert error.call_args[0][0].startswith( "Exception in executor extension 'extension2': \n") assert event_reactor.get_queue().put.call_count == 2 assert isinstance( event_reactor.get_queue().put.call_args_list[0][0][0][0], JobQueued) assert isinstance( event_reactor.get_queue().put.call_args_list[1][0][0][0], JobSkipped) # successful execution event_reactor.get_queue().put.reset_mock() jobs['one'].returncode = 0 extensions = get_executor_extensions() extensions[110]['extension2'].execute = \ lambda args, jobs, on_error: 0 callback = Mock() rc = execute_jobs(context, jobs, on_error=OnError.interrupt, pre_execution_callback=callback) assert rc == 0 assert event_reactor.get_queue().put.call_count == 1 assert isinstance(event_reactor.get_queue().put.call_args[0][0][0], JobQueued) assert callback.call_count == 1
def _get_jobs(self, args, installers, decorators): jobs = OrderedDict() workspace_package_names = [ decorator.descriptor.name for decorator in decorators ] logger.info( 'Including {} in bundle...'.format(workspace_package_names)) for decorator in decorators: if not decorator.selected: continue pkg = decorator.descriptor extension = get_task_extension('colcon_bundle.task.bundle', pkg.type) if not extension: logger.warn('No task extension to bundle a {pkg.type} package'. format_map(locals())) continue recursive_dependencies = OrderedDict() for dep_name in decorator.recursive_dependencies: dep_path = args.install_base if not args.merge_install: dep_path = os.path.join(dep_path, dep_name) recursive_dependencies[dep_name] = dep_path dest = self.task_argument_destinations.values() package_args = BundlePackageArguments(pkg, installers, args, additional_destinations=dest) ordered_package_args = ', '.join([ ('%s: %s' % (repr(k), repr(package_args.__dict__[k]))) for k in sorted(package_args.__dict__.keys()) ]) logger.debug( 'Bundling package {pkg.name} with the following arguments: ' '{{{ordered_package_args}}}'.format_map(locals())) task_context = TaskContext(pkg=pkg, args=package_args, dependencies=recursive_dependencies) task_context.installers = installers job = Job(identifier=pkg.name, dependencies=set(recursive_dependencies.keys()), task=extension, task_context=task_context) jobs[pkg.name] = job return jobs
def _get_jobs(self, args, decorators, install_base): jobs = OrderedDict() unselected_packages = set() for decorator in decorators: pkg = decorator.descriptor if not decorator.selected: unselected_packages.add(pkg) continue extension = get_task_extension('colcon_core.task.build', pkg.type) if not extension: logger.warning( "No task extension to 'build' a '{pkg.type}' package". format_map(locals())) continue recursive_dependencies = OrderedDict() for dep_name in decorator.recursive_dependencies: dep_path = install_base if not args.merge_install: dep_path = os.path.join(dep_path, dep_name) recursive_dependencies[dep_name] = dep_path package_args = BuildPackageArguments( pkg, args, additional_destinations=self.task_argument_destinations.values( )) ordered_package_args = ', '.join([ ('%s: %s' % (repr(k), repr(package_args.__dict__[k]))) for k in sorted(package_args.__dict__.keys()) ]) logger.debug( "Building package '{pkg.name}' with the following arguments: " '{{{ordered_package_args}}}'.format_map(locals())) task_context = TaskContext(pkg=pkg, args=package_args, dependencies=recursive_dependencies) job = Job(identifier=pkg.name, dependencies=set(recursive_dependencies.keys()), task=extension, task_context=task_context) jobs[pkg.name] = job return jobs, unselected_packages
def test_job(): task = Task() task_context = Mock() task_context.dependencies = Mock() task_context.pkg = Mock() task_context.pkg.name = 'name' job = Job(identifier='id', dependencies=set(), task=task, task_context=task_context) assert str(job) == 'id' events = [] event_queue = Mock() event_queue.put = lambda event: events.append(event) job.set_event_queue(event_queue) assert len(events) == 1 assert isinstance(events[-1][0], JobQueued) assert events[-1][0].identifier == 'name' assert events[-1][0].dependencies == task_context.dependencies assert events[-1][1] == job # successful task rc = run_until_complete(job()) assert rc == 0 assert len(events) == 3 assert isinstance(events[-2][0], JobStarted) assert events[-2][0].identifier == 'name' assert events[-2][1] == job assert isinstance(events[-1][0], JobEnded) assert events[-1][0].identifier == 'name' assert events[-1][0].rc == 0 assert events[-1][1] == job # canceled task job.returncode = None task.return_value = CancelledError() rc = run_until_complete(job()) assert rc is SIGINT_RESULT assert len(events) == 5 assert isinstance(events[-2][0], JobStarted) assert events[-2][0].identifier == 'name' assert events[-2][1] == job assert isinstance(events[-1][0], JobEnded) assert events[-1][0].identifier == 'name' assert events[-1][0].rc is SIGINT_RESULT assert events[-1][1] == job # task raising exception job.returncode = None task.return_value = RuntimeError('custom exception') with pytest.raises(RuntimeError): run_until_complete(job()) assert len(events) == 8 assert isinstance(events[-3][0], JobStarted) assert events[-3][0].identifier == 'name' assert events[-3][1] == job assert isinstance(events[-2][0], StderrLine) assert events[-2][0].line.endswith(b'\nRuntimeError: custom exception\n') assert events[-2][1] == job assert isinstance(events[-1][0], JobEnded) assert events[-1][0].identifier == 'name' assert events[-1][0].rc == 1 assert events[-1][1] == job # override task return code job.returncode = 2 task.return_value = 0 rc = run_until_complete(job()) assert rc == 2 assert len(events) == 10 assert isinstance(events[-2][0], JobStarted) assert events[-2][0].identifier == 'name' assert events[-2][1] == job assert isinstance(events[-1][0], JobEnded) assert events[-1][0].identifier == 'name' assert events[-1][0].rc == 2 assert events[-1][1] == job
def main(self, *, context): check_and_mark_build_tool(context.args.build_base) lcov_base_abspath = Path(os.path.abspath(context.args.lcov_base)) lcov_base_abspath.mkdir(exist_ok=True) gcc_pkgs = self._get_gcc_packages(context, additional_argument_names=['*']) jobs = OrderedDict() for pkg in gcc_pkgs: task_context = TaskContext(pkg=pkg, args=context.args, dependencies=OrderedDict()) if context.args.zero_counters: extension = LcovZeroCountersTask() else: extension = LcovCaptureTask() extension.PACKAGE_TYPE = pkg.type job = Job( identifier=pkg.name, dependencies=set(), # Can be generated in any order task=extension, task_context=task_context) jobs[pkg.name] = job rc = execute_jobs(context, jobs) if context.args.initial or context.args.zero_counters: return rc print("\nCalculating total coverage... ") total_output_file = str(lcov_base_abspath / 'total_coverage.info') if rc == 0: output_files = [] for pkg in gcc_pkgs: output_file = os.path.abspath( os.path.join(context.args.build_base, pkg.name, 'coverage.info')) if os.stat(output_file).st_size != 0: output_files.append(output_file) if len(output_files) == 0: logger.error( 'No valid coverage.info files found. Did you run tests?') return 1 rc = lcov_add(context, output_files, total_output_file, verbose=context.args.verbose) if rc != 0: return rc if context.args.filter: print("\nApplying filters... ") rc = lcov_remove(context, total_output_file) if rc != 0: return rc print("\nGenerating HTML: ", end='') # Check that genhtml exists if GENHTML_EXECUTABLE is None: raise RuntimeError("Could not find 'genhtml' executable") # Generate html cmd = [ GENHTML_EXECUTABLE, '--quiet', '--output-directory', str(lcov_base_abspath), total_output_file, '--config-file', str(context.args.lcov_config_file) ] if CPP_FILT_EXECUTABLE is not None: cmd.extend(['--demangle-cpp']) # Strip paths to packages for path in context.args.base_paths: cmd.extend(['--prefix', str(os.path.abspath(path))]) rc = subprocess.run(cmd).returncode print("Done") return rc
def main(self, *, context): # noqa: D102 build_base = context.args.build_base check_and_mark_build_tool(build_base) # Check once if the 'coverage' command is available, # otherwise we will need to fall back on using the Python module has_command = has_coverage_command() logger.info("'coverage' command available: {has_command}".format_map( locals())) # Get packages coveragepy_pkgs = self._get_coveragepy_packages(context) if not coveragepy_pkgs: logger.warning('No packages selected or found') return 0 # Combine each package's .coverage files jobs = OrderedDict() for pkg in coveragepy_pkgs: task_context = TaskContext( pkg=pkg, args=context.args, dependencies=OrderedDict(), ) task = CoveragePyTask(has_command) job = Job( identifier=pkg.name, dependencies=set(), task=task, task_context=task_context, ) jobs[pkg.name] = job rc = execute_jobs(context, jobs) # Get all packages' .coverage files coverage_files = [ str( Path( CoveragePyTask.get_package_combine_dir( build_base, pkg.name)) / '.coverage') for pkg in coveragepy_pkgs ] # Filter out non-existing files in case processing failed for some packages coverage_files = list(filter(os.path.exists, coverage_files)) if 0 == len(coverage_files): logger.warning('No coverage files found') return 0 logger.info('Coverage files: {coverage_files}'.format_map(locals())) # Combine .coverage files coveragepy_base_dir = str(os.path.abspath( context.args.coveragepy_base)) Path(coveragepy_base_dir).mkdir(exist_ok=True) rc, stdout, _ = coverage_combine(coverage_files, coveragepy_base_dir, has_command) if 0 == rc and context.args.verbose: # Print report rc, stdout, _ = coverage_report( coveragepy_base_dir, context.args.coverage_report_args, has_command, ) if 0 == rc: print('\n' + stdout) # Generate HTML report rc, stdout, _ = coverage_html( coveragepy_base_dir, context.args.coverage_html_args, has_command, ) return rc