re-written application

This commit is contained in:
2010-04-26 10:37:53 -07:00
parent fad395bd0a
commit a4f7186f1f
41 changed files with 1577 additions and 0 deletions

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

11
topfails/topfails/manage.py Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)

View File

@@ -0,0 +1,86 @@
# Django settings for topfails project.
import os
DEBUG = True
TEMPLATE_DEBUG = DEBUG
DBUSER = DBPASSWD = ''
if os.environ.has_key('dbuser'):
DBUSER=os.environ.get('dbuser')
#print DBUSER
if os.environ.has_key('dbpasswd'):
DBPASSWD=os.environ.get('dbpasswd')
#print DBPASSWD
ADMINS = (
('Murali Nandigama', 'murali.nandigama@gmail.com'),
)
MANAGERS = ADMINS
DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'topfails' # Or path to database file if using sqlite3.
DATABASE_USER = DBUSER # Not used with sqlite3.
DATABASE_PASSWORD = DBPASSWD # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '^_5(02(8sng5+6+x=c$w+3(4xv+x^&b)2ty4y8m01(o7vz$o5_'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
# 'django.template.loaders.eggs.load_template_source',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF = 'topfails.urls'
TEMPLATE_DIRS = (
'./templates/'
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'topfails.viewer'
)

View File

