Merge "Add a test to verify basic console output" into feature/zuulv3
diff --git a/tests/fixtures/config/job-output/git/common-config/playbooks/job-output.yaml b/tests/fixtures/config/job-output/git/common-config/playbooks/job-output.yaml
new file mode 100644
index 0000000..332db87
--- /dev/null
+++ b/tests/fixtures/config/job-output/git/common-config/playbooks/job-output.yaml
@@ -0,0 +1,3 @@
+- hosts: all
+  tasks:
+    - shell: echo "Standard output test {{ zuul.executor.src_root }}"
diff --git a/tests/fixtures/config/job-output/git/common-config/zuul.yaml b/tests/fixtures/config/job-output/git/common-config/zuul.yaml
new file mode 100644
index 0000000..a83f0bc
--- /dev/null
+++ b/tests/fixtures/config/job-output/git/common-config/zuul.yaml
@@ -0,0 +1,27 @@
+- pipeline:
+    name: check
+    manager: independent
+    post-review: true
+    trigger:
+      gerrit:
+        - event: patchset-created
+    success:
+      gerrit:
+        Verified: 1
+    failure:
+      gerrit:
+        Verified: -1
+
+- job:
+    name: base
+    parent: null
+
+- job:
+    parent: base
+    name: job-output
+
+- project:
+    name: org/project
+    check:
+      jobs:
+        - job-output
diff --git a/tests/fixtures/config/job-output/git/org_project/README b/tests/fixtures/config/job-output/git/org_project/README
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/tests/fixtures/config/job-output/git/org_project/README
@@ -0,0 +1 @@
+test
diff --git a/tests/fixtures/config/job-output/main.yaml b/tests/fixtures/config/job-output/main.yaml
new file mode 100644
index 0000000..208e274
--- /dev/null
+++ b/tests/fixtures/config/job-output/main.yaml
@@ -0,0 +1,8 @@
+- tenant:
+    name: tenant-one
+    source:
+      gerrit:
+        config-projects:
+          - common-config
+        untrusted-projects:
+          - org/project
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 98cffcc..60a0986 100755
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -14,6 +14,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import json
 import os
 import textwrap
 
@@ -1338,3 +1339,39 @@
         # paths.
         self.executor_server.verbose = True
         self._test_secret_file_fail()
+
+
+class TestJobOutput(AnsibleZuulTestCase):
+    tenant_config_file = 'config/job-output/main.yaml'
+
+    def _get_file(self, build, path):
+        p = os.path.join(build.jobdir.root, path)
+        with open(p) as f:
+            return f.read()
+
+    def test_job_output(self):
+        # Verify that command standard output appears in the job output
+
+        # This currently only verifies we receive output from
+        # localhost.  Notably, it does not verify we receive output
+        # via zuul_console streaming.
+        self.executor_server.keep_jobdir = True
+        A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
+        self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
+        self.waitUntilSettled()
+        self.assertHistory([
+            dict(name='job-output', result='SUCCESS', changes='1,1'),
+        ], ordered=False)
+
+        token = 'Standard output test %s' % (self.history[0].jobdir.src_root)
+        j = json.loads(self._get_file(self.history[0],
+                                      'work/logs/job-output.json'))
+        self.assertEqual(token,
+                         j[0]['plays'][0]['tasks'][0]
+                         ['hosts']['localhost']['stdout'])
+
+        print(self._get_file(self.history[0],
+                             'work/logs/job-output.txt'))
+        self.assertIn(token,
+                      self._get_file(self.history[0],
+                                     'work/logs/job-output.txt'))
diff --git a/zuul/ansible/callback/zuul_stream.py b/zuul/ansible/callback/zuul_stream.py
index 11da1e5..1ffeb9c 100644
--- a/zuul/ansible/callback/zuul_stream.py
+++ b/zuul/ansible/callback/zuul_stream.py
@@ -256,8 +256,12 @@
                 is_localhost = True
         else:
             task_hostvars = result._task._variable_manager._hostvars[task_host]
+            # Normally hosts in the inventory will have ansible_host
+            # or ansible_inventory host defined.  The implied
+            # inventory record for 'localhost' will have neither, so
+            # default to that if none are supplied.
             if task_hostvars.get('ansible_host', task_hostvars.get(
-                    'ansible_inventory_host')) in localhost_names:
+                    'ansible_inventory_host', 'localhost')) in localhost_names:
                 is_localhost = True
 
         if not is_localhost and is_task: