merge in oc-release history after reset to master
diff --git a/server/cros/tradefed_test.py b/server/cros/tradefed_test.py
index f5d9e95..6c480b1 100644
--- a/server/cros/tradefed_test.py
+++ b/server/cros/tradefed_test.py
@@ -807,16 +807,20 @@
                    raise error.TestFail('Error: Unexpected test end: ' + line)
                npass, nfail, nnotexec = map(int, match.group(2,3,4))
 
-               if accumulative_count:
-                   total_test[abi] = ntest
-                   total_pass[abi] = npass
-                   total_fail[abi] = nfail
-               else:
-                   total_test[abi] = (total_test.get(abi, 0) + ntest -
-                       last_notexec.get(abi, 0))
-                   total_pass[abi] = total_pass.get(abi, 0) + npass
-                   total_fail[abi] = total_fail.get(abi, 0) + nfail
-               last_notexec[abi] = nnotexec
+               # When the test crashes too ofen, tradefed seems to finish the
+               # iteration by running "0 tests, 0 passed, ...". Do not count
+               # that in.
+               if ntest > 0:
+                   if accumulative_count:
+                       total_test[abi] = ntest
+                       total_pass[abi] = npass
+                       total_fail[abi] = nfail
+                   else:
+                       total_test[abi] = (total_test.get(abi, 0) + ntest -
+                           last_notexec.get(abi, 0))
+                       total_pass[abi] = total_pass.get(abi, 0) + npass
+                       total_fail[abi] = total_fail.get(abi, 0) + nfail
+                   last_notexec[abi] = nnotexec
                abi = None
 
         if abi:
diff --git a/server/site_tests/cheets_CTS_N/cheets_CTS_N.py b/server/site_tests/cheets_CTS_N/cheets_CTS_N.py
index 619b1ab..fe3dcf8 100644
--- a/server/site_tests/cheets_CTS_N/cheets_CTS_N.py
+++ b/server/site_tests/cheets_CTS_N/cheets_CTS_N.py
@@ -390,12 +390,20 @@
                     # Consistency check, did we really run as many as we
                     # thought initially?
                     if expected_tests != tests:
-                        retry_inconsistency_error = ('Retry inconsistency - '
+                        msg = ('Retry inconsistency - '
                            'initially saw %d failed+notexecuted, ran %d tests. '
                            'passed=%d, failed=%d, notexecuted=%d, waived=%d.' %
                            (expected_tests, tests, passed, failed, notexecuted,
                             waived))
-                        logging.warning(retry_inconsistency_error)
+                        logging.warning(msg)
+                        if expected_tests > tests:
+                            # See b/36523200#comment8. Due to the existence of
+                            # the multiple tests having the same ID, more cases
+                            # may be run than previous fail count. As a
+                            # workaround, making it an error only when the tests
+                            # run were less than expected.
+                            # TODO(kinaba): Find a way to handle this dup.
+                            retry_inconsistency_error = msg
                     if not self._consistent(tests, passed, failed, notexecuted):
                         logging.warning('Tradefed inconsistency - retrying.')
                         session_id, counts = self._tradefed_retry(test_name,
diff --git a/site_utils/sponge_lib/autotest_job_info.py b/site_utils/sponge_lib/autotest_job_info.py
index 111b03f..797217f 100644
--- a/site_utils/sponge_lib/autotest_job_info.py
+++ b/site_utils/sponge_lib/autotest_job_info.py
@@ -26,6 +26,9 @@
     # Tell the uploader what type of info this object holds.
     tags=['autotest']
 
+    # Version of the data stored.
+    version = 2
+
     def __init__(self, job):
         self._job = job
         self._tasks = list(
@@ -41,6 +44,11 @@
         return job_directories.get_job_id_or_task_id(self._job.dir)
 
     @property
+    def label(self):
+        """The label of the autotest job."""
+        return self._job.label
+
+    @property
     def user(self):
         """The user who launched the autotest job."""
         return self._job.user
@@ -66,6 +74,11 @@
         return self._job.keyval_dict.get('drone', socket.gethostname())
 
     @property
+    def keyvals(self):
+        """Keyval dict for this job."""
+        return self._job.keyval_dict
+
+    @property
     def tasks(self):
         """All tests that this job ran."""
         return self._tasks
@@ -106,6 +119,9 @@
     # A list of logs to upload for this task.
     logs = ['debug', 'status.log', 'crash', 'keyval']
 
+    # Version of the data stored.
+    version = 2
+
     def __init__(self, test, job):
         """
         @param test: The autotest test to create this task from.
@@ -143,6 +159,11 @@
         return self._test.subdir
 
     @property
+    def attributes(self):
+        """Attributes of this task."""
+        return getattr(self._test, 'attributes', {})
+
+    @property
     def results_dir(self):
         """The full directory where results are stored for this test."""
         if self.subdir == '----' or not self.subdir: