def _filter_mods(command_loader, help_file_entries, modules=None, exclude=False, include_whl_extensions=False): modules = modules or [] # command tables and help entries must be copied to allow for seperate linter scope command_table = command_loader.command_table.copy() command_group_table = command_loader.command_group_table.copy() command_loader = copy.copy(command_loader) command_loader.command_table = command_table command_loader.command_group_table = command_group_table help_file_entries = help_file_entries.copy() name_index = get_name_index(include_whl_extensions=include_whl_extensions) for command_name in list(command_loader.command_table.keys()): try: source_name, _ = _get_command_source(command_name, command_loader.command_table) except LinterError as ex: # command is unrecognized logger.warning(ex) source_name = None try: long_name = name_index[source_name] is_specified = source_name in modules or long_name in modules except KeyError: is_specified = False if is_specified == exclude: # brute force method of ignoring commands from a module or extension command_loader.command_table.pop(command_name, None) help_file_entries.pop(command_name, None) # Remove unneeded command groups retained_command_groups = { ' '.join(x.split(' ')[:-1]) for x in command_loader.command_table } excluded_command_groups = set( command_loader.command_group_table.keys()) - retained_command_groups for group_name in excluded_command_groups: command_loader.command_group_table.pop(group_name, None) help_file_entries.pop(group_name, None) return command_loader, help_file_entries
def _discover_tests(profile): """ Builds an index of tests so that the user can simply supply the name they wish to test instead of the full path. """ profile_split = profile.split('-') profile_namespace = '_'.join([profile_split[-1]] + profile_split[:-1]) heading('Discovering Tests') path_table = get_path_table() core_modules = path_table['core'].items() command_modules = path_table['mod'].items() extensions = path_table['ext'].items() inverse_name_table = get_name_index(invert=True) module_data = {} logger.info('\nCore Modules: %s', ', '.join([name for name, _ in core_modules])) for mod_name, mod_path in core_modules: file_path = mod_path for comp in mod_name.split('-'): file_path = os.path.join(file_path, comp) mod_data = { 'alt_name': 'main' if mod_name == 'azure-cli' else mod_name.replace(COMMAND_MODULE_PREFIX, ''), 'filepath': os.path.join(file_path, 'tests'), 'base_path': '{}.tests'.format(mod_name).replace('-', '.'), 'files': {} } tests = _discover_module_tests(mod_name, mod_data) if tests: module_data[mod_name] = tests logger.info('\nCommand Modules: %s', ', '.join([name for name, _ in command_modules])) for mod_name, mod_path in command_modules: mod_data = { # Modules don't technically have azure-cli-foo moniker anymore, but preserving # for consistency. 'alt_name': '{}{}'.format(COMMAND_MODULE_PREFIX, mod_name), 'filepath': os.path.join( mod_path, 'tests', profile_namespace), 'base_path': 'azure.cli.command_modules.{}.tests.{}'.format(mod_name, profile_namespace), 'files': {} } tests = _discover_module_tests(mod_name, mod_data) if tests: module_data[mod_name] = tests logger.info('\nExtensions: %s', ', '.join([name for name, _ in extensions])) for mod_name, mod_path in extensions: glob_pattern = os.path.normcase(os.path.join('{}*'.format(EXTENSION_PREFIX))) try: file_path = glob.glob(os.path.join(mod_path, glob_pattern))[0] except IndexError: logger.debug("No extension found at: %s", os.path.join(mod_path, glob_pattern)) continue import_name = os.path.basename(file_path) mod_data = { 'alt_name': inverse_name_table[mod_name], 'filepath': os.path.join(file_path, 'tests', profile_namespace), 'base_path': '{}.tests.{}'.format(import_name, profile_namespace), 'files': {} } tests = _discover_module_tests(import_name, mod_data) if tests: module_data[mod_name] = tests test_index = {} conflicted_keys = [] def add_to_index(key, path): from azdev.utilities import extract_module_name key = key or mod_name if key in test_index: if key not in conflicted_keys: conflicted_keys.append(key) mod1 = extract_module_name(path) mod2 = extract_module_name(test_index[key]) if mod1 != mod2: # resolve conflicted keys by prefixing with the module name and a dot (.) logger.warning("'%s' exists in both '%s' and '%s'. Resolve using `%s.%s` or `%s.%s`", key, mod1, mod2, mod1, key, mod2, key) test_index['{}.{}'.format(mod1, key)] = path test_index['{}.{}'.format(mod2, key)] = test_index[key] else: logger.error("'%s' exists twice in the '%s' module. " "Please rename one or both and re-run --discover.", key, mod1) else: test_index[key] = path # build the index for mod_name, mod_data in module_data.items(): # don't add empty mods to the index if not mod_data: continue mod_path = mod_data['filepath'] for file_name, file_data in mod_data['files'].items(): file_path = os.path.join(mod_path, file_name) + '.py' for class_name, test_list in file_data.items(): for test_name in test_list: test_path = '{}::{}::{}'.format(file_path, class_name, test_name) add_to_index(test_name, test_path) class_path = '{}::{}'.format(file_path, class_name) add_to_index(class_name, class_path) add_to_index(file_name, file_path) add_to_index(mod_name, mod_path) add_to_index(mod_data['alt_name'], mod_path) # remove the conflicted keys since they would arbitrarily point to a random implementation for key in conflicted_keys: del test_index[key] return test_index