- add automated testday reporting
- rejig sidebar -> divide up testing and reporting links
- added management category for testdays


git-svn-id: svn://10.0.0.236/trunk@214554 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ccooper%deadsquid.com
2006-11-01 22:13:32 +00:00
parent c1c2a209b8
commit 4c65a00994
32 changed files with 1660 additions and 50 deletions

View File

@@ -0,0 +1,53 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License
# at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and
# limitations under the License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::DB::TestDay;
$VERSION = 1.00;
use strict;
use base 'Litmus::DBI';
Litmus::DB::TestDay->table('testdays');
Litmus::DB::TestDay->columns(All => qw/testday_id last_updated start_timestamp finish_timestamp description product_id testgroup_id build_id branch_id locale_abbrev/);
Litmus::DB::TestDay->columns(Essential => qw/testday_id last_updated start_timestamp finish_timestamp description product_id testgroup_id build_id branch_id locale_abbrev/);
Litmus::DB::TestDay->columns(TEMP => qw //);
Litmus::DB::TestDay->column_alias("product_id", "product");
Litmus::DB::TestDay->column_alias("testgroup_id", "testgroup");
Litmus::DB::TestDay->column_alias("branch_id", "branch");
Litmus::DB::TestDay->column_alias("locale_abbrev", "locale");
Litmus::DB::TestDay->has_a(product => "Litmus::DB::Product");
Litmus::DB::TestDay->has_a(testgroup => "Litmus::DB::Testgroup");
Litmus::DB::TestDay->has_a(branch => "Litmus::DB::Branch");
Litmus::DB::TestDay->has_a(locale => "Litmus::DB::Locale");
1;

View File

@@ -46,6 +46,7 @@ BEGIN {
use DBI;
use Litmus::DBI;
use Litmus::DB::TestDay;
our $_dbh = Litmus::DBI->db_Main();
@@ -115,7 +116,7 @@ See Also :
#########################################################################
sub getProducts()
{
my $sql = "SELECT name, product_id FROM products ORDER BY name";
my $sql = "SELECT name, product_id FROM products ORDER BY name ASC";
return _getValues($sql);
}
@@ -136,7 +137,7 @@ sub getPlatforms()
#########################################################################
sub getBranches()
{
my $sql = "SELECT name, branch_id FROM branches ORDER BY name ASC";
my $sql = "SELECT name, branch_id, product_id FROM branches ORDER BY name ASC";
return _getValues($sql);
}
@@ -150,7 +151,7 @@ sub getUniqueBranches()
#########################################################################
sub getOpsyses()
{
my $sql = "SELECT name, opsys_id FROM opsyses ORDER BY name ASC";
my $sql = "SELECT name, opsys_id, platform_id FROM opsyses ORDER BY name ASC";
return _getValues($sql);
}
@@ -226,6 +227,13 @@ sub getUsers()
return \@users;
}
#########################################################################
sub getTestdays()
{
my @testdays = reverse Litmus::DB::TestDay->retrieve_all();
return \@testdays;
}
#########################################################################
sub getAuthors()
{
@@ -235,7 +243,7 @@ sub getAuthors()
#########################################################################
sub getTestRuns() {
my $sql = "SELECT test_run_id, name FROM test_runs ORDER BY finish_timestamp DESC, name ASC";
my $sql = "SELECT test_run_id, name FROM test_runs ORDER BY finish_timestamp DESC, name DESC";
return _getValues($sql);
}

View File

@@ -0,0 +1,394 @@
# -*- mode: cperl; c-basic-offset: 8; indent-tabs-mode: nil; -*-
=head1 COPYRIGHT
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License
# at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and
# limitations under the License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
=cut
package Litmus::TestEvent;
$VERSION = 1.00;
use strict;
use Litmus::DBI;
use Litmus::DB::TestDay;
use Date::Manip;
sub new {
my ($class, %args) = @_;
my $self = bless {}, ref($class)||$class;
$self->_init(%args);
return $self;
}
sub _init {
my ($self, %args) = @_;
if (!$args{testday_id} and
!$args{testdate} and
!($args{start_timestamp} and $args{finish_timestamp})) {
warn "Error initializing TestEvent - please supply either a testday_id, testdate or a start_timestamp/finish_timestamp pair.";
return 1;
}
$self->{_dbh} = Litmus::DBI->db_Main;
if ($args{testday_id}) {
my $testday = Litmus::DB::TestDay->retrieve($args{testday_id});
if ($testday) {
$self->{_planned_testday} = 1;
$self->{_start_timestamp} = &UnixDate($testday->start_timestamp,"%q");
$self->{_finish_timestamp} = &UnixDate($testday->finish_timestamp,"%q");
$self->{_description} = $testday->description;
$self->{_product_id} = $testday->product_id;
$self->{_testgroup_id} = $testday->testgroup_id;
$self->{_build_id} = $testday->build_id;
$self->{_branch_id} = $testday->branch_id;
$self->{_locale} = $testday->locale_abbrev;
} else {
warn "Unable to lookup testday for testday_id: " . $args{testday_id};
return 1;
}
return;
}
if ($args{testdate}) {
$self->{_start_timestamp} = &UnixDate($args{testdate} . " 07:00:00", "%q");
$self->{_finish_timestamp} = &UnixDate($args{testdate} . " 17:00:00", "%q");
} elsif ($args{start_timestamp} and $args{finish_timestamp}) {
$self->{_start_timestamp} = &UnixDate($args{start_timestamp}, "%q");
$self->{_finish_timestamp} = &UnixDate($args{finish_timestamp}, "%q");
}
$self->{_description} = "User-defined";
$self->{_product_id} = $args{product_id};
$self->{_testgroup_id} = $args{testgroup_id};
$self->{_build_id} = $args{build_id};
$self->{_branch_id} = $args{branch_id};
$self->{_locale} = $args{locale};
}
#########################################################################
sub getBreakdownByLocale {
my ($self) = @_;
my $locale_sql_select = "SELECT tr.locale_abbrev,count(tr.testresult_id) as num_results";
my $locale_sql_from = "FROM test_results tr";
my $locale_sql_where ="WHERE tr.submission_time>=" . $self->{_start_timestamp} . " and tr.submission_time<" . $self->{_finish_timestamp};
my $locale_sql_group_by = "GROUP BY tr.locale_abbrev";
my $locale_sql_order_by = "ORDER BY num_results DESC";
if ($self->{_testgroup_id}) {
$locale_sql_from .= ", testcase_subgroups tsg, subgroup_testgroups sgtg";
$locale_sql_where .= " AND tr.testcase_id=tsg.testcase_id AND tsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=".$self->{_testgroup_id};
}
if ($self->{_build_id}) {
$locale_sql_where .= " AND tr.build_id LIKE '" . $self->{_build_id} . "%'";
}
if ($self->{_branch_id}) {
$locale_sql_where .= " AND tr.branch_id=" . $self->{_branch_id};
}
if ($self->{_locale}) {
$locale_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $locale_sql = "$locale_sql_select $locale_sql_from $locale_sql_where $locale_sql_group_by $locale_sql_order_by";
my $sth = $self->{_dbh}->prepare($locale_sql);
$sth->execute();
my @locales;
while (my $result = $sth->fetchrow_hashref) {
push @locales, $result;
}
$sth->finish;
return \@locales;
}
#########################################################################
sub getBreakdownByPlatform {
my ($self) = @_;
my $platform_sql_select = "SELECT pl.name,count(tr.testresult_id) AS num_results";
my $platform_sql_from = "FROM test_results tr, testcases t, platforms pl, opsyses o";
my $platform_sql_where = "WHERE tr.testcase_id=t.testcase_id AND tr.submission_time>=$self->{_start_timestamp} and tr.submission_time<$self->{_finish_timestamp} AND tr.opsys_id=o.opsys_id AND o.platform_id=pl.platform_id";
my $platform_sql_group_by = "GROUP BY o.platform_id";
my $platform_sql_order_by = "ORDER BY num_results DESC";
if ($self->{_testgroup_id}) {
$platform_sql_from .= ", testcase_subgroups tsg, subgroup_testgroups sgtg";
$platform_sql_where .= " AND tr.testcase_id=tsg.testcase_id AND tsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=$self->{_testgroup_id}";
}
if ($self->{_build_id}) {
$platform_sql_where .= " AND tr.build_id LIKE '" . $self->{_build_id} . "%'";
}
if ($self->{_branch_id}) {
$platform_sql_where .= " AND tr.branch_id=" . $self->{_branch_id};
}
if ($self->{_locale}) {
$platform_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $platform_sql = "$platform_sql_select $platform_sql_from $platform_sql_where $platform_sql_group_by $platform_sql_order_by";
my $sth = $self->{_dbh}->prepare($platform_sql);
$sth->execute();
my @platforms;
while (my $result = $sth->fetchrow_hashref) {
push @platforms, $result;
}
$sth->finish;
return \@platforms;
}
#########################################################################
sub getBreakdownByResultStatus {
my ($self) = @_;
my $status_sql_select = "SELECT rs.name,count(tr.testresult_id) AS num_results,rs.class_name";
my $status_sql_from = "FROM test_results tr, test_result_status_lookup rs";
my $status_sql_where = "WHERE tr.submission_time>=$self->{_start_timestamp} and tr.submission_time<$self->{_finish_timestamp} AND rs.result_status_id=tr.result_status_id";
my $status_sql_group_by = "GROUP BY tr.result_status_id";
my $status_sql_order_by = "ORDER BY num_results DESC";
if ($self->{_testgroup_id}) {
$status_sql_from .= ", testcase_subgroups tsg, subgroup_testgroups sgtg";
$status_sql_where .= " AND tr.testcase_id=tsg.testcase_id AND tsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=" . $self->{_testgroup_id};
}
if ($self->{_build_id}) {
$status_sql_where .= " AND tr.build_id LIKE '" . $self->{_build_id} . "%'";
}
if ($self->{_branch_id}) {
$status_sql_where .= " AND tr.branch_id=" . $self->{_branch_id};
}
if ($self->{_locale}) {
$status_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $status_sql = "$status_sql_select $status_sql_from $status_sql_where $status_sql_group_by $status_sql_order_by";
my $sth = $self->{_dbh}->prepare($status_sql);
$sth->execute();
my @statuses;
while (my $result = $sth->fetchrow_hashref) {
push @statuses, $result;
}
$sth->finish;
return \@statuses;
}
#########################################################################
sub getBreakdownBySubgroup {
my ($self) = @_;
my $subgroup_sql_select = "SELECT CONCAT(p.name,':',tg.name,':',s.name) as name,count(tr.testresult_id) as num_results,sgtg.subgroup_id";
my $subgroup_sql_from = "FROM test_results tr, testcases t, testcase_subgroups tsg, subgroups s, subgroup_testgroups sgtg, testgroups tg, products p";
my $subgroup_sql_where = "WHERE tr.submission_time>=$self->{_start_timestamp} and tr.submission_time<$self->{_finish_timestamp} AND tg.product_id=p.product_id AND tg.testgroup_id=sgtg.testgroup_id AND sgtg.subgroup_id=s.subgroup_id AND tsg.subgroup_id=s.subgroup_id AND tsg.testcase_id=t.testcase_id AND tr.testcase_id=t.testcase_id";
my $subgroup_sql_group_by = "GROUP BY tg.product_id,tg.testgroup_id,s.subgroup_id";
my $subgroup_sql_order_by = "ORDER BY num_results DESC, p.name ASC, tg.name ASC, sgtg.sort_order ASC";
if ($self->{_testgroup_id}) {
$subgroup_sql_where .= " AND tg.testgroup_id=" . $self->{_testgroup_id};
}
if ($self->{_build_id}) {
$subgroup_sql_where .= " AND tr.build_id LIKE '" . $self->{_build_id} . "%'";
}
if ($self->{_branch_id}) {
$subgroup_sql_where .= " AND tr.branch_id=$self->{_branch_id}";
}
if ($self->{_locale}) {
$subgroup_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $subgroup_sql = "$subgroup_sql_select $subgroup_sql_from $subgroup_sql_where $subgroup_sql_group_by $subgroup_sql_order_by";
my @subgroups;
my $sth = $self->{_dbh}->prepare($subgroup_sql);
$sth->execute();
while (my $result = $sth->fetchrow_hashref) {
push @subgroups, $result;
}
$sth->finish;
my $subgroup_count_sql = "SELECT COUNT(t.testcase_id) FROM testcases t, testcase_subgroups tsg WHERE tsg.subgroup_id=? AND t.testcase_id=tsg.testcase_id AND t.enabled=1 AND t.community_enabled=1";
$sth = $self->{_dbh}->prepare($subgroup_count_sql);
$sth->execute();
foreach my $result (@subgroups) {
$sth->execute($result->{'subgroup_id'});
my ($testcase_count) = $sth->fetchrow_array;
$result->{'testcase_count'} = $testcase_count;
}
$sth->finish;
return \@subgroups;
}
#########################################################################
sub getBreakdownByUser {
my ($self) = @_;
my $user_sql_select = "SELECT u.user_id,u.email,count(tr.testresult_id) AS num_results,u.irc_nickname";
my $user_sql_from = "FROM test_results tr, testcases t, users u";
my $user_sql_where = "WHERE tr.testcase_id=t.testcase_id AND tr.submission_time>=$self->{_start_timestamp} and tr.submission_time<$self->{_finish_timestamp} AND tr.user_id=u.user_id";
my $user_sql_group_by = "GROUP BY tr.user_id";
my $user_sql_order_by = "ORDER BY num_results DESC";
if ($self->{_testgroup_id}) {
$user_sql_from .= ", testcase_subgroups tsg, subgroup_testgroups sgtg";
$user_sql_where .= " AND tr.testcase_id=tsg.testcase_id AND tsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=" . $self->{_testgroup_id};
}
if ($self->{_build_id}) {
$user_sql_where .= " AND tr.build_id LIKE '" . $self->{_build_id} . "%'";
}
if ($self->{_branch_id}) {
$user_sql_where .= " AND tr.branch_id=" . $self->{_branch_id};
}
if ($self->{_locale}) {
$user_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $user_sql = "$user_sql_select $user_sql_from $user_sql_where $user_sql_group_by $user_sql_order_by";
my $sth = $self->{_dbh}->prepare($user_sql);
$sth->execute();
my @users;
while (my $result = $sth->fetchrow_hashref) {
push @users, $result;
}
$sth->finish;
return \@users;
}
#########################################################################
sub getBreakdownByUserAndResultStatus {
my ($self) = @_;
my $tester_sql_select = "SELECT u.email,rs.class_name AS result_status,count(rs.name) as num_results,u.irc_nickname";
my $tester_sql_from = "FROM test_results tr, users u, test_result_status_lookup rs";
my $tester_sql_where = "WHERE tr.submission_time>=$self->{_start_timestamp} and tr.submission_time<$self->{_finish_timestamp} AND tr.user_id=u.user_id AND rs.result_status_id=tr.result_status_id";
my $tester_sql_group_by = "GROUP BY tr.user_id,rs.name";
my $tester_sql_order_by = "ORDER BY u.irc_nickname DESC, u.email DESC";
if ($self->{_testgroup_id}) {
$tester_sql_from .= ", testcase_subgroups tsg, subgroup_testgroups sgtg";
$tester_sql_where .= " AND tr.testcase_id=tsg.testcase_id AND tsg.subgroup_id=sgtg.subgroup_id AND sgtg.testgroup_id=$self->{_testgroup_id}";
}
if ($self->{_build_id}) {
$tester_sql_where .= " AND tr.build_id LIKE '$self->{_build_id}%'";
}
if ($self->{_branch_id}) {
$tester_sql_where .= " AND tr.branch_id=$self->{_branch_id}";
}
if ($self->{_locale}) {
$tester_sql_where .= " AND tr.locale_abbrev='" . $self->{_locale} . "'";
}
my $tester_sql = "$tester_sql_select $tester_sql_from $tester_sql_where $tester_sql_group_by $tester_sql_order_by";
my $sth = $self->{_dbh}->prepare($tester_sql);
$sth->execute();
my $testers;
while (my @result = $sth->fetchrow_array) {
$testers->{$result[0]}->{$result[1]} = $result[2];
$testers->{$result[0]}->{'irc_nickname'} = $result[3];
}
$sth->finish;
my @tester_result_statuses;
foreach my $key (sort keys %$testers) {
my $hash_ref;
$hash_ref->{'email'} = $key;
$hash_ref->{'irc_nickname'} = $testers->{$key}->{'irc_nickname'};
$hash_ref->{'pass'} = $testers->{$key}->{'pass'} || 0;
$hash_ref->{'fail'} = $testers->{$key}->{'fail'} || 0;
$hash_ref->{'unclear'} = $testers->{$key}->{'unclear'} || 0;
push @tester_result_statuses, $hash_ref;
}
return \@tester_result_statuses;
}
#########################################################################
sub getDescription {
my ($self) = @_;
return $self->{_description};
}
#########################################################################
sub getStartTimestamp {
my ($self, $for_display) = @_;
if ($for_display) {
return &UnixDate($self->{_start_timestamp},"%Y-%m-%d %H:%M:%S");
}
return $self->{_start_timestamp};
}
#########################################################################
sub getFinishTimestamp {
my ($self, $for_display) = @_;
if ($for_display) {
return &UnixDate($self->{_finish_timestamp},"%Y-%m-%d %H:%M:%S");
}
return $self->{_finish_timestamp};
}
1;

View File

@@ -944,11 +944,11 @@ table.manage input.button {
margin: 5px;
}
select.testcase-subgroups, select.subgroup-testgroups {
select.testcase-subgroups, select.subgroup-testgroups, select.testgroup-test-runs {
width: 300px;
}
select.testcase, select.testcase_id, select.subgroup_id, select.testgroup_id {
select.testcase, select.testcase_id, select.subgroup_id, select.testgroup_id, select.test_run_id {
width: 700px;
}
@@ -1137,7 +1137,7 @@ div.section-content {
padding-right: 10px;
}
div.testcase-content, div.subgroup-content, div.testgroup-content {
div.testcase-content, div.subgroup-content, div.testgroup-content, div.test-run-content {
padding: 0px;
margin: 5px 10px 0px 10px;
width: auto;
@@ -1239,7 +1239,17 @@ table.testcase-search th, table.test-runs th {
border: 0;
}
table.testcases th, table.testcases td.headerleft {
table.result_container th {
vertical-align: middle;
font-weight: bold;
text-transform: lowercase;
color: #000000;
padding: 0px 5px 0px 5px;
border: 0;
}
table.testcases th, table.testcases td.headerleft, table.testday_results td.headerleft, table.testday_results th {
vertical-align: middle;
font-weight: bold;
text-transform: lowercase;
@@ -1248,10 +1258,6 @@ table.testcases th, table.testcases td.headerleft {
border: 0;
}
table.testcases td.headerleft {
text-align: left;
}
table.testcases td {
padding-left: 5px;
}

View File

@@ -25,7 +25,6 @@ use strict;
use Litmus;
use Litmus::Error;
use Litmus::DB::Product;
use Litmus::DB::TestcaseSubgroup;
use Litmus::Auth;
use Litmus::Utils;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

View File

@@ -367,6 +367,19 @@ function verifySelected(theField, fieldName) {
}
}
function verifySelectNotEmpty(selectBox, message) {
if (selectBox.options.length > 0) {
// We just need to find one option with a non-empty value.
var ems = selectBox.getElementsByTagName('option');
for (var i in ems) {
if (!isEmpty(ems[i].value)) {
return true;
}
}
}
return warnInvalid (selectBox, message + ' Please make a selection now.');
}
function toggleMessage(msgType,msg) {
var em = document.getElementById("message");
if (toggleMessage.arguments.length < 1) {

View File

@@ -2,6 +2,7 @@ var product;
var platform;
var opsys;
var branch;
var testday;
function enableBranchModeButtons() {
document.getElementById("edit_branch_button").disabled=false;
@@ -409,3 +410,109 @@ function resetProduct() {
switchProductFormToAdd();
}
}
function enableTestdayModeButtons() {
document.getElementById("edit_testday_button").disabled=false;
document.getElementById("delete_testday_button").disabled=false;
}
function disableTestdayModeButtons() {
document.getElementById("edit_testday_button").disabled=true;
document.getElementById("delete_testday_button").disabled=true;
}
function loadTestday() {
var testday_select = document.getElementById("testday_id");
if (! testday_select ||
testday_select.options[testday_select.selectedIndex].value=="") {
disableTestdayModeButtons();
document.getElementById('edit_testday_form_div').style.display = 'none';
disableForm('edit_testday_form');
blankTestdayForm('edit_testday_form');
return false;
}
var testday_id = testday_select.options[testday_select.selectedIndex].value;
disableForm('edit_testday_form');
toggleMessage('loading','Loading Testday ID# ' + testday_id + '...');
var url = 'json.cgi?testday_id=' + testday_id;
fetchJSON(url,populateTestday);
}
function populateTestday(data) {
testday=data;
document.getElementById('edit_testday_form_testday_id').value = testday.testday_id;
document.getElementById('edit_testday_form_testday_id_display').innerHTML = testday.testday_id;
document.getElementById('edit_testday_form_desc').value = testday.description;
document.getElementById('edit_testday_form_start_timestamp').value = testday.start_timestamp.replace(/-| |:/g, "");
document.getElementById('edit_testday_form_finish_timestamp').value = testday.finish_timestamp.replace(/-| |:/g, "");
productBox = document.getElementById('testday_product_id');
branchBox = document.getElementById('testday_branch_id');
testgroupBox = document.getElementById('testday_testgroup_id');
if (testday.product_id) {
changeSelected(productBox,testday.product_id.product_id);
changeProduct(productBox,branchBox,testgroupBox);
if (testday.branch_id) {
changeSelected(branchBox,testday.branch_id.branch_id);
changeBranch(branchBox,testgroupBox);
if (testday.testgroup_id) {
changeSelected(testgroupBox,testday.testgroup_id.testgroup_id);
}
}
} else {
changeSelected(productBox,"");
changeProduct(productBox,branchBox,testgroupBox);
}
document.getElementById('testday_build_id').value = testday.build_id
localeBox = document.getElementById('testday_locale');
if (testday.locale_abbrev) {
changeSelected(localeBox,testday.locale_abbrev.abbrev);
} else {
changeSelected(localeBox,"");
}
document.getElementById('edit_testday_form_div').style.display = 'block';
enableTestdayModeButtons();
}
function blankTestdayForm(formid) {
blankForm(formid);
document.getElementById('edit_testday_form_testday_id_display').innerHTML = '';
}
function switchTestdayFormToAdd() {
disableTestdayModeButtons();
blankTestdayForm('edit_testday_form');
document.getElementById('edit_testday_form_testday_id_display').innerHTML = '<em>Automatically generated for a new testday</em>';
document.getElementById('edit_testday_form_submit').value = 'Add Testday';
document.getElementById('edit_testday_form_mode').value = 'add';
enableForm('edit_testday_form');
document.getElementById('edit_testday_form_div').style.display = 'block';
}
function switchTestdayFormToEdit() {
document.getElementById('edit_testday_form_submit').value = 'Submit Edits';
document.getElementById('edit_testday_form_mode').value = 'edit';
enableForm('edit_testday_form');
document.getElementById('edit_testday_form_div').style.display = 'block';
}
function checkTestdayForm(f) {
return (
checkString(f.edit_testday_form_name,"testday description",false) &&
checkString(f.edit_testday_form_start_timestamp,"testday start timestamp",false) &&
checkString(f.edit_testday_form_finish_timestamp,"testday finish timestamp",false)
);
}
function resetTestday() {
if (document.getElementById('edit_testday_form_testday_id').value != '') {
populateTestday(testday);
switchTestdayFormToEdit();
} else {
switchTestdayFormToAdd();
}
}

View File

@@ -0,0 +1,70 @@
function populateProductSelect(selectID)
{
if (products) {
var selectBox = document.getElementById(selectID)
selectBox.options.length = 0;
selectBox.options[0] = new Option('-Product-','');
for (var i=0; i<products.length; i++) {
selectBox.options[i+1] = new Option(products[i].name,products[i].product_id);
}
}
}
function changeProduct(productSelectBox,branchSelectBox,testgroupSelectBox)
{
if (productSelectBox.selectedIndex &&
productSelectBox.options[productSelectBox.selectedIndex].value != '') {
if (branchSelectBox) {
branchSelectBox.options.length = 0;
branchSelectBox.options[0] = new Option('-Branch-','');
var i = 1;
for (var j=0; j<branches.length; j++) {
if (branches[j].product_id == productSelectBox.options[productSelectBox.selectedIndex].value) {
branchSelectBox.options[i] = new Option(branches[j].name,branches[j].branch_id);
i++;
}
}
}
if (testgroupSelectBox) {
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
var i = 1;
for (var j=0; j<testgroups.length; j++) {
if (testgroups[j].product_id == productSelectBox.options[productSelectBox.selectedIndex].value) {
testgroupSelectBox.options[i] = new Option(testgroups[j].name,testgroups[j].testgroup_id);
i++;
}
}
}
} else {
branchSelectBox.options.length = 0;
branchSelectBox.options[0] = new Option('-Branch-','');
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
}
}
function changeBranch(branchSelectBox,testgroupSelectBox)
{
if (branchSelectBox.selectedIndex &&
branchSelectBox.options[branchSelectBox.selectedIndex].value != '') {
if (testgroupSelectBox) {
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
var i = 1;
for (var j=0; j<testgroups.length; j++) {
if (testgroups[j].branch_id == branchSelectBox.options[branchSelectBox.selectedIndex].value) {
testgroupSelectBox.options[i] = new Option(testgroups[j].name,testgroups[j].testgroup_id);
i++;
}
}
}
} else {
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
}
}

View File

@@ -42,6 +42,9 @@ function load_testgroups(selects) {
if (!product) {
return;
}
var branchbox = document.getElementById("branch"+groupbox.name.substr(9));
// now get the list of testgroups that goes with that product:
var testgroups = product['testgroups'];
for (var group=0; group<testgroups.length; group++) {
@@ -90,6 +93,9 @@ function load_platforms(selects) {
addNullEntry(platformbox);
// find the currently selected product that goes with this select
var productbox = document.getElementById("product"+platformbox.name.substr(8));
if (!productbox) {
return;
}
var productid = productbox.options[productbox.selectedIndex].value;
var product = getProductById(productid);
if (!product) {
@@ -160,13 +166,32 @@ function changeProduct(testid) {
var testidflag = "";
if (testid) { testidflag = "_"+testid; }
load_testgroups([document.getElementById("testgroup"+testidflag)]);
changeTestgroup(testid);
var em = document.getElementById("testgroup"+testidflag);
if (em) {
load_testgroups([em]);
changeTestgroup(testid);
}
em = document.getElementById("platform"+testidflag);
if (em) {
load_platforms([em]);
changePlatform(testid);
}
em = document.getElementById("branch"+testidflag);
if (em) {
load_branches([document.getElementById("branch"+testidflag)]);
}
}
function changeBranch(testid) {
var testidflag = "";
if (testid) { testidflag = "_"+testid; }
load_platforms([document.getElementById("platform"+testidflag)]);
changePlatform(testid);
load_branches([document.getElementById("branch"+testidflag)]);
var em = document.getElementById("testgroup"+testidflag);
if (em) {
load_testgroups([em]);
}
}
function changeTestgroup(testid) {
@@ -196,6 +221,10 @@ function addNullEntry(select) {
select.add(new Option("-Subgroup-", "", false, false), null);
} else if (select.className == 'select_branch') {
select.add(new Option("-Branch-", "", false, false), null);
} else if (select.className == 'select_platform') {
select.add(new Option("-Platform-", "", false, false), null);
} else if (select.className == 'select_opsys') {
select.add(new Option("-Operating System-", "", false, false), null);
} else {
select.add(new Option("---", "", false, false), null);
}

View File

@@ -367,4 +367,11 @@ function copyToList(from,to)
}
}
function changeSelected(selectBox,value) {
var options = selectBox.options;
for (iOpt = 0; iOpt < options.length; iOpt++) {
if (options[iOpt].value == value) {
options[iOpt].selected = true;;
}
}
}

View File

@@ -110,6 +110,13 @@ if ($c->param("testcase_id")) {
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($branch);
print $js;
} elsif ($c->param("testday_id")) {
use Litmus::DB::TestDay;
my $testday_id = $c->param("testday_id");
my $testday = Litmus::DB::TestDay->retrieve($testday_id);
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $js = $json->objToJson($testday);
print $js;
} elsif ($c->param("products")) {
my @products = Litmus::DB::Product->retrieve_all();
my $json = JSON->new(skipinvalid => 1, convblessed => 1);

View File

@@ -40,10 +40,9 @@ use Litmus::Error;
use Litmus::FormWidget;
use CGI;
use JSON;
use Time::Piece::MySQL;
Litmus->init();
Litmus::Auth::requireAdmin("edit_categories.cgi");
@@ -309,6 +308,100 @@ if ($c->param) {
}
}
# Process testday changes.
if ($c->param("delete_testday_button") and
$c->param("testday_id")) {
my $testday_id = $c->param("testday_id");
my $testday = Litmus::DB::TestDay->retrieve($testday_id);
if ($testday) {
$rv = $testday->delete;
if ($rv) {
$status = "success";
$message = "Testday ID# $testday_id deleted successfully.";
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to delete testday ID# $testday_id.";
}
} else {
$status = "failure";
$message = "Testday ID# $testday_id does not exist. (Already deleted?)";
}
} elsif ($c->param("edit_testday_form_mode")) {
if ($c->param("edit_testday_form_mode") eq "add") {
my %hash = (
description => $c->param('edit_testday_form_desc'),
start_timestamp => $c->param('edit_testday_form_start_timestamp'),
finish_timestamp => $c->param('edit_testday_form_finish_timestamp'),
);
if ($c->param('testday_product_id')) {
$hash{product_id} = $c->param('testday_product_id');
}
if ($c->param('testday_branch_id')) {
$hash{branch_id} = $c->param('testday_branch_id');
}
if ($c->param('testday_testgroup_id')) {
$hash{testgroup_id} = $c->param('testday_testgroup_id');
}
if ($c->param('testday_build_id')) {
$hash{build_id} = $c->param('testday_build_id');
}
if ($c->param('testday_locale') and
$c->param('testday_locale') ne "") {
$hash{locale_abbrev} = $c->param('testday_locale');
}
my $new_testday =
Litmus::DB::TestDay->create(\%hash);
if ($new_testday) {
$status = "success";
$message = "Testday added successfully. New testday ID# is " . $new_testday->testday_id;
$defaults->{'testday_id'} = $new_testday->testday_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to add testday.";
}
} elsif ($c->param("edit_testday_form_mode") eq "edit") {
my $testday_id = $c->param("edit_testday_form_testday_id");
my $testday = Litmus::DB::TestDay->retrieve($testday_id);
if ($testday) {
$testday->description($c->param('edit_testday_form_desc'));
$testday->start_timestamp($c->param('edit_testday_form_start_timestamp'));
$testday->finish_timestamp($c->param('edit_testday_form_finish_timestamp'));
if ($c->param('testday_product_id')) {
$testday->product_id($c->param('testday_product_id'));
}
if ($c->param('testday_branch_id')) {
$testday->branch_id($c->param('testday_branch_id'));
}
if ($c->param('testday_testgroup_id')) {
$testday->testgroup_id($c->param('testday_testgroup_id'));
}
if ($c->param('testday_build_id')) {
$testday->build_id($c->param('testday_build_id'));
}
if ($c->param('testday_locale') and
$c->param('testday_locale') ne "") {
$testday->locale_abbrev($c->param('testday_locale'));
}
$rv = $testday->update();
if ($rv) {
$status = "success";
$message = "Testday ID# $testday_id updated successfully.";
$defaults->{'testday_id'} = $testday_id;
$rebuild_cache=1;
} else {
$status = "failure";
$message = "Failed to update testday ID# $testday_id.";
}
} else {
$status = "failure";
$message = "Testday ID# $testday_id not found.";
}
}
}
}
if ($rebuild_cache) {
@@ -318,7 +411,15 @@ if ($rebuild_cache) {
my $products = Litmus::FormWidget->getProducts();
my $platforms = Litmus::FormWidget->getPlatforms();
my $branches = Litmus::FormWidget->getBranches();
my $testgroups = Litmus::FormWidget->getTestgroups();
my $opsyses = Litmus::FormWidget->getOpsyses();
my $testdays = Litmus::FormWidget->getTestdays();
my $locales = Litmus::FormWidget->getLocales;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $products_js = $json->objToJson($products);
my $branches_js = $json->objToJson($branches);
my $testgroups_js = $json->objToJson($testgroups);
my $vars = {
title => 'Manage Categories',
@@ -326,8 +427,14 @@ my $vars = {
platforms => $platforms,
branches => $branches,
opsyses => $opsyses,
testdays => $testdays,
locales => $locales,
};
$vars->{'products_js'} = $products_js;
$vars->{'branches_js'} = $branches_js;
$vars->{'testgroups_js'} = $testgroups_js;
if ($status and $message) {
$vars->{'onload'} = "toggleMessage('$status','$message');";
}

View File

@@ -323,6 +323,27 @@ $table{testcases} =
fulltext key(summary,steps,expected_results)';
$table{testdays} =
'testday_id smallint(6) not null primary key auto_increment,
last_updated timestamp(14),
start_timestamp timestamp(14) not null,
finish_timestamp timestamp(14) not null,
description varchar(255) not null,
product_id tinyint(4),
testgroup_id smallint(6),
build_id int(10) unsigned,
branch_id smallint(6),
locale_abbrev varchar(16),
index(start_timestamp),
index(finish_timestamp),
index(description),
index(product_id),
index(testgroup_id),
index(build_id),
index(branch_id),
index(locale_abbrev)';
$table{testgroup_branches} =
'testgroup_id smallint(6) not null,
branch_id smallint(6) not null,

View File

@@ -25,9 +25,15 @@
# ***** END LICENSE BLOCK *****
#%]
[% INCLUDE global/html_header.tmpl js_files=['js/prototype.lite.js','js/moo.fx.js','js/moo.fx.pack.js','js/FormValidation.js','js/EditCategories.js','js/MochiKit/MochiKit.js','js/json.js','js/Help.js','js/SelectBoxes.js','js/SelectSort.js','js/ManageCategories.js'] %]
[% INCLUDE global/html_header.tmpl js_files=['js/prototype.lite.js','js/moo.fx.js','js/moo.fx.pack.js','js/FormValidation.js','js/EditCategories.js','js/MochiKit/MochiKit.js','js/json.js','js/Help.js','js/SelectBoxes.js','js/SelectSort.js','js/ManageCategories.js','js/ManageTestdays.js'] %]
[% INCLUDE global/litmus_header.tmpl %]
<script type="text/javascript">
var products=[% products_js %];
var branches=[% branches_js %];
var testgroups=[% testgroups_js %];
</script>
<div id="page">
@@ -39,6 +45,7 @@
[% INCLUDE admin/form_widgets/update_platforms.tmpl %]
[% INCLUDE admin/form_widgets/update_opsyses.tmpl %]
[% INCLUDE admin/form_widgets/update_branches.tmpl %]
[% INCLUDE admin/form_widgets/update_testdays.tmpl %]
</div> <!--END content-->
@@ -47,6 +54,7 @@
Element.cleanWhitespace('manage_platforms_div');
Element.cleanWhitespace('manage_opsyses_div');
Element.cleanWhitespace('manage_branches_div');
Element.cleanWhitespace('manage_testdays_div');
ec_init();
</script>

View File

@@ -0,0 +1,98 @@
<h1 id="testdays_header" class="firstHeading"><a name="manage_testdays" class="collapse-link">Manage Testdays&nbsp;&raquo;</a></h1>
<div id="manage_testdays_div" class="collapsable">
<div class="section-full">
<div class="section-header">Existing Testdays</div>
<div class="section-content">
<form id="select_testday_and_mode_form" name="select_testday_and_mode_form" method="post" action="manage_categories.cgi">
<table border="0" cellspacing="0" cellpadding="5">
<tr>
<td>
[% INCLUDE form_widgets/select_testday_id.tmpl name="testday_id" placeholder=1 size=5 show_name=1 onchange="loadTestday();" %]
</td>
</tr>
<tr>
<td>
<input id="add_testday_button" name="add_testday_button" class="manage" type="button" onClick="switchTestdayFormToAdd();" value="Add new testday">&nbsp;
<input id="edit_testday_button" name="edit_testday_button" class="manage" type="button" onClick="switchTestdayFormToEdit();" value="Edit testday" disabled>&nbsp;
<input id="delete_testday_button" name="delete_testday_button" class="manage" type="submit" onClick="return confirm('Really delete this testday?')
;" value="Delete testday" disabled>&nbsp;
</td>
</tr>
</table>
</form>
</div> <!--end section-content-->
<div style="display: none;" id="edit_testday_form_div">
<hr />
<div id="testday-title" class="section-header">Testday Info</div>
<div class="section-content">
<form id="edit_testday_form" name="edit_testday_form" method="post" action="manage_categories.cgi" onSubmit="return checkTestdayForm(this);">
<input id="edit_testday_form_mode" name="edit_testday_form_mode" type="hidden" value="edit">
<input id="edit_testday_form_testday_id" name="edit_testday_form_testday_id" type="hidden" value="">
<table class="manage">
<tr>
<td class="headerleft">Testday ID#:</td>
<td name="edit_testday_form_testday_id_display" id="edit_testday_form_testday_id_display"></td>
</tr>
<tr>
<td class="headerleft">Description:</td>
<td colspan="2"><input name="edit_testday_form_desc"
id="edit_testday_form_desc"
value=""
size="55"/ disabled></td>
</tr>
<tr>
<td class="headerleft">Start Timestamp:</td>
<td><input name="edit_testday_form_start_timestamp"
id="edit_testday_form_start_timestamp"
value=""
size="14"/ disabled></td>
<td>&lArr; YYMMDDHHmmSS (required)</td>
</tr>
<tr>
<td class="headerleft">Finish Timestamp:</td>
<td><input name="edit_testday_form_finish_timestamp"
id="edit_testday_form_finish_timestamp"
value=""
size="14"/ disabled></td>
<td>&lArr; YYMMDDHHmmSS (required)</td>
</tr>
<tr>
<td class="headerleft">Product:</td>
<td colspan="2">[% INCLUDE form_widgets/select_product_id.tmpl name="testday_product_id" placeholder=1 onChange="changeProduct(this,document.getElementById('testday_branch_id'),document.getElementById('testday_testgroup_id'));" %]</td>
</tr>
<tr>
<td class="headerleft">Branch:</td>
<td>[% INCLUDE form_widgets/select_branch_id.tmpl name="testday_branch_id" placeholder=1 onChange="changeBranch(this,document.getElementById('testday_testgroup_id'));" %]</td>
<td>&lArr; Select Product first</td>
</tr>
<tr>
<td class="headerleft">Testgroup:</td>
<td>[% INCLUDE form_widgets/select_testgroup_id.tmpl name="testday_testgroup_id" placeholder=1 %]</td>
<td>&lArr; Select Branch first</td>
</tr>
<tr>
<td class="headerleft">Build ID:</td>
<td><input name="testday_build_id" id="testday_build_id" type="text" size="10"></td>
</tr>
<tr>
<td class="headerleft">Locale:</td>
<td>[% INCLUDE form_widgets/select_locale.tmpl name="testday_locale" placeholder=1 %]
</tr>
<tr>
<td colspan="3" align="right"><input id="edit_testday_form_reset" class="button" type="button" value="Reset" disabled onClick="resetTestday();" />&nbsp;<input class="button" type="submit" id="edit_testday_form_submit" name="edit_testday_form_submit" value="Submit Edits" disabled /></div>
</td>
</tr>
</table>
</form>
</div>
</div>
</div> <!--end section-full-->
</div>

View File

@@ -1,9 +1,17 @@
<select id="[% name %]" name="[% name %]"[% IF size %] size="[% size %]"[% END %][% IF disabled %] disabled[% END %][% IF onChange %] onChange="[% onChange %]"[% END %][% IF multiple %] multiple[% END %]>
[% IF placeholder %]<option value="">-Operating System-</option>[% END %]
[% IF opsyses %]
[% FOREACH opsys=opsyses %]
<option[% IF defaults.opsys==opsys.name %] selected[% END %]
<select
[% IF classname %]class="[% classname %]"[% END %]
id="[% name %]"
name="[% name %]"
[% IF size %] size="[% size %]"[% END %]
[% IF disabled %] disabled[% END %]
[% IF onChange %] onChange="[% onChange %]"[% END %]
[% IF multiple %] multiple[% END %]>
[% IF placeholder %]<option value="">-Operating System-</option>[% END %]
[% IF opsyses %]
[% FOREACH opsys=opsyses %]
<option[% IF defaults.opsys==opsys.name %] selected[% END %]
value="[% opsys.opsys_id | html %]">[% opsys.name | html %] ([% opsys.opsys_id %])</option>
[% END %]
[% END %]
[% END %]
[% END %]
</select>

View File

@@ -1,9 +1,15 @@
<select id="[% name %]" name="[% name %]"[% IF size %] size="[% size %]"[% END %][% IF disabled %] disabled[% END %][% IF onChange %] onChange="[% onChange %]"[% END %]>
[% IF placeholder %]<option value="">-Platform-</option>[% END %]
[% IF platforms %]
[% FOREACH platform=platforms %]
<option[% IF defaults.platform==platform.name %] selected[% END %]
<select
[% IF classname %] class="[% classname %]"[% END %]
id="[% name %]" name="[% name %]"
[% IF size %] size="[% size %]"[% END %]
[% IF disabled %] disabled[% END %]
[% IF onChange %] onChange="[% onChange %]"[% END %]>
[% IF placeholder %]<option value="">-Platform-</option>[% END %]
[% IF platforms %]
[% FOREACH platform=platforms %]
<option[% IF defaults.platform==platform.name %] selected[% END %]
value="[% platform.platform_id | html %]">[% platform.name | html %] ([% platform.platform_id %])</option>
[% END %]
[% END %]
[% END %]
[% END %]
</select>

View File

@@ -0,0 +1,9 @@
<select class="testday" id="[% name %]" name="[% name %]"[% IF size %] size="[% size %]"[% END %][% IF onchange %] onChange="[% onchange %]"[% END %][% IF disabled %] disabled[% END %]>
[% IF placeholder %]<option value="">-Testday Description, Start - Finish-</option>[% END %]
[% IF testdays %]
[% FOREACH testday=testdays %]
<option[% IF defaults.testday_id==testday.testday_id %] selected[% END %]
value="[% testday.testday_id | html %]">[% testday.description | html %], [% testday.start_timestamp | html %] - [% testday.finish_timestamp | html %]</option>
[% END %]
[% END %]
</select>

View File

@@ -1,9 +1,9 @@
<select class="testgroup" id="[% name %]" name="[% name %]"[% IF size %] size="[% size %]"[% END %][% IF onchange %] onChange="[% onchange %]"[% END %][% IF disabled %] disabled[% END %]>
[% IF placeholder %]<option value="">-Testgroup Name (Testgroup ID#)-</option>[% END %]
[% IF placeholder %]<option value="">-Testgroup-</option>[% END %]
[% IF testgroups %]
[% FOREACH testgroup=testgroups %]
<option[% IF defaults.testgroup_id==testgroup.testgroup_id %] selected[% END %]
value="[% testgroup.testgroup_id | html %]">[% testgroup.name %] ([% testgroup.testgroup_id | html%])</option>
value="[% testgroup.testgroup_id | html %]">[% testgroup.name %]</option>
[% END %]
[% END %]
</select>

View File

@@ -28,11 +28,11 @@
[% INCLUDE global/html_header.tmpl js_files=['js/Help.js'] %]
[% INCLUDE global/litmus_header.tmpl %]
[% staricon="<img class=icon src=\"images/star1.gif\" title=\"This result has comments\" alt=\"*\">" %]
[% commenticon="<img class=icon src=\"images/comment.png\" title=\"This result has comments\" alt=\"*\">" %]
<script type="text/javascript">
var navigationHelpTitle = "Navigation";
var navigationHelpText = '<ul class="instructions"><li>Click on the number in the "result id#" column to see a full listing of the test result, including comments.</li><li>Click on the number at the start of the "testcase id#: summary" column to see a more detailed description of that particular testcase.</li><li>Results marked with the star icon ([% staricon %]) have comments associated with them. Clicking on the star will display the comments in-page.</li></ul>';
var navigationHelpText = '<ul class="instructions"><li>Click on the number in the "result id#" column to see a full listing of the test result, including comments.</li><li>Click on the number at the start of the "testcase id#: summary" column to see a more detailed description of that particular testcase.</li><li>Results marked with the comment icon ([% commenticon %]) have comments associated with them. Clicking on the icon will display the comments in-page.</li></ul>';
</script>
<div id="page">

View File

@@ -25,7 +25,7 @@
# ***** END LICENSE BLOCK *****
#%]
[% staricon="<img class='icon' src='images/star1.gif' title='This result has comments' alt='*'>" %]
[% commenticon="<img class='icon' src='images/comment.png' title='This result has comments' alt='*'>" %]
[% IF results %]
<script type="text/javascript" src="js/Comments.js"></script>
@@ -39,7 +39,7 @@
var comments = new Array();
[% subscript=0 %]
[% FOREACH result=results %]
comments[[% subscript | js %]] = "[% IF result.comments %][% FOREACH comment=result.comments %][% IF loop.count>1 %]<hr/>[% END %]<p class='comment'><b>[% IF show_admin %]<a href=\"mailto:[% comment.user.email | html | email | uri %]\">[% END %][% comment.user.getDisplayName | html | js | email %][% IF show_admin %]</a>[% END %]<br/>[% comment.submission_time.strftime("%Y-%m-%d&nbsp;%T") %]</b><br/>[% staricon | none %]&nbsp;[% comment.comment | js | html %]<br/></p>[% END %][% END %]";
comments[[% subscript | js %]] = "[% IF result.comments %][% FOREACH comment=result.comments %][% IF loop.count>1 %]<hr/>[% END %]<p class='comment'><b>[% IF show_admin %]<a href=\"mailto:[% comment.user.email | html | email | uri %]\">[% END %][% comment.user.getDisplayName | html | js | email %][% IF show_admin %]</a>[% END %]<br/>[% comment.submission_time.strftime("%Y-%m-%d&nbsp;%T") %]</b><br/>[% commenticon | none %]&nbsp;[% comment.comment | js | html %]<br/></p>[% END %][% END %]";
[% subscript=subscript+1 %]
[% END %]
</script>
@@ -67,12 +67,12 @@
[% FOREACH result=results %]
<tr class="[% result.result_status_class | html %]">
<td colspan="2" align="center">[% result.created | html %]</td>
<td align="center"><a href="single_result.cgi?id=[% result.testresult_id | html | uri%]">
[% result.testresult_id | html %]</a><br/>
<td align="center">
<a href="single_result.cgi?id=[% result.testresult_id | html | uri%]">[% result.testresult_id | html %]</a><br/>
[% IF result.comments %]
<a href="" onclick="return comment(event,[% subscript | js | html %],'');">
[% staricon | none%]</a>
[% END %]
[% commenticon | none%]</a>
[% END %]
</td>
<td align="left"><a href="show_test.cgi?id=[% result.testcase_id | html | uri %]">
[% result.testcase_id | html %]</a>: [% result.summary | html %]</td>

View File

@@ -0,0 +1,55 @@
[%# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# The Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
#%]
[%# INTERFACE:
#%]
[% INCLUDE global/html_header.tmpl js_files=['js/prototype.lite.js','js/moo.fx.js','js/moo.fx.pack.js','js/MochiKit/MochiKit.js','js/json.js'] %]
[% INCLUDE global/litmus_header.tmpl %]
<div id="page">
[% INCLUDE sidebar/sidebar.tmpl %]
<div id="content">
[% IF display_results %]
<h1 class="firstHeading">[% title %]</h1>
[% INCLUDE reporting/testday_results.tmpl %]
[% END %]
<h1 class="firstHeading">Testday Report - Search Criteria</h1>
[% INCLUDE reporting/testday_search.tmpl %]
</div> <!--END content-->
</div> <!--END page-->
[% INCLUDE global/litmus_footer.tmpl %]
[% INCLUDE global/html_footer.tmpl %]

View File

@@ -0,0 +1,277 @@
[%# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# The Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
#%]
[%# INTERFACE:
# no interface for this template
#%]
<div class="section-full">
<table class="result_container">
[% IF user_results %]
<tr>
<th>Breakdown By Tester</th>
</tr>
[% IF user_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Tester</th><th># Results</th>
</tr>
[% FOR user_result IN user_results %]
[% IF not (loop.count % 2) %]
[% rowstyle = 'even' %]
[% ELSE %]
[% rowstyle = 'odd' %]
[% END %]
<tr class="[% rowstyle %]">
<td align="center">[% IF loop.first OR user_result.num_results == num_results %][% num_results = user_result.num_results %]<img src="images/trophy.gif" alt="Trophy!" align="absmiddle" />&nbsp;[% END %]<a href="mailto:[% user_result.email | email %]">[% IF user_result.irc_nickname %][% user_result.irc_nickname | email | html %][% ELSE %][user_result.email | email %][% END %]</a></td>
<td align="center"><a href="advanced_search.cgi?email=[% user_result.email %]&amp;start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;limit=[% user_result.num_results %]">[% user_result.num_results %]</a></td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
[% IF user_status_results %]
<tr>
<th>Breakdown By Tester and Result Status</th>
</tr>
[% IF user_status_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Tester</th><th>Pass</th><th>Fail</th><th>Unclear</th>
</tr>
[% FOR user_status_result IN user_status_results %]
<tr>
<td align="center"><a href="mailto:[% user_status_result.email | email %]">[% IF user_status_result.irc_nickname %][% user_status_result.irc_nickname | email | html %][% ELSE %][user_status_result.email | email %][% END %]</a></td>
<td class="pass" align="center">[% IF user_status_result.pass %]<a href="advanced_search.cgi?email=[% user_status_result.email %]&amp;start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;result_status=pass&amp;limit=[% user_status_result.pass %]">[% user_status_result.pass %]</a>[% ELSE %]0[% END %]</td>
<td class="fail" align="center">[% IF user_status_result.fail %]<a href="advanced_search.cgi?email=[% user_status_result.email %]&amp;start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;result_status=fail&amp;limit=[% user_status_result.fail %]">[% user_status_result.fail %]</a>[% ELSE %]0[% END %]</td>
<td class="unclear" align="center">[% IF user_status_result.unclear %]<a href="advanced_search.cgi?email=[% user_status_result.email %]&amp;start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;result_status=unclear&amp;limit=[% user_status_result.unclear %]">[% user_status_result.unclear %]</a>[% ELSE %]0[% END %]</td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
[% IF locale_results %]
<tr>
<th>Breakdown By Locale</th>
</tr>
[% IF locale_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Locale</th><th># Results</th>
</tr>
[% FOR locale_result IN locale_results %]
[% IF not (loop.count % 2) %]
[% rowstyle = 'even' %]
[% ELSE %]
[% rowstyle = 'odd' %]
[% END %]
<tr class="[% rowstyle %]">
<td align="center">[% locale_result.locale_abbrev %]</td>
<td align="center"><a href="advanced_search.cgi?start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;locale=[% locale_result.locale_abbrev %]&amp;limit=[% locale_result.num_results %]">[% locale_result.num_results %]</a></td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
[% IF platform_results %]
<tr>
<th>Breakdown By Platform</th>
</tr>
[% IF platform_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Platform</th><th># Results</th>
</tr>
[% FOR platform_result IN platform_results %]
[% IF not (loop.count % 2) %]
[% rowstyle = 'even' %]
[% ELSE %]
[% rowstyle = 'odd' %]
[% END %]
<tr class="[% rowstyle %]">
<td align="center">[% platform_result.name %]</td>
<td align="center"><a href="advanced_search.cgi?start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;platform=[% platform_result.name %]&amp;limit=[% platform_result.num_results %]">[% platform_result.num_results %]</a></td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
[% IF status_results %]
<tr>
<th>Breakdown By Result Status</th>
</tr>
[% IF status_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Result Status</th><th># Results</th>
</tr>
[% FOR status_result IN status_results %]
<tr class="[% status_result.class_name %]">
<td align="center">[% status_result.name %]</td>
<td align="center"><a href="advanced_search.cgi?start_date=[% test_event.getStartTimestamp %]&amp;end_date=[% test_event.getFinishTimestamp %]&amp;result_status=[% status_result.class_name %]&amp;limit=[% status_result.num_results %]">[% status_result.num_results %]</a></td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
[% IF subgroup_results %]
<tr>
<th>Breakdown By Subgroup</th>
</tr>
[% IF subgroup_results.size <= 0 %]
<tr>
<td class="no-results">No results</td>
</tr>
[% ELSE %]
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table class="testday_results">
<tr>
<th>Product:Testgroup:Subgroup</th><th># Results</th><th># Testcases in Subgroup</th>
</tr>
[% FOR subgroup_result IN subgroup_results %]
[% IF not (loop.count % 2) %]
[% rowstyle = 'even' %]
[% ELSE %]
[% rowstyle = 'odd' %]
[% END %]
<tr class="[% rowstyle %]">
<td align="left">[% subgroup_result.name %]</td>
<td align="center">[% subgroup_result.num_results %]</td>
<td align="center">[% subgroup_result.testcase_count %]</td>
</tr>
[% END %]
</table>
</div>
</td>
</tr>
[% END %]
<tr>
<td><hr/></td>
</tr>
[% END %]
</table>
</div>

View File

@@ -0,0 +1,204 @@
[%# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is
# The Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Cooper <ccooper@deadsquid.com>
# Zach Lipton <zach@zachlipton.com>
#
# ***** END LICENSE BLOCK *****
#%]
[%# INTERFACE:
# no interface for this template
#%]
<script type="text/javascript">
var products=[% products_js %];
var branches=[% branches_js %];
var testgroups=[% testgroups_js %];
function init()
{
populateProductSelect("product_id");
productBox = document.getElementById('product_id');
branchBox = document.getElementById('branch_id');
FormInit(document.forms['testday_report'], document.location.search);
FormInit(document.forms['testevent_report'], document.location.search);
changeProduct(productBox);
FormInit(document.forms['testevent_report'], document.location.search);
changeBranch(branchBox);
FormInit(document.forms['testevent_report'], document.location.search);
}
function populateProductSelect(selectID)
{
if (products) {
var selectBox = document.getElementById(selectID)
selectBox.options.length = 0;
selectBox.options[0] = new Option('-Product-','');
for (var i=0; i<products.length; i++) {
selectBox.options[i+1] = new Option(products[i].name,products[i].product_id);
}
}
}
function changeProduct(productSelectBox)
{
if (productSelectBox.selectedIndex &&
productSelectBox.options[productSelectBox.selectedIndex].value != '') {
var branchSelectBox = document.getElementById('branch_id');
if (branchSelectBox) {
branchSelectBox.options.length = 0;
branchSelectBox.options[0] = new Option('-Branch-','');
var i = 1;
for (var j=0; j<branches.length; j++) {
if (branches[j].product_id == productSelectBox.options[productSelectBox.selectedIndex].value) {
branchSelectBox.options[i] = new Option(branches[j].name,branches[j].branch_id);
i++;
}
}
}
var testgroupSelectBox = document.getElementById('testgroup_id');
if (testgroupSelectBox) {
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
var i = 1;
for (var j=0; j<testgroups.length; j++) {
if (testgroups[j].product_id == productSelectBox.options[productSelectBox.selectedIndex].value) {
testgroupSelectBox.options[i] = new Option(testgroups[j].name,testgroups[j].testgroup_id);
i++;
}
}
}
}
}
function changeBranch(branchSelectBox)
{
if (branchSelectBox.selectedIndex &&
branchSelectBox.options[branchSelectBox.selectedIndex].value != '') {
var testgroupSelectBox = document.getElementById('testgroup_id');
if (testgroupSelectBox) {
testgroupSelectBox.options.length = 0;
testgroupSelectBox.options[0] = new Option('-Testgroup-','');
var i = 1;
for (var j=0; j<testgroups.length; j++) {
if (testgroups[j].branch_id == branchSelectBox.options[branchSelectBox.selectedIndex].value) {
testgroupSelectBox.options[i] = new Option(testgroups[j].name,testgroups[j].testgroup_id);
i++;
}
}
}
}
}
</script>
<div class="section-full">
<form action="testday_report.cgi" method="get" name="testday_report" id="testday_report">
<table class="testcase-search">
<tr>
<th>Scheduled Testdays</th>
</tr>
<tr>
<td valign="top" width="100%">
<div class="testcase-search">
<table>
<tr>
<td>[% INCLUDE form_widgets/select_testday_id.tmpl name="testday_id" %]</td>
</tr>
<tr>
<td><input class="button" type="submit" value="Generate Report"></td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</form>
<form action="testday_report.cgi" method="get" name="testevent_report" id="testevent_report">
<table class="testcase-search">
<tr>
<th colspan="3">User-defined Events</th>
</tr>
<tr>
<td>
<div class="testcase-search">
<table>
<tr>
<td colspan="3">This search form can be used to generate the same set of testday reports for any time period or set of criteria.</td>
</tr>
<tr>
<td colspan="3"><hr/></td>
</tr>
<tr>
<td>Start Time:</td>
<td><input name="start_timestamp" id="start_timestamp" type="text" size="16"></td>
<td>&lArr; YYMMDDHHmmSS (required)</td>
</tr>
<tr>
<td>Finish Time:</td>
<td><input name="finish_timestamp" id="finish_timestamp" type="text" size="16"></td>
<td>&lArr; YYMMDDHHmmSS (required)</td>
</tr>
<tr>
<td>Product:</td>
<td>[% INCLUDE form_widgets/select_product_id.tmpl name="product_id" placeholder=1 onChange="changeProduct(this);" %]</td>
</tr>
<tr>
<td>Branch:</td>
<td>[% INCLUDE form_widgets/select_branch_id.tmpl name="branch_id" placeholder=1 onChange="changeBranch(this);" %]</td>
<td>&lArr; Select Product first</td>
</tr>
<tr>
<td>Testgroup:</td>
<td>[% INCLUDE form_widgets/select_testgroup_id.tmpl name="testgroup_id" placeholder=1 %]</td>
<td>&lArr; Select Branch first</td>
</tr>
<tr>
<td>Build ID:</td>
<td><input name="build_id" id="build_id" type="text" size="10"></td>
</tr>
<tr>
<td>Locale:</td>
<td>[% INCLUDE form_widgets/select_locale.tmpl name="locale" placeholder=1 %]
</tr>
<tr>
<td><input class="button" type="submit" value="Generate Report"></td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</form>
</div>

View File

@@ -6,7 +6,9 @@
[% INCLUDE sidebar/widget_testcases.tmpl %]
[% INCLUDE sidebar/widget_options.tmpl %]
[% INCLUDE sidebar/widget_testing.tmpl %]
[% INCLUDE sidebar/widget_reporting.tmpl %]
[% INCLUDE sidebar/widget_admin.tmpl %]

View File

@@ -4,7 +4,9 @@
[% INCLUDE sidebar/widget_login.tmpl %]
[% INCLUDE sidebar/widget_options.tmpl %]
[% INCLUDE sidebar/widget_testing.tmpl %]
[% INCLUDE sidebar/widget_reporting.tmpl %]
[% INCLUDE sidebar/widget_admin.tmpl %]

View File

@@ -1,6 +1,6 @@
<div class="pagetools">
<div>
<h3>Welcome!</h3>
<h3>Welcome</h3>
[% IF defaultemail %]
<span class="email">[% defaultemail.getDisplayName.replace('\@.*','') %]</span>
<p align="right">[% IF ! show_admin %]<a href="edit_users.cgi">Update profile</a><br/>[% END %]<a href="logout.cgi">Log out</a></p>

View File

@@ -0,0 +1,11 @@
<div class="pagetools">
<div>
<h3>Reporting</h3>
<ul>
<li><a href="search_results.cgi">Search Results</a></li>
<li><a href="advanced_search.cgi">Advanced Search</a></li>
<li><a href="testday_report.cgi">Testdays</a></li>
<li><a href="stats.cgi">Statistics</a></li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,9 @@
<div class="pagetools">
<div>
<h3>Get Testing!</h3>
<ul>
<li><a href="run_tests.cgi">Run Tests</a></li>
<li><a href="show_test.cgi">View Tests</a></li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,100 @@
#!/usr/bin/perl -w
# -*- Mode: cperl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Litmus.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Zach Lipton <zach@zachlipton.com>
use strict;
use Litmus;
use Litmus::Error;
use Litmus::FormWidget;
use Litmus::UserAgentDetect;
use Litmus::SysConfig;
use Litmus::Auth;
use Litmus::Utils;
use Litmus::TestEvent;
use CGI;
use Date::Manip;
use JSON;
use Time::Piece::MySQL;
Litmus->init();
my $c = Litmus->cgi();
print $c->header();
my $vars;
my $cookie = Litmus::Auth::getCookie();
$vars->{"defaultemail"} = $cookie;
$vars->{"show_admin"} = Litmus::Auth::istrusted($cookie);
$vars->{'title'} = "Testday Report";
if ($c->param) {
my $testday;
if ($c->param("testday_id")) {
$testday = Litmus::TestEvent->new(testday_id => $c->param("testday_id"));
} elsif ($c->param("start_timestamp") and
$c->param("finish_timestamp")) {
$testday = Litmus::TestEvent->new(start_timestamp => $c->param("start_timestamp"),
finish_timestamp => $c->param("finish_timestamp"),
testgroup_id => $c->param("testgroup_id"),
build_id => $c->param("build_id"),
branch_id => $c->param("branch_id"),
locale => $c->param("locale"),
);
}
if ($testday) {
$vars->{'title'} .= " - " . $testday->getDescription . ", " . $testday->getStartTimestamp(1) . " - " . $testday->getFinishTimestamp(1);
$vars->{'display_results'} = 1;
$vars->{'locale_results'} = $testday->getBreakdownByLocale();
$vars->{'platform_results'} = $testday->getBreakdownByPlatform();
$vars->{'status_results'} = $testday->getBreakdownByResultStatus();
$vars->{'subgroup_results'} = $testday->getBreakdownBySubgroup();
$vars->{'user_results'} = $testday->getBreakdownByUser();
$vars->{'user_status_results'} = $testday->getBreakdownByUserAndResultStatus();
$vars->{'test_event'} = $testday;
}
}
my $products = Litmus::FormWidget->getProducts;
my $branches = Litmus::FormWidget->getBranches;
my $testgroups = Litmus::FormWidget->getTestgroups;
my $json = JSON->new(skipinvalid => 1, convblessed => 1);
my $products_js = $json->objToJson($products);
my $branches_js = $json->objToJson($branches);
my $testgroups_js = $json->objToJson($testgroups);
$vars->{'products_js'} = $products_js;
$vars->{'branches_js'} = $branches_js;
$vars->{'testgroups_js'} = $testgroups_js;
my $locales = Litmus::FormWidget->getLocales;
my $testdays = Litmus::FormWidget->getTestdays;
$vars->{'locales'} = $locales;
$vars->{'testdays'} = $testdays;
Litmus->template()->process("reporting/testday_report.tmpl", $vars) ||
internalError(Litmus->template()->error());