From dff662fa0f245216e5554474fe8c6ff72a7fe66a Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Wed, 23 May 2018 06:48:22 -0700 Subject: [PATCH] Add plugins to ansible-doc test and fix issues. --- lib/ansible/plugins/callback/null.py | 2 +- lib/ansible/plugins/lookup/_redis_kv.py | 2 +- .../plugins/lookup/cyberarkpassword.py | 1 + lib/ansible/plugins/lookup/shelvefile.py | 1 + test/runner/lib/sanity/ansible_doc.py | 92 +++++++++++++------ 5 files changed, 69 insertions(+), 29 deletions(-) diff --git a/lib/ansible/plugins/callback/null.py b/lib/ansible/plugins/callback/null.py index b40b6d2b3a7..7cf9f9c4e77 100644 --- a/lib/ansible/plugins/callback/null.py +++ b/lib/ansible/plugins/callback/null.py @@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type DOCUMENTATION = ''' - callback: null + callback: 'null' callback_type: stdout requirements: - set as main display callback diff --git a/lib/ansible/plugins/lookup/_redis_kv.py b/lib/ansible/plugins/lookup/_redis_kv.py index fae1fb653bb..d3ce9d62664 100644 --- a/lib/ansible/plugins/lookup/_redis_kv.py +++ b/lib/ansible/plugins/lookup/_redis_kv.py @@ -11,7 +11,7 @@ DOCUMENTATION = """ short_description: fetch data from Redis deprecated: why: This lookup uses options intermingled with terms which blurs the interface between settings and data - version: '2.9' + removed_in: '2.9' alternative: new 'redis' lookup description: - this lookup returns a list of items given to it, if any of the top level items is also a list it will flatten it, but it will not recurse diff --git a/lib/ansible/plugins/lookup/cyberarkpassword.py b/lib/ansible/plugins/lookup/cyberarkpassword.py index eb49f0eb05e..d18d3224b8a 100644 --- a/lib/ansible/plugins/lookup/cyberarkpassword.py +++ b/lib/ansible/plugins/lookup/cyberarkpassword.py @@ -11,6 +11,7 @@ DOCUMENTATION = """ requirements: - CyberArk AIM tool installed description: + - Get secrets from CyberArk AIM. options : _command: description: Cyberark CLI utility. diff --git a/lib/ansible/plugins/lookup/shelvefile.py b/lib/ansible/plugins/lookup/shelvefile.py index bfb4077f045..c19e4d41b6a 100644 --- a/lib/ansible/plugins/lookup/shelvefile.py +++ b/lib/ansible/plugins/lookup/shelvefile.py @@ -10,6 +10,7 @@ DOCUMENTATION = """ version_added: "2.0" short_description: read keys from Python shelve file description: + - Read keys from Python shelve file. optoins: _terms: description: sets of key value pairs of parameters diff --git a/test/runner/lib/sanity/ansible_doc.py b/test/runner/lib/sanity/ansible_doc.py index 68590b02b2d..2e5c73e8092 100644 --- a/test/runner/lib/sanity/ansible_doc.py +++ b/test/runner/lib/sanity/ansible_doc.py @@ -1,6 +1,8 @@ """Sanity test for ansible-doc.""" from __future__ import absolute_import, print_function +import collections +import os import re from lib.sanity import ( @@ -38,51 +40,87 @@ class AnsibleDocTest(SanityMultipleVersion): with open('test/sanity/ansible-doc/skip.txt', 'r') as skip_fd: skip_modules = set(skip_fd.read().splitlines()) + plugin_type_blacklist = set([ + # not supported by ansible-doc + 'action', + 'cliconf', + 'filter', + 'httpapi', + 'netconf', + 'terminal', + 'test', + ]) + modules = sorted(set(m for i in targets.include_external for m in i.modules) - set(m for i in targets.exclude_external for m in i.modules) - skip_modules) - if not modules: + plugins = [os.path.splitext(i.path)[0].split('/')[-2:] + [i.path] for i in targets.include if os.path.splitext(i.path)[1] == '.py' and + os.path.basename(i.path) != '__init__.py' and + re.search(r'^lib/ansible/plugins/[^/]+/', i.path) + and i.path != 'lib/ansible/plugins/cache/base.py'] + + doc_targets = collections.defaultdict(list) + target_paths = collections.defaultdict(dict) + + for module in modules: + doc_targets['module'].append(module) + + for plugin_type, plugin_name, plugin_path in plugins: + if plugin_type in plugin_type_blacklist: + continue + + doc_targets[plugin_type].append(plugin_name) + target_paths[plugin_type][plugin_name] = plugin_path + + if not doc_targets: return SanitySkipped(self.name, python_version=python_version) - module_paths = dict((t.module, t.path) for t in targets.targets if t.module) + target_paths['module'] = dict((t.module, t.path) for t in targets.targets if t.module) env = ansible_environment(args, color=False) - cmd = ['ansible-doc'] + modules + error_messages = [] + + for doc_type in sorted(doc_targets): + cmd = ['ansible-doc', '-t', doc_type] + sorted(doc_targets[doc_type]) + + try: + stdout, stderr = intercept_command(args, cmd, target_name='ansible-doc', env=env, capture=True, python_version=python_version) + status = 0 + except SubprocessError as ex: + stdout = ex.stdout + stderr = ex.stderr + status = ex.status - try: - stdout, stderr = intercept_command(args, cmd, target_name='ansible-doc', env=env, capture=True, python_version=python_version) - status = 0 - except SubprocessError as ex: - stdout = ex.stdout - stderr = ex.stderr - status = ex.status + if stderr: + errors = stderr.strip().splitlines() + messages = [self.parse_error(e, target_paths) for e in errors] - if stderr: - errors = stderr.strip().splitlines() - messages = [self.parse_error(e, module_paths) for e in errors] + if messages and all(messages): + error_messages += messages + continue - if messages and all(messages): - return SanityFailure(self.name, messages=messages, python_version=python_version) + if status: + summary = u'%s' % SubprocessError(cmd=cmd, status=status, stderr=stderr) + return SanityFailure(self.name, summary=summary, python_version=python_version) - if status: - summary = u'%s' % SubprocessError(cmd=cmd, status=status, stderr=stderr) - return SanityFailure(self.name, summary=summary, python_version=python_version) + if stdout: + display.info(stdout.strip(), verbosity=3) - if stdout: - display.info(stdout.strip(), verbosity=3) + if stderr: + summary = u'Output on stderr from ansible-doc is considered an error.\n\n%s' % SubprocessError(cmd, stderr=stderr) + return SanityFailure(self.name, summary=summary, python_version=python_version) - if stderr: - summary = u'Output on stderr from ansible-doc is considered an error.\n\n%s' % SubprocessError(cmd, stderr=stderr) - return SanityFailure(self.name, summary=summary, python_version=python_version) + if error_messages: + return SanityFailure(self.name, messages=error_messages, python_version=python_version) return SanitySuccess(self.name, python_version=python_version) @staticmethod - def parse_error(error, module_paths): + def parse_error(error, target_paths): """ :type error: str - :type module_paths: dict[str, str] + :type target_paths: dict[str, dict[str, str]] :rtype: SanityMessage | None """ # example error messages from lib/ansible/cli/doc.py: @@ -97,10 +135,10 @@ class AnsibleDocTest(SanityMultipleVersion): error_name = groups['name'] error_text = groups['text'] - if error_type == 'module' and error_name in module_paths: + if error_name in target_paths.get(error_type, {}): return SanityMessage( message=error_text, - path=module_paths[error_name], + path=target_paths[error_type][error_name], ) return None