@@ -0,0 +1,114 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Topfails</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<style type="text/css">
/*----------Text Styles----------*/
.ws6 {font-size: 8px;}
.ws7 {font-size: 9.3px;}
.ws8 {font-size: 11px;}
.ws9 {font-size: 12px;}
.ws10 {font-size: 13px;}
.ws11 {font-size: 15px;}
.ws12 {font-size: 16px;}
.ws14 {font-size: 19px;}
.ws16 {font-size: 21px;}
.ws18 {font-size: 24px;}
.ws20 {font-size: 27px;}
.ws22 {font-size: 29px;}
.ws24 {font-size: 32px;}
.ws26 {font-size: 35px;}
.ws28 {font-size: 37px;}
.ws36 {font-size: 48px;}
.ws48 {font-size: 64px;}
.ws72 {font-size: 96px;}
.wpmd {font-size: 13px;font-family: 'Arial';font-style: normal;font-weight: normal;}
/*----------Para Styles----------*/
DIV,UL,OL /* Left */
{
margin-top: 0px;
margin-bottom: 0px;
}
</style>
<script language="javascript" type="text/javascript">
<!--
function SwapImgRestore() {
var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}
function PreloadImages() {
var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
var i,j=d.MM_p.length,a=PreloadImages.arguments; for(i=0; i<a.length; i++)
if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}
function FindObject(n, d) {
var p,i,x; if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=FindObject(n,d.layers[i].document);
if(!x && d.getElementById) x=d.getElementById(n); return x;
}
function SwapImage() {
var i,j=0,x,a=SwapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
if ((x=FindObject(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}
//-->
</script>
<script type="text/javascript">
<!--
function MyTip(arg)
{
switch(arg)
{
case "trunk":
alert("Press this button to get the Tinderbox Topfails for Firefox Trunk");
case "3.6":
alert("Press this button to get the Tinderbox Topfails for Firefox 3.6");
case "thunderbird":
alert("Press this button to get the Tinderbox Topfails for Thunderbird Trunk");
case "sea":
alert("Press this button to get the Tinderbox Topfails for SeaMonkey");
}
}
//-->
</script>
</head>
<body>
<div id="nav10d" style="position:absolute; left:3px; top:102px; z-index:0"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav10','','http://people.mozilla.com/~mnandigama/images/nav11363110a.gif',1)" href="{% url latest tree=tree %}" <img name="nav10" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav11363110a.gif')" alt="Latest Failures" border=0 src="http://people.mozilla.com/~mnandigama/images/nav11363110i.gif"></a></div>
<div id="nav11d" style="position:absolute; left:3px; top:135px; z-index:0"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav11','','http://people.mozilla.com/~mnandigama/images/nav11363111a.gif',1)" href="{% url topfails tree=tree %}"><img name="nav11" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav11363111a.gif')" alt="Top 25 Failures" border=0 src="http://people.mozilla.com/~mnandigama/images/nav11363111i.gif"></a></div>
<div id="nav12d" style="position:absolute; left:3px; top:168px; z-index:0"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav12','','http://people.mozilla.com/~mnandigama/images/nav11363112a.gif',1)" href="{% url tests tree=tree %}"><img name="nav12" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav11363112a.gif')" alt="All Failed Tests" border=0 src="http://people.mozilla.com/~mnandigama/images/nav11363112i.gif"></a></div>
<div id="nav13d" style="position:absolute; left:3px; top:201px; z-index:0"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav13','','http://people.mozilla.com/~mnandigama/images/nav11363113a.gif',1)" href="{% url failswindow tree=tree %}?window=7d"<img name="nav13" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav11363113a.gif')" alt="Failures from last X days" border=0 src="http://people.mozilla.com/~mnandigama/images/nav11363113i.gif"></a></div>
<div id="nav14d" style="position:absolute; left:3px; top:234px; z-index:0"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav14','','http://people.mozilla.com/~mnandigama/images/nav11363114a.gif',1)" href="{% url Help tree=tree %}"><img name="nav14" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav11363114a.gif')" alt="Help" border=0 src="http://people.mozilla.com/~mnandigama/images/nav11363114i.gif"></a></div>
<div id="image1" style="position:absolute; overflow:hidden; left:3px; top:1px; width:179px; height:68px; z-index:1"><img src="http://people.mozilla.com/~mnandigama/images/logo-wordmark.png" alt="Firefox Logo" title="http://www.mozilla.com" border=0 width=179 height=68></div>
<div id="text1" style="position:absolute; overflow:hidden; left:351px; top:2px; width:491px; height:41px; z-index:3">
<div class="wpmd">
<div><font color="#CC4200" face="Tahoma" class="ws24"><B>Mozilla Tinderbox Topfails Dashboard</B></font></div>
</div></div>
<div id="nav20d" style="position:absolute; left:311px; top:45px; z-index:2"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav20','','http://people.mozilla.com/~mnandigama/images/nav14052410a.gif',1)" title="Click for Firefox Trunk Topfails Dashboard" href="{% url latest tree='Firefox' %}" ><img name="nav20" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav14052410a.gif')" alt="Firefox Trunk" border=0 src="http://people.mozilla.com/~mnandigama/images/nav14052410i.gif"></a></div>
<div id="nav21d" style="position:absolute; left:439px; top:45px; z-index:2"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav21','','http://people.mozilla.com/~mnandigama/images/nav14052411a.gif',1)" href="{% url latest tree='Firefox3.6' %}"><img name="nav21" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav14052411a.gif')" title="Click for Firefox 3.6 Topfails Dashboard" alt="Firefox3.6" border=0 src="http://people.mozilla.com/~mnandigama/images/nav14052411i.gif"></a></div>
<div id="nav22d" style="position:absolute; left:567px; top:45px; z-index:2"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav22','','http://people.mozilla.com/~mnandigama/images/nav14052412a.gif',1)" title="Click for Thunderbird Trunk Topfails Dashboard" href="{% url latest tree='Thunderbird' %}"><img name="nav22" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav14052412a.gif')" alt="Thunderbird" border=0 src="http://people.mozilla.com/~mnandigama/images/nav14052412i.gif"></a></div>
<div id="nav23d" style="position:absolute; left:695px; top:45px; z-index:2"><a onMouseOut="SwapImgRestore()" onMouseOver="SwapImage('nav23','','http://people.mozilla.com/~mnandigama/images/nav14052413a.gif',1)" title="Click for SeaMonkey Topfails Dashboard" href="{% url latest tree='SeaMonkey' %}"><img name="nav23" onLoad="PreloadImages('http://people.mozilla.com/~mnandigama/images/nav14052413a.gif')" alt="SeaMonkey" border=0 src="http://people.mozilla.com/~mnandigama/images/nav14052413i.gif"></a></div>
<div id="text2" style="position:absolute; overflow:hidden; left:190px; top:102px; width:800px; z-index:4">
{% block content %}
{% endblock %}
</div>
</body>
</html>

View File

@@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<div><font face="Calibri" class="ws11">This web site provides the bird eye view of top failures and other details of Firefox unit tests&nbsp; from the&nbsp; Tinderbox daily runs.</font></div>
<div><font face="Calibri" class="ws11"><BR></font></div>
<div><font face="Calibri" class="ws11">Meaning of the Left navigation links</font></div>
<UL>
<li><font face="Calibri" class="ws11">Latest Failures : This link provides the list of latest failures from the Tinderbox.</font></li>
<li><font face="Calibri" class="ws11">Top 25 Failures : This link provides the list of top 25 failures from the entire history of the topfails database. Please note that this data is as complete as the first date we started collecting results. The data we have in the topfails database does not contain all the failures details from the Time ZERO of tinderbox runs.</font></li>
<li><font face="Calibri" class="ws11">All Failed Tests: This link displays all the known failures that are stored in the topfails DB.</font></li>
<li><font face="Calibri" class="ws11"><b>Failures from X days</b>: This is a link which allows you to query for failures from NOW till a specific period in the past.</font></li>
</UL>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Example: 2d&nbsp; =&nbsp;&nbsp; 2 days&nbsp; in the past till&nbsp; now </font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7h&nbsp; =&nbsp;&nbsp; 7 hours in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5w =&nbsp; 5 weeks in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1m =&nbsp; 1 month in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10y =&nbsp; 10 years in the past till now</font></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=2w">2 weeks 'Firefox' failures</a></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=2d">2 days 'Firefox' failures</a></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=24h">24 hours 'Firefox' failures</a></div>
<div style="margin-left:40px;"><font face="Calibri" class="ws11">Example queries for advanced users <a href="../failswindow/Firefox?window=1m">1 month 'Firefox' failures</a></div>
{% endblock %}

View File

@@ -0,0 +1,5 @@
I have done a very bad and crude hack to add a top level navigation page. Instead of storing images for top navigation page in the correct location , I am jammin gall the top site nav stuff in here.
Should fix it when time permits.

View File

@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<h3>Changeset {{ changeset }}</h3>
<ul>
{% for build in builds %}
<li>{{ build.tree }}: {{ build.get_os_display }}: {{ build.get_status_display }}</li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<h3>Changesets</h3>
<ul>
{% for c in changesets %}
<li><a href="{% url viewer.views.changeset c %}">{{ c }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<h3>Failed tests from last {{n}} {{d}} up to now</h3>
<table>
<tr><th>Count</th><th align="left">Test name</th></tr>
{% for f in failures %}
<tr><td>{{ f.count }}</td><td><a href="{% url viewer.views.test tree=tree %}?name={{ f.test__name }}">{{ f.test__name }}</a></td></tr>
{% endfor %}
</table>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block content %}
<style type="text/css">
li {
padding-bottom: 10px; }
</style>
<h3>Most recent test failures</h3>
<ul>
{% for f in failures %}
<li>{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree.name }} {{ f.build.get_os_display }}: <a href="{% url viewer.views.test %}?name={{ f.name }}">{{ f.name }}</a>,
<a href="{% url viewer.views.timeline %}?name={{ f.name }}">timeline</a>
- {{ f.description }}</li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block content %}
<style type="text/css">
li {
padding-bottom: 10px; }
</style>
<h3>Most recent test failures</h3>
<ul>
{% for f in failures %}
<li>{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree.name }} {{ f.build.get_os_display }}: <a href="{% url viewer.views.test tree=tree %}?name={{ f.test.name }}">{{ f.test.name }}</a>
<!--<a href="{% url viewer.views.timeline tree=tree %}?name={{ f.test.name }}">timeline</a> -->
- {{ f.failtext }}</li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,11 @@
{% extends "base.html" %}
{% block content %}
<h3>Logfile links and Changeset links for {{ test }} failures</h3>
<ul>
<li style="display:none"><ul>
{% for f in failures %}{% ifchanged f.build.id %}</ul></li><li>
<a href="{{ f.build.tinderboxlink|safe }}">{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree }} {{ f.build.get_os_display }}</a> [{{ f.build.changesetlink|safe }}]:
<ul>{% endifchanged %}
<!--<li>{{ f.description }}</li>-->{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block content %}
<h3>Logfile links and Changeset links for {{ test }} failures</h3>
<ul>
<li style="display:none"><ul>
{% for f in section %}{% ifchanged f.build.id %}</ul></li><li>
<a href="{{ f.build.tinderboxlink|safe }}">{{ f.build.startdate|date:"Y-m-d H:i" }} {{ f.build.tree }} {{ f.build.get_os_display }}</a> [{{ f.build.changesetlink|safe }}]:
<ul>{% endifchanged %}
<!--<li>{{ f.description }}</li>-->{% endfor %}
</ul>
{% endblock %}
<div class="pagination">
<span class="step-links">
{% if section.has_previous %}
<a href="?page={{ section.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ section.number }} of {{ section.paginator.num_pages }}.
</span>
{% if section.has_next %}
<a href="?page={{ section.next_page_number }}">next</a>
{% endif %}
</span>
</div>

