Synching with revision 2385

This commit is contained in:
ghendricks%novell.com 2006-11-15 21:30:13 +00:00
parent 832773b5d1
commit 4465812575
25 changed files with 664 additions and 449 deletions

View File

@ -310,8 +310,8 @@ safe way to do this.
sub obliterate {
my $self = shift;
my $dbh = Bugzilla->dbh;
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_attachment_data
WHERE attachment_id = ?", undef, $self->{'attachment_id'});
@ -359,8 +359,10 @@ Returns true if the logged in user has rights to delete this attachment
sub candelete {
my $self = shift;
return $self->canedit && Param("allow-test-deletion")
&& (Bugzilla->user->id == $self->submitter->id || Bugzilla->user->in_group('admin'));
return 0 unless $self->canedit && Param("allow-test-deletion");
return 1 if Bugzilla->user->in_group("admin");
return 1 if Bugzilla->user->id == $self->submitter->id;
return 0;
}
###############################

View File

@ -174,6 +174,23 @@ sub check_name {
return $is;
}
=head2 check_build_by_name
Returns id of a build of the specified name
=cut
sub check_build_by_name {
my $self = shift;
my ($name) = @_;
my $dbh = Bugzilla->dbh;
my $id = $dbh->selectrow_array(
"SELECT build_id FROM test_builds
WHERE name = ?", undef, $name);
return $id;
}
=head2 update
Updates an existing build object in the database.

View File

@ -574,15 +574,14 @@ sub obliterate {
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_environment_map WHERE environment_id = ?", undef, $self->id);
foreach my $obj (@{$self->runs}){
$obj->obliterate;
}
foreach my $obj (@{$self->caseruns}){
$obj->obliterate;
}
$dbh->do("DELETE FROM test_environment_map WHERE environment_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_environments WHERE environment_id = ?", undef, $self->id);
return 1;
}
@ -678,9 +677,9 @@ Returns true if the logged in user has rights to delete this environment.
sub candelete {
my $self = shift;
return (UserInGroup('managetestplans')
|| UserInGroup('edittestcases'))
&& Param('allow-test-deletion');
return 0 unless $self->canedit && Param("allow-test-deletion");
return 1 if Bugzilla->user->in_group("admin");
return 0;
}
###############################

View File

@ -202,7 +202,7 @@ sub init {
my $dbh = Bugzilla->switch_to_shadow_db;
my $search = Bugzilla::Testopia::Search->new($cgi, \@selectnames);
my $results = $dbh->selectall_arrayref($search->query);
Bugzilla->switch_to_main_db;
$dbh = Bugzilla->switch_to_main_db;
# We have a hash of hashes for the data itself, and a hash to hold the
# row/col/table names.
@ -365,4 +365,4 @@ sub switchbase {
return $self->{'switchbase'};
}
1;
1;

View File

@ -99,7 +99,6 @@ Private constructor for this class
sub init {
my $self = shift;
my ($type, $url, $cgi, $list, $query) = @_;
my $dbh = Bugzilla->dbh;
$self->{'user'} = Bugzilla->user;
$self->{'type'} = $type || ThrowCodeError('bad_arg',
{argument => 'type',
@ -115,12 +114,14 @@ sub init {
my $countquery = $query;
$countquery =~ s/ LIMIT.*$//;
print "<br> $countquery" if $debug;
my $dbh = Bugzilla->switch_to_shadow_db();
my $count_res = $dbh->selectcol_arrayref($countquery);
my $count = scalar @$count_res;
print "<br> total rows: $count" if $debug;
$self->{'list_count'} = $count;
my @ids;
my $list = $dbh->selectcol_arrayref($query);
$dbh = Bugzilla->switch_to_main_db();
foreach my $id (@$list){
my $o;
if ($type eq 'case'){

View File

@ -573,17 +573,19 @@ sub compare_doc_versions {
detaint_natural($oldversion);
my $dbh = Bugzilla->dbh;
my %diff;
my ($newaction, $neweffect) = $dbh->selectrow_array(
"SELECT action, effect FROM test_case_texts
my ($newaction, $neweffect, $newsetup, $newbreakdown) = $dbh->selectrow_array(
"SELECT action, effect, setup, breakdown FROM test_case_texts
WHERE case_id = ? AND case_text_version = ?",
undef, $self->{'case_id'}, $newversion);
my ($oldaction, $oldeffect) = $dbh->selectrow_array(
"SELECT action, effect FROM test_case_texts
my ($oldaction, $oldeffect, $oldsetup, $oldbreakdown) = $dbh->selectrow_array(
"SELECT action, effect, setup, breakdown FROM test_case_texts
WHERE case_id = ? AND case_text_version = ?",
undef, $self->{'case_id'}, $oldversion);
$diff{'action'} = diff(\$newaction, \$oldaction);
$diff{'effect'} = diff(\$neweffect, \$oldeffect);
$diff{'setup'} = diff(\$newsetup, \$oldsetup);
$diff{'breakdown'} = diff(\$newbreakdown, \$oldbreakdown);
return \%diff;
}
@ -1281,22 +1283,21 @@ sub obliterate {
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_case_texts WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_plans WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_components WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_tags WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_bugs WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_activity WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_dependencies
WHERE dependson = ? OR blocked = ?", undef, ($self->id, $self->id));
foreach my $obj (@{$self->attachments}){
$obj->obliterate;
}
foreach my $obj (@{$self->caseruns}){
$obj->obliterate;
}
$dbh->do("DELETE FROM test_case_texts WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_plans WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_components WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_tags WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_bugs WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_activity WHERE case_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_dependencies
WHERE dependson = ? OR blocked = ?", undef, ($self->id, $self->id));
$dbh->do("DELETE FROM test_cases WHERE case_id = ?", undef, $self->id);
return 1;
}
@ -1339,14 +1340,18 @@ Returns true if the logged in user has rights to delete this test case.
sub candelete {
my $self = shift;
return 0 unless ($self->canedit && Param("allow-test-deletion"));
return 1 if Bugzilla->user->in_group('admin');
return 0 unless $self->canedit && Param("allow-test-deletion");
return 1 if Bugzilla->user->in_group("admin");
# Allow case author to delete as long as this case does not appear in any runs.
return 1 if Bugzilla->user->id == $self->author->id && get_caserun_count == 0;
# Allow case author to delete if this case is not in any runs.
return 1 if Bugzilla->user->id == $self->author->id &&
$self->get_caserun_count == 0;
# Allow plan author to delete if this case is linked to one plan only.
return 1 if scalar(@{$self->plans}) == 1 && Bugzilla->user->id == @{$self->plans}[0]->author->id;
return 1 if Bugzilla->user->id == @{$self->plans}[0]->author->id &&
scalar(@{$self->plans}) == 1;
return 0;
}
###############################

View File

@ -983,9 +983,10 @@ Returns true if the logged in user has rights to delete this case-run.
sub candelete {
my $self = shift;
return 0 unless $self->canedit && Param('allow-test-deletion');
return $self->run->manager->id == Bugzilla->user->id;
return 0 unless $self->canedit && Param("allow-test-deletion");
return 1 if Bugzilla->user->in_group("admin");
return 1 if Bugzilla->user->id == $self->run->manager->id;
return 0;
}
=head2 obliterate
@ -996,8 +997,8 @@ Removes this caserun and all things that reference it.
sub obliterate {
my $self = shift;
my $dbh = Bugzilla->dbh;
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_case_bugs WHERE case_run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_runs WHERE case_run_id = ?", undef, $self->id);

View File

@ -782,9 +782,9 @@ sub lookup_type_by_name {
my ($value) = $dbh->selectrow_array(
"SELECT type_id
FROM test_plan_types
WHERE name = ?",
undef, $name);
FROM test_plan_types
WHERE name = ?",
undef, $name);
return $value;
}
@ -819,9 +819,9 @@ sub lookup_product_by_name {
# TODO 2.22 use Product.pm
my ($value) = $dbh->selectrow_array(
"SELECT id
FROM products
WHERE name = ?",
undef, $name);
FROM products
WHERE name = ?",
undef, $name);
return $value;
}
@ -838,12 +838,6 @@ sub obliterate {
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_plan_texts WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_tags WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_group_map WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_activity WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_plans WHERE plan_id = ?", undef, $self->id);
foreach my $obj (@{$self->attachments}){
$obj->obliterate;
}
@ -853,7 +847,12 @@ sub obliterate {
foreach my $obj (@{$self->test_cases}){
$obj->obliterate if (scalar @{$obj->plans} == 1);
}
$dbh->do("DELETE FROM test_plan_texts WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_tags WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_group_map WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plan_activity WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_case_plans WHERE plan_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_plans WHERE plan_id = ?", undef, $self->id);
return 1;
}
@ -890,7 +889,9 @@ Returns true if the logged in user has rights to delete this plan
sub candelete {
my $self = shift;
return 0 unless $self->canedit && Param("allow-test-deletion");
return (Bugzilla->user->id == $self->author->id || Bugzilla->user->in_group('admin'));
return 1 if Bugzilla->user->in_group("admin");
return 1 if Bugzilla->user->id == $self->author->id;
return 0;
}

View File

@ -433,14 +433,13 @@ sub obliterate {
return 0 unless $self->candelete;
my $dbh = Bugzilla->dbh;
$dbh->do("DELETE FROM test_run_cc WHERE run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_run_tags WHERE run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_run_activity WHERE run_id = ?", undef, $self->id);
foreach my $obj (@{$self->caseruns}){
$obj->obliterate;
}
$dbh->do("DELETE FROM test_run_cc WHERE run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_run_tags WHERE run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_run_activity WHERE run_id = ?", undef, $self->id);
$dbh->do("DELETE FROM test_runs WHERE run_id = ?", undef, $self->id);
return 1;
}
@ -749,10 +748,11 @@ Returns true if the logged in user has rights to delete this test run.
sub candelete {
my $self = shift;
return 0 unless $self->canedit && Param('allow-test-deletion');
return (Bugzilla->user->id == $self->manager->id
|| Bugzilla->user->id == $self->plan->author->id
|| Bugzilla->user->in_group('admin'));
return 0 unless $self->canedit && Param("allow-test-deletion");
return 1 if Bugzilla->user->in_group("admin");
return 1 if Bugzilla->user->id == $self->manager->id;
return 1 if Bugzilla->user->id == $self->plan->author->id;
return 0;
}
###############################

View File

@ -69,6 +69,7 @@ our $DATABASE_ID = "Database_id";
use constant IGNORECASE => 1;
use constant DEPENDSON => "dependson";
use constant PCDATA => "#PCDATA";
use constant REQUIRE => "REQUIRE";
our $TESTOPIA_GT = "&testopia_gt;";
our $TESTOPIA_LT = "&testopia_lt;";
use constant TESTPLAN_REFERENCE => "testplan_reference";
@ -255,29 +256,66 @@ sub error()
sub parse()
{
my ($self, $xml) = @_;
my ($self, $xml, $filename) = @_;
my $twig = XML::Twig->new( load_DTD => 1, keep_encoding => 1 );
$twig->parse($xml);
if ( defined($xml) )
{
$twig->parse($xml);
}
elsif ( defined($filename) )
{
$twig->parsefile($filename);
}
else
{
$self->error("Bugzilla::Testopia::Xml::parse has no XML input source")
}
my $root = $twig->root;
# Check for unimplemented tags.
my @twig_builds = $root->children('build');
$self->error("Support for <build> tags has not been implemented.") if ( $#twig_builds != -1 );
my @twig_testenvironments = $root->children('testenvironment');
$self->error("Support for <testenvironment> tags has not been implemented.") if ( $#twig_testenvironments != -1 );
my @twig_testruns = $root->children('testrun');
$self->error("Support for <testrun> tags has not been implemented.") if ( $#twig_testruns != -1 );
my @twig_testrunlogs = $root->children('testrunlog');
$self->error("Support for <testrunlog> tags has not been implemented.") if ( $#twig_testrunlogs != -1 );
foreach my $twig_category ($root->children('category'))
{
my $product = new Bugzilla::Product({name => $twig_category->field('product')});
my $category_name = $twig_category->field('name');
my $product_name = $twig_category->att('product');
my $description = $twig_category->field('description');
$description = "FIX ME. Created during category import with no description supplied." if ( $description eq "" );
if ( $product_name eq REQUIRE )
{
$self->error("Must supply a product for category '" . $category_name . "'." );
next;
}
my $product = new Bugzilla::Product({name => $product_name});
if ( ! $product )
{
$self->error("Cannot find product '" . $twig_category->field('product') . "' for category '" . $twig_category->field('name') . "'.");
$self->error("Cannot find product '" . $product_name . "' for category '" . $category_name . "'.");
$self->{"parser_error"} = 1;
next;
}
my $category = new Bugzilla::Testopia::Category
({
name => $twig_category->field('name'),
name => $category_name,
product_id => $product->id(),
description => $twig_category->field('description'),
description => $description,
});
push @{$self->categories}, $category;
# Only create the category if it does not exist.
push @{$self->categories}, $category if ( ! $category->check_name($category_name) );
}
my $testplan = Bugzilla::Testopia::TestPlan->new({ 'name' => 'dummy' });
@ -334,16 +372,29 @@ sub parse()
my @attachments = $twig_testplan->children('attachment');
foreach my $twig_attachments (@attachments)
{
my $submitter = $twig_attachments->field('submitter');
# Bugzilla::User::match returns a array with a user hash. Fields of the hash needed
# are 'id' and 'login'.
my $submitter_ref = Bugzilla::User::match($submitter, 1, 0);
my $submitter_id = -1;
if ( ! $submitter_ref->[0] )
{
$self->error("Cannot find submitter '" . $submitter . "' in test plan '" . $twig_testplan->field('name') . "' attachment '" . $twig_attachments->field('description') . "'.");
}
else
{
my $submitter_user = $submitter_ref->[0];
bless($submitter_user,"Bugzilla::User");
$submitter_id = $submitter_user->id();
}
my $attachment = Bugzilla::Testopia::Attachment->new({
'description' => entity_replace_xml($twig_attachments->field('description')),
'filename' => entity_replace_xml($twig_attachments->field('filename')),
'submitter_id' => entity_replace_xml($twig_attachments->field('submitter')),
'submitter_id' => $submitter_id,
'mime_type' => entity_replace_xml($twig_attachments->field('mimetype')),
'creation_ts' => entity_replace_xml($twig_attachments->field('created')),
'data' => entity_replace_xml($twig_attachments->field('data'))
'contents' => entity_replace_xml($twig_attachments->field('data'))
});
push @{$self->attachments}, $attachment;
#$testplan->add_tag($tag->id());
}
}
@ -413,7 +464,6 @@ sub parse()
'breakdown' => entity_replace_testopia($twig_testcase->field('breakdown')),
'case_status_id' => $status_id,
'category_id' => undef,
'creation_date' => $twig_testcase->att('created'),
'default_tester_id' => $tester_id,
'dependson' => undef,
'effect' => entity_replace_testopia($twig_testcase->field('expectedresults')),
@ -449,6 +499,34 @@ sub parse()
# will created when each Test Case is stored.
$xml_testcase->category(entity_replace_xml($twig_testcase->field('categoryname')));
my @attachments = $twig_testcase->children('attachment');
foreach my $twig_attachments (@attachments)
{
my $submitter = $twig_attachments->field('submitter');
# Bugzilla::User::match returns a array with a user hash. Fields of the hash needed
# are 'id' and 'login'.
my $submitter_ref = Bugzilla::User::match($submitter, 1, 0);
my $submitter_id = -1;
if ( ! $submitter_ref->[0] )
{
$self->error("Cannot find submitter '" . $submitter . "' in test case '" . $twig_testcase->field('summary') . "' attachment '" . $twig_attachments->field('description') . "'.");
}
else
{
my $submitter_user = $submitter_ref->[0];
bless($submitter_user,"Bugzilla::User");
$submitter_id = $submitter_user->id();
}
my $attachment = Bugzilla::Testopia::Attachment->new({
'description' => entity_replace_xml($twig_attachments->field('description')),
'filename' => entity_replace_xml($twig_attachments->field('filename')),
'submitter_id' => $submitter_id,
'mime_type' => entity_replace_xml($twig_attachments->field('mimetype')),
'contents' => entity_replace_xml($twig_attachments->field('data'))
});
$xml_testcase->add_attachment($attachment);
}
my @tags = $twig_testcase->children('tag');
foreach my $twig_tag ( @tags )
{
@ -458,7 +536,8 @@ sub parse()
my @components = $twig_testcase->children('component');
foreach my $twig_component ( @components )
{
$xml_testcase->add_component(entity_replace_xml($twig_component->text()));
my $results = $xml_testcase->add_component(entity_replace_xml($twig_component->children_text(PCDATA)),$twig_component->att('product'));
$self->error($results) if ( $results ne "" );
}
foreach my $twig_blocks ( $twig_testcase->children(BLOCKS) )
@ -541,11 +620,18 @@ sub parse()
if ( ! defined $self->parse_error )
{
# Store new categories.
foreach my $category ( @{$self->categories} )
{
$category->store();
print "Created category '" . $category->name() . "': " . $category->description() . "\n";
}
# Store new testplans.
foreach my $testplan ( @{$self->testplans} )
{
my $plan_id = $testplan->store();
$testplan->{'plan_id'} = $plan_id;
print "Created Test Plan $plan_id: " . $testplan->name() . "\n";
foreach my $asciitag ( @{$self->tags} )
{
my $classtag = Bugzilla::Testopia::TestTag->new({'tag_name' => $asciitag});
@ -553,9 +639,15 @@ sub parse()
$testplan->{'tag_id'} = $tagid;
$testplan->add_tag($tagid);
}
foreach my $attachment ( @{$self->attachments} )
{
$attachment->{'plan_id'} = $plan_id;
$attachment->store();
}
print "Created Test Plan $plan_id: " . $testplan->name() . "\n";
}
# Store the testcases.
# Store new testcases.
foreach my $testcase ( @{$self->testcases} )
{
bless($testcase,"Bugzilla::Testopia::XmlTestCase");
@ -569,6 +661,7 @@ sub parse()
print "Created Test Case " . $testcase->testcase->id() . ": " . $testcase->testcase->summary() . "\n";
}
}
# Now that each testcase has been stored we loop though them again and create
# relationships like blocks or dependson.
foreach my $testcase ( @{$self->testcases} )

View File

@ -63,18 +63,24 @@ struct
(
'Bugzilla::Testopia::XmlTestCase',
{
# action => '$',
attachments => '@',
blocks => 'Bugzilla::Testopia::XmlReferences',
category => '$',
components => '@',
component_ids => '@',
dependson => 'Bugzilla::Testopia::XmlReferences',
# expectedresults => '$',
tags => '@',
testcase => 'Bugzilla::Testopia::TestCase',
testplan => 'Bugzilla::Testopia::XmlReferences',
}
);
sub add_attachment()
{
my ($self,$tag) = @_;
push @{$self->attachments}, $tag;
}
sub add_tag()
{
my ($self,$tag) = @_;
@ -84,9 +90,40 @@ sub add_tag()
sub add_component()
{
my ($self,$component) = @_;
push @{$self->components}, $component;
my ($self,$component,$component_product) = @_;
my $component_id = "";
my $product_id = "";
return "Component $component needs to provide a product" if ( $component_product eq "" );
# Find the product identifier.
my $products_ref = Bugzilla::Testopia::TestPlan->get_available_products();
foreach my $product (@$products_ref)
{
if ( $component_product eq $product->{name} )
{
$product_id = $product->{id};
last;
}
}
return "Cannot find product $component_product for component $component" if ( $product_id eq "" );
# Find the component identifier for the product's componet
my $components_ref = Bugzilla::Testopia::TestPlan->get_product_components($product_id);
foreach my $product_component ( @$components_ref )
{
if ( $component eq $product_component->{name} )
{
$component_id = $product_component->{id};
last;
}
}
return "Product $component_product does not have a component named $component" if ( $component_id eq "" );
# Save the component identifier for this Test Case.
push @{$self->component_ids}, $component_id;
return "";
}
sub debug_display()
@ -117,11 +154,6 @@ sub debug_display()
print STDERR " Author " . $author_login . " (id=" . $author_id . ", hash=" . $self->testcase->author() . ")\n";
print STDERR " Blocks " . $self->blocks->display() . "\n";
print STDERR " Category " . $self->category . "\n";
$display_variable = $self->testcase->creation_date();
if ( defined $display_variable )
{
print STDERR " Creation Date " . $display_variable . "\n";
}
print STDERR " Depends On " . $self->dependson->display() . "\n";
print STDERR " Expected Results\n";
if ( defined $text{'effect'} )
@ -160,7 +192,6 @@ sub debug_display()
my %submitter = %{$self->testcase->submitter()};
$author_login = $author{"login"};
print STDERR " Attachment " . $attachment->description() . "\n";
print STDERR " Creation Date " . $attachment->creation_ts(). "\n";
print STDERR " Filename " . $attachment->filename() . "\n";
print STDERR " Mime Type " . $attachment->mime_type(). "\n";
print STDERR " Submitter " . $author_login . "\n";
@ -283,6 +314,11 @@ sub store()
}
my $case_id = $self->testcase->store();
$self->testcase->{'case_id'} = $case_id;
foreach my $attachment ( @{$self->attachments} )
{
$attachment->{'case_id'} = $case_id;
$attachment->store();
}
foreach my $asciitag ( @{$self->tags} )
{
my $classtag = Bugzilla::Testopia::TestTag->new({'tag_name' => $asciitag});
@ -297,12 +333,9 @@ sub store()
}
# Code below requires the testplans to be linked into testcases before being run.
foreach my $component ( @{$self->components} )
foreach my $component_id ( @{$self->component_ids} )
{
foreach my $available_component ( @{$self->testcase->get_selectable_components()} )
{
$self->testcase->add_component($available_component->{'id'}) if ( $component eq $available_component->{'name'} );
}
$self->testcase->add_component($component_id);
}
return $error_message;

View File

@ -0,0 +1,66 @@
# -*- Mode: perl; 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 the Bugzilla Bug Tracking System.
#
# Contributor(s): Marc Schumann <wurblzap@gmail.com>
# Dallas Harken <dharken@novell.com>
package Bugzilla::WebService::Testopia::Build;
use strict;
use base qw(Bugzilla::WebService);
use Bugzilla::Testopia::Build;
sub lookup_name_by_id
{
my $self = shift;
my ($build_id) = @_;
die "Invalid Build ID"
unless defined $build_id && length($build_id) > 0 && $build_id > 0;
Bugzilla->login;
my $build = new Bugzilla::Testopia::Build($build_id);
my $result = defined $build ? $build->name : '';
Bugzilla->logout;
# Result is build name string or empty string if failed
return $result;
}
sub lookup_id_by_name
{
my $self = shift;
my ($name) = @_;
Bugzilla->login;
my $result = Bugzilla::Testopia::Build->check_build_by_name($name);
Bugzilla->logout;
if (!defined $result)
{
$result = 0;
}
# Result is build id or 0 if failed
return $result;
}
1;

View File

@ -77,8 +77,6 @@ sub _list
my $cgi = Bugzilla->cgi;
$cgi->param("viewall", 1);
$cgi->param("current_tab", "case_run");
foreach (keys(%$query))
@ -174,7 +172,12 @@ sub update
_convert_to_ids($new_values);
$$new_values{build_id} = $build_id; # Needed by TestCaseRun's update member function
if (not defined $$new_values{environment_id})
{
$$new_values{environment_id} = $test_case_run->environment; # Needed by TestCaseRun's update member function
}
$test_case_run->update($new_values);
Bugzilla->logout;

View File

@ -48,7 +48,7 @@
<br />
[% IF user.login %]
<a href="tr_list_runs.cgi?current_tab=run&run_status=0">Current Runs</a>&nbsp;|&nbsp;
<a href="tr_list_plans.cgi?current_tab=plan&name_type=allwordssubstr&name=&plan_text_type=allwordssubstr&plan_text=&tag_type=allwords&tags=&author_type=exact&author=[% user.login FILTER url_quote %]&editor_type=exact&editor=&plan_id=">My Plans</a>&nbsp;|&nbsp;
<a href="tr_list_plans.cgi?current_tab=plan&name_type=allwordssubstr&name=&plan_text_type=allwordssubstr&plan_text=&tag_type=allwords&tags=&author_type=exact&author=[% user.login FILTER url_quote %]&plan_id=">My Plans</a>&nbsp;|&nbsp;
<a href="tr_list_cases.cgi?current_tab=case&summary_type=allwordssubstr&summary=&tcaction_type=allwordssubstr&tcaction=&tceffect_type=allwordssubstr&tceffect=&script_type=allwordssubstr&script=&requirement_type=allwordssubstr&requirement=&tag_type=allwords&tags=&author_type=exact&author=&default_tester_type=substring&default_tester=[% user.login FILTER url_quote %]&case_id=&plan_id=">My Cases</a>&nbsp;|&nbsp;
<a href="tr_list_runs.cgi?current_tab=run&summary_type=allwordssubstr&summary=&notes_type=allwordssubstr&notes=&environment_type=allwordssubstr&environment=&tag_type=allwords&tag=&manager_type=substring&manager=[% user.login FILTER url_quote %]&run_id=&plan_id=&assignee_type=substr&assignee=[% user.login FILTER url_quote %]">My Runs</a>
[% END %]

View File

@ -96,6 +96,18 @@
</table>
<div id="diff">
<br>SETUP<hr>
<div id="case_setup">
<pre>
[% diff.setup %]
</pre>
</div>
<br>BREAKDOWN<hr>
<div id="case_breakdown">
<pre>
[% diff.breakdown %]
</pre>
</div>
<br>ACTION<hr>
<div id="case_action">
<pre>

View File

@ -100,7 +100,7 @@
if (selectedNode.actionIsDisabled(selectedNode.actions.REMOVE)) {
return false;
}
var action = confirm("You are about to delete this item with all it's children. Continue?");
var action = confirm("You are about to delete this item with all its children. Continue?");
this.controller = dojo.widget.manager.getWidgetById(controllerId);
if (action){

View File

@ -110,7 +110,7 @@
if (selectedNode.actionIsDisabled(selectedNode.actions.REMOVE)) {
return false;
}
var action = confirm("You are about to remove this item with all it's children from the selected environemnt. Continue?");
var action = confirm("You are about to remove this item with all its children from the selected environment. Continue?");
this.controller = dojo.widget.manager.getWidgetById(controllerId);
if (action){

View File

@ -7,7 +7,7 @@
<!ELEMENT archived (#PCDATA)>
<!ELEMENT arguments (#PCDATA)>
<!ELEMENT assignedto (#PCDATA)>
<!ELEMENT attachment (description, filename, submitter, mimetype, created, data)>
<!ELEMENT attachment (description, filename, submitter, mimetype, data)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT automated (#PCDATA)>
<!ELEMENT blocks (#PCDATA)>
@ -29,7 +29,9 @@
<!ELEMENT cclist (#PCDATA)>
<!ELEMENT closedate (#PCDATA)>
<!ELEMENT component (#PCDATA)>
<!ELEMENT created (#PCDATA)>
<!ATTLIST component
product CDATA #REQUIRED
>
<!ELEMENT data (#PCDATA)>
<!ELEMENT defaulttester (#PCDATA)>
<!ELEMENT dependson (#PCDATA)>
@ -38,7 +40,6 @@
>
<!ELEMENT description (#PCDATA)>
<!ELEMENT document (#PCDATA)>
<!ELEMENT editor (#PCDATA)>
<!ELEMENT environment (#PCDATA)>
<!ELEMENT expectedresults (#PCDATA)>
<!ELEMENT filename (#PCDATA)>
@ -61,10 +62,9 @@
<!ELEMENT submitter (#PCDATA)>
<!ELEMENT summary (#PCDATA)>
<!ELEMENT tag (#PCDATA)>
<!ELEMENT testcase (summary, testplan_reference+, alias*, requirement, defaulttester, categoryname?, script?, arguments*, component*, tag*, attachment*, dependson*, blocks*, setup?, breakdown?, action, expectedresults?)>
<!ELEMENT testcase (summary, testplan_reference+, alias?, requirement?, defaulttester, categoryname?, script?, arguments*, component*, tag*, attachment*, dependson*, blocks*, setup?, breakdown?, action, expectedresults?)>
<!ATTLIST testcase
author CDATA #REQUIRED
created CDATA #IMPLIED
priority (P0|P1|P2|P3|P4|p5) "P5"
automated (Manual|Automatic) "Manual"
status (PROPOSED|CONFIRMED|DISABLED) "CONFIRMED"
@ -75,7 +75,7 @@
type (Database_id|Database_description|Xml_description) #REQUIRED
>
<!ELEMENT testenvironment (name, os, platform)>
<!ELEMENT testplan (name, product, productversion, build*, category*, created?, editor, tag*, attachment*, document?)>
<!ELEMENT testplan (name, product, productversion, build*, category*, tag*, attachment*, document?)>
<!ATTLIST testplan
author CDATA #REQUIRED
type (Acceptance|Function|Installation|Integration|Interoperability|Performance|Product|System|Unit) #REQUIRED

View File

@ -1,77 +1,7 @@
Index: /bmo-2.22.1/Bugzilla.pm
Index: /bmo-2.22/post_bug.cgi
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/Bugzilla.pm,v
retrieving revision 1.29.2.2
diff -u -r1.29.2.2 Bugzilla.pm
--- Bugzilla.pm 8 Aug 2006 20:53:40 -0000 1.29.2.2
+++ Bugzilla.pm 15 Nov 2006 00:30:34 -0000
@@ -46,6 +46,7 @@
use constant SHUTDOWNHTML_EXEMPT => [
'editparams.cgi',
'checksetup.pl',
+ 'tr_install.pl',
];
# Non-cgi scripts that should silently exit.
Index: /bmo-2.22.1/checksetup.pl
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/checksetup.pl,v
retrieving revision 1.469.2.16
diff -u -r1.469.2.16 checksetup.pl
--- checksetup.pl 3 Nov 2006 23:12:01 -0000 1.469.2.16
+++ checksetup.pl 15 Nov 2006 00:30:34 -0000
@@ -314,7 +314,7 @@
},
{
name => 'Template',
- version => '2.10'
+ version => '2.12'
},
{
name => 'Text::Wrap',
@@ -378,6 +378,10 @@
}
}
+print "\nThe following Perl modules are Required for Testopia:\n" unless $silent;
+$missing{'Text::Diff'} = '0.35' unless have_vers("Text::Diff","0.35");
+$missing{'JSON'} = '1.07' unless have_vers("JSON","1.07");
+
print "\nThe following Perl modules are optional:\n" unless $silent;
my $gd = have_vers("GD","1.20");
my $template_gd = have_vers('Template::Plugin::GD::Image', 0);
@@ -1336,7 +1340,7 @@
# These are the files which need to be marked executable
my @executable_files = ('whineatnews.pl', 'collectstats.pl',
'checksetup.pl', 'importxml.pl', 'runtests.pl', 'testserver.pl',
- 'whine.pl');
+ 'whine.pl', 'build_bugmail.pl', 'tr_install.pl', 'tr_importxml.pl');
# tell me if a file is executable. All CGI files and those in @executable_files
# are executable
Index: /bmo-2.22.1/enter_bug.cgi
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/enter_bug.cgi,v
retrieving revision 1.126.2.2
diff -u -r1.126.2.2 enter_bug.cgi
--- enter_bug.cgi 21 Aug 2006 19:26:06 -0000 1.126.2.2
+++ enter_bug.cgi 15 Nov 2006 00:30:34 -0000
@@ -591,6 +591,8 @@
$vars->{'default'} = \%default;
+$vars->{'caserun_id'} = $cgi->param('caserun_id');
+
my $format = $template->get_format("bug/create/create",
scalar $cgi->param('format'),
scalar $cgi->param('ctype'));
Index: /bmo-2.22.1/post_bug.cgi
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/post_bug.cgi,v
retrieving revision 1.135.2.4
diff -u -r1.135.2.4 post_bug.cgi
--- post_bug.cgi 1 Nov 2006 00:58:15 -0000 1.135.2.4
+++ post_bug.cgi 15 Nov 2006 00:30:34 -0000
--- /bmo-2.22/post_bug.cgi 2006-01-08 12:56:03.000000000 -0700
+++ /bmo-2.22-testopia/post_bug.cgi 2006-09-29 13:55:02.000000000 -0600
@@ -32,6 +32,8 @@
use Bugzilla::Util;
use Bugzilla::Bug;
@ -81,7 +11,7 @@ diff -u -r1.135.2.4 post_bug.cgi
use Bugzilla::Field;
# Shut up misguided -w warnings about "used only once". For some reason,
@@ -504,6 +506,18 @@
@@ -494,6 +496,18 @@
}
$vars->{'bug_list'} = \@bug_list;
@ -100,49 +30,68 @@ diff -u -r1.135.2.4 post_bug.cgi
print $cgi->header();
$template->process("bug/create/created.html.tmpl", $vars)
|| ThrowTemplateError($template->error());
Index: /bmo-2.22.1/Bugzilla/DB/Schema/Pg.pm
Index: /bmo-2.22/enter_bug.cgi
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/Bugzilla/DB/Schema/Pg.pm,v
retrieving revision 1.9
diff -u -r1.9 Pg.pm
--- /bmo-2.22.1/Bugzilla/DB/Schema/Pg.pm 15 Jun 2005 03:54:59 -0000 1.9
+++ /bmo-2.22.1-testopia/Bugzilla/DB/Schema/Pg.pm 15 Nov 2006 00:30:34 -0000
@@ -69,6 +69,7 @@
INT3 => 'integer',
INT4 => 'integer',
--- /bmo-2.22/enter_bug.cgi 2006-01-05 07:54:52.000000000 -0700
+++ /bmo-2.22-testopia/enter_bug.cgi 2006-09-29 13:55:02.000000000 -0600
@@ -590,6 +590,8 @@
+ TINYSERIAL => 'serial unique',
SMALLSERIAL => 'serial unique',
MEDIUMSERIAL => 'serial unique',
INTSERIAL => 'serial unique',
Index: /bmo-2.22.1/Bugzilla/DB/Schema/Mysql.pm
$vars->{'default'} = \%default;
+$vars->{'caserun_id'} = $cgi->param('caserun_id');
+
my $format = $template->get_format("bug/create/create",
scalar $cgi->param('format'),
scalar $cgi->param('ctype'));
Index: /bmo-2.22/checksetup.pl
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/Bugzilla/DB/Schema/Mysql.pm,v
retrieving revision 1.12.2.1
diff -u -r1.12.2.1 Mysql.pm
--- /bmo-2.22.1/Bugzilla/DB/Schema/Mysql.pm 19 Jun 2006 14:57:14 -0000 1.12.2.1
+++ /bmo-2.22.1-testopia/Bugzilla/DB/Schema/Mysql.pm 15 Nov 2006 00:30:34 -0000
@@ -103,9 +103,10 @@
INT3 => 'mediumint',
INT4 => 'integer',
--- /bmo-2.22/checksetup.pl 2006-01-12 00:03:46.000000000 -0700
+++ /bmo-2.22-testopia/checksetup.pl 2006-10-04 16:06:13.000000000 -0600
@@ -313,7 +313,7 @@
},
{
name => 'Template',
- version => '2.10'
+ version => '2.12'
},
{
name => 'Text::Wrap',
@@ -376,6 +376,10 @@
}
}
- SMALLSERIAL => 'smallint auto_increment',
- MEDIUMSERIAL => 'mediumint auto_increment',
- INTSERIAL => 'integer auto_increment',
+ TINYSERIAL => 'tinyint unsigned auto_increment',
+ SMALLSERIAL => 'smallint unsigned auto_increment',
+ MEDIUMSERIAL => 'mediumint unsigned auto_increment',
+ INTSERIAL => 'integer unsigned auto_increment',
+print "\nThe following Perl modules are Required for Testopia:\n" unless $silent;
+$missing{'Text::Diff'} = '0.35' unless have_vers("Text::Diff","0.35");
+$missing{'JSON'} = '1.07' unless have_vers("JSON","1.07");
+
print "\nThe following Perl modules are optional:\n" unless $silent;
my $gd = have_vers("GD","1.20");
my $chartbase = have_vers("Chart::Base","1.0");
@@ -1305,7 +1309,7 @@
# These are the files which need to be marked executable
my @executable_files = ('whineatnews.pl', 'collectstats.pl',
'checksetup.pl', 'importxml.pl', 'runtests.pl', 'testserver.pl',
- 'whine.pl');
+ 'whine.pl', 'build_bugmail.pl', 'tr_install.pl', 'tr_importxml.pl');
TINYTEXT => 'tinytext',
MEDIUMTEXT => 'mediumtext',
Index: /bmo-2.22.1/Bugzilla/DB/Schema.pm
# tell me if a file is executable. All CGI files and those in @executable_files
# are executable
Index: /bmo-2.22/Bugzilla.pm
===================================================================
RCS file: /cvsroot/mozilla/webtools/bugzilla/Bugzilla/DB/Schema.pm,v
retrieving revision 1.45.2.2
diff -u -r1.45.2.2 Schema.pm
--- /bmo-2.22.1/Bugzilla/DB/Schema.pm 19 Jun 2006 18:17:38 -0000 1.45.2.2
+++ /bmo-2.22.1-testopia/Bugzilla/DB/Schema.pm 15 Nov 2006 00:30:34 -0000
--- /bmo-2.22/Bugzilla.pm 2006-02-07 15:46:28.000000000 -0700
+++ /bmo-2.22-testopia/Bugzilla.pm 2006-10-04 16:24:33.000000000 -0600
@@ -46,6 +46,7 @@
use constant SHUTDOWNHTML_EXEMPT => [
'editparams.cgi',
'checksetup.pl',
+ 'tr_install.pl',
];
# Non-cgi scripts that should silently exit.
Index: /bmo-2.22/Bugzilla/DB/Schema.pm
===================================================================
--- /bmo-2.22/Bugzilla/DB/Schema.pm 2006-01-06 07:38:42.000000000 -0700
+++ /bmo-2.22-testopia/Bugzilla/DB/Schema.pm 2006-10-04 16:28:11.000000000 -0600
@@ -1039,6 +1039,483 @@
version => {TYPE => 'decimal(3,2)', NOTNULL => 1},
],
@ -627,3 +576,33 @@ diff -u -r1.45.2.2 Schema.pm
};
#--------------------------------------------------------------------------
Index: /bmo-2.22/Bugzilla/DB/Schema/Mysql.pm
===================================================================
--- /bmo-2.22/Bugzilla/DB/Schema/Mysql.pm 2005-12-18 11:53:00.000000000 -0700
+++ /bmo-2.22-testopia/Bugzilla/DB/Schema/Mysql.pm 2006-09-29 14:08:38.000000000 -0600
@@ -103,9 +103,10 @@
INT3 => 'mediumint',
INT4 => 'integer',
- SMALLSERIAL => 'smallint auto_increment',
- MEDIUMSERIAL => 'mediumint auto_increment',
- INTSERIAL => 'integer auto_increment',
+ TINYSERIAL => 'tinyint unsigned auto_increment',
+ SMALLSERIAL => 'smallint unsigned auto_increment',
+ MEDIUMSERIAL => 'mediumint unsigned auto_increment',
+ INTSERIAL => 'integer unsigned auto_increment',
TINYTEXT => 'tinytext',
MEDIUMTEXT => 'mediumtext',
Index: /bmo-2.22/Bugzilla/DB/Schema/Pg.pm
===================================================================
--- /bmo-2.22/Bugzilla/DB/Schema/Pg.pm 2005-06-14 21:54:59.000000000 -0600
+++ /bmo-2.22-testopia/Bugzilla/DB/Schema/Pg.pm 2006-09-21 15:10:19.000000000 -0600
@@ -69,6 +69,7 @@
INT3 => 'integer',
INT4 => 'integer',
+ TINYSERIAL => 'serial unique',
SMALLSERIAL => 'serial unique',
MEDIUMSERIAL => 'serial unique',
INTSERIAL => 'serial unique',

View File

@ -82,7 +82,7 @@ elsif ($action eq 'do_edit') {
elsif ($action eq 'delete') {
Bugzilla->login(LOGIN_REQUIRED);
my $attachment = validate();
ThrowUserError('testopia-no-delete', {'object' => 'Attachment'}) unless Param("allow-test-deletion");
ThrowUserError('testopia-no-delete', {'object' => 'Attachment'}) unless $attachment->candelete;
$vars->{'attachment'} = validate();
print $cgi->header();
$template->process("testopia/attachment/delete.html.tmpl", $vars)
@ -93,7 +93,7 @@ elsif ($action eq 'do_delete') {
Bugzilla->login(LOGIN_REQUIRED);
my $attachment = validate();
$vars->{'tr_message'} = "Attachment ". $attachment->description ." deleted";
ThrowUserError('testopia-no-delete', {'object' => 'Attachment'}) unless Param("allow-test-deletion");
ThrowUserError('testopia-no-delete', {'object' => 'Attachment'}) unless $attachment->candelete;
$attachment->obliterate;
go_on($attachment);
}

View File

@ -59,12 +59,11 @@ xmlfilename in Testopia XML format.
=cut
my $TCDB_CORRECTION_EXTENSION = ".TCDBcorrections";
my $TEST_PLAN_AUTHOR = "Change TEST_PLAN_AUTHOR in import.pl user\@novell.com";
use constant TEST_PLAN_DOCUMENT => "Change TEST_PLAN_DOCUMENT in import.pl";
my $TEST_PLAN_EDITOR = "Change TEST_PLAN_EDITOR in import.pl user\@novell.com";
use constant TEST_PLAN_NAME => "Change TEST_PLAN_NAME";
use constant TEST_PLAN_PRODUCT => "TestProduct";
use constant TEST_PLAN_PRODUCT_VERSION => "other";
# Test Plan types are: Database_id, Database_description or Xml_description.
use constant TEST_PLAN_NAME_TYPE => "Xml_description";
@ -101,68 +100,32 @@ sub map_TCDB_users
}
#
# The TCDB export does not quote doube quotes in the fields. This method finds those
# double quotes and quotes them.
# Print the fields.
#
sub quote_the_doublequote {
my ($line) = @_;
# In each field need to change '\"' to '"' and change all '"' to '""'. The last field
# will also have a '"' at the end of the line that needs to be removed.
#
sub print_tcdb_fields
{
my ($file_descriptor,$fields_ref,$testcasenamefield) = @_;
# Seeing \" in some files as the quote for a double guote.
$line =~ s/\\"/""/g;
my @chars = split(//,$line);
my $index = 0;
my $in_quote_field = 0;
my @return_line;
while ( $index <= $#chars )
while ( $index < @$fields_ref )
{
my $char = $chars[$index];
if ( $char eq "\"" )
$fields_ref->[$index] =~ s/"$//g if ( $index == ( @$fields_ref -1 ) );
$fields_ref->[$index] =~ s/\\"/"/g;
$fields_ref->[$index] =~ s/"/""/g;
if ( $index == $testcasenamefield )
{
if ( $in_quote_field == 0 )
{
$in_quote_field = 1;
push (@return_line,$char);
}
else
{
push (@return_line,$char);
my $index2 = $index+1;
while ( $index2<=$#chars )
{
last if ( $chars[$index2] =~ m/\S/ );
$index2++;
}
if ( # Special condition for end of line.
# If the next character is last character of string and is a " we need to
# quote our current ".
( $index2==$#chars && $chars[$index2] eq "\"" ) ||
# Special condition for eand of field.
# If the next two characters are ", we need to quote our current ".
( ($index2+1)<=$#chars && $chars[$index2] eq "\"" && $chars[$index2+1] eq ",") ||
# If the next non white space character is not a , or " we need to quote the
# current ".
( $index2<$#chars && $chars[$index2] ne "," && $chars[$index2] ne "\"" ) )
{
push (@return_line,"\"") ;
}
else
{
$in_quote_field = 0;
}
}
$fields_ref->[$index] =~ s/__\d\d\d\d\d\d\d//g;
$fields_ref->[$index] =~ s/__\d\d\d\d\d\d//g;
$fields_ref->[$index] =~ s/__\d\d\d\d\d//g;
}
else
{
push (@return_line,$char);
}
$index++;
print $file_descriptor "\"$fields_ref->[$index]\"";
print $file_descriptor "," if ( $index != ( @$fields_ref -1 ) );
$index += 1;
}
return join("",@return_line);
print $file_descriptor "\n";
}
#
@ -173,7 +136,7 @@ sub quote_the_doublequote {
# The Test Case Data Base (TCDB) CSV files also need to be processed to clean up format errors.
#
# The TCDB CSV errors are:
# 1) Does not escape " used in a field with "".
# 1) Does not escape " used in a field with "". May use \" instead of "" but not always.
# 2) Runs the CSV across multiple lines.
# 3) In some cases a line may be missing the last field.
#
@ -181,126 +144,220 @@ sub remove_field_list
{
my ($input_filename,$work_filename,$tcdb_format) = @_;
my $field_list = "";
my @field_buffer;
my @fields;
my $fields_index = 0;
my $in_quote_field = 0;
my $line = "";
my $line_count = 0;
my $matching_expression = "";
my $matching_expression_tcdb_error = "";
my $matching_expression_too_long = "";
my $number_of_fields = 0;
my $parse_line = "";
my $testcasenamefield = "";
open(CSVINPUT, $input_filename) or error("Cannot open file $input_filename");
open(CSVWORK, ">" . $work_filename) or error("Cannot open file $work_filename");
open(CSVWORK, ">", $work_filename) or error("Cannot open file $work_filename");
while (<CSVINPUT>)
{
chop;
my $current_line = $_;
$current_line =~ s/\r//g;
$current_line =~ s/\342\200\231/&#8217;/g;
$current_line =~ s/\342\200\230/&#8216;/g;
$current_line =~ s/\342\200\246/&#133;/g;
$current_line =~ s/\342\200\223/-/g;
$current_line =~ s/\342\200\224/&#8212;/g;
$current_line =~ s/\342\200\234/&#8221;/g;
$current_line =~ s/\342\200\235/&#8222;/g;
s/\r//g;
s/\342\200\231/&#8217;/g;
s/\342\200\230/&#8216;/g;
s/\342\200\246/&#133;/g;
s/\342\200\223/-/g;
s/\342\200\224/&#8212;/g;
s/\342\200\234/&#8221;/g;
s/\342\200\235/&#8222;/g;
s/\302\251/&copy;/g;
s/\031/'/g;
s/\221/&apos;/g;
s/\222/&apos;/g;
s/\224/&apos;/g;
s/\226/-/g;
s/\341/&#224;/g; # small letter a with grave
s/\344/&#228;/g; # small letter a with diaeresis
s/\351/&#232;/g; # small letter e with grave
s/\364/&#244;/g; # small letter o with circumflex
$line_count += 1;
if ( $line_count == 1 )
{
$matching_expression .= "^";
$field_list = $current_line;
my @fields = split(/,/);
for ( my $i=1; $i<=$#fields; $i++ )
$field_list = $_;
$number_of_fields = $field_list;
$number_of_fields =~ s/[^,]//g;
# Counting the number of commas so number of fields is one more.
$number_of_fields = (length $number_of_fields) + 1;
# Returned $field_list needs to be lower case, all spaces, " and \ removed.
$field_list = lc $field_list;
$field_list =~ s/[\s"\/]//g;
my $index = 0;
# Find the field that contains the Test Case name.
foreach my $field ( split(/,/,$field_list) )
{
$matching_expression .= "(\".*\",|,)";
if ( $field eq "testcasename" )
{
$testcasenamefield = $index ;
last;
}
$index++;
}
$matching_expression_too_long = $matching_expression . "(\".*\",|,).+\$";
$matching_expression .= "(\".*\")?\$";
$matching_expression_tcdb_error = $matching_expression;
$matching_expression_tcdb_error =~ s/^\^\("\.\*",\|,\)/^/;
next;
}
if ( ! $tcdb_format )
{
print CSVWORK $current_line . "\n";
print CSVWORK $_ . "\n";
next;
}
error("Found substitution key <TRANSLATE_DOUBLEQUOTE> in $input_filename at line $line_count") if ( /<TRANSLATE_DOUBLEQUOTE>/ );
error("Found substitution key <TRANSLATE_NEWLINE> in $input_filename at line $line_count") if ( /<TRANSLATE_NEWLINE>/ );
if ( $line ne "" )
{
# If we have all the csv fields the line is ready to print.
if ( $line =~ m/$matching_expression/ )
# Two TCDB CSV options that are not handled correctly:
# 1) A unescaped double quote in a field that appears at the end of the line is assumed
# to be the end of the field although it is suppose to be part of the field. This
# could probably be detected by reading the next line and seeing if it begins with a
# double quote. If it does then the double quote was the end of the field.
# 2) If a field contains some thing like:
# '2. Click "Roles and Tasks " , "Storage" , click "Volumes" and' the "," will be
# seen as field seperator and not as part of the field.
# Add the current line onto the line to parse.
$parse_line .= $_;
# The end of the TCDB CSV line will be a double quote at the end of the line. Keep combining
# lines until we have a double quote at the end of the line and try to parse the line.
if ( ! ($parse_line =~ /.+"$/) )
{
$parse_line .= "\\n";
next;
}
# At this point $parse_line will hopefully contain the full CSV line. It may not though since
# we could have found a double quote at the end of the line used in field that spans multiple
# lines. Parse it below and if we have not found all the fields we will loop back and read
# more lines until the next double quote at the end of the line is found.
$in_quote_field = 0;
my $index = 0;
@fields = ();
@field_buffer = ();
my @chars = split(//,$parse_line);
while ( $index <= $#chars )
{
my $char = $chars[$index];
if ( $char eq "\"" )
{
# The TCDB does not double quote double quotes which causes a problem when the last
# field contains a double quote at the end of the line that is should be part of the
# field. The match above is true but we have not really reached the end of the field.
# So we need to break the line up at each field, if the last field contains a even
# number of double quotes we have not reached the end of the line and need to just
# append the current line onto our line buffer.
my @fields = split /","/, $line;
$fields[$#fields] =~ s/[^"]//g;
if ( ((length $fields[$#fields]) % 2) == 0 )
# Following check is for character sequence \". Look at last character in the current
# field_buffer and if it is a \ this " is not the end of the field.
if ( $#field_buffer>=0 && $field_buffer[$#field_buffer] eq "\\" )
{
$line .= $current_line;
next;
push (@field_buffer,$char);
}
print CSVWORK quote_the_doublequote($line) . "\n";
$line = $current_line;
}
# If current line begins with a ", see if it's the start of a new line. Check to see if this line might have
# TCDB error of a missing field. If line has exceeded the matching criteria display a error.
elsif ( $current_line =~ /^"/ )
{
if ( $line =~ m/$matching_expression_tcdb_error/ )
elsif ( ! $in_quote_field )
{
$line .= ",\"\"";
print CSVWORK quote_the_doublequote($line) . "\n";
$line = $current_line;
}
elsif ( $line =~ m/$matching_expression_too_long/ )
{
error("Confused in $input_filename at line $line_count. Cannot figure out how to proceed");
$in_quote_field = 1;
}
else
{
$line .= "<TRANSLATE_NEWLINE>" . $current_line;
# If this double quote is followed by a comma double quote ',"' it would be the end of the field
# otherwise it should included in the field. Need to ignore white space when searching for the
# next two characters.
# The TCDB never breaks a line at field separators (have not seen it yet anyway) so the code does
# not need to worry about finding a comma at the end of the line and checking for a double quote at
# the beginning of the next line.
my $comma_index = $index+1;
while ( $comma_index<=$#chars )
{
last if ( $chars[$comma_index] =~ m/\S/ );
$comma_index++;
}
my $double_quote_index = $comma_index+1;
while ( $double_quote_index<=$#chars )
{
last if ( $chars[$double_quote_index] =~ m/\S/ );
$double_quote_index++;
}
# Is the next non-white space character a comma followed by a double quote? If yes then we
# have reached the end of the field.
if ( ( $comma_index <= $#chars && $chars[$comma_index] eq "," ) &&
( $double_quote_index <= $#chars && $chars[$double_quote_index] eq "\"" ) )
{
push (@fields,join("",@field_buffer));
@field_buffer = ();
# Skip past the comma.
$index++;
$in_quote_field = 0;
}
# This quote is at end of the line. Assume it's the last double quote on the CSV line.
elsif ( $index == $#chars )
{
push (@fields,join("",@field_buffer));
@field_buffer = ();
$in_quote_field = 0;
}
else
{
push (@field_buffer,$char);
}
}
}
else
{
$line .= "<TRANSLATE_NEWLINE>" . $current_line;
if ( $in_quote_field )
{
push (@field_buffer,$char);
}
else
{
# Only allow white space between fields.
error("Found unexpected character $char after phrase '" .
join("",@field_buffer) .
"' on line $line_count in file $input_filename") if ( $char =~ '\S');
}
}
$index++;
}
# Do we have all the fields we need?
if ( ($#fields == ($number_of_fields-1)) && (! $in_quote_field) )
{
print_tcdb_fields(\*CSVWORK,\@fields,$testcasenamefield);
$parse_line = "";
@fields = ();
}
# Is this the TCDB export error? We have one less field than needed and the next line begins with a
# double quote.
elsif ( ($#fields == ($number_of_fields-2)) && (! $in_quote_field ) )
{
if ( $_ =~ m/^"/ )
{
# Pull double quote of the end of the last field.
$fields[$#fields] =~ s/"$//;
# Create the missing field. Need to insert a double quote since print_fields expects a double
# quote at end of last field.
push (@fields,"\"");
print_tcdb_fields(\*CSVWORK,\@fields,$testcasenamefield);
$parse_line = "";
@fields = ();
}
}
else
elsif ( $#fields >= $number_of_fields )
{
$line = $current_line;
}
print STDERR " line=$line\ncurrent_line=$current_line\n" if ( $debug );
}
# Probably will still have a line in the $line buffer.
if ( $line ne "" )
{
if ( $line =~ m/$matching_expression/ )
{
print CSVWORK quote_the_doublequote($line) . "\n";
error("Read too many lines. Parse line '$parse_line' at line $line_count in file $input_filename");
}
else
# Not enough fields yet. Need to append a \n to the $parse_line buffer and starting reading
# until we find another double quote at the end of the line.
{
$line .= ",\"\"" if ( $line =~ m/$matching_expression_tcdb_error/ );
if ( $line =~ m/$matching_expression/ )
{
print CSVWORK quote_the_doublequote($line) . "\n";
}
else
{
error("Incomplete line in $input_filename at line $line_count. Line follows" . $line);
}
$parse_line .= "\\n";
}
}
# When End of File is read the parse_line is suppose to be empty.
error("Reached end of file while parsing '$parse_line'") if ( $parse_line ne "" );
close(CSVINPUT);
close(CSVWORK);
error("Did not find the last double quote in file") if ( $in_quote_field );
#
# Sort the corrected CSV to remove duplicate records.
@ -330,15 +387,10 @@ sub remove_white_space {
# Characters that are entities in XML and HTML need to be
# converted to their entity representation.
#
# TRANSLATE_NEWLINE is a character inserted by this script
# where a new line needs to be but not orginally contained
# in the field.
#
# Some new lines have been showing up as \\n in exports.
#
sub fix_entities {
my ($line) = @_;
$line =~ s/<TRANSLATE_NEWLINE>/\n/g;
$line =~ s/\\n/\n/g;
$line =~ s/\&/&amp;/g;
$line =~ s/\</&lt;/g;
@ -358,10 +410,9 @@ error("Need to supply XML output file") if ( $#ARGV == 0 );
error("Too many arguments") if ( $#ARGV >= 2 );
my $csv_input_filename = $ARGV[0];
my $xml_output_filename = $ARGV[1];
my $csv_work_filename = $csv_input_filename . ".work";
open(XMLOUTPUT, "> $xml_output_filename") or error("Cannot open file $xml_output_filename");
open(XMLOUTPUT, ">", $xml_output_filename) or error("Cannot open file $xml_output_filename");
my %tcdb_user;
my $field_list = remove_field_list($csv_input_filename,$csv_work_filename,$tcdb);
map_TCDB_users(\%tcdb_user);
@ -399,14 +450,13 @@ map_TCDB_users(\%tcdb_user);
# The order of the fields is not important. The fields supplied to Class::CSV will be in
# order found on the first line of the CSV file.
#
# Steps needed are:
# The field_list returned from remove_field_list() will have:
# Change to lower case.
# Remove spaces.
# Remove all "'s
# Remove all /'s.'
#
$field_list = lc $field_list;
$field_list =~ s/[\s"\/]//g;
# More sources for the CSV's other than TCDB, transform some of the column names.
$field_list =~ s/author/owner/g;
$field_list =~ s/result/passfaildefinition/g;
@ -433,15 +483,14 @@ while (<DTDINPUT>)
}
close(DTDINPUT);
print XMLOUTPUT "]>\n";
print XMLOUTPUT "<testopia version=\"2.21\">\n";
print XMLOUTPUT "<testopia version=\"1.1\">\n";
if ( $TEST_PLAN_AUTHOR ne "Change TEST_PLAN_AUTHOR in import.pl user\@novell.com" )
{
print XMLOUTPUT " <testplan author=\"" . $TEST_PLAN_AUTHOR . "\" type=\"System\" archived=\"False\">\n";
print XMLOUTPUT " <name>" . TEST_PLAN_NAME . "</name>\n";
print XMLOUTPUT " <product>TestProduct</product>\n";
print XMLOUTPUT " <productversion>other</productversion>\n";
print XMLOUTPUT " <editor>" . $TEST_PLAN_EDITOR . "</editor>\n";
print XMLOUTPUT " <product>" . TEST_PLAN_PRODUCT . "</product>\n";
print XMLOUTPUT " <productversion>" . TEST_PLAN_PRODUCT_VERSION . "</productversion>\n";
print XMLOUTPUT " <document>" . TEST_PLAN_DOCUMENT . "</document>\n";
print XMLOUTPUT " </testplan>\n";
}
@ -468,7 +517,7 @@ foreach my $line (@{$csv->lines()}) {
}
print XMLOUTPUT "automated=\"Manual\" ";
print XMLOUTPUT "status=\"CONFIRMED\">\n";
print XMLOUTPUT " <testplan_reference type=\"" . TEST_PLAN_NAME_TYPE . "\">" . TEST_PLAN_NAME . "</testplan_reference>\n";
print XMLOUTPUT " <testplan_reference type=\"" . TEST_PLAN_NAME_TYPE . "\">" . TEST_PLAN_NAME . "</testplan_reference>\n";
my $summary;
if ( defined($fields{'testcasename'}) )
{
@ -517,7 +566,7 @@ foreach my $line (@{$csv->lines()}) {
}
if ( defined($fields{'component'}) && ( $line->component() ne "") )
{
print XMLOUTPUT " <component>" . fix_entities(remove_white_space($line->component())) . "</component>\n";
print XMLOUTPUT " <component product=\"" . TEST_PLAN_PRODUCT . "\">" . fix_entities(remove_white_space($line->component())) . "</component>\n";
}
if ( defined($fields{'category'}) && ( $line->category() ne "") )
{
@ -564,13 +613,13 @@ foreach my $line (@{$csv->lines()}) {
print XMLOUTPUT fix_entities($line->steps());
}
print XMLOUTPUT "</action>\n";
print XMLOUTPUT " <expectedresults>";
if ( defined($fields{'passfaildefinition'}) && ( $line->passfaildefinition() ne "") )
{
print XMLOUTPUT " <expectedresults>";
print XMLOUTPUT "[TCDB Pass Fail Definition]\n" if ( $tcdb );
print XMLOUTPUT fix_entities($line->passfaildefinition());
print XMLOUTPUT "</expectedresults>\n";
}
print XMLOUTPUT "</expectedresults>\n";
print XMLOUTPUT " </testcase>\n";
}
print XMLOUTPUT "</testopia>\n";

View File

@ -29,30 +29,6 @@
use strict;
#####################################################################
#
# This script is used import bugs from another installation of bugzilla.
# It can be used in two ways.
# First using the move function of bugzilla
# on another system will send mail to an alias provided by
# the administrator of the target installation (you). Set up an alias
# similar to the one given below so this mail will be automatically
# run by this script and imported into your database. Run 'newaliases'
# after adding this alias to your aliases file. Make sure your sendmail
# installation is configured to allow mail aliases to execute code.
#
# bugzilla-import: "|/usr/bin/perl /opt/bugzilla/importxml.pl"
#
# Second it can be run from the command line with any xml file from
# STDIN that conforms to the bugzilla DTD. In this case you can pass
# an argument to set whether you want to send the
# mail that will be sent to the exporter and maintainer normally.
#
# importxml.pl [--sendmail] < bugsfile.xml
#
#####################################################################
# figure out which path this script lives in. Set the current path to
# this and add it to @INC so this will work when run as part of mail
# alias by the mailer daemon
@ -96,17 +72,6 @@ pod2usage(0) if $help;
use constant DEBUG_LEVEL => 2;
use constant ERR_LEVEL => 1;
GetVersionTable();
our $log;
our @attachments;
our $bugtotal;
our @recipients;
my $xml;
# This can go away as soon as data/versioncache is removed. Since we still
# have to use GetVersionTable() though, it stays for now.
sub Debug {
return unless ($debug);
my ($message, $level) = (@_);
@ -114,26 +79,29 @@ sub Debug {
print STDERR "$message\n" if (($debug == $level) && ($level == DEBUG_LEVEL));
}
sub Error {
my ($reason,$errtype) = @_;
my $subject = "Bug import error: $reason";
my $message = "Cannot import these bugs because $reason ";
$message .= "\n\nPlease re-open the original bug.\n" if ($errtype);
$message .= "For more info, contact ". Param("maintainer") . ".\n";
my @to = (Param("maintainer"));
Debug($message, ERR_LEVEL);
exit(1);
}
Debug("Reading xml", DEBUG_LEVEL);
# Read STDIN in slurp mode. VERY dangerous, but we live on the wild side ;-)
local($/);
$xml = <>;
my $xml;
my $filename;
if ( $#ARGV == -1 )
{
# Read STDIN in slurp mode. VERY dangerous, but we live on the wild side ;-)
local($/);
$xml = <>;
}
elsif ( $#ARGV == 0 )
{
$filename = $ARGV[0];
}
else
{
pod2usage(0);
}
Debug("Parsing tree", DEBUG_LEVEL);
my $testopiaXml = Bugzilla::Testopia::Xml->new();
$testopiaXml->parse($xml);
$testopiaXml->parse($xml,$filename);
exit 0;
@ -141,16 +109,18 @@ __END__
=head1 NAME
importxml - Import bugzilla bug data from xml.
tr_importxml - Import Testopia data from xml.
=head1 SYNOPSIS
importxml.pl [options] [file ...]
tr_importxml.pl [options] [file]
Options:
-? --help Brief help message.
-v --verbose Print error and debug information.
Multiple -v options increase verbosity.
With no file read standard input.
=head1 OPTIONS
@ -164,31 +134,11 @@ importxml - Import bugzilla bug data from xml.
Print error and debug information. Mulltiple -v increases verbosity
=item B<-m>
Send mail to exporter with a log of bugs imported and any errors.
=back
=head1 DESCRIPTION
This script is used import bugs from another installation of bugzilla.
It can be used in two ways.
First using the move function of bugzilla
on another system will send mail to an alias provided by
the administrator of the target installation (you). Set up an alias
similar to the one given below so this mail will be automatically
run by this script and imported into your database. Run 'newaliases'
after adding this alias to your aliases file. Make sure your sendmail
installation is configured to allow mail aliases to execute code.
bugzilla-import: "|/usr/bin/perl /opt/bugzilla/importxml.pl --mail"
Second it can be run from the command line with any xml file from
STDIN that conforms to the bugzilla DTD. In this case you can pass
an argument to set whether you want to send the
mail that will be sent to the exporter and maintainer normally.
importxml.pl [options] < bugsfile.xml
This script is used import Test Plans and Test Cases into Testopia.
=cut

View File

@ -19,6 +19,7 @@
#
# Contributor(s): Maciej Maczynski <macmac@xdsnet.pl>
# Ed Fuentetaja <efuentetaja@acm.org>
# Vance Baarda <vrb@novell.com>
use File::Copy;
use Bugzilla;

View File

@ -61,8 +61,7 @@ unless ($env_id || $action){
if ($action eq 'delete'){
my $env = Bugzilla::Testopia::Environment->new($env_id);
ThrowUserError('testopia-no-delete', {'object' => 'Environment'}) unless Param("allow-test-deletion");
ThrowUserError("testopia-read-only", {'object' => 'Environment'}) unless $env->canedit;
ThrowUserError('testopia-no-delete', {'object' => 'Environment'}) unless $env->candelete;
$vars->{'environment'} = $env;
$template->process("testopia/environment/delete.html.tmpl", $vars)
|| print $template->error();
@ -71,8 +70,7 @@ if ($action eq 'delete'){
elsif ($action eq 'do_delete'){
my $env = Bugzilla::Testopia::Environment->new($env_id);
ThrowUserError('testopia-no-delete', {'object' => 'Environment'}) unless Param("allow-test-deletion");
ThrowUserError("testopia-read-only", {'object' => 'Environment'}) unless $env->canedit;
ThrowUserError('testopia-no-delete', {'object' => 'Environment'}) unless $env->candelete;
ThrowUserError("testopia-non-zero-run-count", {'object' => 'Environment'}) if $env->get_run_count;
$env->obliterate;
$vars->{'tr_message'} = "Environment Deleted";

View File

@ -1,4 +1,4 @@
#!/usr/bin/perl -wT
#!/usr/bin/perl
####!/usr/bin/perl -d:ptkdb -wT
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
@ -36,6 +36,8 @@ use Bugzilla::WebService;
# To be used in version 2.23/3.0 of Bugzilla
# Bugzilla->usage_mode(Bugzilla::Constants::USAGE_MODE_WEBSERVICE);
Bugzilla->batch(1);
die 'Content-Type must be "text/xml" when using API' unless
$ENV{'CONTENT_TYPE'} eq 'text/xml';
@ -44,5 +46,8 @@ my $response = Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI
'TestCase' => 'Bugzilla::WebService::Testopia::TestCase',
'TestRun' => 'Bugzilla::WebService::Testopia::TestRun',
'TestCaseRun' => 'Bugzilla::WebService::Testopia::TestCaseRun',
'User' => 'Bugzilla::WebService::User',
'Product' => 'Bugzilla::WebService::Testopia::Product',
'Build' => 'Bugzilla::WebService::Testopia::Build',
})
->handle;