Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Unified Diff: scheduler/scheduler_models.py

Issue 3554003: Merge remote branch 'cros/upstream' into tempbranch3 (Closed) Base URL: http://git.chromium.org/git/autotest.git
Patch Set: Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « scheduler/monitor_db.py ('k') | server/autotest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: scheduler/scheduler_models.py
diff --git a/scheduler/scheduler_models.py b/scheduler/scheduler_models.py
index bafaf5ff6612601a3f4cd18ce54f30f67c03047f..0a6ae7b3a6b5274e7a1937ceddb3a389dbc15c98 100644
--- a/scheduler/scheduler_models.py
+++ b/scheduler/scheduler_models.py
@@ -19,6 +19,7 @@ _drone_manager: reference to global DroneManager instance.
import datetime, itertools, logging, os, re, sys, time, weakref
from django.db import connection
from autotest_lib.client.common_lib import global_config, host_protections
+from autotest_lib.client.common_lib import global_config, utils
from autotest_lib.frontend.afe import models, model_attributes
from autotest_lib.database import database_connection
from autotest_lib.scheduler import drone_manager, email_manager
@@ -591,14 +592,57 @@ class HostQueueEntry(DBObject):
_drone_manager.unregister_pidfile(pidfile_id)
+ def _get_status_email_contents(self, status, summary=None, hostname=None):
+ """
+ Gather info for the status notification e-mails.
+
+ If needed, we could start using the Django templating engine to create
+ the subject and the e-mail body, but that doesn't seem necessary right
+ now.
+
+ @param status: Job status text. Mandatory.
+ @param summary: Job summary text. Optional.
+ @param hostname: A hostname for the job. Optional.
+
+ @return: Tuple (subject, body) for the notification e-mail.
+ """
+ job_stats = Job(id=self.job.id).get_execution_details()
+
+ subject = ('Autotest | Job ID: %s "%s" | Status: %s ' %
+ (self.job.id, self.job.name, status))
+
+ if hostname is not None:
+ subject += '| Hostname: %s ' % hostname
+
+ if status not in ["1 Failed", "Failed"]:
+ subject += '| Success Rate: %.2f %%' % job_stats['success_rate']
+
+ body = "Job ID: %s\n" % self.job.id
+ body += "Job name: %s\n" % self.job.name
+ if hostname is not None:
+ body += "Host: %s\n" % hostname
+ if summary is not None:
+ body += "Summary: %s\n" % summary
+ body += "Status: %s\n" % status
+ body += "Results interface URL: %s\n" % self._view_job_url()
+ body += "Execution time (HH:MM:SS): %s\n" % job_stats['execution_time']
+ if int(job_stats['total_executed']) > 0:
+ body += "User tests executed: %s\n" % job_stats['total_executed']
+ body += "User tests passed: %s\n" % job_stats['total_passed']
+ body += "User tests failed: %s\n" % job_stats['total_failed']
+ body += ("User tests success rate: %.2f %%\n" %
+ job_stats['success_rate'])
+
+ if job_stats['failed_rows']:
+ body += "Failures:\n"
+ body += job_stats['failed_rows']
+
+ return subject, body
+
+
def _email_on_status(self, status):
hostname = self._get_hostname()
-
- subject = 'Autotest: Job ID: %s "%s" Host: %s %s' % (
- self.job.id, self.job.name, hostname, status)
- body = "Job ID: %s\nJob Name: %s\nHost: %s\nStatus: %s\n%s\n" % (
- self.job.id, self.job.name, hostname, status,
- self._view_job_url())
+ subject, body = self._get_status_email_contents(status, None, hostname)
email_manager.manager.send_email(self.job.email_list, subject, body)
@@ -606,24 +650,20 @@ class HostQueueEntry(DBObject):
if not self.job.is_finished():
return
- summary_text = []
+ summary = []
hosts_queue = HostQueueEntry.fetch('job_id = %s' % self.job.id)
for queue_entry in hosts_queue:
- summary_text.append("Host: %s Status: %s" %
+ summary.append("Host: %s Status: %s" %
(queue_entry._get_hostname(),
queue_entry.status))
- summary_text = "\n".join(summary_text)
+ summary = "\n".join(summary)
status_counts = models.Job.objects.get_status_counts(
[self.job.id])[self.job.id]
status = ', '.join('%d %s' % (count, status) for status, count
in status_counts.iteritems())
- subject = 'Autotest: Job ID: %s "%s" %s' % (
- self.job.id, self.job.name, status)
- body = "Job ID: %s\nJob Name: %s\nStatus: %s\n%s\nSummary:\n%s" % (
- self.job.id, self.job.name, status, self._view_job_url(),
- summary_text)
+ subject, body = self._get_status_email_contents(status, summary, None)
email_manager.manager.send_email(self.job.email_list, subject, body)
@@ -821,6 +861,83 @@ class Job(DBObject):
return entries
+ def get_execution_details(self):
+ """
+ Get test execution details for this job.
+
+ @return: Dictionary with test execution details
+ """
+ def _find_test_jobs(rows):
+ """
+ Here we are looking for tests such as SERVER_JOB and CLIENT_JOB.*
+ Those are autotest 'internal job' tests, so they should not be
+ counted when evaluating the test stats.
+
+ @param rows: List of rows (matrix) with database results.
+ """
+ job_test_pattern = re.compile('SERVER|CLIENT\\_JOB\.[\d]')
+ n_test_jobs = 0
+ for r in rows:
+ test_name = r[0]
+ if job_test_pattern.match(test_name):
+ n_test_jobs += 1
+
+ return n_test_jobs
+
+ stats = {}
+
+ rows = _db.execute("""
+ SELECT t.test, s.word, t.reason
+ FROM tko_tests AS t, tko_jobs AS j, tko_status AS s
+ WHERE t.job_idx = j.job_idx
+ AND s.status_idx = t.status
+ AND j.afe_job_id = %s
+ """ % self.id)
+
+ failed_rows = [r for r in rows if not 'GOOD' in r]
+
+ n_test_jobs = _find_test_jobs(rows)
+ n_test_jobs_failed = _find_test_jobs(failed_rows)
+
+ total_executed = len(rows) - n_test_jobs
+ total_failed = len(failed_rows) - n_test_jobs_failed
+
+ if total_executed > 0:
+ success_rate = 100 - ((total_failed / float(total_executed)) * 100)
+ else:
+ success_rate = 0
+
+ stats['total_executed'] = total_executed
+ stats['total_failed'] = total_failed
+ stats['total_passed'] = total_executed - total_failed
+ stats['success_rate'] = success_rate
+
+ status_header = ("Test Name", "Status", "Reason")
+ if failed_rows:
+ stats['failed_rows'] = utils.matrix_to_string(failed_rows,
+ status_header)
+ else:
+ stats['failed_rows'] = ''
+
+ time_row = _db.execute("""
+ SELECT started_time, finished_time
+ FROM tko_jobs
+ WHERE afe_job_id = %s
+ """ % self.id)
+
+ if time_row:
+ t_begin, t_end = time_row[0]
+ delta = t_end - t_begin
+ minutes, seconds = divmod(delta.seconds, 60)
+ hours, minutes = divmod(minutes, 60)
+ stats['execution_time'] = ("%02d:%02d:%02d" %
+ (hours, minutes, seconds))
+ else:
+ stats['execution_time'] = '(none)'
+
+ return stats
+
+
def set_status(self, status, update_queues=False):
self.update_field('status',status)
« no previous file with comments | « scheduler/monitor_db.py ('k') | server/autotest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698