Added support for large numbers of objects using server push for processing huge queries and updates to avoid timeouts. Also added limits to queries but added support for user defined page size as a URL paramater.

This commit is contained in:
ghendricks%novell.com 2006-10-20 23:27:56 +00:00
Родитель 88e9f40af8
Коммит 9dcc69bd65
19 изменённых файлов: 483 добавлений и 89 удалений

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

@ -88,7 +88,9 @@ sub init {
my $page = $cgi->param('page') || 0;
detaint_natural($page) if $page;
$page = undef if ($cgi->param('viewall'));
my $pagesize = 25;
my $pagesize = $cgi->param('pagesize') if $cgi->param('pagesize');
detaint_natural($pagesize);
$pagesize ||= 25;
my @specialchart;
my @supptables;

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

@ -142,6 +142,7 @@ sub init {
push (@list, $o);
}
$self->{'list'} = \@list;
$self->{'view_count'} = scalar @list;
$self->{'id_list'} = join(",", @$count_res);
}
if ($cgi){
@ -349,6 +350,7 @@ sub get_next{
sub list { return $_[0]->{'list'}; }
sub id_list { return $_[0]->{'id_list'}; }
sub list_count { return $_[0]->{'list_count'}; }
sub view_count { return $_[0]->{'view_count'}; }
sub page { return $_[0]->{'page'}; }
sub url_loc { return $_[0]->{'url_loc'}; }

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

@ -434,6 +434,27 @@ sub get_product_components {
return $ref;
}
=head2 get_case_ids_by_category
Returns a list of case_ids in this plan from the selected categories.
=cut
sub get_case_ids_by_category {
my $self = shift;
my ($categories) = @_;
my $dbh = Bugzilla->dbh;
my $ref = $dbh->selectcol_arrayref(
"SELECT DISTINCT test_cases.case_id from test_cases
JOIN test_case_plans AS tcp ON tcp.case_id = test_cases.case_id
WHERE tcp.plan_id = ?
AND category_id in (". join(',',@$categories) . ")",
undef, $self->id);
return $ref;
}
=head2 get_plan_types
Returns a list of types from the test_plan_types table

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

@ -40,7 +40,7 @@ use base qw(Exporter);
can_view_product GetProducts
get_field_id get_time_stamp
validate_test_id validate_selection
validate_version);
validate_version support_server_push);
use Bugzilla;
use Bugzilla::Config;
@ -238,6 +238,19 @@ sub validate_version {
return $res;
}
sub support_server_push {
my ($cgi) = @_;
my $serverpush =
exists $ENV{'HTTP_USER_AGENT'}
&& $ENV{'HTTP_USER_AGENT'} =~ /Mozilla.[3-9]/
&& $ENV{'HTTP_USER_AGENT'} !~ /[Cc]ompatible/
&& $ENV{'HTTP_USER_AGENT'} !~ /WebKit/
&& !defined($cgi->param('serverpush'))
|| $cgi->param('serverpush');
return $serverpush;
}
=head1 AUTHOR
Greg Hendricks <ghendricks@novell.com>

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

@ -23,7 +23,7 @@
You are not authorized to view this [% object FILTER html %]
[% ELSIF error == "testopia-read-only" %]
[% title = "Insufficient Permissions" %]
You are not authorized to edit this [% object FILTER html %]
You are not authorized to edit [% object FILTER html %]&nbsp;[% id FILTER html %]
[% ELSIF error == "testopia-no-delete" %]
[% title = "Insufficient Permissions" %]
You are not authorized to delete this [% object FILTER html %]
@ -109,5 +109,13 @@
[% ELSIF error == "testopia-none-selected" %]
[% title = "Nothing Selected" %]
You did not select any [% object FILTER none %]s to change.
[% ELSIF error == "testopia-query-too-large" %]
This query returns more than [% limit FILTER none %] rows. <br>
Please do one of the following:
<ol>
<li>Try to narrow your search.</li>
<li>Try using the pagesize and page URL paramaters to limit your results.</li>
<li>Use the XML-RPC Interface.</li>
</ol>
[% END %]

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

@ -39,6 +39,7 @@
[% END %]
[% BLOCK navigation %]
[% SET MAX_LIMIT = 10000 %]
[% IF ajax %]
[% url = "javascript:page(" %]
[% pc = ")" %]
@ -101,15 +102,21 @@
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="button" onclick="jumpToPage(document.getElementById('jump').value)" value="Jump To Page">
<input id="jump" size="4">
[% IF ajax %]
&nbsp;Out of [% table.page_count %]
&nbsp;&nbsp;&nbsp;
[% IF ajax %]
<a href="[% url %]null,1[% pc %]">All</a>&nbsp;
[% ELSE %]
[% ELSE %]
[% IF table.list_count < MAX_LIMIT %]
<a href="[% url %]&viewall=1">All</a>&nbsp;
[% ELSE %]
<span style="color:gray">All</span>
[% END %]
[% END %]
</td>
[% IF table.page < table.page_count - 1 %]
<td><a href="[% url %][% table.page + 1 %][% pc %]">Next&nbsp;&gt;</a></td>
<td><a href="[% url %][% table.page_count - 1 %][% pc %]">Last&nbsp;&gt;&gt;</a></td>
<td><a href="[% url %][% table.page_count - 1 %][% pc %]" title="Jump to Page [% table.page_count %]">Last&nbsp;&gt;&gt;</a></td>
[% ELSE %]
<td>Next&nbsp;&gt;</td>
<td>Last&nbsp;&gt;&gt;</td>

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