View File

@@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block content %}
<style type="text/css">
li {
padding-bottom: 10px; }
</style>
<h3>All known failing tests</h3>
<ul>
{% for t in tests %}
<li><a href="{% url viewer.views.test tree=tree %}?name={{ t }}">{{ t }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,72 @@
<html>
<head>
<title>Timeline for {{ test }}</title>
<script src="http://static.simile.mit.edu/exhibit/api-2.0/exhibit-api.js?autoCreate=false"
type="text/javascript"></script>
<script src="http://static.simile.mit.edu/exhibit/extensions-2.0/time/time-extension.js"></script>
<script type="application/javascript">
var json = {"items": [
{% for bd in builds %}
{
"type": "Build",
"id": "bld{{ bd.build.id }}",
"label": "{{ bd.os }} {{ bd.build.changeset }}",
"desc": "{{ bd.description|escapejs|escape }}",
"desc_id": "{{ bd.desctype }}",
"time": "{{ bd.time }}",
"os": "{{ bd.os }}",
"rev": "{{ bd.build.changeset }}",
},
{% endfor %}
],
"properties": {
"time": {"valueType": "date"},
}
};
$(document).ready(function() {
window.database = Exhibit.Database.create();
window.database.loadData(json);
window.exhibit = Exhibit.create();
window.exhibit.configureFromDOM();
});
</script>
</head>
<body>
<h2>Timeline for {{ test }}</h2>
<div ex:role="lens" ex:itemTypes="Build">
<div><span ex:content=".os"></span> <a
ex:href-subcontent="http://hg.mozilla.org/mozilla-central/rev/&#123;{.rev}&#125;"
target="_blank" ex:content=".rev"></a></div> <pre ex:content=".desc"></pre>
</div>
<div id="blds" ex:role="exhibit-collection" ex:itemTypes="Build"></div>
<div ex:role="view"
ex:viewClass="Timeline"
ex:start=".time"
ex:topBandPixelsPerUnit="50",
ex:bottomBandPixelsPerUnit="50",
></div>
<table border="0">
<tr>
<td>
{% for desc in descriptions %}
<pre>{{desc}}</pre>
{% endfor %}
</td>
<td valign="top" style="padding-left: 5em;">
<div ex:role="facet" ex:expression=".desc_id"
ex:facetLabel="Description"></div>
</td>
<td valign="top" style="padding-left: 5em;">
<div ex:role="facet" ex:expression=".os"
ex:facetLabel="OS"></div>
</td>
</tr>
</table>
</body> </html>

View File

@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<h3>Top 25 failing tests</h3>
<table>
<tr><th>Count</th><th align="left">Test name</th></tr>
{% for f in failures %}
<tr><td>{{ f.count }}</td><td><a href="{% url viewer.views.test tree=tree %}?name={{ f.test__name }}">{{ f.test__name}}</a></td></tr>
{% endfor %}
</table>
{% endblock %}

Binary file not shown.

View File

@@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block content %}
<h3>{{ tree }}</h3>
<ul>
{% for build in newestbuilds %}
<li>{{ build.get_os_display }}: {{ build.get_status_display }}</li>
{% endfor %}
</ul>
{% endblock %}

