summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll
diff options
context:
space:
mode:
Diffstat (limited to 'test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll')
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/meta/runtime.yml52
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/default_collection_playbook.yml49
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/play.yml4
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/library/embedded_module.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/tasks/main.yml29
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role_to_call/tasks/main.yml7
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/play.yml4
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/subtype/play.yml4
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/action_subdir/subdir_ping_action.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/bypass_host_loop.py17
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/plugin_lookup.py40
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/subclassed_normal.py11
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/uses_redirected_import.py20
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/callback/usercallback.py26
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/connection/localconn.py41
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/doc_fragments/frag.py18
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/filter_subdir/my_subdir_filters.py14
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters.py14
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters2.py14
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/lookup_subdir/my_subdir_lookup.py11
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup.py11
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup2.py12
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/AnotherCSMU.cs12
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMU.cs19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm116
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/base.py12
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/leaf.py6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/__init__.py0
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/__init__.py0
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/nested_same.py6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/secondary.py6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/__init__.py0
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subcs.cs13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/submod.py6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subps.psm19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init.py11
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/__init__.py10
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/mod_in_subpkg_with_init.py6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/deprecated_ping.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/module_subdir/subdir_ping_module.py14
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/ping.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule.py21
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule_bad_docfrags.py25
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_base_mu_granular_nested_import.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_collection_redirected_mu.py21
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_core_redirected_mu.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.bak3
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.yml3
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_granular_import.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_module_import_from.py31
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing.py16
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_collection.py16
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_module.py16
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_func.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_module.py19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_csbasic_only.ps122
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.ps19
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.py1
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_csmu.ps126
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_psmu.ps125
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps133
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests2.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/test_subdir/my_subdir_tests.py13
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/vars/custom_vars.py48
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/call_standalone/tasks/main.yml6
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/meta/main.yml2
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/tasks/main.yml7
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/common_handlers/handlers/main.yml27
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/role_subdir/subdir_testrole/tasks/main.yml10
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/meta/main.yml2
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/tasks/main.yml16
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/meta/main.yml4
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/tasks/main.yml39
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/meta/main.yml4
-rw-r--r--test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/tasks/main.yml33
79 files changed, 1249 insertions, 0 deletions
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/meta/runtime.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/meta/runtime.yml
new file mode 100644
index 0000000..f5b617d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/meta/runtime.yml
@@ -0,0 +1,52 @@
+plugin_routing:
+ action:
+ uses_redirected_action:
+ redirect: testns.testcoll.subclassed_normal
+ callback:
+ removedcallback:
+ tombstone:
+ removal_date: '2020-01-01'
+ connection:
+ redirected_local:
+ redirect: ansible.builtin.local
+ modules:
+ multilevel1:
+ redirect: testns.testcoll.multilevel2
+ multilevel2:
+ redirect: testns.testcoll.multilevel3
+ multilevel3:
+ redirect: testns.testcoll.ping
+ uses_redirected_action:
+ redirect: ansible.builtin.ping
+ setup.ps1: ansible.windows.setup
+ looped_ping:
+ redirect: testns.testcoll.looped_ping2
+ looped_ping2:
+ redirect: testns.testcoll.looped_ping
+ bogus_redirect:
+ redirect: bogus.collection.shouldbomb
+ deprecated_ping:
+ deprecation:
+ removal_date: 2020-12-31
+ warning_text: old_ping will be removed in a future release of this collection. Use new_ping instead.
+ foobar_facts:
+ redirect: foobar_info
+ aliased_ping:
+ redirect: ansible.builtin.ping
+ dead_ping:
+ tombstone:
+ removal_date: 2019-12-31
+ warning_text: dead_ping has been removed
+ module_utils:
+ moved_out_root:
+ redirect: testns.content_adj.sub1.foomodule
+ formerly_testcoll_pkg:
+ redirect: ansible_collections.testns.othercoll.plugins.module_utils.formerly_testcoll_pkg
+ formerly_testcoll_pkg.submod:
+ redirect: ansible_collections.testns.othercoll.plugins.module_utils.formerly_testcoll_pkg.submod
+ missing_redirect_target_collection:
+ redirect: bogusns.boguscoll.bogusmu
+ missing_redirect_target_module:
+ redirect: testns.othercoll.bogusmu
+
+requires_ansible: '>=2.11'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/default_collection_playbook.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/default_collection_playbook.yml
new file mode 100644
index 0000000..1d1aee7
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/default_collection_playbook.yml
@@ -0,0 +1,49 @@
+# verify default collection action/module lookup works
+# since we're running this playbook inside a collection, it will set that collection as the default search for all playboooks
+# and non-collection roles to allow for easy migration of old integration tests to collections
+- hosts: testhost
+ tasks:
+ - testmodule:
+
+- hosts: testhost
+ vars:
+ test_role_input: task static default collection
+ tasks:
+ - import_role:
+ name: testrole # unqualified role lookup should work; inheriting from the containing collection
+ - assert:
+ that:
+ - test_role_output.msg == test_role_input
+ - vars:
+ test_role_input: task static legacy embedded default collection
+ block:
+ - import_role:
+ name: non_coll_role
+ - assert:
+ that:
+ - test_role_output.msg == test_role_input
+
+- hosts: testhost
+ vars:
+ test_role_input: keyword static default collection
+ roles:
+ - testrole
+ tasks:
+ - debug: var=test_role_input
+ - debug: var=test_role_output
+ - assert:
+ that:
+ - test_role_output.msg == test_role_input
+
+- hosts: testhost
+ vars:
+ test_role_input: task dynamic default collection
+ tasks:
+ - include_role:
+ name: testrole # unqualified role lookup should work; inheriting from the containing collection
+ - include_role:
+ name: non_coll_role
+ - assert:
+ that:
+ - testmodule_out_from_non_coll_role is success
+ - embedded_module_out_from_non_coll_role is success
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/play.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/play.yml
new file mode 100644
index 0000000..6be246c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/play.yml
@@ -0,0 +1,4 @@
+- hosts: localhost
+ gather_facts: false
+ tasks:
+ - set_fact: play='tldr'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/library/embedded_module.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/library/embedded_module.py
new file mode 100644
index 0000000..54402d1
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/library/embedded_module.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='collection_embedded_non_collection_role')))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/tasks/main.yml
new file mode 100644
index 0000000..3fab7fe
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/tasks/main.yml
@@ -0,0 +1,29 @@
+- testmodule:
+ register: testmodule_out_from_non_coll_role
+
+- embedded_module:
+ register: embedded_module_out_from_non_coll_role
+
+- name: check collections list from role meta
+ plugin_lookup:
+ register: pluginlookup_out
+
+- debug: var=pluginlookup_out
+
+- debug:
+ msg: '{{ test_role_input | default("(undefined)") }}'
+ register: test_role_output
+
+- assert:
+ that:
+ - test_role_input is not defined or test_role_input == test_role_output.msg
+
+- vars:
+ test_role_input: include another non-coll role
+ block:
+ - include_role:
+ name: non_coll_role_to_call
+
+ - assert:
+ that:
+ - non_coll_role_to_call_test_role_output.msg == test_role_input
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role_to_call/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role_to_call/tasks/main.yml
new file mode 100644
index 0000000..2b1c15f
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role_to_call/tasks/main.yml
@@ -0,0 +1,7 @@
+- debug:
+ msg: '{{ test_role_input | default("(undefined)") }}'
+ register: non_coll_role_to_call_test_role_output
+
+- assert:
+ that:
+ - 'non_coll_role_to_call_test_role_output.msg == "include another non-coll role"'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/play.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/play.yml
new file mode 100644
index 0000000..dd6d563
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/play.yml
@@ -0,0 +1,4 @@
+- hosts: localhost
+ gather_facts: false
+ tasks:
+ - set_fact: play_type='in type subdir'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/subtype/play.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/subtype/play.yml
new file mode 100644
index 0000000..0e33a76
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/subtype/play.yml
@@ -0,0 +1,4 @@
+- hosts: localhost
+ gather_facts: false
+ tasks:
+ - set_fact: play_type_subtype='in subtype subdir'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/action_subdir/subdir_ping_action.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/action_subdir/subdir_ping_action.py
new file mode 100644
index 0000000..5af7334
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/action_subdir/subdir_ping_action.py
@@ -0,0 +1,19 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action import ActionBase
+
+
+class ActionModule(ActionBase):
+ TRANSFERS_FILES = False
+ _VALID_ARGS = frozenset()
+
+ def run(self, tmp=None, task_vars=None):
+ if task_vars is None:
+ task_vars = dict()
+
+ result = super(ActionModule, self).run(None, task_vars)
+
+ result = dict(changed=False)
+
+ return result
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/bypass_host_loop.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/bypass_host_loop.py
new file mode 100644
index 0000000..b15493d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/bypass_host_loop.py
@@ -0,0 +1,17 @@
+# Copyright: (c) 2020, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action import ActionBase
+
+
+class ActionModule(ActionBase):
+
+ BYPASS_HOST_LOOP = True
+
+ def run(self, tmp=None, task_vars=None):
+ result = super(ActionModule, self).run(tmp, task_vars)
+ result['bypass_inventory_hostname'] = task_vars['inventory_hostname']
+ return result
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/plugin_lookup.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/plugin_lookup.py
new file mode 100644
index 0000000..3fa41e8
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/plugin_lookup.py
@@ -0,0 +1,40 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action import ActionBase
+from ansible.plugins import loader
+
+
+class ActionModule(ActionBase):
+ TRANSFERS_FILES = False
+ _VALID_ARGS = frozenset(('type', 'name'))
+
+ def run(self, tmp=None, task_vars=None):
+ if task_vars is None:
+ task_vars = dict()
+
+ result = super(ActionModule, self).run(None, task_vars)
+
+ plugin_type = self._task.args.get('type')
+ name = self._task.args.get('name')
+
+ result = dict(changed=False, collection_list=self._task.collections)
+
+ if all([plugin_type, name]):
+ attr_name = '{0}_loader'.format(plugin_type)
+
+ typed_loader = getattr(loader, attr_name, None)
+
+ if not typed_loader:
+ return (dict(failed=True, msg='invalid plugin type {0}'.format(plugin_type)))
+
+ context = typed_loader.find_plugin_with_context(name, collection_list=self._task.collections)
+
+ if not context.resolved:
+ result['plugin_path'] = None
+ result['redirect_list'] = []
+ else:
+ result['plugin_path'] = context.plugin_resolved_path
+ result['redirect_list'] = context.redirect_list
+
+ return result
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/subclassed_normal.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/subclassed_normal.py
new file mode 100644
index 0000000..f0eff30
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/subclassed_normal.py
@@ -0,0 +1,11 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action.normal import ActionModule as NormalAction
+
+
+class ActionModule(NormalAction):
+ def run(self, *args, **kwargs):
+ result = super(ActionModule, self).run(*args, **kwargs)
+ result['hacked'] = 'I got run under a subclassed normal, yay'
+ return result
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/uses_redirected_import.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/uses_redirected_import.py
new file mode 100644
index 0000000..701d7b4
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/uses_redirected_import.py
@@ -0,0 +1,20 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action import ActionBase
+from ansible.module_utils.formerly_core import thingtocall
+
+
+class ActionModule(ActionBase):
+ TRANSFERS_FILES = False
+ _VALID_ARGS = frozenset()
+
+ def run(self, tmp=None, task_vars=None):
+ if task_vars is None:
+ task_vars = dict()
+
+ result = super(ActionModule, self).run(None, task_vars)
+
+ result = dict(changed=False, ttc_res=thingtocall())
+
+ return result
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/callback/usercallback.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/callback/usercallback.py
new file mode 100644
index 0000000..b534df2
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/callback/usercallback.py
@@ -0,0 +1,26 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.callback import CallbackBase
+
+DOCUMENTATION = '''
+ callback: usercallback
+ callback_type: notification
+ short_description: does stuff
+ description:
+ - does some stuff
+'''
+
+
+class CallbackModule(CallbackBase):
+ CALLBACK_VERSION = 2.0
+ CALLBACK_TYPE = 'aggregate'
+ CALLBACK_NAME = 'usercallback'
+
+ def __init__(self):
+
+ super(CallbackModule, self).__init__()
+ self._display.display("loaded usercallback from collection, yay")
+
+ def v2_runner_on_ok(self, result):
+ self._display.display("usercallback says ok")
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/connection/localconn.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/connection/localconn.py
new file mode 100644
index 0000000..fc19a99
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/connection/localconn.py
@@ -0,0 +1,41 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.module_utils._text import to_native
+from ansible.plugins.connection import ConnectionBase
+
+DOCUMENTATION = """
+ connection: localconn
+ short_description: do stuff local
+ description:
+ - does stuff
+ options:
+ connectionvar:
+ description:
+ - something we set
+ default: the_default
+ vars:
+ - name: ansible_localconn_connectionvar
+"""
+
+
+class Connection(ConnectionBase):
+ transport = 'local'
+ has_pipelining = True
+
+ def _connect(self):
+ return self
+
+ def exec_command(self, cmd, in_data=None, sudoable=True):
+ stdout = 'localconn ran {0}'.format(to_native(cmd))
+ stderr = 'connectionvar is {0}'.format(to_native(self.get_option('connectionvar')))
+ return (0, stdout, stderr)
+
+ def put_file(self, in_path, out_path):
+ raise NotImplementedError('just a test')
+
+ def fetch_file(self, in_path, out_path):
+ raise NotImplementedError('just a test')
+
+ def close(self):
+ self._connected = False
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/doc_fragments/frag.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/doc_fragments/frag.py
new file mode 100644
index 0000000..4549f2d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/doc_fragments/frag.py
@@ -0,0 +1,18 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+class ModuleDocFragment(object):
+ DOCUMENTATION = r'''
+options:
+ normal_doc_frag:
+ description:
+ - an option
+'''
+
+ OTHER_DOCUMENTATION = r'''
+options:
+ other_doc_frag:
+ description:
+ - another option
+'''
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/filter_subdir/my_subdir_filters.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/filter_subdir/my_subdir_filters.py
new file mode 100644
index 0000000..a5498a4
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/filter_subdir/my_subdir_filters.py
@@ -0,0 +1,14 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def test_subdir_filter(data):
+ return "{0}_via_testfilter_from_subdir".format(data)
+
+
+class FilterModule(object):
+
+ def filters(self):
+ return {
+ 'test_subdir_filter': test_subdir_filter
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters.py
new file mode 100644
index 0000000..0ce239e
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters.py
@@ -0,0 +1,14 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def testfilter(data):
+ return "{0}_via_testfilter_from_userdir".format(data)
+
+
+class FilterModule(object):
+
+ def filters(self):
+ return {
+ 'testfilter': testfilter
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters2.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters2.py
new file mode 100644
index 0000000..0723922
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters2.py
@@ -0,0 +1,14 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def testfilter2(data):
+ return "{0}_via_testfilter2_from_userdir".format(data)
+
+
+class FilterModule(object):
+
+ def filters(self):
+ return {
+ 'testfilter2': testfilter2
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/lookup_subdir/my_subdir_lookup.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/lookup_subdir/my_subdir_lookup.py
new file mode 100644
index 0000000..dd9818c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/lookup_subdir/my_subdir_lookup.py
@@ -0,0 +1,11 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.lookup import LookupBase
+
+
+class LookupModule(LookupBase):
+
+ def run(self, terms, variables, **kwargs):
+
+ return ['subdir_lookup_from_user_dir']
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup.py
new file mode 100644
index 0000000..1cf3d28
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup.py
@@ -0,0 +1,11 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.lookup import LookupBase
+
+
+class LookupModule(LookupBase):
+
+ def run(self, terms, variables, **kwargs):
+
+ return ['mylookup_from_user_dir']
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup2.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup2.py
new file mode 100644
index 0000000..bda671f
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup2.py
@@ -0,0 +1,12 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+from ansible.plugins.lookup import LookupBase
+
+
+class LookupModule(LookupBase):
+
+ def run(self, terms, variables, **kwargs):
+
+ return ['mylookup2_from_user_dir']
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/AnotherCSMU.cs b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/AnotherCSMU.cs
new file mode 100644
index 0000000..68d2bc7
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/AnotherCSMU.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU
+{
+ public class AnotherThing
+ {
+ public static string CallMe()
+ {
+ return "Hello from nested user-collection-hosted AnotherCSMU";
+ }
+ }
+}
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMU.cs b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMU.cs
new file mode 100644
index 0000000..2b7843d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMU.cs
@@ -0,0 +1,19 @@
+using System;
+
+using ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU;
+using ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs;
+
+//TypeAccelerator -Name MyCSMU -TypeName CustomThing
+
+namespace ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU
+{
+ public class CustomThing
+ {
+ public static string HelloWorld()
+ {
+ string res1 = AnotherThing.CallMe();
+ string res2 = NestedUtil.HelloWorld();
+ return String.Format("Hello from user_mu collection-hosted MyCSMU, also {0} and {1}", res1, res2);
+ }
+ }
+}
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs
new file mode 100644
index 0000000..0a3e758
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs
@@ -0,0 +1,19 @@
+using System;
+
+using ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU;
+using ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs;
+
+//TypeAccelerator -Name MyCSMU -TypeName CustomThing
+
+namespace ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU
+{
+ public class CustomThing
+ {
+ public static string HelloWorld()
+ {
+ string res1 = AnotherThing.CallMe();
+ string res2 = NestedUtil.HelloWorld();
+ return String.Format("Hello from user_mu collection-hosted MyCSMUOptional, also {0} and {1}", res1, res2);
+ }
+ }
+}
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm1
new file mode 100644
index 0000000..09da66d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm1
@@ -0,0 +1,9 @@
+Function Invoke-FromUserPSMU {
+ <#
+ .SYNOPSIS
+ Test function
+ #>
+ return "from user_mu"
+}
+
+Export-ModuleMember -Function Invoke-FromUserPSMU
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1
new file mode 100644
index 0000000..1e36159
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1
@@ -0,0 +1,16 @@
+#AnsibleRequires -CSharpUtil Ansible.Invalid -Optional
+#AnsibleRequires -Powershell Ansible.ModuleUtils.Invalid -Optional
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional
+
+Function Invoke-FromUserPSMU {
+ <#
+ .SYNOPSIS
+ Test function
+ #>
+ return "from optional user_mu"
+}
+
+Export-ModuleMember -Function Invoke-FromUserPSMU
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/base.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/base.py
new file mode 100644
index 0000000..0654d18
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/base.py
@@ -0,0 +1,12 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible_collections.testns.testcoll.plugins.module_utils import secondary
+import ansible_collections.testns.testcoll.plugins.module_utils.secondary
+
+
+def thingtocall():
+ if secondary != ansible_collections.testns.testcoll.plugins.module_utils.secondary:
+ raise Exception()
+
+ return "thingtocall in base called " + ansible_collections.testns.testcoll.plugins.module_utils.secondary.thingtocall()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/leaf.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/leaf.py
new file mode 100644
index 0000000..ad84710
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/leaf.py
@@ -0,0 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def thingtocall():
+ return "thingtocall in leaf"
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/__init__.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/__init__.py
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/__init__.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/__init__.py
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/nested_same.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/nested_same.py
new file mode 100644
index 0000000..7740756
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/nested_same.py
@@ -0,0 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def nested_same():
+ return 'hello from nested_same'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/secondary.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/secondary.py
new file mode 100644
index 0000000..9a31568
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/secondary.py
@@ -0,0 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def thingtocall():
+ return "thingtocall in secondary"
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/__init__.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/__init__.py
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subcs.cs b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subcs.cs
new file mode 100644
index 0000000..ebeb8ce
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subcs.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs
+{
+ public class NestedUtil
+ {
+ public static string HelloWorld()
+ {
+ string res = "Hello from subpkg.subcs";
+ return res;
+ }
+ }
+}
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/submod.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/submod.py
new file mode 100644
index 0000000..3c24bc4
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/submod.py
@@ -0,0 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def thingtocall():
+ return "thingtocall in subpkg.submod"
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subps.psm1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subps.psm1
new file mode 100644
index 0000000..1db0ab9
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subps.psm1
@@ -0,0 +1,9 @@
+Function Invoke-SubUserPSMU {
+ <#
+ .SYNOPSIS
+ Test function
+ #>
+ return "from subpkg.subps.psm1"
+}
+
+Export-ModuleMember -Function Invoke-SubUserPSMU
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init.py
new file mode 100644
index 0000000..b48a717
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init.py
@@ -0,0 +1,11 @@
+# NB: this module should never be loaded, since we'll see the subpkg_with_init package dir first
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def thingtocall():
+ raise Exception('this should never be called (loaded discrete module instead of package module)')
+
+
+def anotherthingtocall():
+ raise Exception('this should never be called (loaded discrete module instead of package module)')
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/__init__.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/__init__.py
new file mode 100644
index 0000000..d424796
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/__init__.py
@@ -0,0 +1,10 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+# exercise relative imports in package init; they behave differently
+from .mod_in_subpkg_with_init import thingtocall as submod_thingtocall
+from ..subpkg.submod import thingtocall as cousin_submod_thingtocall # pylint: disable=relative-beyond-top-level
+
+
+def thingtocall():
+ return "thingtocall in subpkg_with_init"
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/mod_in_subpkg_with_init.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/mod_in_subpkg_with_init.py
new file mode 100644
index 0000000..27747da
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/mod_in_subpkg_with_init.py
@@ -0,0 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def thingtocall():
+ return "thingtocall in mod_in_subpkg_with_init"
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/deprecated_ping.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/deprecated_ping.py
new file mode 100644
index 0000000..9698ba6
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/deprecated_ping.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='user', is_deprecated=True)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/module_subdir/subdir_ping_module.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/module_subdir/subdir_ping_module.py
new file mode 100644
index 0000000..5a70174
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/module_subdir/subdir_ping_module.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='user')))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/ping.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/ping.py
new file mode 100644
index 0000000..2ca079c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/ping.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='user')))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule.py
new file mode 100644
index 0000000..e2efada
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+DOCUMENTATION = r'''
+module: testmodule
+description: for testing
+extends_documentation_fragment:
+ - testns.testcoll.frag
+ - testns.testcoll.frag.other_documentation
+'''
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='user')))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule_bad_docfrags.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule_bad_docfrags.py
new file mode 100644
index 0000000..46ccb76
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule_bad_docfrags.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+
+DOCUMENTATION = r'''
+module: testmodule
+description: for testing
+extends_documentation_fragment:
+ - noncollbogusfrag
+ - noncollbogusfrag.bogusvar
+ - bogusns.testcoll.frag
+ - testns.boguscoll.frag
+ - testns.testcoll.bogusfrag
+ - testns.testcoll.frag.bogusvar
+'''
+
+
+def main():
+ print(json.dumps(dict(changed=False, source='user')))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_base_mu_granular_nested_import.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_base_mu_granular_nested_import.py
new file mode 100644
index 0000000..4054e36
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_base_mu_granular_nested_import.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils.base import thingtocall
+
+
+def main():
+ mu_result = thingtocall()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_collection_redirected_mu.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_collection_redirected_mu.py
new file mode 100644
index 0000000..b169fde
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_collection_redirected_mu.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils.moved_out_root import importme
+from ..module_utils.formerly_testcoll_pkg import thing as movedthing # pylint: disable=relative-beyond-top-level
+from ..module_utils.formerly_testcoll_pkg.submod import thing as submodmovedthing # pylint: disable=relative-beyond-top-level
+
+
+def main():
+ mu_result = importme()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result, mu_result2=movedthing, mu_result3=submodmovedthing)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_core_redirected_mu.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_core_redirected_mu.py
new file mode 100644
index 0000000..28a0772
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_core_redirected_mu.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible.module_utils.formerly_core import thingtocall
+
+
+def main():
+ mu_result = thingtocall()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.bak b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.bak
new file mode 100644
index 0000000..703f454
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.bak
@@ -0,0 +1,3 @@
+# Intentionally blank, and intentionally attempting to shadow
+# uses_leaf_mu_flat_import.py. MODULE_IGNORE_EXTS should prevent this file
+# from ever being loaded.
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.py
new file mode 100644
index 0000000..295d432
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+import ansible_collections.testns.testcoll.plugins.module_utils.leaf
+
+
+def main():
+ mu_result = ansible_collections.testns.testcoll.plugins.module_utils.leaf.thingtocall()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.yml
new file mode 100644
index 0000000..703f454
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.yml
@@ -0,0 +1,3 @@
+# Intentionally blank, and intentionally attempting to shadow
+# uses_leaf_mu_flat_import.py. MODULE_IGNORE_EXTS should prevent this file
+# from ever being loaded.
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_granular_import.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_granular_import.py
new file mode 100644
index 0000000..3794f49
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_granular_import.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils.leaf import thingtocall as aliasedthing
+
+
+def main():
+ mu_result = aliasedthing()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_module_import_from.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_module_import_from.py
new file mode 100644
index 0000000..559e3e5
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_module_import_from.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils import leaf, secondary
+# FIXME: this one needs pkginit synthesis to work
+# from ansible_collections.testns.testcoll.plugins.module_utils.subpkg import submod
+from ansible_collections.testns.testcoll.plugins.module_utils.subpkg_with_init import (thingtocall as spwi_thingtocall,
+ submod_thingtocall as spwi_submod_thingtocall,
+ cousin_submod_thingtocall as spwi_cousin_submod_thingtocall)
+
+
+def main():
+ mu_result = leaf.thingtocall()
+ mu2_result = secondary.thingtocall()
+ mu3_result = "thingtocall in subpkg.submod" # FIXME: this one needs pkginit synthesis to work
+ # mu3_result = submod.thingtocall()
+ mu4_result = spwi_thingtocall()
+ mu5_result = spwi_submod_thingtocall()
+ mu6_result = spwi_cousin_submod_thingtocall()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result, mu2_result=mu2_result,
+ mu3_result=mu3_result, mu4_result=mu4_result, mu5_result=mu5_result, mu6_result=mu6_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing.py
new file mode 100644
index 0000000..b945eb6
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ..module_utils import bogusmu # pylint: disable=relative-beyond-top-level
+
+
+def main():
+ raise Exception('should never get here')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_collection.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_collection.py
new file mode 100644
index 0000000..59cb3c5
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_collection.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ..module_utils import missing_redirect_target_collection # pylint: disable=relative-beyond-top-level
+
+
+def main():
+ raise Exception('should never get here')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_module.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_module.py
new file mode 100644
index 0000000..31ffd17
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_module.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ..module_utils import missing_redirect_target_module # pylint: disable=relative-beyond-top-level
+
+
+def main():
+ raise Exception('should never get here')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_func.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_func.py
new file mode 100644
index 0000000..26fa53c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_func.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils.nested_same.nested_same.nested_same import nested_same
+
+
+def main():
+ mu_result = nested_same()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_module.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_module.py
new file mode 100644
index 0000000..e017c14
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_module.py
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import json
+import sys
+
+from ansible_collections.testns.testcoll.plugins.module_utils.nested_same.nested_same import nested_same
+
+
+def main():
+ mu_result = nested_same.nested_same()
+ print(json.dumps(dict(changed=False, source='user', mu_result=mu_result)))
+
+ sys.exit()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_csbasic_only.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_csbasic_only.ps1
new file mode 100644
index 0000000..df17583
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_csbasic_only.ps1
@@ -0,0 +1,22 @@
+#!powershell
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+
+$spec = @{
+ options = @{
+ data = @{ type = "str"; default = "pong" }
+ }
+ supports_check_mode = $true
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+$data = $module.Params.data
+
+if ($data -eq "crash") {
+ throw "boom"
+}
+
+$module.Result.ping = $data
+$module.Result.source = "user"
+$module.ExitJson() \ No newline at end of file
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.ps1
new file mode 100644
index 0000000..986d515
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.ps1
@@ -0,0 +1,9 @@
+#!powershell
+
+$res = @{
+ changed = $false
+ source = "user"
+ msg = "hi from selfcontained.ps1"
+}
+
+ConvertTo-Json $res \ No newline at end of file
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.py
new file mode 100644
index 0000000..ce99bfa
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.py
@@ -0,0 +1 @@
+# docs for Windows module would go here; just ensure we don't accidentally load this instead of the .ps1
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_csmu.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_csmu.ps1
new file mode 100644
index 0000000..af00627
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_csmu.ps1
@@ -0,0 +1,26 @@
+#!powershell
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs
+
+$spec = @{
+ options = @{
+ data = @{ type = "str"; default = "called from $([ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU.CustomThing]::HelloWorld())" }
+ }
+ supports_check_mode = $true
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+$data = $module.Params.data
+
+if ($data -eq "crash") {
+ throw "boom"
+}
+
+$module.Result.ping = $data
+$module.Result.source = "user"
+$module.Result.subpkg = [ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs.NestedUtil]::HelloWorld()
+$module.Result.type_accelerator = "called from $([MyCSMU]::HelloWorld())"
+$module.ExitJson()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_psmu.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_psmu.ps1
new file mode 100644
index 0000000..cbca7b7
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_psmu.ps1
@@ -0,0 +1,25 @@
+#!powershell
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.MyPSMU
+#AnsibleRequires -PowerShell ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subps
+
+$spec = @{
+ options = @{
+ data = @{ type = "str"; default = "called from $(Invoke-FromUserPSMU)" }
+ }
+ supports_check_mode = $true
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+$data = $module.Params.data
+
+if ($data -eq "crash") {
+ throw "boom"
+}
+
+$module.Result.ping = $data
+$module.Result.source = "user"
+$module.Result.subpkg = Invoke-SubUserPSMU
+$module.ExitJson()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1
new file mode 100644
index 0000000..c44dcfe
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1
@@ -0,0 +1,33 @@
+#!powershell
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Test builtin C# still works with -Optional
+#AnsibleRequires -CSharpUtil Ansible.Basic -Optional
+
+# Test no failure when importing an invalid builtin C# and pwsh util with -Optional
+#AnsibleRequires -CSharpUtil Ansible.Invalid -Optional
+#AnsibleRequires -PowerShell Ansible.ModuleUtils.Invalid -Optional
+
+# Test valid module_util still works with -Optional
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.MyCSMUOptional -Optional
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.MyPSMUOptional -Optional
+
+# Test no failure when importing an invalid collection C# and pwsh util with -Optional
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional
+#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional
+#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional
+
+$spec = @{
+ options = @{
+ data = @{ type = "str"; default = "called $(Invoke-FromUserPSMU)" }
+ }
+ supports_check_mode = $true
+}
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$module.Result.data = $module.Params.data
+$module.Result.csharp = [MyCSMU]::HelloWorld()
+
+$module.ExitJson()
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests.py
new file mode 100644
index 0000000..ba610fb
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests.py
@@ -0,0 +1,13 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def testtest(data):
+ return data == 'from_user'
+
+
+class TestModule(object):
+ def tests(self):
+ return {
+ 'testtest': testtest
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests2.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests2.py
new file mode 100644
index 0000000..183944f
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests2.py
@@ -0,0 +1,13 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def testtest(data):
+ return data == 'from_user2'
+
+
+class TestModule(object):
+ def tests(self):
+ return {
+ 'testtest2': testtest
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/test_subdir/my_subdir_tests.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/test_subdir/my_subdir_tests.py
new file mode 100644
index 0000000..98a8f89
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/test_subdir/my_subdir_tests.py
@@ -0,0 +1,13 @@
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def subdir_test(data):
+ return data == 'subdir_from_user'
+
+
+class TestModule(object):
+ def tests(self):
+ return {
+ 'subdir_test': subdir_test
+ }
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/vars/custom_vars.py b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/vars/custom_vars.py
new file mode 100644
index 0000000..da4e776
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/vars/custom_vars.py
@@ -0,0 +1,48 @@
+# Copyright 2019 RedHat, inc
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#############################################
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = '''
+ vars: custom_vars
+ version_added: "2.10"
+ short_description: load host and group vars
+ description: test loading host and group vars from a collection
+ options:
+ stage:
+ choices: ['all', 'inventory', 'task']
+ type: str
+ ini:
+ - key: stage
+ section: custom_vars
+ env:
+ - name: ANSIBLE_VARS_PLUGIN_STAGE
+'''
+
+from ansible.plugins.vars import BaseVarsPlugin
+
+
+class VarsModule(BaseVarsPlugin):
+
+ # Vars plugins in collections are only loaded when they are enabled by the user.
+ # If a vars plugin sets REQUIRES_ENABLED = False, a warning should occur (assuming it is loaded).
+ REQUIRES_ENABLED = False
+
+ def get_vars(self, loader, path, entities, cache=True):
+ super(VarsModule, self).get_vars(loader, path, entities)
+ return {'collection': 'collection_root_user'}
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/call_standalone/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/call_standalone/tasks/main.yml
new file mode 100644
index 0000000..f5dcc0f
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/call_standalone/tasks/main.yml
@@ -0,0 +1,6 @@
+- include_role:
+ name: standalone
+
+- assert:
+ that:
+ - standalone_role_var is defined
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/meta/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/meta/main.yml
new file mode 100644
index 0000000..b3a8819
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - testrole # since testrole lives in this collection, we'll check there first
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/tasks/main.yml
new file mode 100644
index 0000000..99297f7
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/tasks/main.yml
@@ -0,0 +1,7 @@
+- debug:
+ msg: '{{ outer_role_input | default("(undefined)") }}'
+ register: outer_role_output
+
+- assert:
+ that:
+ - outer_role_input is not defined or outer_role_input == outer_role_output.msg
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/common_handlers/handlers/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/common_handlers/handlers/main.yml
new file mode 100644
index 0000000..186368f
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/common_handlers/handlers/main.yml
@@ -0,0 +1,27 @@
+# This handler should only be called 1 time, if it's called more than once
+# this task should fail on subsequent executions
+- name: test_fqcn_handler
+ set_fact:
+ handler_counter: '{{ handler_counter|int + 1 }}'
+ failed_when: handler_counter|int > 1
+
+# The following handler contains the role name and should be callable as:
+# 'common_handlers test_fqcn_handler'
+# 'common_handlers : common_handlers test_fqcn_handler`
+# 'testns.testcoll.common_handlers : common_handlers test_fqcn_handler'
+- name: common_handlers test_fqcn_handler
+ set_fact:
+ handler_counter: '{{ handler_counter|int + 1}}'
+ failed_when: handler_counter|int > 2
+
+# The following handler starts with 'role name : ' and should _not_ be listed as:
+# 'common_handlers : common_handlers : test_fqcn_handler`
+# 'testns.testcoll.common_handlers : common_handlers : test_fqcn_handler'
+- name: 'common_handlers : test_fqcn_handler'
+ meta: noop
+
+# The following handler starts with 'fqcn : ' and should _not_ be listed as:
+# 'common_handlers : testns.testcoll.common_handlers : test_fqcn_handler`
+# 'testns.testcoll.common_handlers : testns.testcoll.common_handlers : test_fqcn_handler'
+- name: 'testns.testcoll.common_handlers : test_fqcn_handler'
+ meta: noop
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/role_subdir/subdir_testrole/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/role_subdir/subdir_testrole/tasks/main.yml
new file mode 100644
index 0000000..64f5242
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/role_subdir/subdir_testrole/tasks/main.yml
@@ -0,0 +1,10 @@
+- debug:
+ msg: '{{ test_role_input | default("(undefined)") }}'
+ register: test_role_output
+
+- set_fact:
+ testrole_source: collection
+
+- assert:
+ that:
+ - test_role_input is not defined or test_role_input == test_role_output.msg
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/meta/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/meta/main.yml
new file mode 100644
index 0000000..9218f3d
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - testns.testcoll.common_handlers
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/tasks/main.yml
new file mode 100644
index 0000000..6eadb7c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/tasks/main.yml
@@ -0,0 +1,16 @@
+- name: Fire fqcn handler 1
+ debug:
+ msg: Fire fqcn handler
+ changed_when: true
+ notify:
+ - 'testns.testcoll.common_handlers : test_fqcn_handler'
+ - 'common_handlers : test_fqcn_handler'
+ - 'test_fqcn_handler'
+
+- debug:
+ msg: Fire fqcn handler with role name
+ changed_when: true
+ notify:
+ - 'testns.testcoll.common_handlers : common_handlers test_fqcn_handler'
+ - 'common_handlers : common_handlers test_fqcn_handler'
+ - 'common_handlers test_fqcn_handler'
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/meta/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/meta/main.yml
new file mode 100644
index 0000000..8c22c1c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/meta/main.yml
@@ -0,0 +1,4 @@
+collections:
+- ansible.builtin
+- testns.coll_in_sys
+- bogus.fromrolemeta
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/tasks/main.yml
new file mode 100644
index 0000000..7c05abb
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/tasks/main.yml
@@ -0,0 +1,39 @@
+# test using builtin module of multiple types in a role in a collection
+# https://github.com/ansible/ansible/issues/65298
+- name: Run setup module because there is both setup.ps1 and setup.py
+ setup:
+ gather_subset: min
+
+- name: check collections list from role meta
+ plugin_lookup:
+ register: pluginlookup_out
+
+- name: call role-local ping module
+ ping:
+ register: ping_out
+
+- name: call unqualified module in another collection listed in role meta (testns.coll_in_sys)
+ systestmodule:
+ register: systestmodule_out
+
+# verify that pluginloader caching doesn't prevent us from explicitly calling a builtin plugin with the same name
+- name: call builtin ping module explicitly
+ ansible.builtin.ping:
+ register: builtinping_out
+
+- debug:
+ msg: '{{ test_role_input | default("(undefined)") }}'
+ register: test_role_output
+
+- set_fact:
+ testrole_source: collection
+
+# FIXME: add tests to ensure that block/task level stuff in a collection-hosted role properly inherit role default/meta values
+
+- assert:
+ that:
+ - pluginlookup_out.collection_list == ['testns.testcoll', 'ansible.builtin', 'testns.coll_in_sys', 'bogus.fromrolemeta']
+ - ping_out.source is defined and ping_out.source == 'user'
+ - systestmodule_out.source is defined and systestmodule_out.source == 'sys'
+ - builtinping_out.ping is defined and builtinping_out.ping == 'pong'
+ - test_role_input is not defined or test_role_input == test_role_output.msg
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/meta/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/meta/main.yml
new file mode 100644
index 0000000..8c22c1c
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/meta/main.yml
@@ -0,0 +1,4 @@
+collections:
+- ansible.builtin
+- testns.coll_in_sys
+- bogus.fromrolemeta
diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/tasks/main.yml b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/tasks/main.yml
new file mode 100644
index 0000000..31e3af5
--- /dev/null
+++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/tasks/main.yml
@@ -0,0 +1,33 @@
+- name: check collections list from role meta
+ plugin_lookup:
+ register: pluginlookup_out
+
+- name: call role-local ping module
+ ping:
+ register: ping_out
+
+- name: call unqualified module in another collection listed in role meta (testns.coll_in_sys)
+ systestmodule:
+ register: systestmodule_out
+
+# verify that pluginloader caching doesn't prevent us from explicitly calling a builtin plugin with the same name
+- name: call builtin ping module explicitly
+ ansible.builtin.ping:
+ register: builtinping_out
+
+- debug:
+ msg: '{{ test_role_input | default("(undefined)") }}'
+ register: test_role_output
+
+- set_fact:
+ testrole_source: collection
+
+# FIXME: add tests to ensure that block/task level stuff in a collection-hosted role properly inherit role default/meta values
+
+- assert:
+ that:
+ - pluginlookup_out.collection_list == ['testns.testcoll', 'ansible.builtin', 'testns.coll_in_sys', 'bogus.fromrolemeta']
+ - ping_out.source is defined and ping_out.source == 'user'
+ - systestmodule_out.source is defined and systestmodule_out.source == 'sys'
+ - builtinping_out.ping is defined and builtinping_out.ping == 'pong'
+ - test_role_input is not defined or test_role_input == test_role_output.msg