@ -24,6 +24,13 @@
[% PROCESS testopia/blocks.html.tmpl %]
[% IF table.list_count > 0 %]
[%# More than this will cause your browser to get really slow
# So we won't show the action and effects %]
[% SET MAX_LIMIT = 1000 %]
[% IF table.view_count >= MAX_LIMIT %]
<p><b>This list is too big to display quickly. Action and Effect will not be included.</b></p>
[% END %]
<a href="javascript:coal()">Collapse All</a>
<a href="javascript:exal()">Expand All</a>
[% IF dotweak %]
@ -58,14 +65,14 @@ Select:
<th align="left"><a href="[% link %]priority[% paren %]">Priority[% table.arrow IF table.last_sort == 'priority' %]</a></th>
<th align="left"><a href="[% link %]case_status[% paren %]">Status[% table.arrow IF table.last_sort == 'status' %]</a></th>
</tr>
[% FOREACH case = table.list %]
[% FOREACH case = table.list %]
[% index = loop.count %]
<tr id="trr[% index FILTER none %]" class="[% loop.count % 2 == 0 ? "bz_row_odd" : "bz_row_even" %]" onclick="sr([% loop.count %]);" style="cursor:pointer;">
<tr id="trr[% index FILTER none %]" class="[% loop.count % 2 == 0 ? "bz_row_odd" : "bz_row_even" %]" [% IF loop.size < MAX_LIMIT %]onclick="sr([% loop.count %]);" style="cursor:pointer;"[% END %]>
<td class="cc_trg" valign="top" width="24">
<table style="border-spacing:0px;border-collapse:collapse;" width="24">
<tr>
<td style="padding:0;border-width:0;">[% IF dotweak %]<input type="checkbox" id="c_[% case.id FILTER none %]" name="c_[% case.id FILTER none %]" onclick="[% IF canedit %]ck(this);[% ELSE %]_disable_sr=true;[% END %]">[% END %]</td>
<td style="padding:0;border-width:0;"><img id="id[% index FILTER none %]" src="testopia/img/tr.gif" width="11" height="11"></td>
<td style="padding:0;border-width:0;">[% IF loop.size < MAX_LIMIT %]<img id="id[% index FILTER none %]" src="testopia/img/tr.gif" width="11" height="11">[% END %]</td>
</tr>
</table>
</td>
@ -81,7 +88,7 @@ Select:
<td align="left" valign="top">[% case.priority FILTER html %]</td>
<td align="left" valign="top"><span id="sta[% case.status %]">[% case.status %]</span></td>
</tr>
[% IF loop.size < MAX_LIMIT %]
<tr class="[% loop.count % 2 == 0 ? "bz_row_odd" : "bz_row_even" %]">
<td></td>
<td colspan="10" style="margin:0px;padding:0px;">
@ -122,7 +129,8 @@ Select:
</div>
</td>
</tr>
[% END %]
[% END %]
[% END %]
</table>
[% IF NOT table.viewall %]
[% PROCESS navigation %]

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

@ -227,6 +227,7 @@
[% PROCESS testopia/case/table.html.tmpl
table = case_table %]
<a href="tr_new_case.cgi?plan_id=[% plan.id FILTER none %]">Create a New Test Case</a>
<a href="tr_list_cases.cgi?plan_id=[% plan.id FILTER none %]">List Cases</a>
</div>
[%##### Test Runs #####%]
@ -239,6 +240,7 @@
[% PROCESS testopia/run/table.html.tmpl
table = run_table %]
<a href="tr_new_run.cgi?plan_id=[% plan.id FILTER none %]&case_status_id=2">Create a New Test Run</a>
<a href="tr_list_runs.cgi?plan_id=[% plan.id FILTER none %]&case_status_id=2">List Runs</a>
</div>
[%##### Attachments #####%]
<br><br>

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

@ -0,0 +1,44 @@
[%# 1.0@bugzilla.org %]
[%# 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 the Bugzilla Test Runner System.
#
# The Initial Developer of the Original Code is Maciej Maczynski.
# Portions created by Maciej Maczynski are Copyright (C) 2001
# Maciej Maczynski. All Rights Reserved.
#
# Contributor(s): Ed Fuentetaja <efuentetaja@acm.org>
# Greg Hendricks <ghendricks@novell.com>
#%]
[%# INTERFACE:
# complete: The number processed up till now
# total: The total number to process
#%]
[% SET percent = ((complete / total) * 100) %]
<html>
<head>
<title>Processing</title>
</head>
<body>
<h1 style="margin-top: 20%; text-align: center;">Processing...</h1>
<table align="center"><tr><td>
<span style="width:302px;text-align: center;" >
<span style="float:left;width:1px;height:25px;background-color:black;"></span>
<span style="float:left;"><img src="testopia/img/pb.gif" style="width:[% percent * 3 %]px;height:25px;padding:0px;margin:0px;border-width:0px;"/></span>
<span style="float:left;"><img src="testopia/img/pg.gif" style="width:[% 300 - percent * 3 %]px;height:25px;"/></span>
<span style="float:left;width:1px;height:25px;background-color:black;"></span>
</span></td></tr>
</table>
</body>
</html>

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

@ -41,8 +41,15 @@
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/messages.html.tmpl %]
[%# More than this will cause your browser to get really slow
# So we won't show the action and effects %]
[% SET MAX_LIMIT = 500 %]
<script src="testopia/js/util.js" type="text/javascript"></script>
[% IF table.view_count < MAX_LIMIT %]
<script src="testopia/dojo/dojo.js" type="text/javascript"></script>
[% END %]
<form id="table" action="tr_list_runs.cgi" method="POST">
[% PROCESS testopia/run/table.html.tmpl %]

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

@ -38,6 +38,7 @@ require 'globals.pl';
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $query_limit = 15000;
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
@ -45,7 +46,20 @@ $cgi->send_cookie(-name => "TEST_LAST_ORDER",
-value => $cgi->param('order'),
-expires => "Fri, 01-Jan-2038 00:00:00 GMT");
Bugzilla->login();
print $cgi->header;
my $serverpush = support_server_push($cgi);
if ($serverpush) {
print $cgi->multipart_init;
print $cgi->multipart_start;
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
else {
print $cgi->header;
}
# prevent DOS attacks from multiple refreshes of large data
$::SIG{TERM} = 'DEFAULT';
$::SIG{PIPE} = 'DEFAULT';
my $action = $cgi->param('action') || '';
@ -54,20 +68,35 @@ if ($action eq 'Commit'){
# Get the list of checked items. This way we don't have to cycle through
# every test case, only the ones that are checked.
my $reg = qr/r_([\d]+)/;
my @caseruns;
foreach my $p ($cgi->param()){
push @caseruns, Bugzilla::Testopia::TestCaseRun->new($1) if $p =~ $reg;
}
ThrowUserError('testopia-none-selected', {'object' => 'case-run'}) if (scalar @caseruns < 1);
my $params = join(" ", $cgi->param());
my @params = $cgi->param();
my @buglist;
ThrowUserError('testopia-none-selected', {'object' => 'case-run'}) unless $params =~ $reg;
foreach my $bug (split(/[\s,]+/, $cgi->param('bugs'))){
ValidateBugID($bug);
push @buglist, $bug;
}
foreach my $caserun (@caseruns){
ThrowUserError("testopia-read-only", {'object' => 'Case Run'}) unless $caserun->canedit;
my $progress_interval = 250;
my $i = 0;
my $total = scalar @params;
foreach my $p ($cgi->param()){
my $caserun = Bugzilla::Testopia::TestCaseRun->new($1) if $p =~ $reg;
next unless $caserun;
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
ThrowUserError("testopia-read-only", {'object' => 'Case Run', 'id' => $caserun->id}) unless $caserun->canedit;
my $status = $cgi->param('status') == -1 ? $caserun->status_id : $cgi->param('status');
my $build = $cgi->param('caserun_build') == -1 ? $caserun->build->id : $cgi->param('caserun_build');
my $assignee = $cgi->param('assignee') eq '--Do Not Change--' ? $caserun->assignee->id : DBNameToIdAndCheck(trim($cgi->param('assignee')));
@ -104,8 +133,11 @@ if ($action eq 'Commit'){
$caserun->append_note($notes);
}
$vars->{'title'} = "Update Successful";
$vars->{'tr_message'} = scalar @caseruns . ' Test Case-Runs Updated';
$vars->{'tr_message'} = "$i Test Case-Runs Updated";
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
if ($cgi->param('run_id')){
my $run_id = $cgi->param('run_id');
my $run = Bugzilla::Testopia::TestRun->new($run_id);
@ -130,6 +162,7 @@ if ($action eq 'Commit'){
$template->process("testopia/search/advanced.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
}
print $cgi->multipart_final if $serverpush;
exit;
}
elsif ($action eq 'Delete Selected'){
@ -141,6 +174,10 @@ elsif ($action eq 'Delete Selected'){
ThrowUserError("testopia-read-only", {'object' => 'case run'}) if ($caserun && !$caserun->candelete);
push @caseruns, $caserun if $caserun;
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
ThrowUserError('testopia-none-selected', {'object' => 'case-run'}) if (scalar @caseruns < 1);
$vars->{'caseruns'} = \@caseruns;
$vars->{'caseruncount'} = scalar @caseruns;
@ -149,6 +186,7 @@ elsif ($action eq 'Delete Selected'){
$vars->{'run_id'} = $cgi->param('run_id');
$template->process("testopia/caserun/delete.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
exit;
}
elsif ($action eq 'do_delete'){
@ -159,13 +197,30 @@ elsif ($action eq 'do_delete'){
push @caseruns, $caserun;
ThrowUserError("testopia-read-only", {'object' => 'case run'}) if !$caserun->candelete;
}
my $progress_interval = 250;
my $i = 0;
my $total = scalar @caseruns;
foreach my $c (@caseruns){
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
$c->obliterate;
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
$vars->{'deleted'} = 1;
$vars->{'run_id'} = $cgi->param('run_id');
$template->process("testopia/caserun/delete.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
exit;
}
@ -173,6 +228,7 @@ elsif ($action eq 'do_delete'){
$cgi->param('current_tab', 'case_run');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case_run', 'tr_list_caseruns.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
if ($table->list_count > 0){
my $prod_id = $table->list->[0]->run->plan->product_id;
@ -198,6 +254,10 @@ $vars->{'component_list'} = $case->get_available_components();
$vars->{'dotweak'} = UserInGroup('edittestcases');
$vars->{'table'} = $table;
$vars->{'action'} = 'tr_list_caserun.cgi';
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
$template->process("testopia/caserun/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;

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

@ -40,6 +40,7 @@ require "globals.pl";
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $query_limit = 10000;
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
@ -47,21 +48,56 @@ $cgi->send_cookie(-name => "TEST_LAST_ORDER",
-value => $cgi->param('order'),
-expires => "Fri, 01-Jan-2038 00:00:00 GMT");
Bugzilla->login();
print $cgi->header;
my $action = $cgi->param('action') || '';
my $action = $cgi->param('action') || '';
my $serverpush = support_server_push($cgi);
if ($serverpush) {
print $cgi->multipart_init;
print $cgi->multipart_start;
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
else {
print $cgi->header;
}
# prevent DOS attacks from multiple refreshes of large data
$::SIG{TERM} = 'DEFAULT';
$::SIG{PIPE} = 'DEFAULT';
###############
### Actions ###
###############
if ($action eq 'Commit'){
Bugzilla->login(LOGIN_REQUIRED);
# Get the list of checked items. This way we don't have to cycle through
# every test case, only the ones that are checked.
# Match the list of checked items.
my $reg = qr/c_([\d]+)/;
my @cases;
my $params = join(" ", $cgi->param());
my @params = $cgi->param();
ThrowUserError('testopia-none-selected', {'object' => 'case'}) unless $params =~ $reg;
my $progress_interval = 250;
my $i = 0;
my $total = scalar @params;
foreach my $p ($cgi->param()){
push @cases, Bugzilla::Testopia::TestCase->new($1) if $p =~ $reg;
}
ThrowUserError('testopia-none-selected', {'object' => 'case'}) if (scalar @cases < 1);
foreach my $case (@cases){
ThowUserError('insufficient-perms') unless $case->canedit;
my $case = Bugzilla::Testopia::TestCase->new($1) if $p =~ $reg;
next unless $case;
ThrowUserError("testopia-read-only", {'object' => 'case', 'id' => $case->id}) unless $case->canedit;
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
my $requirement = $cgi->param('requirement') eq '--Do Not Change--' ? $case->requirement : $cgi->param('requirement');
my $arguments = $cgi->param('arguments') eq '--Do Not Change--' ? $case->arguments : $cgi->param('requirement');
my $script = $cgi->param('script') eq '--Do Not Change--' ? $case->script : $cgi->param('requirement');
@ -121,6 +157,10 @@ if ($action eq 'Commit'){
$case->link_plan($planid);
}
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
my @runlist = split(/[\s,]+/, $cgi->param('addruns'));
if (scalar @runlist == 1){
my $run_id = $cgi->param('addruns');
@ -146,17 +186,20 @@ if ($action eq 'Commit'){
my $case = Bugzilla::Testopia::TestCase->new({ 'case_id' => 0 });
$vars->{'case'} = $case;
$vars->{'title'} = "Update Successful";
$vars->{'tr_message'} = scalar @cases . " Test Cases Updated";
$vars->{'tr_message'} = "$i Test Cases Updated";
$vars->{'current_tab'} = 'case';
$template->process("testopia/search/advanced.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
exit;
}
}
# Take the search from the URL params and convert it to SQL
$cgi->param('current_tab', 'case');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case', 'tr_list_cases.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
# Check that all of the test cases returned only belong to one product.
if ($table->list_count > 0){
@ -210,7 +253,11 @@ $vars->{'status_list'} = $status_list;
$vars->{'priority_list'} = $priority_list;
$vars->{'dotweak'} = UserInGroup('edittestcases');
$vars->{'table'} = $table;
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
$template->process("testopia/case/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;

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

@ -37,9 +37,23 @@ require "globals.pl";
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $query_limit = 5000;
Bugzilla->login();
print $cgi->header;
my $serverpush = support_server_push($cgi);
if ($serverpush) {
print $cgi->multipart_init;
print $cgi->multipart_start;
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
else {
print $cgi->header;
}
# prevent DOS attacks from multiple refreshes of large data
$::SIG{TERM} = 'DEFAULT';
$::SIG{PIPE} = 'DEFAULT';
my $action = $cgi->param('action') || '';
if ($action eq 'Commit'){
@ -47,13 +61,30 @@ if ($action eq 'Commit'){
# Get the list of checked items. This way we don't have to cycle through
# every test case, only the ones that are checked.
my $reg = qr/p_([\d]+)/;
my @plans;
my $params = join(" ", $cgi->param());
my @params = $cgi->param();
ThrowUserError('testopia-none-selected', {'object' => 'plan'}) unless $params =~ $reg;
my $progress_interval = 250;
my $i = 0;
my $total = scalar @params;
foreach my $p ($cgi->param()){
push @plans, Bugzilla::Testopia::TestPlan->new($1) if $p =~ $reg;
}
ThrowUserError('testopia-none-selected', {'object' => 'plan'}) if (scalar @plans < 1);
foreach my $plan (@plans){
ThowUserError('insufficient-perms') unless $plan->canedit;
my $plan = Bugzilla::Testopia::TestPlan->new($1) if $p =~ $reg;
next unless $plan;
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
ThrowUserError("testopia-read-only", {'object' => 'plan', 'id' => $plan->id}) unless $plan->canedit;
my $plan_type = $cgi->param('plan_type') == -1 ? $plan->type_id : $cgi->param('plan_type');
my $product = $cgi->param('product_id') == -1 ? $plan->product_id : $cgi->param('product_id');
my $prodver = $cgi->param('prod_version') == -1 ? $plan->product_version : $cgi->param('prod_version');
@ -80,20 +111,26 @@ if ($action eq 'Commit'){
}
}
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
my $plan = Bugzilla::Testopia::TestPlan->new({ 'plan_id' => 0 });
$vars->{'plan'} = $plan;
$vars->{'title'} = "Update Successful";
$vars->{'tr_message'} = scalar @plans . " Test Plan(s) Updated";
$vars->{'tr_message'} = "$i Test Plan(s) Updated";
$vars->{'current_tab'} = 'plan';
$template->process("testopia/search/advanced.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
exit;
}
else {
$cgi->param('current_tab', 'plan');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('plan', 'tr_list_plans.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
my $p = Bugzilla::Testopia::TestPlan->new({'plan_id' => 0 });
my $product_list = $p->get_available_products;
@ -110,7 +147,11 @@ else {
$vars->{'fullwidth'} = 1; #novellonly
$vars->{'dotweak'} = UserInGroup('managetestplans');
$vars->{'table'} = $table;
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
$template->process("testopia/plan/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
}

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

@ -38,9 +38,23 @@ require "globals.pl";
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
my $template = Bugzilla->template;
my $query_limit = 5000;
Bugzilla->login();
print $cgi->header;
my $serverpush = support_server_push($cgi);
if ($serverpush) {
print $cgi->multipart_init;
print $cgi->multipart_start;
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
else {
print $cgi->header;
}
# prevent DOS attacks from multiple refreshes of large data
$::SIG{TERM} = 'DEFAULT';
$::SIG{PIPE} = 'DEFAULT';
my $action = $cgi->param('action') || '';
if ($action eq 'Commit'){
@ -48,14 +62,31 @@ if ($action eq 'Commit'){
# Get the list of checked items. This way we don't have to cycle through
# every test case, only the ones that are checked.
my $reg = qr/r_([\d]+)/;
my @runs;
foreach my $r ($cgi->param()){
push @runs, Bugzilla::Testopia::TestRun->new($1) if $r =~ $reg;
}
ThrowUserError('testopia-none-selected', {'object' => 'run'}) if (scalar @runs < 1);
my $params = join(" ", $cgi->param());
my @params = $cgi->param();
ThrowUserError('testopia-none-selected', {'object' => 'run'}) unless $params =~ $reg;
ThrowUserError('testopia-missing-required-field', {'field' => 'environment'}) if ($cgi->param('environment') eq '');
foreach my $run (@runs){
ThowUserError('insufficient-perms') unless $run->canedit;
my $progress_interval = 250;
my $i = 0;
my $total = scalar @params;
foreach my $p ($cgi->param()){
my $run = Bugzilla::Testopia::TestRun->new($1) if $p =~ $reg;
next unless $run;
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
ThrowUserError("testopia-read-only", {'object' => 'run', 'id' => $run->id}) unless $run->canedit;
my $manager = DBNameToIdAndCheck(trim($cgi->param('manager'))) if $cgi->param('manager');
my $status;
if ($cgi->param('run_status')){
@ -89,21 +120,28 @@ if ($action eq 'Commit'){
}
}
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
my $run = Bugzilla::Testopia::TestRun->new({ 'run_id' => 0 });
$vars->{'run'} = $run;
$vars->{'title'} = "Update Successful";
$vars->{'tr_message'} = scalar @runs . " Test Runs Updated";
$vars->{'tr_message'} = "$i Test Runs Updated";
$vars->{'current_tab'} = 'run';
$vars->{'build_list'} = $run->get_distinct_builds();
$template->process("testopia/search/advanced.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
exit;
}
else {
$cgi->param('current_tab', 'run');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('run', 'tr_list_runs.cgi', $cgi, undef, $search->query);
my $table = Bugzilla::Testopia::Table->new('run', 'tr_list_runs.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
if ($table->list_count > 0){
my $plan_id = $table->list->[0]->plan->product_id;
foreach my $run (@{$table->list}){
@ -131,7 +169,11 @@ else {
$vars->{'fullwidth'} = 1; #novellonly
$vars->{'dotweak'} = UserInGroup('runtests');
$vars->{'table'} = $table;
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
}
$template->process("testopia/run/list.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
}

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

@ -36,21 +36,24 @@ require "globals.pl";
use vars qw($template $vars);
my $template = Bugzilla->template;
my $query_limit = 10000;
Bugzilla->login(LOGIN_REQUIRED);
ThrowUserError("testopia-create-denied", {'object' => 'Test Run'}) unless UserInGroup('edittestcases');
print Bugzilla->cgi->header();
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
unless (UserInGroup('edittestcases')){
print $cgi->header;
ThrowUserError("testopia-create-denied", {'object' => 'Test Run'});
}
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
my $action = $cgi->param('action') || '';
my $plan_id = $cgi->param('plan_id');
unless ($plan_id){
$vars->{'form_action'} = 'tr_new_run.cgi';
print $cgi->header;
$template->process("testopia/plan/choose.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
exit;
@ -59,11 +62,22 @@ unless ($plan_id){
detaint_natural($plan_id);
validate_test_id($plan_id, 'plan');
ThrowUserError("testopia-missing-parameter", {'param' => 'plan_id'}) unless ($plan_id);
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
ThrowUserError('testopia-create-build', {'plan' => $plan}) unless (scalar @{$plan->builds} >0);
unless (scalar @{$plan->builds} >0){
print $cgi->header;
ThrowUserError('testopia-create-build', {'plan' => $plan});
}
if ($action eq 'Add'){
my $serverpush = support_server_push($cgi);
if ($serverpush) {
print $cgi->multipart_init;
print $cgi->multipart_start;
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
my $manager = DBNameToIdAndCheck($cgi->param('manager'));
my $status = $cgi->param('status');
my $prodver = $cgi->param('product_version');
@ -121,23 +135,43 @@ if ($action eq 'Add'){
});
my $run_id = $run->store;
$run = Bugzilla::Testopia::TestRun->new($run_id);
foreach my $case_id (@c){
my $progress_interval = 250;
my $i = 0;
my $total = scalar @c;
foreach my $case_id (@c){
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
$run->add_case_run($case_id);
}
# clear the params so we don't confuse search.
$cgi->delete_all;
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
} else {
print $cgi->header;
}
$cgi->param('current_tab', 'case_run');
$cgi->param('run_id', $run_id);
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case_run', 'tr_show_run.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
$vars->{'run'} = $run;
$vars->{'table'} = $table;
$vars->{'action'} = 'Commit';
$vars->{'form_action'} = 'tr_show_run.cgi';
$template->process("testopia/run/show.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
print $cgi->multipart_final if $serverpush;
}
@ -160,6 +194,7 @@ else {
'plan' => $plan,
'plan_text_version' => $plan->version } );
ThrowUserError('testopia-create-environment') unless (scalar @{$run->environments} > 0);
print $cgi->header;
$vars->{'run'} = $run;
$template->process("testopia/run/add.html.tmpl", $vars) ||
ThrowTemplateError($template->error());

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

@ -37,7 +37,7 @@ use Bugzilla::Testopia::Table;
use vars qw($template $vars);
my $template = Bugzilla->template;
my $query_limit = 15000;
require "globals.pl";
Bugzilla->login();
@ -392,6 +392,7 @@ sub display {
$cgi->param('current_tab', 'case_run');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case_run', 'tr_show_case.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
$vars->{'case'} = $case;
$vars->{'table'} = $table;
$template->process("testopia/case/show.html.tmpl", $vars) ||

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

@ -36,7 +36,7 @@ use Bugzilla::Testopia::TestCaseRun;
use vars qw($template $vars);
my $template = Bugzilla->template;
my $query_limit = 15000;
# These are going away after 2.22
require "globals.pl";
@ -159,6 +159,7 @@ elsif ($action eq 'do_delete'){
$cgi->param('run_id', $caserun->run->id);
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case_run', 'tr_show_run.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
my @case_list;
foreach my $cr (@{$table->list}){
@ -329,6 +330,7 @@ sub display {
my $caserun = shift;
ThrowUserError('insufficient-view-perms') if !$caserun->canview;
my $table = Bugzilla::Testopia::Table->new('case_run');
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
$vars->{'table'} = $table;
$vars->{'caserun'} = $caserun;
$vars->{'action'} = 'tr_show_caserun.cgi';

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

@ -42,10 +42,11 @@ require "globals.pl";
use vars qw($template $vars);
my $template = Bugzilla->template;
my $run_query_limit = 5000;
my $case_query_limit = 10000;
Bugzilla->login();
print Bugzilla->cgi->header();
my $dbh = Bugzilla->dbh;
my $cgi = Bugzilla->cgi;
@ -53,6 +54,7 @@ my $plan_id = trim(Bugzilla->cgi->param('plan_id') || '');
unless ($plan_id){
$vars->{'form_action'} = 'tr_show_plan.cgi';
print $cgi->header;
$template->process("testopia/plan/choose.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
exit;
@ -60,6 +62,8 @@ unless ($plan_id){
validate_test_id($plan_id, 'plan');
push @{$::vars->{'style_urls'}}, 'testopia/css/default.css';
my $serverpush = support_server_push($cgi);
my $action = $cgi->param('action') || '';
$vars->{'action'} = "Commit";
$vars->{'form_action'} = "tr_show_plan.cgi";
@ -78,6 +82,7 @@ if ($action eq 'Archive' || $action eq 'Unarchive'){
$plan->toggle_archive(Bugzilla->user->id);
$vars->{'tr_message'} =
$plan->isactive == 0 ? "Plan archived":"Plan Unarchived";
print $cgi->header;
display($plan);
}
@ -90,6 +95,7 @@ elsif ($action eq 'Clone'){
ThrowUserError("testopia-read-only", {'object' => 'plan'}) unless $plan->canedit;
do_update($plan);
$vars->{'plan'} = $plan;
print $cgi->header;
$template->process("testopia/plan/clone.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@ -99,6 +105,14 @@ elsif ($action eq 'do_clone'){
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
ThrowUserError("testopia-read-only", {'object' => 'plan'}) unless $plan->canedit;
my $plan_name = $cgi->param('plan_name');
if ($serverpush) {
print $cgi->multipart_init();
print $cgi->multipart_start();
$template->process("list/server-push.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
# All DB actions use place holders so we are OK doing this
trick_taint($plan_name);
@ -114,28 +128,49 @@ elsif ($action eq 'do_clone'){
}
}
if ($cgi->param('copy_cases')){
my @caseids;
my @catids;
#TODO: Copy case to the new category
foreach my $id ($cgi->param('clone_categories')){
my $cat = Bugzilla::Testopia::Category->new($id);
push @caseids, @{$cat->case_ids};
detaint_natural($id);
validate_selection($id,'category_id','test_case_categories');
push @catids, $id;
}
foreach my $case (@{$plan->test_cases}){
if (lsearch(\@caseids, $case->category->id)){
if ($cgi->param('copy_cases') == 2 ){
my $caseid = $case->copy($newplan->id, 1);
$case->link_plan($newplan->id, $caseid);
}
else {
$case->link_plan($newplan->id);
}
my $caseids_ref = $plan->get_case_ids_by_category(\@catids);
my $progress_interval = 250;
my $i = 0;
my $total = scalar @$caseids_ref;
foreach my $id (@$caseids_ref){
$i++;
if ($i % $progress_interval == 0 && $serverpush){
print $cgi->multipart_end;
print $cgi->multipart_start;
$vars->{'complete'} = $i;
$vars->{'total'} = $total;
$template->process("testopia/progress.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
my $case = Bugzilla::Testopia::TestCase->new($id);
if ($cgi->param('copy_cases') == 2 ){
my $caseid = $case->copy($newplan->id, 1);
$case->link_plan($newplan->id, $caseid);
}
else {
$case->link_plan($newplan->id);
}
}
}
if ($serverpush) {
print $cgi->multipart_end;
print $cgi->multipart_start;
} else {
print $cgi->header;
}
$vars->{'tr_message'} = "Plan ". $plan->name ." cloned as " . $newplan->name .".";
$cgi->param('plan_id', $newplan->id);
display($newplan);
display($newplan);
print $cgi->multipart_final if $serverpush;
}
### Changes to Plan Attributes or Doc ###
@ -145,13 +180,15 @@ elsif ($action eq 'Commit'){
ThrowUserError("testopia-read-only", {'object' => 'plan'}) unless $plan->canedit;
do_update($plan);
$vars->{'tr_message'} = "Test plan updated";
print $cgi->header;
display($plan);
}
elsif ($action eq 'Print'){
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
ThrowUserError("testopia-permission-denied", {'object' => 'plan'}) unless $plan->canview;
$vars->{'plan'} = $plan;
$vars->{'plan'} = $plan;
print $cgi->header;
$template->process("testopia/plan/show-document.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
}
@ -163,6 +200,7 @@ elsif ($action eq 'History'){
$vars->{'diff'} = $plan->diff_plan_doc($cgi->param('new'),$cgi->param('old'));
$vars->{'new'} = $cgi->param('new');
$vars->{'old'} = $cgi->param('old');
print $cgi->header;
$template->process("testopia/plan/history.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@ -203,6 +241,7 @@ elsif ($action eq 'Attach'){
$vars->{'tr_message'} = "Attachment added successfully";
do_update($plan);
print $cgi->header;
display(Bugzilla::Testopia::TestPlan->new($plan_id));
}
#TODO: Import plans
@ -214,6 +253,7 @@ elsif ($action eq 'Delete'){
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
ThrowUserError("testopia-read-only", {'object' => 'plan'}) unless $plan->candelete;
$vars->{'plan'} = $plan;
print $cgi->header;
$template->process("testopia/plan/delete.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
@ -224,6 +264,7 @@ elsif ($action eq 'do_delete'){
ThrowUserError("testopia-read-only", {'object' => 'plan'}) unless $plan->candelete;
$plan->obliterate;
$vars->{'deleted'} = 1;
print $cgi->header;
$template->process("testopia/plan/delete.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
}
@ -255,6 +296,7 @@ elsif ($action eq 'caselist'){
my $table = Bugzilla::Testopia::Table->new('case', 'tr_list_cases.cgi', $cgi, $plan->test_cases);
$table->{'ajax'} = 1;
$vars->{'table'} = $table;
print $cgi->header;
$template->process("testopia/case/table.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
@ -265,6 +307,7 @@ elsif ($action eq 'caselist'){
else{
my $plan = Bugzilla::Testopia::TestPlan->new($plan_id);
ThrowUserError("testopia-permission-denied", {'object' => 'plan'}) unless $plan->canview;
print $cgi->header;
display($plan);
}
###################
@ -335,28 +378,32 @@ sub display {
if (($cgi->param('order') || $cgi->param('page') || $cgi->param('viewall')) && $cgi->param('current_tab') eq 'case'){
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case', 'tr_show_plan.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $case_query_limit}) if $table->list_count > $case_query_limit;
$vars->{'case_table'} = $table;
$runquery->delete('order');
$runquery->delete('page');
$runquery->delete('viewall');
$runquery->param('current_tab', 'run');
$search = Bugzilla::Testopia::Search->new($runquery);
$table = Bugzilla::Testopia::Table->new('run', 'tr_show_plan.cgi', $runquery, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $run_query_limit}) if $table->list_count > $run_query_limit;
$vars->{'run_table'} = $table;
}
elsif (($cgi->param('order') || $cgi->param('page') || $cgi->param('viewall')) && $cgi->param('current_tab') eq 'run'){
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('run', 'tr_show_plan.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $run_query_limit}) if $table->list_count > $run_query_limit;
$vars->{'run_table'} = $table;
$casequery->delete('order');
$casequery->delete('page');
$casequery->delete('viewall');
$casequery->param('current_tab', 'case');
$search = Bugzilla::Testopia::Search->new($casequery);
$table = Bugzilla::Testopia::Table->new('case', 'tr_show_plan.cgi', $casequery, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $case_query_limit}) if $table->list_count > $case_query_limit;
$vars->{'case_table'} = $table;
}
else {
@ -364,11 +411,13 @@ sub display {
$casequery->param('current_tab', 'case');
my $search = Bugzilla::Testopia::Search->new($casequery);
my $table = Bugzilla::Testopia::Table->new('case', 'tr_show_plan.cgi', $casequery, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $case_query_limit}) if $table->list_count > $case_query_limit;
$vars->{'case_table'} = $table;
$runquery->param('current_tab', 'run');
$search = Bugzilla::Testopia::Search->new($runquery);
$table = Bugzilla::Testopia::Table->new('run', 'tr_show_plan.cgi', $runquery, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $run_query_limit}) if $table->list_count > $run_query_limit;
$vars->{'run_table'} = $table;
}
@ -379,6 +428,7 @@ sub display {
push @dojo_search, "plandoc";
$vars->{'dojo_search'} = objToJson(\@dojo_search);
$vars->{'plan'} = $plan;
$template->process("testopia/plan/show.html.tmpl", $vars) ||
ThrowTemplateError($template->error());
}

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

@ -36,6 +36,7 @@ use Bugzilla::Testopia::Table;
use vars qw($template $vars);
my $template = Bugzilla->template;
my $query_limit = 15000;
require "globals.pl";
@ -294,6 +295,7 @@ sub display {
$cgi->param('current_tab', 'case_run');
my $search = Bugzilla::Testopia::Search->new($cgi);
my $table = Bugzilla::Testopia::Table->new('case_run', 'tr_show_run.cgi', $cgi, undef, $search->query);
ThrowUserError('testopia-query-too-large', {'limit' => $query_limit}) if $table->list_count > $query_limit;
my @case_list;
foreach my $caserun (@{$table->list}){