View File

@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block content %}
<h3>Trees</h3>
<ul>
{% for tree in trees %}
<li><a href="{% url viewer.views.tree tree.name %}">{{ tree.name }}</a></li>
{% endfor %}
</ul>
{% endblock %}

20
topfails/topfails/urls.py Normal file
View File

@@ -0,0 +1,20 @@
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('topfails.viewer.views',
(r'^$', 'index'),
url(r'^trees/(?P<tree>.+)?$','trees', name='trees'),
url(r'^tree/(?P<tree>.+)?$','tree', name='tree'),
url(r'^changesets/(?P<tree>.+)?$','changesets', name='changesets'),
url(r'^changesets/(?P<tree>.+)/(?P<changeset>[a-f0-9]+)$', 'changeset', name='changeset'),
url(r'^tests/(?P<tree>.+)?$','tests', name='tests'),
url(r'^test/(?P<tree>.+)?$','test', name='test'),
url(r'^timeline/(?P<tree>.+)?$','timeline', name='timeline'),
url(r'^topfails/(?P<tree>.+)?$','topfails', name='topfails'),
url(r'^failswindow/(?P<tree>.+)?$','failswindow', name='failswindow'),
url(r'^latest/(?P<tree>.+)?$','latest', name='latest'),
url(r'^Help/(?P<tree>.+)?$','Help', name='Help'),
)

