diff --git a/test/integration/targets/module_no_log/aliases b/test/integration/targets/module_no_log/aliases
new file mode 100644
index 00000000000..e0437b6c627
--- /dev/null
+++ b/test/integration/targets/module_no_log/aliases
@@ -0,0 +1,4 @@
+shippable/posix/group1
+skip/aix  # not configured to log user.info to /var/log/syslog
+skip/freebsd  # not configured to log user.info to /var/log/syslog
+skip/osx  # not configured to log user.info to /var/log/syslog
diff --git a/test/integration/targets/module_no_log/library/module_that_logs.py b/test/integration/targets/module_no_log/library/module_that_logs.py
new file mode 100644
index 00000000000..44b36eeb808
--- /dev/null
+++ b/test/integration/targets/module_no_log/library/module_that_logs.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+    module = AnsibleModule(argument_spec=dict(
+        number=dict(type='int'),
+    ))
+
+    module.log('My number is: (%d)' % module.params['number'])
+    module.exit_json()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/test/integration/targets/module_no_log/tasks/main.yml b/test/integration/targets/module_no_log/tasks/main.yml
new file mode 100644
index 00000000000..cf9e5802570
--- /dev/null
+++ b/test/integration/targets/module_no_log/tasks/main.yml
@@ -0,0 +1,61 @@
+- name: Detect syslog
+  stat:
+    path: /var/log/syslog
+  register: syslog
+
+- name: Detect journalctl
+  shell: command -V journalctl
+  ignore_errors: yes
+  changed_when: no
+  register: journalctl
+
+- block:
+    - name: Skip tests if logs were not found.
+      debug:
+        msg: Did not find /var/log/syslog or journalctl. Tests will be skipped.
+    - meta: end_play
+  when: journalctl is failed and not syslog.stat.exists
+
+- name: Generate random numbers for unique log entries
+  set_fact:
+    good_number: "{{ 999999999999 | random }}"
+    bad_number: "{{ 999999999999 | random }}"
+
+- name: Generate expected log entry messages
+  set_fact:
+    good_message: 'My number is: ({{ good_number }})'
+    bad_message: 'My number is: ({{ bad_number }})'
+
+- name: Generate log message search patterns
+  set_fact:
+    # these search patterns are designed to avoid matching themselves
+    good_search: '{{ good_message.replace(":", "[:]") }}'
+    bad_search: '{{ bad_message.replace(":", "[:]") }}'
+
+- name: Generate grep command
+  set_fact:
+    grep_command: "grep -e '{{ good_search }}' -e '{{ bad_search }}'"
+
+- name: Run a module that logs without no_log
+  module_that_logs:
+    number: "{{ good_number }}"
+
+- name: Run a module that logs with no_log
+  module_that_logs:
+    number: "{{ bad_number }}"
+  no_log: yes
+
+- name: Search for expected log messages
+  # if this fails the tests are probably running on a system which stores logs elsewhere
+  shell: "({{ grep_command }} /var/log/syslog) || (journalctl | {{ grep_command }})"
+  changed_when: no
+  register: grep
+
+- name: Verify the correct log messages were found
+  assert:
+    that:
+      # if the good message is not found then the cause is likely one of:
+      # 1) the remote system does not write user.info messages to the logs
+      # 2) the AnsibleModule.log method is not working
+      - good_message in grep.stdout
+      - bad_message not in grep.stdout
diff --git a/test/integration/targets/tasks/aliases b/test/integration/targets/tasks/aliases
new file mode 100644
index 00000000000..a6dafcf8cd8
--- /dev/null
+++ b/test/integration/targets/tasks/aliases
@@ -0,0 +1 @@
+shippable/posix/group1
diff --git a/test/integration/targets/tasks/tasks/main.yml b/test/integration/targets/tasks/tasks/main.yml
new file mode 100644
index 00000000000..f6ac1114d0f
--- /dev/null
+++ b/test/integration/targets/tasks/tasks/main.yml
@@ -0,0 +1,4 @@
+# make sure tasks with an undefined variable in the name are gracefully handled
+- name: "Task name with undefined variable: {{ not_defined }}"
+  debug:
+    msg: Hello