From 10a8c6bc2531f1b42509c80bf3b746aacedaec4e Mon Sep 17 00:00:00 2001
From: Sam Doran <sdoran@ansible.com>
Date: Fri, 19 Jan 2018 11:23:48 -0500
Subject: [PATCH] Integration tests for import/include (#33418)

* First pass at include_role tests

* Reorganize test structure

Do all import and include tests in a single target.

* Build out more tests and test with linear and free strategy for each type

* import_role tests

* Set target host for play test

* Basic import_playbook tests

* Basic import/include_tasks tests

* Add recursion test

* import_playbook tests

* Add import_playbook group_vars test

Issue #33177

* Additional group_var tests for import_playbook

* Enable recursion test

* More work on import_tasks

* Run all tests via run.sh, improve conditional tests, add never tag

Add never tag to certain failining tests and explicitly skip it for now until #34104 is merged. Some tasks need to remain commented out because they cause the entire play to fail and aren't skippable by tags because they are syntax and/or variable checks.

Improve test for whether or not a role was run based on a conditional. Since the [import|include]_role does not register a variable, use a variable that is set inside a role as a canary test for whether or not the role was run.

* Use a fail task rather than trigger a failure via bogus command

This should resolve the "unstable" test results.

* Import tag tests

Fix bug it tests where validate tasks weren't run on tag tests.
Add tests for task import/include with tags.

* Remove test for playbook group_var inheritance
---
 test/integration/inventory                    |   2 +-
 .../targets/include_import/aliases            |   1 +
 .../playbook/group_vars/all.yml               |   1 +
 .../include_import/playbook/playbook1.yml     |   9 ++
 .../include_import/playbook/playbook2.yml     |   9 ++
 .../include_import/playbook/playbook3.yml     |  10 ++
 .../include_import/playbook/playbook4.yml     |   9 ++
 .../playbook/test_import_playbook.yml         |  16 ++
 .../playbook/test_import_playbook_tags.yml    |  10 ++
 .../include_import/playbook/validate1.yml     |  10 ++
 .../include_import/playbook/validate2.yml     |  10 ++
 .../include_import/playbook/validate34.yml    |  11 ++
 .../include_import/playbook/validate_tags.yml |  11 ++
 .../include_import/role/test_import_role.yml  | 138 ++++++++++++++++++
 .../include_import/role/test_include_role.yml | 128 ++++++++++++++++
 .../roles/role1/tasks/canary1.yml             |   2 +
 .../roles/role1/tasks/canary2.yml             |   2 +
 .../include_import/roles/role1/tasks/fail.yml |   3 +
 .../include_import/roles/role1/tasks/main.yml |   3 +
 .../roles/role1/tasks/r1t01.yml               |   1 +
 .../roles/role1/tasks/r1t02.yml               |   1 +
 .../roles/role1/tasks/r1t03.yml               |   1 +
 .../roles/role1/tasks/r1t04.yml               |   1 +
 .../roles/role1/tasks/r1t05.yml               |   1 +
 .../roles/role1/tasks/r1t06.yml               |   1 +
 .../roles/role1/tasks/r1t07.yml               |   1 +
 .../roles/role1/tasks/r1t08.yml               |   1 +
 .../roles/role1/tasks/r1t09.yml               |   1 +
 .../roles/role1/tasks/r1t10.yml               |   1 +
 .../roles/role1/tasks/r1t11.yml               |   1 +
 .../roles/role1/tasks/r1t12.yml               |   2 +
 .../roles/role1/tasks/tasks.yml               |   2 +
 .../roles/role1/tasks/vartest.yml             |   2 +
 .../include_import/roles/role1/vars/main.yml  |   1 +
 .../roles/role1/vars/role1vars.yml            |   1 +
 .../include_import/roles/role2/tasks/main.yml |   2 +
 .../roles/role3/defaults/main.yml             |   2 +
 .../roles/role3/handlers/main.yml             |   3 +
 .../include_import/roles/role3/tasks/main.yml |   2 +
 .../roles/role3/tasks/tasks.yml               |   2 +
 .../roles/role3/tasks/vartest.yml             |   2 +
 .../include_import/roles/role3/vars/main.yml  |   1 +
 .../roles/role3/vars/role3vars.yml            |   2 +
 .../roles/role_with_deps/meta/main.yml        |   3 +
 .../roles/role_with_deps/tasks/main.yml       |   2 +
 .../targets/include_import/runme.sh           |  38 +++++
 .../targets/include_import/tasks/tasks1.yml   |   5 +
 .../targets/include_import/tasks/tasks2.yml   |   5 +
 .../targets/include_import/tasks/tasks3.yml   |   5 +
 .../targets/include_import/tasks/tasks4.yml   |   5 +
 .../targets/include_import/tasks/tasks5.yml   |   6 +
 .../targets/include_import/tasks/tasks6.yml   |   5 +
 .../tasks/test_import_tasks.yml               |  41 ++++++
 .../tasks/test_import_tasks_tags.yml          |  23 +++
 .../tasks/test_include_tasks.yml              |  41 ++++++
 .../tasks/test_include_tasks_tags.yml         |  25 ++++
 .../include_import/tasks/test_recursion.yml   |   6 +
 .../include_import/tasks/validate3.yml        |   4 +
 .../include_import/tasks/validate_tags.yml    |   8 +
 .../targets/include_import/test_recursion.yml |   7 +
 .../targets/includes/test_includes2.yml       |   3 +-
 .../targets/includes/test_includes3.yml       |   1 -
 62 files changed, 650 insertions(+), 3 deletions(-)
 create mode 100644 test/integration/targets/include_import/aliases
 create mode 100644 test/integration/targets/include_import/playbook/group_vars/all.yml
 create mode 100644 test/integration/targets/include_import/playbook/playbook1.yml
 create mode 100644 test/integration/targets/include_import/playbook/playbook2.yml
 create mode 100644 test/integration/targets/include_import/playbook/playbook3.yml
 create mode 100644 test/integration/targets/include_import/playbook/playbook4.yml
 create mode 100644 test/integration/targets/include_import/playbook/test_import_playbook.yml
 create mode 100644 test/integration/targets/include_import/playbook/test_import_playbook_tags.yml
 create mode 100644 test/integration/targets/include_import/playbook/validate1.yml
 create mode 100644 test/integration/targets/include_import/playbook/validate2.yml
 create mode 100644 test/integration/targets/include_import/playbook/validate34.yml
 create mode 100644 test/integration/targets/include_import/playbook/validate_tags.yml
 create mode 100644 test/integration/targets/include_import/role/test_import_role.yml
 create mode 100644 test/integration/targets/include_import/role/test_include_role.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/canary1.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/canary2.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/fail.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t01.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t02.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t03.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t04.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t05.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t06.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t07.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t08.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t09.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t10.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t11.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/r1t12.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/tasks.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/tasks/vartest.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/vars/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role1/vars/role1vars.yml
 create mode 100644 test/integration/targets/include_import/roles/role2/tasks/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/defaults/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/handlers/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/tasks/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/tasks/tasks.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/tasks/vartest.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/vars/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role3/vars/role3vars.yml
 create mode 100644 test/integration/targets/include_import/roles/role_with_deps/meta/main.yml
 create mode 100644 test/integration/targets/include_import/roles/role_with_deps/tasks/main.yml
 create mode 100755 test/integration/targets/include_import/runme.sh
 create mode 100644 test/integration/targets/include_import/tasks/tasks1.yml
 create mode 100644 test/integration/targets/include_import/tasks/tasks2.yml
 create mode 100644 test/integration/targets/include_import/tasks/tasks3.yml
 create mode 100644 test/integration/targets/include_import/tasks/tasks4.yml
 create mode 100644 test/integration/targets/include_import/tasks/tasks5.yml
 create mode 100644 test/integration/targets/include_import/tasks/tasks6.yml
 create mode 100644 test/integration/targets/include_import/tasks/test_import_tasks.yml
 create mode 100644 test/integration/targets/include_import/tasks/test_import_tasks_tags.yml
 create mode 100644 test/integration/targets/include_import/tasks/test_include_tasks.yml
 create mode 100644 test/integration/targets/include_import/tasks/test_include_tasks_tags.yml
 create mode 100644 test/integration/targets/include_import/tasks/test_recursion.yml
 create mode 100644 test/integration/targets/include_import/tasks/validate3.yml
 create mode 100644 test/integration/targets/include_import/tasks/validate_tags.yml
 create mode 100644 test/integration/targets/include_import/test_recursion.yml

diff --git a/test/integration/inventory b/test/integration/inventory
index 697a6a8ba06..3b53217928d 100644
--- a/test/integration/inventory
+++ b/test/integration/inventory
@@ -1,5 +1,5 @@
 [local]
-testhost ansible_ssh_host=127.0.0.1 ansible_connection=local
+testhost ansible_ssh_host=127.0.0.1 ansible_connection=local host_var_role_name=role3
 testhost2 ansible_ssh_host=127.0.0.1 ansible_connection=local
 # For testing delegate_to
 testhost3 ansible_ssh_host=127.0.0.3
diff --git a/test/integration/targets/include_import/aliases b/test/integration/targets/include_import/aliases
new file mode 100644
index 00000000000..79d8b9285eb
--- /dev/null
+++ b/test/integration/targets/include_import/aliases
@@ -0,0 +1 @@
+posix/ci/group3
diff --git a/test/integration/targets/include_import/playbook/group_vars/all.yml b/test/integration/targets/include_import/playbook/group_vars/all.yml
new file mode 100644
index 00000000000..9acd8c64cd7
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/group_vars/all.yml
@@ -0,0 +1 @@
+group_var1: set in group_vars/all.yml
diff --git a/test/integration/targets/include_import/playbook/playbook1.yml b/test/integration/targets/include_import/playbook/playbook1.yml
new file mode 100644
index 00000000000..55c66d8096f
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/playbook1.yml
@@ -0,0 +1,9 @@
+- name: Playbook 1
+  hosts: testhost2
+
+  tasks:
+    - name: Set fact in playbook 1
+      set_fact:
+        canary_var1: playbook1 imported
+      tags:
+        - canary1
diff --git a/test/integration/targets/include_import/playbook/playbook2.yml b/test/integration/targets/include_import/playbook/playbook2.yml
new file mode 100644
index 00000000000..c986165e858
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/playbook2.yml
@@ -0,0 +1,9 @@
+- name: Playbook 2
+  hosts: testhost2
+
+  tasks:
+    - name: Set fact in playbook 2
+      set_fact:
+        canary_var2: playbook2 imported
+      tags:
+        - canary2
diff --git a/test/integration/targets/include_import/playbook/playbook3.yml b/test/integration/targets/include_import/playbook/playbook3.yml
new file mode 100644
index 00000000000..b62b96c33ee
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/playbook3.yml
@@ -0,0 +1,10 @@
+- name: Playbook 3
+  hosts: testhost2
+
+  tasks:
+    - name: Set fact in playbook 3
+      set_fact:
+        canary_var3: playbook3 imported
+        include_next_playbook: yes
+      tags:
+        - canary3
diff --git a/test/integration/targets/include_import/playbook/playbook4.yml b/test/integration/targets/include_import/playbook/playbook4.yml
new file mode 100644
index 00000000000..330612a96f7
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/playbook4.yml
@@ -0,0 +1,9 @@
+- name: Playbook 4
+  hosts: testhost2
+
+  tasks:
+    - name: Set fact in playbook 4
+      set_fact:
+        canary_var4: playbook4 imported
+      tags:
+        - canary4
diff --git a/test/integration/targets/include_import/playbook/test_import_playbook.yml b/test/integration/targets/include_import/playbook/test_import_playbook.yml
new file mode 100644
index 00000000000..51443ea80ff
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/test_import_playbook.yml
@@ -0,0 +1,16 @@
+# Test and validate playbook import
+- import_playbook: playbook1.yml
+- import_playbook: validate1.yml
+
+
+# Test and validate conditional import
+- import_playbook: playbook2.yml
+  when: no
+
+- import_playbook: validate2.yml
+
+- import_playbook: playbook3.yml
+- import_playbook: playbook4.yml
+  when: include_next_playbook
+
+- import_playbook: validate34.yml
diff --git a/test/integration/targets/include_import/playbook/test_import_playbook_tags.yml b/test/integration/targets/include_import/playbook/test_import_playbook_tags.yml
new file mode 100644
index 00000000000..46136f6fb82
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/test_import_playbook_tags.yml
@@ -0,0 +1,10 @@
+- import_playbook: playbook1.yml            # Test tag in tasks in included play
+- import_playbook: playbook2.yml            # Test tag added to import_playbook
+  tags:
+    - canary22
+
+- import_playbook: playbook3.yml            # Test skipping tags added to import_playbook
+  tags:
+    - skipme
+
+- import_playbook: validate_tags.yml        # Validate
diff --git a/test/integration/targets/include_import/playbook/validate1.yml b/test/integration/targets/include_import/playbook/validate1.yml
new file mode 100644
index 00000000000..0018344d14e
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/validate1.yml
@@ -0,0 +1,10 @@
+- hosts: testhost2
+
+  tasks:
+    - name: Assert that variable was set in playbook1.yml
+      assert:
+        that:
+          - canary_var1 == 'playbook1 imported'
+      tags:
+        - validate
+        - validate1
diff --git a/test/integration/targets/include_import/playbook/validate2.yml b/test/integration/targets/include_import/playbook/validate2.yml
new file mode 100644
index 00000000000..f22bcb6ebf9
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/validate2.yml
@@ -0,0 +1,10 @@
+- hosts: testhost2
+
+  tasks:
+    - name: Assert that playbook2.yml was skipeed
+      assert:
+        that:
+          - canary_var2 is not defined
+      tags:
+        - validate
+        - validate2
diff --git a/test/integration/targets/include_import/playbook/validate34.yml b/test/integration/targets/include_import/playbook/validate34.yml
new file mode 100644
index 00000000000..fd53a30539e
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/validate34.yml
@@ -0,0 +1,11 @@
+- hosts: testhost2
+
+  tasks:
+    - name: Assert that playbook3.yml and playbook4.yml were imported
+      assert:
+        that:
+          - canary_var3 == 'playbook3 imported'
+          - canary_var4 == 'playbook4 imported'
+      tags:
+        - validate
+        - validate34
diff --git a/test/integration/targets/include_import/playbook/validate_tags.yml b/test/integration/targets/include_import/playbook/validate_tags.yml
new file mode 100644
index 00000000000..acdcb1f2a45
--- /dev/null
+++ b/test/integration/targets/include_import/playbook/validate_tags.yml
@@ -0,0 +1,11 @@
+- hosts: testhost2
+
+  tasks:
+    - name: Assert that only tasks with tags were run
+      assert:
+        that:
+          - canary_var1 == 'playbook1 imported'
+          - canary_var2 == 'playbook2 imported'
+          - canary_var3 is not defined
+      tags:
+        - validate
diff --git a/test/integration/targets/include_import/role/test_import_role.yml b/test/integration/targets/include_import/role/test_import_role.yml
new file mode 100644
index 00000000000..8a8bdc17245
--- /dev/null
+++ b/test/integration/targets/include_import/role/test_import_role.yml
@@ -0,0 +1,138 @@
+- name: Test import_role
+  hosts: testhost
+
+  vars:
+    run_role: yes
+    do_not_run_role: no
+    role_name: role1
+    test_var: templating test in playbook
+    role_vars:
+      where_am_i_defined: in the playbook
+    entire_task:
+      include_role:
+        name: role1
+
+  tasks:
+    - name: Test basic role import
+      import_role:
+        name: role1
+
+    - name: Assert that basic include works
+      assert:
+        that:
+          - _role1_result.msg == 'In role1'
+
+    - name: Test conditional role include
+      import_role:
+        name: role1
+        tasks_from: canary1.yml
+      when: run_role
+
+    - name: Assert that role ran
+      assert:
+        that:
+          - role1_canary1 == 'r1c1'
+
+    - name: Test conditional role import that should be skipped
+      import_role:
+        name: role1
+        tasks_from: canary2.yml
+      when: do_not_run_role
+
+    - name: Assert that role did not run
+      assert:
+        that:
+          - role1_canary2 is not defined
+
+    # FIXME We expect this to fail, but I'm not sure how best to test for
+    # syntax level failures.
+    #
+    # - name: Test role import with a loop
+    #   import_role:
+    #     name: "{{ item }}"
+    #   register: loop_test
+    #   with_items:
+    #     - role1
+    #     - role3
+    #     - role2
+
+    - name: Test importing a task file from a role
+      import_role:
+        name: role1
+        tasks_from: tasks.yml
+
+    - name: Test importing vars file and tasks file from a role
+      import_role:
+        name: role3
+        tasks_from: vartest.yml
+        vars_from: role3vars.yml
+        private: no
+
+    # FIXME Setting private: no in previous task does not make the variables
+    # available to the play
+    #
+    - name: Assert that variables defined in previous task are available to play
+      assert:
+        that:
+          - role3_default == 'defined in role3/defaults/main.yml'
+          - role3_main == 'defined in role3/vars/main.yml'
+          - role3_var == 'defined in role3/vars/role3vars.yml'
+      ignore_errors: yes
+
+    - name: Test using a play variable for role name
+      import_role:
+        name: "{{ role_name }}"
+
+    # FIXME Trying to use a host_var here causes play execution to fail because
+    # the variable is undefined.
+    #
+    # - name: Test using a host variable for role name
+    #   import_role:
+    #     name: "{{ host_var_role_name }}"
+
+    - name: Pass variable to role
+      import_role:
+        name: role1
+        tasks_from: vartest.yml
+      vars:
+        where_am_i_defined: in the task
+
+    ## FIXME Currently failing
+    ## ERROR! Vars in a IncludeRole must be specified as a dictionary, or a list of dictionaries
+    # - name: Pass all variables in a variable to role
+    #   import_role:
+    #     name: role1
+    #     tasks_from: vartest.yml
+    #   vars: "{{ role_vars }}"
+
+    - name: Pass templated variable to a role
+      import_role:
+        name: role1
+        tasks_from: vartest.yml
+      vars:
+        where_am_i_defined: "{{ test_var }}"
+
+    # FIXME This fails with the following error:
+    # The module {u'import_role': {u'name': u'role1'}} was not found in configured module paths.
+    #
+    - name: Include an entire task
+      action:
+        module: "{{ entire_task }}"
+      tags:
+        - never
+
+    - block:
+        - name: Include a role that will fail
+          import_role:
+            name: role1
+            tasks_from: fail.yml
+
+      rescue:
+        - name: Include a role inside rescue
+          import_role:
+            name: role2
+
+      always:
+        - name: Include role inside always
+          import_role:
+            name: role3
diff --git a/test/integration/targets/include_import/role/test_include_role.yml b/test/integration/targets/include_import/role/test_include_role.yml
new file mode 100644
index 00000000000..79f4a78f0b6
--- /dev/null
+++ b/test/integration/targets/include_import/role/test_include_role.yml
@@ -0,0 +1,128 @@
+- name: Test include_role
+  hosts: testhost
+
+  vars:
+    run_role: yes
+    do_not_run_role: no
+    role_name: role1
+    test_var: templating test in playbook
+    role_vars:
+      where_am_i_defined: in the playbook
+    entire_task:
+      include_role:
+        name: role1
+
+  tasks:
+    - name: Test basic role include
+      include_role:
+        name: role1
+
+    - name: Assert that basic include works
+      assert:
+        that:
+          - _role1_result.msg == 'In role1'
+
+    - name: Test conditional role include
+      include_role:
+        name: role1
+        tasks_from: canary1.yml
+      when: run_role
+
+    - name: Assert that role ran
+      assert:
+        that:
+          - role1_canary1 == 'r1c1'
+
+    - name: Test conditional role include that should be skipped
+      include_role:
+        name: role1
+        tasks_from: canary2.yml
+      when: do_not_run_role
+
+    - name: Assert that role did not run
+      assert:
+        that:
+          - role1_canary2 is not defined
+
+    - name: Test role include with a loop
+      include_role:
+        name: "{{ item }}"
+      register: loop_test
+      with_items:
+        - role1
+        - role3
+        - role2
+
+    - name: Test including a task file from a role
+      include_role:
+        name: role1
+        tasks_from: tasks.yml
+
+    - name: Test including vars file and tasks file from a role
+      include_role:
+        name: role3
+        tasks_from: vartest.yml
+        vars_from: role3vars.yml
+        private: no
+
+    # FIXME Setting private: no in previous task does not make the variables
+    # available to the play
+    - name: Assert that variables defined in previous task are available to play
+      assert:
+        that:
+          - role3_default == 'defined in role3/defaults/main.yml'
+          - role3_main == 'defined in role3/vars/main.yml'
+          - role3_var == 'defined in role3/vars/role3vars.yml'
+      ignore_errors: yes
+
+    - name: Test using a play variable for role name
+      include_role:
+        name: "{{ role_name }}"
+
+    - name: Test using a host variable for role name
+      include_role:
+        name: "{{ host_var_role_name }}"
+
+    - name: Pass variable to role
+      include_role:
+        name: role1
+        tasks_from: vartest.yml
+      vars:
+        where_am_i_defined: in the task
+
+    ## FIXME Currently failing with
+    ## ERROR! Vars in a IncludeRole must be specified as a dictionary, or a list of dictionaries
+    # - name: Pass all variables in a variable to role
+    #   include_role:
+    #     name: role1
+    #     tasks_from: vartest.yml
+    #   vars: "{{ role_vars }}"
+
+    - name: Pass templated variable to a role
+      include_role:
+        name: role1
+        tasks_from: vartest.yml
+      vars:
+        where_am_i_defined: "{{ test_var }}"
+
+    ## FIXME This fails with the following error:
+    ## The module {u'include_role': {u'name': u'role1'}} was not found in configured module paths.
+    # - name: Include an entire task
+    #   action:
+    #     module: "{{ entire_task }}"
+
+    - block:
+        - name: Include a role that will fail
+          include_role:
+            name: role1
+            tasks_from: fail.yml
+
+      rescue:
+        - name: Include a role inside rescue
+          include_role:
+            name: role2
+
+      always:
+        - name: Include role inside always
+          include_role:
+            name: role3
diff --git a/test/integration/targets/include_import/roles/role1/tasks/canary1.yml b/test/integration/targets/include_import/roles/role1/tasks/canary1.yml
new file mode 100644
index 00000000000..9f202ba3370
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/canary1.yml
@@ -0,0 +1,2 @@
+- set_fact:
+    role1_canary1: r1c1
diff --git a/test/integration/targets/include_import/roles/role1/tasks/canary2.yml b/test/integration/targets/include_import/roles/role1/tasks/canary2.yml
new file mode 100644
index 00000000000..80e18b8ddae
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/canary2.yml
@@ -0,0 +1,2 @@
+- set_fact:
+    role1_canary2: r1c2
diff --git a/test/integration/targets/include_import/roles/role1/tasks/fail.yml b/test/integration/targets/include_import/roles/role1/tasks/fail.yml
new file mode 100644
index 00000000000..b1b5f1553aa
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/fail.yml
@@ -0,0 +1,3 @@
+- name: EXPECTED FAILURE
+  fail:
+    msg: This command should always fail
diff --git a/test/integration/targets/include_import/roles/role1/tasks/main.yml b/test/integration/targets/include_import/roles/role1/tasks/main.yml
new file mode 100644
index 00000000000..a8b641ee44d
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/main.yml
@@ -0,0 +1,3 @@
+- debug:
+    msg: In role1
+  register: _role1_result
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t01.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t01.yml
new file mode 100644
index 00000000000..e4a1e63e9cf
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t01.yml
@@ -0,0 +1 @@
+- import_tasks: r1t02.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t02.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t02.yml
new file mode 100644
index 00000000000..d3d37507eb5
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t02.yml
@@ -0,0 +1 @@
+- import_tasks: r1t03.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t03.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t03.yml
new file mode 100644
index 00000000000..1d3330aea8f
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t03.yml
@@ -0,0 +1 @@
+- import_tasks: r1t04.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t04.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t04.yml
new file mode 100644
index 00000000000..f3eece23f46
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t04.yml
@@ -0,0 +1 @@
+- import_tasks: r1t05.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t05.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t05.yml
new file mode 100644
index 00000000000..4c7371eebc0
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t05.yml
@@ -0,0 +1 @@
+- import_tasks: r1t06.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t06.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t06.yml
new file mode 100644
index 00000000000..96d56609460
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t06.yml
@@ -0,0 +1 @@
+- import_tasks: r1t07.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t07.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t07.yml
new file mode 100644
index 00000000000..ee8d325255f
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t07.yml
@@ -0,0 +1 @@
+- import_tasks: r1t08.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t08.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t08.yml
new file mode 100644
index 00000000000..33b8109641e
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t08.yml
@@ -0,0 +1 @@
+- import_tasks: r1t09.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t09.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t09.yml
new file mode 100644
index 00000000000..8973c2911b0
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t09.yml
@@ -0,0 +1 @@
+- import_tasks: r1t10.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t10.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t10.yml
new file mode 100644
index 00000000000..eafdca25fb8
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t10.yml
@@ -0,0 +1 @@
+- import_tasks: r1t11.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t11.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t11.yml
new file mode 100644
index 00000000000..9ab828f3c52
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t11.yml
@@ -0,0 +1 @@
+- import_tasks: r1t12.yml
diff --git a/test/integration/targets/include_import/roles/role1/tasks/r1t12.yml b/test/integration/targets/include_import/roles/role1/tasks/r1t12.yml
new file mode 100644
index 00000000000..882848611af
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/r1t12.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: r1t12
diff --git a/test/integration/targets/include_import/roles/role1/tasks/tasks.yml b/test/integration/targets/include_import/roles/role1/tasks/tasks.yml
new file mode 100644
index 00000000000..45430bc407a
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/tasks.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: Tasks file inside role1
diff --git a/test/integration/targets/include_import/roles/role1/tasks/vartest.yml b/test/integration/targets/include_import/roles/role1/tasks/vartest.yml
new file mode 100644
index 00000000000..5a49d8dd4b5
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/tasks/vartest.yml
@@ -0,0 +1,2 @@
+- debug:
+    var: where_am_i_defined
diff --git a/test/integration/targets/include_import/roles/role1/vars/main.yml b/test/integration/targets/include_import/roles/role1/vars/main.yml
new file mode 100644
index 00000000000..57d31cf7531
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/vars/main.yml
@@ -0,0 +1 @@
+where_am_i_defined: role1 vars/main.yml
diff --git a/test/integration/targets/include_import/roles/role1/vars/role1vars.yml b/test/integration/targets/include_import/roles/role1/vars/role1vars.yml
new file mode 100644
index 00000000000..57d31cf7531
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role1/vars/role1vars.yml
@@ -0,0 +1 @@
+where_am_i_defined: role1 vars/main.yml
diff --git a/test/integration/targets/include_import/roles/role2/tasks/main.yml b/test/integration/targets/include_import/roles/role2/tasks/main.yml
new file mode 100644
index 00000000000..80d6a81fc30
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role2/tasks/main.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: In role2
diff --git a/test/integration/targets/include_import/roles/role3/defaults/main.yml b/test/integration/targets/include_import/roles/role3/defaults/main.yml
new file mode 100644
index 00000000000..c3464c4d90a
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/defaults/main.yml
@@ -0,0 +1,2 @@
+where_am_i_defined: defaults in role3
+role3_default: defined in role3/defaults/main.yml
diff --git a/test/integration/targets/include_import/roles/role3/handlers/main.yml b/test/integration/targets/include_import/roles/role3/handlers/main.yml
new file mode 100644
index 00000000000..c8baa270239
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/handlers/main.yml
@@ -0,0 +1,3 @@
+- name: runme
+  debug:
+    msg: role3 handler
diff --git a/test/integration/targets/include_import/roles/role3/tasks/main.yml b/test/integration/targets/include_import/roles/role3/tasks/main.yml
new file mode 100644
index 00000000000..76608a9b198
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/tasks/main.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: In role3
diff --git a/test/integration/targets/include_import/roles/role3/tasks/tasks.yml b/test/integration/targets/include_import/roles/role3/tasks/tasks.yml
new file mode 100644
index 00000000000..0e822695ef1
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/tasks/tasks.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: Tasks file inside role3
diff --git a/test/integration/targets/include_import/roles/role3/tasks/vartest.yml b/test/integration/targets/include_import/roles/role3/tasks/vartest.yml
new file mode 100644
index 00000000000..cb21c53f885
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/tasks/vartest.yml
@@ -0,0 +1,2 @@
+- debug:
+    var: role3_var
diff --git a/test/integration/targets/include_import/roles/role3/vars/main.yml b/test/integration/targets/include_import/roles/role3/vars/main.yml
new file mode 100644
index 00000000000..9adac6b87d8
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/vars/main.yml
@@ -0,0 +1 @@
+role3_main: defined in role3/vars/main.yml
diff --git a/test/integration/targets/include_import/roles/role3/vars/role3vars.yml b/test/integration/targets/include_import/roles/role3/vars/role3vars.yml
new file mode 100644
index 00000000000..f324d56a6e5
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role3/vars/role3vars.yml
@@ -0,0 +1,2 @@
+where_am_i_defined: role3vars.yml
+role3_var: defined in role3/vars/role3vars.yml
diff --git a/test/integration/targets/include_import/roles/role_with_deps/meta/main.yml b/test/integration/targets/include_import/roles/role_with_deps/meta/main.yml
new file mode 100644
index 00000000000..a2446bba230
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role_with_deps/meta/main.yml
@@ -0,0 +1,3 @@
+dependencies:
+  - role1
+  - role2
diff --git a/test/integration/targets/include_import/roles/role_with_deps/tasks/main.yml b/test/integration/targets/include_import/roles/role_with_deps/tasks/main.yml
new file mode 100644
index 00000000000..060fe42f15d
--- /dev/null
+++ b/test/integration/targets/include_import/roles/role_with_deps/tasks/main.yml
@@ -0,0 +1,2 @@
+- debug:
+    msg: In role_with_deps
diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh
new file mode 100755
index 00000000000..fbe961c574c
--- /dev/null
+++ b/test/integration/targets/include_import/runme.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+set -eux
+
+export ANSIBLE_ROLES_PATH=./roles
+
+## Import (static)
+
+# Playbook
+ANSIBLE_STRATEGY='linear' ansible-playbook playbook/test_import_playbook.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook playbook/test_import_playbook.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='linear' ansible-playbook playbook/test_import_playbook_tags.yml -i ../../inventory "$@" --tags canary1,canary22,validate --skip-tags skipme,never
+
+# Tasks
+ANSIBLE_STRATEGY='linear' ansible-playbook tasks/test_import_tasks.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook tasks/test_import_tasks.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook tasks/test_import_tasks_tags.yml -i ../../inventory "$@" --tags tasks1,canary1,validate --skip-tags never
+
+# Role
+ANSIBLE_STRATEGY='linear' ansible-playbook role/test_import_role.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook role/test_import_role.yml -i ../../inventory "$@" --skip-tags never
+
+
+## Include (dynamic)
+
+# Tasks
+ANSIBLE_STRATEGY='linear' ansible-playbook tasks/test_include_tasks.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook tasks/test_include_tasks.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook tasks/test_include_tasks_tags.yml -i ../../inventory "$@" --tags tasks1,canary1,validate --skip-tags never
+
+# Role
+ANSIBLE_STRATEGY='linear' ansible-playbook role/test_include_role.yml -i ../../inventory "$@" --skip-tags never
+ANSIBLE_STRATEGY='free' ansible-playbook role/test_include_role.yml -i ../../inventory "$@" --skip-tags never
+
+
+## Recursion
+# https://github.com/ansible/ansible/issues/23609
+ANSIBLE_STRATEGY='linear' ansible-playbook test_recursion.yml -i ../../inventory "$@" --skip-tags never
diff --git a/test/integration/targets/include_import/tasks/tasks1.yml b/test/integration/targets/include_import/tasks/tasks1.yml
new file mode 100644
index 00000000000..e1d83d92b49
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks1.yml
@@ -0,0 +1,5 @@
+- name: Set variable inside tasks1.yml
+  set_fact:
+    set_in_tasks1: yes
+  tags:
+    - tasks1
diff --git a/test/integration/targets/include_import/tasks/tasks2.yml b/test/integration/targets/include_import/tasks/tasks2.yml
new file mode 100644
index 00000000000..1b4c86fc419
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks2.yml
@@ -0,0 +1,5 @@
+- name: Set variable inside tasks2.yml
+  set_fact:
+    set_in_tasks2: yes
+  tags:
+    - tasks2
diff --git a/test/integration/targets/include_import/tasks/tasks3.yml b/test/integration/targets/include_import/tasks/tasks3.yml
new file mode 100644
index 00000000000..6da371910f5
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks3.yml
@@ -0,0 +1,5 @@
+- name: Set variable inside tasks3.yml
+  set_fact:
+    set_in_tasks3: yes
+  tags:
+    - tasks3
diff --git a/test/integration/targets/include_import/tasks/tasks4.yml b/test/integration/targets/include_import/tasks/tasks4.yml
new file mode 100644
index 00000000000..fc2eb6cbcc7
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks4.yml
@@ -0,0 +1,5 @@
+- name: Set variable inside tasks4.yml
+  set_fact:
+    set_in_tasks4: yes
+  tags:
+    - tasks4
diff --git a/test/integration/targets/include_import/tasks/tasks5.yml b/test/integration/targets/include_import/tasks/tasks5.yml
new file mode 100644
index 00000000000..f2ee6b9ecbe
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks5.yml
@@ -0,0 +1,6 @@
+- name: Set variable inside tasks5.yml
+  set_fact:
+    set_in_tasks5: yes
+  tags:
+    - tasks5
+    - canary1
diff --git a/test/integration/targets/include_import/tasks/tasks6.yml b/test/integration/targets/include_import/tasks/tasks6.yml
new file mode 100644
index 00000000000..fa03079d686
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/tasks6.yml
@@ -0,0 +1,5 @@
+- name: Set variable inside tasks6.yml
+  set_fact:
+    set_in_tasks6: yes
+  tags:
+    - tasks6
diff --git a/test/integration/targets/include_import/tasks/test_import_tasks.yml b/test/integration/targets/include_import/tasks/test_import_tasks.yml
new file mode 100644
index 00000000000..8f07bb9090f
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/test_import_tasks.yml
@@ -0,0 +1,41 @@
+- name: Test import_tasks
+  hosts: testhost
+
+  tasks:
+    - name: Test basic task import
+      import_tasks: tasks1.yml
+
+    - name: Assert that fact was set in import
+      assert:
+        that:
+          - set_in_tasks1
+
+    - name: Test conditional task import
+      import_tasks: tasks2.yml
+      when: no
+
+    - name: Assert that tasks were skipped
+      assert:
+        that:
+          - set_in_tasks2 is not defined
+
+    - block:
+        - name: Import tasks inside a block
+          import_tasks: tasks3.yml
+
+        - name: Assert that task3 was included
+          assert:
+            that:
+              - set_in_tasks3
+
+      always:
+        - name: Import task inside always
+          import_tasks: tasks4.yml
+
+        - name: Validate that variables set in previously improted tasks are passed down.
+          import_tasks: validate3.yml
+
+        - name: Assert that tasks4 was included
+          assert:
+            that:
+              - set_in_tasks4
diff --git a/test/integration/targets/include_import/tasks/test_import_tasks_tags.yml b/test/integration/targets/include_import/tasks/test_import_tasks_tags.yml
new file mode 100644
index 00000000000..3b1d68fcade
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/test_import_tasks_tags.yml
@@ -0,0 +1,23 @@
+- name: Test import_tasks using tags
+  hosts: testhost
+
+  tasks:
+    - name: Import tasks1.yml
+      import_tasks: tasks1.yml
+
+    - name: Import tasks4.yml using tag on import task
+      import_tasks: tasks4.yml
+      tags:
+        - canary1
+
+    - name: Import tasks2.yml
+      import_tasks: tasks2.yml
+
+    - name: Assert that appropriate tasks were run
+      assert:
+        that:
+          - set_in_tasks1
+          - set_in_tasks4
+          - set_in_tasks2 is not defined
+      tags:
+        - validate
diff --git a/test/integration/targets/include_import/tasks/test_include_tasks.yml b/test/integration/targets/include_import/tasks/test_include_tasks.yml
new file mode 100644
index 00000000000..76471ffd4cc
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/test_include_tasks.yml
@@ -0,0 +1,41 @@
+- name: Test include_tasks
+  hosts: testhost
+
+  tasks:
+    - name: Test basic task include
+      include_tasks: tasks1.yml
+
+    - name: Assert that fact was set in include
+      assert:
+        that:
+          - set_in_tasks1
+
+    - name: Test conditional task include
+      include_tasks: tasks2.yml
+      when: no
+
+    - name: Assert that tasks were skipped
+      assert:
+        that:
+          - set_in_tasks2 is not defined
+
+    - block:
+        - name: Include tasks inside a block
+          include_tasks: tasks3.yml
+
+        - name: Assert that task3 was included
+          assert:
+            that:
+              - set_in_tasks3
+
+      always:
+        - name: Include task inside always
+          include_tasks: tasks4.yml
+
+        - name: Validate that variables set in previously improted tasks are passed down
+          include_tasks: validate3.yml
+
+        - name: Assert that tasks4 was included
+          assert:
+            that:
+              - set_in_tasks4
diff --git a/test/integration/targets/include_import/tasks/test_include_tasks_tags.yml b/test/integration/targets/include_import/tasks/test_include_tasks_tags.yml
new file mode 100644
index 00000000000..3fe43809cdf
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/test_include_tasks_tags.yml
@@ -0,0 +1,25 @@
+- name: Test include_tasks using tags
+  hosts: testhost
+
+  tasks:
+    # This should not be included
+    - name: Include tasks1.yml
+      include_tasks: tasks1.yml
+
+    # This should be included but tasks inside should not run because they do not have
+    # the canary1 tag and tasks2 is not in the list of tags for the ansible-playbook command
+    - name: Include tasks2.yml
+      include_tasks: tasks2.yml
+      tags:
+        - canary1
+
+    # This should be included and tasks inside should be run
+    - name: Include tasks5.yml using tag on include task
+      include_tasks: tasks5.yml
+      tags:
+        - canary1
+
+    - name: Include validate_tags.yml
+      include_tasks: validate_tags.yml
+      tags:
+        - validate
diff --git a/test/integration/targets/include_import/tasks/test_recursion.yml b/test/integration/targets/include_import/tasks/test_recursion.yml
new file mode 100644
index 00000000000..96754ec8004
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/test_recursion.yml
@@ -0,0 +1,6 @@
+- hosts: testhost
+
+  tasks:
+    - include_role:
+        name: role
+        tasks_from: r1t1.yml
diff --git a/test/integration/targets/include_import/tasks/validate3.yml b/test/integration/targets/include_import/tasks/validate3.yml
new file mode 100644
index 00000000000..e3166aa307e
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/validate3.yml
@@ -0,0 +1,4 @@
+- name: Assert than variable set in previously included task is defined
+  assert:
+    that:
+      - set_in_tasks3
diff --git a/test/integration/targets/include_import/tasks/validate_tags.yml b/test/integration/targets/include_import/tasks/validate_tags.yml
new file mode 100644
index 00000000000..e2f3377bdc8
--- /dev/null
+++ b/test/integration/targets/include_import/tasks/validate_tags.yml
@@ -0,0 +1,8 @@
+- name: Assert that appropriate tasks were run
+  assert:
+    that:
+      - set_in_tasks1 is undefined
+      - set_in_tasks2 is undefined
+      - set_in_tasks5
+  tags:
+    - validate
diff --git a/test/integration/targets/include_import/test_recursion.yml b/test/integration/targets/include_import/test_recursion.yml
new file mode 100644
index 00000000000..ad2489a0b22
--- /dev/null
+++ b/test/integration/targets/include_import/test_recursion.yml
@@ -0,0 +1,7 @@
+- name: Test max recursion depth
+  hosts: testhost
+
+  tasks:
+    - import_role:
+        name: role1
+        tasks_from: r1t01.yml
diff --git a/test/integration/targets/includes/test_includes2.yml b/test/integration/targets/includes/test_includes2.yml
index d8dcf10e155..a32e851384e 100644
--- a/test/integration/targets/includes/test_includes2.yml
+++ b/test/integration/targets/includes/test_includes2.yml
@@ -10,7 +10,8 @@
   hosts: testhost
   gather_facts: True
   roles:
-    - { role: test_includes, tags: test_includes }
+    - role: test_includes
+      tags: test_includes
   tasks:
     - include: roles/test_includes/tasks/not_a_role_task.yml
     - include: roles/test_includes/tasks/empty.yml
diff --git a/test/integration/targets/includes/test_includes3.yml b/test/integration/targets/includes/test_includes3.yml
index 012ee205688..bd3b0d30dab 100644
--- a/test/integration/targets/includes/test_includes3.yml
+++ b/test/integration/targets/includes/test_includes3.yml
@@ -1,4 +1,3 @@
----
 - hosts: localhost
   tasks:
     - include: test_includes4.yml