View File

View File

@@ -0,0 +1,130 @@
import re
from django.db import models, connection
from datetime import datetime
from time import ctime, sleep, time
class OS():
Windows = 0
Mac = 1
Linux = 2
Unknown = 3
OS_CHOICES = (
(OS.Windows, 'Windows'),
(OS.Mac, 'Mac'),
(OS.Linux, 'Linux'),
(OS.Unknown, 'Unknown')
)
class BuildStatus():
Success = 0
TestFailed = 1
Burning = 2
Exception = 3
Unknown = 4
BUILDSTATUS_CHOICES = (
(BuildStatus.Success, 'Success'),
(BuildStatus.TestFailed, 'Test Failed'),
(BuildStatus.Burning, 'Burning'),
(BuildStatus.Exception, 'Exception'),
(BuildStatus.Unknown, 'Unknown')
)
class Tree(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=45, blank=True)
def __unicode__(self):
return self.name
class Build(models.Model):
id = models.AutoField(primary_key=True)
os = models.IntegerField(choices=OS_CHOICES)
tree = models.ForeignKey(Tree)
starttime = models.IntegerField(null=True, blank=True)
status = models.IntegerField(choices=BUILDSTATUS_CHOICES)
changeset = models.CharField(max_length=80,blank=True)
logfile = models.CharField(max_length=300,blank=True)
def startdate(self):
return datetime.fromtimestamp(self.starttime)
def changesetlink(self):
if str(self.tree) == 'Firefox':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
elif str(self.tree) == 'Firefox3.6':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/releases/mozilla-1.9.2", self.changeset, self.changeset)
elif str(self.tree) == 'Thunderbird' or str(self.tree) == 'SeaMonkey':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/comm-central", self.changeset, self.changeset)
else :
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
def jsonchangesetlink(self):
return "%s/rev/%s" % ("http://hg.mozilla.org/mozilla-central", self.changeset)
def tinderboxlink(self):
if self.logfile:
return "http://tinderbox.mozilla.org/showlog.cgi?log=%s/%s" % (self.tree.name, self.logfile)
return "http://tinderbox.mozilla.org/showbuilds.cgi?tree=%s&maxdate=%d&hours=3" % (self.tree.name, self.starttime)
class Test(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=300, blank=True)
def __unicode__(self):
return self.name
class TestFailure(models.Model):
id = models.AutoField(primary_key=True)
build = models.ForeignKey(Build)
test = models.ForeignKey(Test)
failtext = models.CharField(max_length=400, blank=True)
def get_most_failing_tests(tree):
return TestFailure.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')[:25]
def get_time_failing_tests(tree):
return TestFailure.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')
#This def is never used not intended to be used. I kept it here as a refresher
def get_latest_fails(tree):
cursor = connection.cursor()
statement="""SELECT viewer_testfailure.id, viewer_testfailure.build_id, viewer_test.name, viewer_testfailure.failtext
FROM viewer_testfailure, viewer_test, viewer_build, viewer_tree
WHERE (viewer_testfailure.build_id = viewer_build.id)
AND (viewer_build.tree_id = viewer_tree.id)
AND ( viewer_testfailure.test_id = viewer_test.id)
AND viewer_tree.name ='"""+tree+"""' ORDER BY viewer_build.starttime DESC LIMIT 20"""
cursor.execute(statement)
for row in cursor:
yield row
def get_fails_in_timerange(self,tree):
# Get current time, in seconds.
endtime = int(time())
#print endtime
m = re.match("(\d+)([ymwdh])", self)
#print m.group(1), m.group(2)
if m is None:
print >>sys.stderr, "ERROR: bad timespan = '%s'!" % options.timespan
sys.exit(1)
timespan = int(m.group(1)) * {'y': 365 * 24 * 3600,
'm': 30 * 24 * 3600,
'w': 7 * 24 * 3600,
'd': 24 * 3600,
'h': 3600}[m.group(2)]
# Set current time to beginning of requested timespan ending now.
curtime = endtime - timespan
qs = get_time_failing_tests(tree)
return qs.filter(build__starttime__gt=curtime)

