- fix percentage calculation for run tests -> now based on community and personal testing coverage percentages, as limited by the chosen platform and build ID;

- some CSS changes, mostly to decrease the default font size;
- added template framework for displaying collapsable instruction text on just about any page.
This commit is contained in:
ccooper%deadsquid.com 2005-10-24 17:57:50 +00:00
Родитель 7ad0782599
Коммит 9f9626cd0e
11 изменённых файлов: 317 добавлений и 147 удалений

Просмотреть файл

@ -50,15 +50,15 @@ Litmus::DB::Subgroup->has_a(testgroup => "Litmus::DB::Testgroup");
Litmus::DB::Subgroup->has_many(tests => "Litmus::DB::Test");
# find the percentage of testing completed for a particular platform in
# this subgroup, optionally restricting to community enabled tests only
sub percentcompleted {
#########################################################################
sub community_coverage() {
my $self = shift;
my $platform = shift;
my $communityonly = shift;
my $build_id = shift;
my $community_only = shift;
my @tests;
if (! $communityonly) {
if (! $community_only) {
@tests = Litmus::DB::Test->search(
subgroup => $self,
status => Litmus::DB::Status->search(name => "Enabled"),
@ -71,24 +71,60 @@ sub percentcompleted {
);
}
if (@tests == 0) { return "N/A" }
my $numcompleted = 0;
my $num_completed = 0;
foreach my $curtest (@tests) {
if ($curtest->iscompleted($platform)) {
$numcompleted++;
if ($curtest->is_completed($platform,$build_id)) {
$num_completed++;
}
}
my $result = ($numcompleted/scalar @tests) * 100;
my $result = $num_completed/(scalar @tests) * 100;
unless ($result) {
return "0";
}
# truncate to a whole number:
if ($result =~ /\./) {
$result =~ /^(\d*)/;
return $1;
return sprintf("%d",$result);
}
#########################################################################
sub personal_coverage() {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $community_only = shift;
my $user = shift;
my @tests;
if (! $community_only) {
@tests = Litmus::DB::Test->search(
subgroup => $self,
status => Litmus::DB::Status->search(name => "Enabled"),
);
} else {
return $result;
@tests = Litmus::DB::Test->search(
subgroup => $self,
status => Litmus::DB::Status->search(name => "Enabled"),
communityenabled => 1,
);
}
if (@tests == 0) { return "N/A" }
my $num_completed = 0;
foreach my $curtest (@tests) {
if ($curtest->is_completed($platform,$build_id,$user)) {
$num_completed++;
}
}
my $result = $num_completed/(scalar @tests) * 100;
unless ($result) {
return "0";
}
return sprintf("%d",$result);
}
1;

Просмотреть файл

@ -57,48 +57,10 @@ Litmus::DB::Test->has_a("format" => "Litmus::DB::Format");
Litmus::DB::Test->has_many(testresults => "Litmus::DB::Testresult", {order_by => 'submission_time DESC'});
# we override Class::DBI's find_column() so that when we refer to
# formatted names like steps and expected results, we use the actual
# database columns t1 and t2.
#memoize('find_column'); # we use this _a lot_
#sub find_column {
# my $self = shift;
# my $want = shift;
#
# my $col = undef;
# if (ref $self) {
# $want =~ s/^.*::(\w+)$/$1/;
# $col = $self->format_id()->getColumnMapping($want);
# }
#
# if ($col) {
# return $self->SUPER::find_column($col);
# } else {
# # didn't find it, so we fall back on the normal
# # find_column from Litmus::DBI:
# $self->SUPER::find_column($want);
# }
#}
# we need to have accessors that correspond to
# the "virtual columns" created by our format. sounds like a job for
# autoload...
#sub AUTOLOAD {
# my $self = shift;
# my @args = @_;
# my $name = our $AUTOLOAD;
#
# my $col = $self->find_column($name);
#
# if (!$col) {
# internalError("tried to call Litmus::DB::Test method $name which does not exist");
# }
#
# return $self->$col(@args);
#}
#########################################################################
# does the test have at least one recent result?
# optionally, just check for a particular platform.
#########################################################################
memoize('isrecent');
sub isrecent {
my $self = shift;
@ -116,22 +78,37 @@ sub isrecent {
return 0;
}
# Right now, a test is considered completed as long as it has at least
# one recent result for that platform. In the future, we would want to
# use some sort of more advanced system where we look at what results
# were found and schedule tests with inconsistant results as incomplete.
memoize('iscompleted');
sub iscompleted {
my $self = shift;
my $platform = shift;
if ($self->isrecent($platform)) {
return 1;
} else {
return 0;
}
#########################################################################
# is_completed($$$$)
#
# Check whether we have test results for the current test that correspond
# to the provided platform, build_id, and user(optional).
#########################################################################
memoize('is_completed');
sub is_completed {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $user = shift; # optional
my @results;
if ($user) {
@results = $self->testresults(
platform => $platform,
buildid => $build_id,
user => $user,
);
} else {
@results = $self->testresults(
platform => $platform,
buildid => $build_id,
);
}
return scalar @results;
}
#########################################################################
# You might think that getting the state of a test for a particular platform
# would be pretty easy. In reality, it's more of an art then a science, since
# we get to consider all the test results submitted for a particular test,
@ -141,6 +118,11 @@ sub iscompleted {
# have bugs, then they'd be algorithms."
#
# XXX: Rewrite all this as an SQL query so it doesn't take so long.
#
# YYY: 'state' is even less simple than you might think, and should be
# based per-branch and make note of the most recent build ID per
# platform.
#########################################################################
memoize('state');
sub state {
my $self = shift;
@ -211,8 +193,10 @@ sub state {
return Litmus::DB::Result->retrieve($maxkey);
}
#########################################################################
# calculate the percent of the time this test has been in existance that it
# has had a particular state (default state is the current one)
#########################################################################
sub percentinstate {
my $self = shift;
my $state = shift || $self->state();
@ -220,7 +204,9 @@ sub percentinstate {
}
#########################################################################
# find the number of recent results for this test
#########################################################################
memoize('num_recent_results');
sub num_recent_results {
my $self = shift;
@ -234,16 +220,29 @@ sub num_recent_results {
return $count;
}
#########################################################################
# these are just convenience functions since they are pretty common needs
# and templates would be pretty verbose without them:
#########################################################################
sub product {
my $self = shift;
return $self->testgroup()->product();
}
#########################################################################
#########################################################################
sub testgroup {
my $self = shift;
return $self->subgroup()->testgroup();
}
1;

Просмотреть файл

@ -47,36 +47,72 @@ Litmus::DB::Testgroup->has_a(product => "Litmus::DB::Product");
Litmus::DB::Testgroup->has_many(subgroups => "Litmus::DB::Subgroup");
# find the total number of tests completed for the group for
# a particular platform and optionally just for community enabled tests
sub percentcompleted {
#########################################################################
sub community_coverage {
my $self = shift;
my $platform = shift;
my $communityonly = shift;
my $percentcompleted;
my $build_id = shift;
my $community_only = shift;
my $percent_completed = 0;
my @subgroups = $self->subgroups();
my $numemptysubgroups = 0;
foreach my $cursubgroup (@subgroups) {
if ($cursubgroup->percentcompleted($platform, $communityonly) eq "N/A") {
$numemptysubgroups++;
my $num_empty_subgroups = 0;
foreach my $subgroup (@subgroups) {
my $subgroup_percent = $subgroup->community_coverage(
$platform,
$build_id,
$community_only
);
if ($subgroup_percent eq "N/A") {
$num_empty_subgroups++;
} else {
$percentcompleted += $cursubgroup->percentcompleted($platform,
$communityonly);
$percent_completed += $subgroup_percent;
}
}
if (scalar(@subgroups) - $numemptysubgroups == 0) { return "N/A" }
my $totalpercentage = $percentcompleted/(scalar @subgroups - $numemptysubgroups);
# truncate to a whole number:
if ($totalpercentage =~ /\./) {
$totalpercentage =~ /^(\d*)/;
my $percentage = $1;
return $1;
} else {
return $totalpercentage;
if (scalar(@subgroups) - $num_empty_subgroups == 0) {
return "N/A"
}
my $total_percentage = $percent_completed /
(scalar @subgroups - $num_empty_subgroups);
return sprintf("%d",$total_percentage);
}
#########################################################################
sub personal_coverage {
my $self = shift;
my $platform = shift;
my $build_id = shift;
my $community_only = shift;
my $user = shift;
my $percent_completed = 0;
my @subgroups = $self->subgroups();
my $num_empty_subgroups = 0;
foreach my $subgroup (@subgroups) {
my $subgroup_percent = $subgroup->personal_coverage(
$platform,
$build_id,
$community_only,
$user,
);
if ($subgroup_percent eq "N/A") {
$num_empty_subgroups++;
} else {
$percent_completed += $subgroup_percent;
}
}
if (scalar(@subgroups) - $num_empty_subgroups == 0) {
return "N/A"
}
my $total_percentage = $percent_completed /
(scalar @subgroups - $num_empty_subgroups);
return sprintf("%d",$total_percentage);
}
1;

Просмотреть файл

@ -31,7 +31,7 @@ h1.firstHeading, h1.errorHeading {
padding-top: 15px;
border-bottom: none;
margin-top: 0;
font-size: 1.8em;
font-size: 1.4em;
line-height: 1.2em;
text-transform: lowercase;
}
@ -235,7 +235,7 @@ a:active {
right: 0;
margin: 0;
padding: 0 0.4em 0 0;
height: 1.8em;
height: 1.4em;
list-style-type: none;
background: url("images/navigation-bottom-right.gif") no-repeat bottom right;
}
@ -425,7 +425,7 @@ table.section {
.test-results td, .single-result td, .comments td {
vertical-align: top;
padding: 3px 5px 3px 5px;
font-size: .90em;
font-size: .8em;
}
.single-result td {
@ -446,7 +446,7 @@ td.header, th {
background: #DDD;
border: solid #BBB 1px;
font-weight: bold;
font-size: 1.05em;
font-size: .85em;
text-transform: lowercase;
text-align: center;
color: #666666;
@ -548,7 +548,7 @@ table.radio-testresults tr {
vertical-align: top;
padding: 3px 5px 3px 5px;
border: solid #BBB 1px;
font-size: .90em;
font-size: .8em;
text-align: center;
}
@ -601,8 +601,8 @@ div.sec_head td.l, div.testcase-head td.l {
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
font-size: 1.4em;
line-height: 1.4em;
font-size: 1.0em;
line-height: 1.0em;
text-transform: lowercase;
color: #666666;
}
@ -614,7 +614,7 @@ div.sec_head td.r, div.testcase-head td.r {
text-align: right;
padding: 5px;
vertical-align: middle;
font-size: 0.8em;
font-size: 0.7em;
}
div.nav {
@ -635,15 +635,20 @@ div.nav a:hover {
}
div.summary {
display:block;
background-color: #efefef;
}
div.summary td {
vertical-align:top;
background-color:#efefef;
padding:10px; width:25%;
vertical-align: top;
background-color: #efefef;
padding: 10px;
width: 25%;
}
div.summary p {
padding: 10px;
}
table.tc_nav {
width:100%;
background-color:#efefef;
@ -753,7 +758,7 @@ fieldset {
legend {
font-weight: bold;
font-size: 1.1em;
font-size: 1.0em;
}
div.error {
@ -802,16 +807,16 @@ textarea {
font-weight: normal;
}
/* #content ul {
* list-style-type: none;
* margin: 0;
* padding: 5px;
*}
*/
ul.select-group {
list-style-type: none;
margin: 0;
padding: 5px;
}
div.instructions {
padding: 10px;
font-size: 0.8em;
border-collapse: collapse;
padding: 10px;
font-size: 0.8em;
}
ul.instructions {
@ -847,7 +852,7 @@ ol {
background-color: #666666;
}
div.section-full, div.instructions {
div.section-full {
border: solid #bbbbbb 1px;
margin-bottom: 5px;
background-color: #dddddd;
@ -859,8 +864,8 @@ div.section-full {
div.section-header {
padding: 10px;
font-size: 1.4em;
line-height: 1.4em;
font-size: 1.0em;
line-height: 1.0em;
font-weight: bold;
color: #666666;
text-transform: lowercase;
@ -870,6 +875,7 @@ div.section-content {
padding: 5px;
padding-left: 10px;
padding-right: 10px;
font-size: 0.8em;
}
.submit {

Просмотреть файл

@ -119,11 +119,12 @@ sub page_pickGroupSubgroup {
}
my $vars = {
title => $title,
opsys => $sysconfig->opsys(),
groups => \@groups,
subgroups => \%subgroups,
sysconfig => $sysconfig,
title => $title,
user => $user,
opsys => $sysconfig->opsys(),
groups => \@groups,
subgroups => \%subgroups,
sysconfig => $sysconfig,
defaultgroup => $defaultgroup,
};

Просмотреть файл

@ -1,4 +1,24 @@
[% INCLUDE global/html_header.tmpl %]
[%# 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>
#%]
[% INCLUDE global/html_header.tmpl js_files=['js/RunTests.js'] %]
[% INCLUDE global/litmus_header.tmpl %]
<div id="page">

Просмотреть файл

@ -0,0 +1,8 @@
<p>The testing coverage percentages are based on Platform (Windows, Mac, Linux) and Build ID. Since the Build ID is datestamp-based, this should mean that there are always some tests that need running if you update to the latest nightly build.</p>
<p>While we appreciate all testing efforts, it is more helpful if you select a testing group or subgroup for testing that does not already have complete testing coverage by the community.</p>
<p>Please note that groups/subgroups that you have already tested in their entirety (100%) are not selectable.</p>
<p>If there are problems with an existing test result that you have submitted (e.g. invalid status), please add a comment to the test result in question.</p>

Просмотреть файл

@ -0,0 +1,5 @@
<ul class="instructions">
<li>results marked with the star icon ([% icon %]) have comments associated with them. Clicking on the star will display the comments in-page;</li>
<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>
</ul>

Просмотреть файл

@ -13,12 +13,20 @@
[% END %]
[% IF show_instructions==1 %]
<div class="instructions"><strong>Navigation:</strong>
<ul class="instructions">
<li>results marked with the star icon ([% icon %]) have comments associated with them. Clicking on the star will display the comments in-page;</li>
<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>
</ul>
<div class="section-full">
<div class="sec_head">
<table width="100%">
<tr>
<td class="l">&raquo;&nbsp;Navigation</td>
<td class="r"><a href="#" onclick="divSWAP('instructions'); return false;">Hide / Show</a></td>
</tr>
</table>
</div>
<div id="instructions" class="instructions" style="display: none;">
[% INCLUDE instructions/test_result_navigation.tmpl %]
</div>
</div>
[% END %]

Просмотреть файл

@ -44,13 +44,13 @@
<div class="sec_head">
<table width="100%">
<tr>
<td class="l">Testing Summary</td>
<td class="r"><a href="#" onclick="divSWAP('sum'); return false;">Hide / Show Summary</a></td>
<td class="l">&raquo;&nbsp;Testing Configuration Summary</td>
<td class="r"><a href="#" onclick="divSWAP('sum'); return false;">Hide / Show</a></td>
</tr>
</table>
</div>
<div id="sum" class="summary">
<div id="sum" class="summary" style="display: none;">
<table class="test-config">
<tr>
@ -69,10 +69,26 @@
</tr>
</table>
</div> <!--END section-content-->
</div> <!--END sum-->
</div> <!--END section-full-->
<div class="section-full">
<div class="sec_head">
<table width="100%">
<tr>
<td class="l">&raquo;&nbsp;Percentages Explained</td>
<td class="r"><a href="#" onclick="divSWAP('instructions'); return false;">Hide / Show</a></td>
</tr>
</table>
</div>
<div id="instructions" class="instructions" style="display: none;">
[% INCLUDE instructions/percentages_explained.tmpl %]
</div>
</div>
<hr />
<div class="section-full">
@ -80,9 +96,16 @@
Select Testing Group
</div>
<div class="section-content">
<form action="run_tests.cgi" method="post" name="form" id="form">
<ul>
<p>
<table class="run-tests">
<tr>
<th>Name</th>
<th>Personal Testing Coverage</th>
<th>Community Testing Coverage</th>
</tr>
[% IF defaultgroup.testgroupid=="" %]
[% select_first_avail_group=1 %]
@ -90,24 +113,48 @@ Select Testing Group
[% select_first_avail_group=0 %]
[% END %]
[% FOREACH curgroup = groups %]
[% group_completed = curgroup.percentcompleted(sysconfig.platform, 0) %]
[% IF group_completed != 100 AND group_completed!= 'N/A' AND (defaultgroup.testgroupid==curgroup.testgroupid OR select_first_avail_group==1) %]
[% community_completed = curgroup.community_coverage(sysconfig.platform, sysconfig.buildid, 0) %]
[% personal_completed = curgroup.personal_coverage(sysconfig.platform, sysconfig.buildid, 0, user) %]
[% IF community_completed == 100 OR completed == 'N/A' %]
[% groupstyle = 'completegroup' %]
[% ELSE %]
[% IF not (loop.count % 2) %]
[% groupstyle = 'even' %]
[% ELSE %]
[% groupstyle = 'odd' %]
[% END %]
[% END %]
<tr class="[% groupstyle %]">
[% IF personal_completed != 100 AND
personal_completed != 'N/A' AND
(defaultgroup.testgroupid==curgroup.testgroupid OR
select_first_avail_group==1) %]
[% selected = "checked" %]
[% select_first_avail_group=0 %]
[% ELSE %]
[% selected = "" %]
[% END %]
<li><input [% IF group_completed == 100 OR group_completed == 'N/A' %]disabled [% END %] type="radio" name="group" value="[% curgroup.testgroupid FILTER html %]"
<td><input [% IF personal_completed == 100 OR
personal_completed == 'N/A' %]disabled [% END %] type="radio" name="group" value="[% curgroup.testgroupid FILTER html %]"
onchange="showsubgroup()" [% selected %]>
[% curgroup.name FILTER html %] - [% group_completed %][% IF group_completed != 'N/A' %]%[% END %]</li>
[% curgroup.name FILTER html %]</td>
<td align="center">[% personal_completed FILTER html %][% IF personal_completed != 'N/A' %]%[% END %]</td>
<td align="center">[% community_completed FILTER html %][% IF community_completed != 'N/A' %]%[% END %]</td>
</tr>
[% END %]
[% # for some boneheaded reason, our js breaks if there is only one group,
# so we create a fake dummy group if this is the case: %]
[% IF groups.size == 1 %]
<input type="radio" name="group" value="null" style="visibility: hidden;">
[% END %]
</ul>
</table>
</p>
</div> <!--END section-content-->
@ -120,13 +167,13 @@ Select Subgroup
</div>
<div class="section-content">
<p>
[% headerrow = '<tr><th>Name</th><th>Number of Tests</th><th>% Completed</th></tr>' %]
[% headerrow = '<tr><th>Name</th><th>Number of Tests</th><th>Personal Testing Coverage</th><th>Community Testing Coverage</th></tr>' %]
<div id="divsubgroup_null" style="visibility: visible;">
<table class="run-tests">
[% headerrow %]
<tr>
<td colspan="3" class="no-results">
<td colspan="4" class="no-results">
Please select a testing group with testcases, or that has not yet been tested in its entirety.
</td>
</tr>
@ -138,10 +185,13 @@ Please select a testing group with testcases, or that has not yet been tested in
<div id="divsubgroup_[% curgroup FILTER html %]" style="display: none;">
<table class="run-tests">
[% headerrow %]
[% select_first_avail_subgroup=1 %]
[% FOREACH cursubgroup = cursubgrouplist %]
[% completed = cursubgroup.percentcompleted(sysconfig.platform, 0) %]
[% IF completed == 100 OR completed == 'N/A' %]
[% community_completed = cursubgroup.community_coverage(sysconfig.platform, sysconfig.buildid, 0) %]
[% personal_completed = cursubgroup.personal_coverage(sysconfig.platform, sysconfig.buildid, 0, user) %]
[% IF community_completed == 100 OR completed == 'N/A' %]
[% groupstyle = 'completegroup' %]
[% ELSE %]
[% IF not (loop.count % 2) %]
@ -152,7 +202,7 @@ Please select a testing group with testcases, or that has not yet been tested in
[% END %]
<tr class="[% groupstyle %]">
<td align="left"><input [% IF completed == 100 OR completed == 'N/A' %]disabled [% END %]type="radio" name="subgroup_[% curgroup FILTER html %]"
<td align="left"><input [% IF personal_completed == 100 OR personal_completed == 'N/A' %]disabled [% ELSIF select_first_avail_subgroup==1 %][% select_first_avail_subgroup=0 %]checked [% END %]type="radio" name="subgroup_[% curgroup FILTER html %]"
value="[% cursubgroup.id FILTER html %]">
[% cursubgroup.name FILTER html %]</input></td>
<td align="center">[% counttests = cursubgroup.tests %]
@ -160,7 +210,8 @@ Please select a testing group with testcases, or that has not yet been tested in
[% ELSIF ! counttests.testid %][% counttests.list.size %]
[% ELSE %]
1[% END %]</td>
<td align="center">[% completed FILTER html %][% IF completed != 'N/A' %]%[% END %]</td>
<td align="center">[% personal_completed FILTER html %][% IF personal_completed != 'N/A' %]%[% END %]</td>
<td align="center">[% community_completed FILTER html %][% IF community_completed != 'N/A' %]%[% END %]</td>
</tr>
[% END %]
</table>

Просмотреть файл

@ -44,13 +44,13 @@
<div class="sec_head">
<table width="100%">
<tr>
<td class="l">Testing Summary</td>
<td class="l">&raquo;&nbsp;Testing Configuration Summary</td>
<td class="r"><a href="#" onclick="divSWAP('sum'); return false;">Hide / Show Summary</a></td>
</tr>
</table>
</div>
<div id="sum" class="summary">
<div id="sum" class="summary" style="display: none;">
<table class="test-config">
<tr>