Fix sql reporting start/end times

* Always send a build start event for noop jobs so that we get
  start and end times for them
* Handle builds without start or end times in the sql reporter.
  These should no longer include noop builds, but may still include
  SKIPPED builds.

Test both.

Change-Id: I73eb6bda482ebb515d231492c0769d49cf6ff28a
diff --git a/tests/fixtures/config/sql-driver/git/common-config/playbooks/project-test3.yaml b/tests/fixtures/config/sql-driver/git/common-config/playbooks/project-test3.yaml
new file mode 100644
index 0000000..f679dce
--- /dev/null
+++ b/tests/fixtures/config/sql-driver/git/common-config/playbooks/project-test3.yaml
@@ -0,0 +1,2 @@
+- hosts: all
+  tasks: []
diff --git a/tests/fixtures/config/sql-driver/git/common-config/zuul.yaml b/tests/fixtures/config/sql-driver/git/common-config/zuul.yaml
index b8f4d67..8fce9e7 100644
--- a/tests/fixtures/config/sql-driver/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/sql-driver/git/common-config/zuul.yaml
@@ -27,6 +27,9 @@
 - job:
     name: project-test2
 
+- job:
+    name: project-test3
+
 - project:
     name: org/project
     check:
@@ -36,3 +39,9 @@
             dependencies: project-merge
         - project-test2:
             dependencies: project-merge
+        # Make sure we have a "SKIPPED" result
+        - project-test3:
+            dependencies: project-test1
+        # The noop job can have timing quirks
+        - noop:
+            dependencies: project-test2
diff --git a/tests/unit/test_connection.py b/tests/unit/test_connection.py
index 4214e9f..1e12bce 100644
--- a/tests/unit/test_connection.py
+++ b/tests/unit/test_connection.py
@@ -74,6 +74,7 @@
 
     def test_sql_results(self):
         "Test results are entered into an sql table"
+        self.executor_server.hold_jobs_in_build = True
         # Grab the sa tables
         tenant = self.sched.abide.tenants.get('tenant-one')
         reporter = _get_reporter_from_connection_name(
@@ -85,6 +86,8 @@
         A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
         self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
         self.waitUntilSettled()
+        self.orderedRelease()
+        self.waitUntilSettled()
 
         # Add a failed result
         B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
@@ -92,6 +95,8 @@
         self.executor_server.failJob('project-test1', B)
         self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
         self.waitUntilSettled()
+        self.orderedRelease()
+        self.waitUntilSettled()
 
         conn = self.connections.connections['resultsdb'].engine.connect()
         result = conn.execute(
@@ -141,15 +146,15 @@
             )
         ).fetchall()
 
-        # Check the second last result, which should be the project-test1 job
+        # Check the second result, which should be the project-test1 job
         # which failed
-        self.assertEqual('project-test1', buildset1_builds[-2]['job_name'])
-        self.assertEqual("FAILURE", buildset1_builds[-2]['result'])
+        self.assertEqual('project-test1', buildset1_builds[1]['job_name'])
+        self.assertEqual("FAILURE", buildset1_builds[1]['result'])
         self.assertEqual(
             'finger://{hostname}/{uuid}'.format(
                 hostname=self.executor_server.hostname,
-                uuid=buildset1_builds[-2]['uuid']),
-            buildset1_builds[-2]['log_url'])
+                uuid=buildset1_builds[1]['uuid']),
+            buildset1_builds[1]['log_url'])
 
     def test_multiple_sql_connections(self):
         "Test putting results in different databases"
diff --git a/zuul/driver/sql/sqlreporter.py b/zuul/driver/sql/sqlreporter.py
index ca35577..fdc280a 100644
--- a/zuul/driver/sql/sqlreporter.py
+++ b/zuul/driver/sql/sqlreporter.py
@@ -61,15 +61,19 @@
 
                 (result, url) = item.formatJobResult(job)
 
+                start = end = None
+                if build.start_time:
+                    start = datetime.datetime.fromtimestamp(build.start_time)
+                if build.end_time:
+                    end = datetime.datetime.fromtimestamp(build.end_time)
+
                 build_inserts.append({
                     'buildset_id': buildset_ins_result.inserted_primary_key,
                     'uuid': build.uuid,
                     'job_name': build.job.name,
                     'result': result,
-                    'start_time': datetime.datetime.fromtimestamp(
-                        build.start_time),
-                    'end_time': datetime.datetime.fromtimestamp(
-                        build.end_time),
+                    'start_time': start,
+                    'end_time': end,
                     'voting': build.job.voting,
                     'log_url': url,
                     'node_name': build.node_name,
diff --git a/zuul/executor/client.py b/zuul/executor/client.py
index eb2bfdf..96fce2d 100644
--- a/zuul/executor/client.py
+++ b/zuul/executor/client.py
@@ -282,6 +282,7 @@
         build.parameters = params
 
         if job.name == 'noop':
+            self.sched.onBuildStarted(build)
             self.sched.onBuildCompleted(build, 'SUCCESS', {})
             return build