View File

@@ -0,0 +1,129 @@
import re
from django.db import models, connection
from datetime import datetime
from time import ctime, sleep, time
class OS():
Windows = 0
Mac = 1
Linux = 2
Unknown = 3
OS_CHOICES = (
(OS.Windows, 'Windows'),
(OS.Mac, 'Mac'),
(OS.Linux, 'Linux'),
(OS.Unknown, 'Unknown')
)
class BuildStatus():
Success = 0
TestFailed = 1
Burning = 2
Exception = 3
Unknown = 4
BUILDSTATUS_CHOICES = (
(BuildStatus.Success, 'Success'),
(BuildStatus.TestFailed, 'Test Failed'),
(BuildStatus.Burning, 'Burning'),
(BuildStatus.Exception, 'Exception'),
(BuildStatus.Unknown, 'Unknown')
)
class Tree(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=45, blank=True)
def __unicode__(self):
return self.name
class Build(models.Model):
id = models.AutoField(primary_key=True)
os = models.IntegerField(choices=OS_CHOICES)
tree = models.ForeignKey(Tree)
starttime = models.IntegerField(null=True, blank=True)
status = models.IntegerField(choices=BUILDSTATUS_CHOICES)
changeset = models.CharField(max_length=80,blank=True)
logfile = models.CharField(max_length=300,blank=True)
def startdate(self):
return datetime.fromtimestamp(self.starttime)
def changesetlink(self):
if str(self.tree) == 'Firefox':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
elif str(self.tree) == 'Firefox3.6':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/releases/mozilla-1.9.2", self.changeset, self.changeset)
elif str(self.tree) == 'Thunderbird' or str(self.tree) == 'SeaMonkey':
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/comm-central", self.changeset, self.changeset)
else :
return '<a href="%s/rev/%s">%s</a>' % ("http://hg.mozilla.org/mozilla-central", self.changeset, self.changeset)
def jsonchangesetlink(self):
return "%s/rev/%s" % ("http://hg.mozilla.org/mozilla-central", self.changeset)
def tinderboxlink(self):
if self.logfile:
return "http://tinderbox.mozilla.org/showlog.cgi?log=%s/%s" % (self.tree.name, self.logfile)
return "http://tinderbox.mozilla.org/showbuilds.cgi?tree=%s&maxdate=%d&hours=3" % (self.tree.name, self.starttime)
class Test(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=300, blank=True)
def __unicode__(self):
return self.name
class TestFailure(models.Model):
id = models.AutoField(primary_key=True)
build = models.ForeignKey(Build)
test = models.ForeignKey(Test)
failtext = models.CharField(max_length=400, blank=True)
def get_most_failing_tests(tree):
return TestFailure.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')[:25]
def get_time_failing_tests(tree):
return TestFailure.objects.filter(build__tree__name=tree).values('test__name').annotate(count=models.Count('test__name')).order_by('-count')
def get_latest_fails(tree):
cursor = connection.cursor()
statement="""SELECT viewer_testfailure.id, viewer_testfailure.build_id, viewer_test.name, viewer_testfailure.failtext
FROM viewer_testfailure, viewer_test, viewer_build, viewer_tree
WHERE (viewer_testfailure.build_id = viewer_build.id)
AND (viewer_build.tree_id = viewer_tree.id)
AND ( viewer_testfailure.test_id = viewer_test.id)
AND viewer_tree.name ='"""+tree+"""' ORDER BY viewer_build.starttime DESC LIMIT 20"""
cursor.execute(statement)
for row in cursor:
yield row
def get_fails_in_timerange(self,tree):
# Get current time, in seconds.
endtime = int(time())
#print endtime
m = re.match("(\d+)([ymwdh])", self)
#print m.group(1), m.group(2)
if m is None:
print >>sys.stderr, "ERROR: bad timespan = '%s'!" % options.timespan
sys.exit(1)
timespan = int(m.group(1)) * {'y': 365 * 24 * 3600,
'm': 30 * 24 * 3600,
'w': 7 * 24 * 3600,
'd': 24 * 3600,
'h': 3600}[m.group(2)]
# Set current time to beginning of requested timespan ending now.
curtime = endtime - timespan
qs = get_time_failing_tests(tree)
return qs.filter(build__starttime__gt=curtime)

View File

@@ -0,0 +1,107 @@
from django.shortcuts import render_to_response, get_list_or_404
from topfails.viewer.models import Build, Tree, Test,TestFailure, OS_CHOICES, get_most_failing_tests, get_fails_in_timerange
import re
from django.http import HttpResponse
import json
def latest(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
if request.GET.has_key('json'):
jtext = [{"Test_name":f.test.name, "Build_status":f.build.status, "Logfile": f.build.tinderboxlink(),"Changeset":f.build.jsonchangesetlink() , "Failure_description":f.failtext} for f in failures]
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
def index(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
def trees(request,tree='Firefox'):
alltrees = Tree.objects.all().order_by('name')
return render_to_response('viewer/trees.html', {'trees': alltrees , 'tree' : tree})
def tree(request, tree='Firefox'):
newestbuilds = get_list_or_404(Build.objects.filter(tree__name__exact=tree).order_by('-starttime')[:5])
return render_to_response('viewer/tree.html', {'tree': tree, 'newestbuilds': newestbuilds})
def changesets(request,tree='Firefox'):
build_csets = Build.objects.filter(tree__name__exact=tree).values('changeset').distinct()
return render_to_response('viewer/changesets.html', { 'tree' : tree,'changesets': [b['changeset'] for b in build_csets]})
def changeset(request, changeset,tree='Firefox'):
builds = get_list_or_404(Build, changeset__exact=changeset)
return render_to_response('viewer/changeset.html', {'changeset': changeset, 'builds': builds, 'tree' : tree})
def tests(request,tree='Firefox'):
test_names = TestFailure.objects.filter(build__tree__name__exact=tree).values('test__name').distinct()
if request.GET.has_key('json'):
jtext = list(test_names)
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/tests.html', { 'tree' : tree, 'tests': [t['test__name'] for t in test_names]})
def test(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name__exact=tree).filter(test__name__exact=request.GET['name']).order_by('-build__starttime'))
#if request.GET.has_key('json'):
#jtext = list(failures)
#return HttpResponse(json.dumps(jtext))
#else:
return render_to_response('viewer/test.html', {'test': request.GET['name'], 'failures': failures, 'tree' : tree})
def topfails(request,tree='Firefox'):
failures = get_most_failing_tests(tree)
if request.GET.has_key('json'):
jtext = list(failures)
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/topfails.html', {'failures': failures, 'tree' : tree})
def Help(request,tree):
return render_to_response('viewer/Help.html',{'tree':tree})
def timeline(request,tree='Firefox'):
name = request.GET['name']
builds = get_list_or_404(Build.objects.filter(tree__name__exact=tree), test__name__exact=name)
buildlist = []
desc_list = []
for b in builds:
descs = b.testfailure_set.filter(testfailure__name__exact=name).order_by('id')
desc = '\n'.join(descs.values_list('description', flat=True))
if desc not in desc_list:
desc_list.append(desc)
desc_i = desc_list.index(desc)
buildlist.append({'build': b,
'desctype': desc_i,
'description': desc,
'os': OS_CHOICES[b.os][1],
'time': b.startdate().isoformat() + "Z",
})
return render_to_response('viewer/timeline.html', {'test': name,
'descriptions': desc_list,
'builds': buildlist, 'tree' : tree})
def failswindow(request,tree='Firefox'):
period=request.GET['window']
m = re.match("(\d+)([ymwdh])", period)
failures = get_fails_in_timerange(period,tree)
if request.GET.has_key('json'):
jtext = list(failures)
return HttpResponse(json.dumps(jtext))
else:
if m.group(2) == 'd':
prd='days'
elif m.group(2) == 'h':
prd = 'hours'
elif m.group(2) == 'w':
prd = 'weeks'
elif m.group(2) == 'm':
prd = 'months'
elif m.group(2) == 'y':
prd = 'years'
else:
prd = 'days'
return render_to_response('viewer/failswindow.html', {'failures': failures,'n':m.group(1),'d':prd, 'tree' : tree})

View File

@@ -0,0 +1,118 @@
from django.shortcuts import render_to_response, get_list_or_404
from topfails.viewer.models import Build, Tree, Test,TestFailure, OS_CHOICES, get_most_failing_tests, get_fails_in_timerange
import re
from django.http import HttpResponse
import json
def latest(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
if request.GET.has_key('json'):
jtext = [{"Test_name":f.test.name, "Build_status":f.build.status, "Logfile": f.build.tinderboxlink(),"Changeset":f.build.jsonchangesetlink() , "Failure_description":f.failtext} for f in failures]
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
def index(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name=tree).order_by('-build__starttime')[:20])
return render_to_response('viewer/latest.html', {'failures': failures, 'tree' : tree})
def trees(request,tree='Firefox'):
alltrees = Tree.objects.all().order_by('name')
return render_to_response('viewer/trees.html', {'trees': alltrees , 'tree' : tree})
def tree(request, tree='Firefox'):
newestbuilds = get_list_or_404(Build.objects.filter(tree__name__exact=tree).order_by('-starttime')[:5])
return render_to_response('viewer/tree.html', {'tree': tree, 'newestbuilds': newestbuilds})
def changesets(request,tree='Firefox'):
build_csets = Build.objects.filter(tree__name__exact=tree).values('changeset').distinct()
return render_to_response('viewer/changesets.html', { 'tree' : tree,'changesets': [b['changeset'] for b in build_csets]})
def changeset(request, changeset,tree='Firefox'):
builds = get_list_or_404(Build, changeset__exact=changeset)
return render_to_response('viewer/changeset.html', {'changeset': changeset, 'builds': builds, 'tree' : tree})
def tests(request,tree='Firefox'):
test_names = TestFailure.objects.filter(build__tree__name__exact=tree).values('test__name').distinct()
if request.GET.has_key('json'):
jtext = list(test_names)
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/tests.html', { 'tree' : tree, 'tests': [t['test__name'] for t in test_names]})
from django.core.paginator import Paginator, InvalidPage, EmptyPage
def test(request,tree='Firefox'):
failures = get_list_or_404(TestFailure.objects.filter(build__tree__name__exact=tree).filter(test__name__exact=request.GET['name']).order_by('-build__starttime'))
paginator = Paginator(failures, 25) # Show 25 failures per page
# Make sure page request is an int. If not, deliver first page.
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
# If page request (9999) is out of range, deliver last page of results.
try:
section = paginator.page(page)
except (EmptyPage, InvalidPage):
section = paginator.page(paginator.num_pages)
return render_to_response('viewer/test.html', {'test': request.GET['name'], 'failures': section, 'tree' : tree})
def topfails(request,tree='Firefox'):
failures = get_most_failing_tests(tree)
if request.GET.has_key('json'):
jtext = list(failures)
return HttpResponse(json.dumps(jtext))
else:
return render_to_response('viewer/topfails.html', {'failures': failures, 'tree' : tree})
def Help(request,tree):
return render_to_response('viewer/Help.html',{'tree':tree})
def timeline(request,tree='Firefox'):
name = request.GET['name']
builds = get_list_or_404(Build.objects.filter(tree__name__exact=tree), test__name__exact=name)
buildlist = []
desc_list = []
for b in builds:
descs = b.testfailure_set.filter(testfailure__name__exact=name).order_by('id')
desc = '\n'.join(descs.values_list('description', flat=True))
if desc not in desc_list:
desc_list.append(desc)
desc_i = desc_list.index(desc)
buildlist.append({'build': b,
'desctype': desc_i,
'description': desc,
'os': OS_CHOICES[b.os][1],
'time': b.startdate().isoformat() + "Z",
})
return render_to_response('viewer/timeline.html', {'test': name,
'descriptions': desc_list,
'builds': buildlist, 'tree' : tree})
def failswindow(request,tree='Firefox'):
period=request.GET['window']
m = re.match("(\d+)([ymwdh])", period)
failures = get_fails_in_timerange(period,tree)
if request.GET.has_key('json'):
jtext = list(failures)
return HttpResponse(json.dumps(jtext))
else:
if m.group(2) == 'd':
prd='days'
elif m.group(2) == 'h':
prd = 'hours'
elif m.group(2) == 'w':
prd = 'weeks'
elif m.group(2) == 'm':
prd = 'months'
elif m.group(2) == 'y':
prd = 'years'
else:
prd = 'days'
return render_to_response('viewer/failswindow.html', {'failures': failures,'n':m.group(1),'d':prd, 'tree' : tree})