diff --git a/webtools/testopia/Bugzilla/Testopia/TestCase.pm b/webtools/testopia/Bugzilla/Testopia/TestCase.pm index 3f559ba0f88..a1640d66efc 100644 --- a/webtools/testopia/Bugzilla/Testopia/TestCase.pm +++ b/webtools/testopia/Bugzilla/Testopia/TestCase.pm @@ -104,6 +104,11 @@ use constant DB_COLUMNS => qw( test_cases.alias ); +use constant ALIAS_MAX_LENGTH => 255; +use constant REQUIREMENT_MAX_LENGTH => 255; +use constant SUMMARY_MAX_LENGTH => 255; +use constant TAG_MAX_LENGTH => 255; + our $columns = join(", ", DB_COLUMNS); sub display_columns { diff --git a/webtools/testopia/Bugzilla/Testopia/TestCaseRun.pm b/webtools/testopia/Bugzilla/Testopia/TestCaseRun.pm index f35e8230ac7..c146a806947 100644 --- a/webtools/testopia/Bugzilla/Testopia/TestCaseRun.pm +++ b/webtools/testopia/Bugzilla/Testopia/TestCaseRun.pm @@ -169,7 +169,7 @@ sub _init { detaint_natural($case_id) || return undef; $obj = $dbh->selectrow_hashref( "SELECT $columns FROM test_case_runs - WHERE case__id = ? + WHERE case_id = ? AND run_id = ? AND build_id = ? AND environment_id = ?", @@ -274,6 +274,7 @@ sub switch { my $oldenv = $self->{'environment_id'}; $self = Bugzilla::Testopia::TestCaseRun->new($self->clone($build_id,$env_id)); + $self->set_as_current; if ($oldbuild != $build_id){ my $build = Bugzilla::Testopia::Build->new($build_id); @@ -292,7 +293,6 @@ sub switch { $self->append_note($note); } } - $self->set_as_current; return $self; } diff --git a/webtools/testopia/Bugzilla/Testopia/TestPlan.pm b/webtools/testopia/Bugzilla/Testopia/TestPlan.pm index dc133fc6c8e..a5db08edb43 100644 --- a/webtools/testopia/Bugzilla/Testopia/TestPlan.pm +++ b/webtools/testopia/Bugzilla/Testopia/TestPlan.pm @@ -87,6 +87,8 @@ use constant DB_COLUMNS => qw( test_plans.isactive ); +use constant NAME_MAX_LENGTH => 255; + our $columns = join(", ", DB_COLUMNS); sub report_columns { @@ -151,7 +153,7 @@ sub _init { } else { ThrowCodeError('bad_arg', {argument => 'param', - function => 'Testopia::TestRun::_init'}); + function => 'Testopia::TestPlan::_init'}); } return undef unless (defined $obj); @@ -781,6 +783,7 @@ Returns the id of the type name passed. =cut sub lookup_type_by_name { + my $self = shift; my ($name) = @_; my $dbh = Bugzilla->dbh; diff --git a/webtools/testopia/Bugzilla/Testopia/Xml.pm b/webtools/testopia/Bugzilla/Testopia/Xml.pm index 9b5cd06db50..88dbae992b0 100644 --- a/webtools/testopia/Bugzilla/Testopia/Xml.pm +++ b/webtools/testopia/Bugzilla/Testopia/Xml.pm @@ -24,22 +24,14 @@ Bugzilla::Testopia::Xml - Testopia Xml object =head1 DESCRIPTION -This module parsers a XML representation of a Testopia test plan, -test case, test environment, category or build and returns Testopia -objects re +This module parsers a XML representation of a Testopia Test Plans, +Test Cases, or Categories and stores them in Testopia if not errors +are detected. =head1 SYNOPSIS use Bugzilla::Testopia::Xml; -=head1 SEE ALSO - -Testopia::(TestPlan, TestCase, TestRun, Category, Build, Environment) - -=head1 AUTHOR - -David Koenig - =cut package Bugzilla::Testopia::Xml; @@ -62,6 +54,26 @@ use Bugzilla::Testopia::XmlTestCase; use Bugzilla::User; use Bugzilla::Util; +############################### +#### Initialization #### +############################### + +=head1 CONSTANTS + +=over 4 + +=item STRIP_NONE - Do not strip white space from string. + +=item STRIP_LEFT - Strip white space from left side of string. + +=item STRIP_RIGHT - Strip white space from right side of string. + +=item STRIP_BOTH - Strinp white space from left and right side of string. + +=back + +=cut + use constant AUTOMATIC => "AUTOMATIC"; use constant BLOCKS => "blocks"; our $DATABASE_DESCRIPTION = "Database_descripiton"; @@ -70,6 +82,10 @@ use constant IGNORECASE => 1; use constant DEPENDSON => "dependson"; use constant PCDATA => "#PCDATA"; use constant REQUIRE => "REQUIRE"; +use constant STRIP_NONE => 0; +use constant STRIP_LEFT => 1; +use constant STRIP_RIGHT => 2; +use constant STRIP_BOTH => 3; our $TESTOPIA_GT = "&testopia_gt;"; our $TESTOPIA_LT = "&testopia_lt;"; use constant TESTPLAN_REFERENCE => "testplan_reference"; @@ -83,7 +99,6 @@ our $XML_QUOT = "&[Qq][Uu][Oo][Tt];"; use constant XMLREFERENCES_FIELDS => "Database_descripiton Database_id Xml_description"; @Bugzilla::Testopia::Xml::EXPORT = qw($DATABASE_DESCRIPTION $DATABASE_ID $XML_DESCRIPTION); - use Class::Struct; # # The Xml structure is used to keep track of all new Testopia objects being created. @@ -101,7 +116,7 @@ struct #TODO testenvironments => '@', # Array of testcases read from xml source. testcases => '@', - # Hash of testcase aliases indexed by testcase id. Used during verfication to + # Hash of testcase aliases indexed by testcase summary. Used during verfication to # insure that alias does not exist and that new aliases are used in only one testcase. testcase_aliases => '%', # Array of testplans read from xml source. @@ -116,94 +131,24 @@ struct use Text::Diff; - -############################### -#### Initialization #### -############################### - -=head1 FIELDS - -=cut - ############################### #### Methods #### ############################### -sub debug_display() -{ - my ($self) = @_; +=head1 METHODS - foreach my $category ( @{$self->categories}) - { - bless($category,"Bugzilla::Testopia::Category"); - - print STDERR "Category: " . $category->name() . "\n"; - my $category_id = "null"; - $category_id = $category->id() if ( $category->id() ); - print STDERR " ID " . $category_id . "\n"; - print STDERR " Product ID " . $category->product_id() . "\n"; - print STDERR " Description " . $category->description() . "\n"; - } +=over 4 - foreach my $testplan ( @{$self->testplans} ) - { - bless($testplan,"Bugzilla::Testopia::TestPlan"); - - print STDERR "Testplan: " . $testplan->name() . "\n"; - my $testplan_id = "null"; - $testplan_id = $testplan->id() if ( $testplan->id() ); - print STDERR " ID " . $testplan_id . "\n"; - my %author = %{$testplan->author()}; - my $author_id = $author{"id"}; - my $author_login = $author{"login"}; - print STDERR " Author " . $author_login . " (id=" . $author_id . ", hash=" . $testplan->author() . ")\n"; - print STDERR " Creation Date " . $testplan->creation_date() . "\n"; - print STDERR " Description " . $testplan->text() . "\n"; - print STDERR " Default Product Version " . $testplan->product_version() . "\n"; - print STDERR " Document " . $testplan->text() . "\n"; - print STDERR " Is Active " . $testplan->isactive() . "\n"; - print STDERR " Product " . $testplan->product_id() . "\n"; - print STDERR " Type " . $testplan->type_id() . "\n"; - - foreach my $tag ( @{$self->tags} ) - { - print STDERR " Tag " . $tag . "\n"; - } - - my @attachments = @{$testplan->attachments()}; - foreach my $attachment (@attachments) - { - my %submitter = %{$testplan->submitter()}; - my $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"; - } - } - - foreach my $testcase ( @{$self->testplans} ) - { - bless($testcase,"Bugzilla::Testopia::XmlTestCase"); - $testcase->debug_display(); - } -} +=item C -=head2 entity_replace_testopia - -Replace testopia entities in the string supplied. - -This method is called for any field that is stored in HTML format. The Testopia entities are -provided to allow users to pass HTML tags. - -For example, if you want to store a < in Bold font, the following XML - -&testopia_lt;B&testopia_gt;<&testopia_lt;/B&testopia_gt; - -is passed to the HTML field as - -< + Description: This method is called for any field that is stored in HTML format. The Testopia + entities are provided to allow users to pass HTML tags. For example, if you want to + store a < in Bold font, the following XML + &testopia_lt;B&testopia_gt;<&testopia_lt;/B&testopia_gt; + is passed to the HTML field as + < + Params: $string - String to convert. + Returns: converted string. =cut @@ -220,22 +165,33 @@ sub entity_replace_testopia return $string; } -=head2 entity_replace_xml +=pod -Replace xml entities in the string supplied. +=item C -This method is called for any field that is not stored in HTML format. The source is XML so any -XML entity will be in the &; format. These entities need to be converted back to their -character representation. + Description: This method is called for any field that is not stored in HTML format. The source + is XML so any XML entity will be in the &; format. These entities need to be + converted back to their character representation. + Params: $string - String to convert. + $strip - STRIP_NONE, STRIP_LEFT, STRIP_RIGHT, or STRIP_BOTH. White space stripping + is included because MySQL 5.0.3 retains trailing spaces when values are + stored and retrieved while prior versions stripped the trailing spaces. + Any non HTML field should use STRIP_BOTH to prevent searching issues if the + database was orginally pre MySQL 5.0.3. + Returns: converted string. + +=back =cut sub entity_replace_xml { - my ($string) = @_; + my ($string,$strip) = @_; return undef if ( ! defined $string ); + $string =~ s/^\s+// if ( $strip & STRIP_LEFT ); + $string =~ s/\s+$// if ( $strip & STRIP_RIGHT ); $string =~ s/$XML_GT/>/g; $string =~ s/$XML_LT/children('category')) { - my $category_name = $twig_category->field('name'); - my $product_name = $twig_category->att('product'); - my $description = $twig_category->field('description'); + my $category_name = entity_replace_xml($twig_category->field('name'),STRIP_BOTH); + my $product_name = entity_replace_xml($twig_category->att('product'),STRIP_BOTH); + my $description = entity_replace_xml($twig_category->field('description'),STRIP_BOTH); $description = "FIX ME. Created during category import with no description supplied." if ( $description eq "" ); @@ -351,22 +307,26 @@ sub parse() $self->error("Cannot find product '" . $twig_testplan->field('product') . "' in test plan '" . $twig_testplan->field('name') . "'."); } + my $name = entity_replace_xml($twig_testplan->field('name'),STRIP_BOTH) || undef; + $self->error("Found empty Test Plan name.") if ( ! defined($name) ); + $self->error("Length of Test Plan name '" . $name . "' must be " . Bugzilla::Testopia::TestPlan->NAME_MAX_LENGTH . " characters or less.") if ( defined($name) && ( length($name) > Bugzilla::Testopia::TestPlan->NAME_MAX_LENGTH ) ); + $testplan = Bugzilla::Testopia::TestPlan->new({ - 'name' => entity_replace_xml($twig_testplan->field('name')), + 'name' => $name, 'product_id' => $product_id, - 'default_product_version' => entity_replace_xml($twig_testplan->field('productversion')), + 'default_product_version' => entity_replace_xml($twig_testplan->field('productversion'),STRIP_BOTH), 'type_id' => $plantype_ids{$twig_testplan->att('type')}, 'text' => entity_replace_testopia($twig_testplan->field('document')), 'author_id' => $author_id, - 'isactive' => entity_replace_xml($twig_testplan->field('archive')), - 'creation_date' => entity_replace_xml($twig_testplan->field('created')) + 'isactive' => entity_replace_xml($twig_testplan->field('archive'),STRIP_BOTH), + 'creation_date' => entity_replace_xml($twig_testplan->field('created'),STRIP_BOTH) }); push @{$self->testplans}, $testplan; my @tags = $twig_testplan->children('tag'); foreach my $twig_tag (@tags) { - push @{$self->tags}, entity_replace_xml($twig_tag->text()); + push @{$self->tags}, entity_replace_xml($twig_tag->text(),STRIP_BOTH); } my @attachments = $twig_testplan->children('attachment'); @@ -388,11 +348,11 @@ sub parse() $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')), + 'description' => entity_replace_xml($twig_attachments->field('description'),STRIP_BOTH), + 'filename' => entity_replace_xml($twig_attachments->field('filename'),STRIP_BOTH), 'submitter_id' => $submitter_id, - 'mime_type' => entity_replace_xml($twig_attachments->field('mimetype')), - 'contents' => entity_replace_xml($twig_attachments->field('data')) + 'mime_type' => entity_replace_xml($twig_attachments->field('mimetype'),STRIP_BOTH), + 'contents' => entity_replace_xml($twig_attachments->field('data'),STRIP_BOTH) }); push @{$self->attachments}, $attachment; } @@ -414,7 +374,9 @@ sub parse() } foreach my $twig_testcase ($root->children('testcase')) { - my $summary = entity_replace_xml($twig_testcase->field('summary')) || undef; + my $summary = entity_replace_xml($twig_testcase->field('summary'),STRIP_BOTH) || undef; + $self->error("Found empty Test Case summary.") if ( ! defined($summary) ); + $self->error("Length of summary '" . $summary . "' must be " . Bugzilla::Testopia::TestCase->SUMMARY_MAX_LENGTH . " characters or less.") if ( defined($summary) && ( length($summary) > Bugzilla::Testopia::TestCase->SUMMARY_MAX_LENGTH ) ); my $author = $twig_testcase->att('author'); # Bugzilla::User::match returns a array with a user hash. Fields of the hash needed # are 'id' and 'login'. @@ -430,7 +392,7 @@ sub parse() bless($author_user,"Bugzilla::User"); $author_id = $author_user->id(); } - my $tester = entity_replace_xml($twig_testcase->field('defaulttester')); + my $tester = entity_replace_xml($twig_testcase->field('defaulttester'),STRIP_BOTH); # Bugzilla::User::match returns a array with a user hash. Fields of the hash needed # are 'id' and 'login'. my $tester_ref = Bugzilla::User::match($tester, 1, 0); @@ -453,12 +415,15 @@ sub parse() $xml_testcase->dependson(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS)); $xml_testcase->testplan(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS)); push @{$self->testcases}, $xml_testcase; - my $alias = entity_replace_xml($twig_testcase->field('alias')) || undef; - + my $alias = entity_replace_xml($twig_testcase->field('alias'),STRIP_BOTH) || undef; + $self->error("Length of alias '" . $alias . "' in test case '" . $summary . "' must be " . Bugzilla::Testopia::TestCase->ALIAS_MAX_LENGTH . " characters or less.") if ( defined($alias) && ( length($alias) > Bugzilla::Testopia::TestCase->ALIAS_MAX_LENGTH ) ); + my $requirement = entity_replace_xml($twig_testcase->field('requirement'),STRIP_BOTH) || undef; + $self->error("Length of requirement '" . $requirement . "' in test case '" . $summary . "' must be " . Bugzilla::Testopia::TestCase->REQUIREMENT_MAX_LENGTH . " characters or less.") if ( defined($requirement) && ( length($requirement) > Bugzilla::Testopia::TestCase->REQUIREMENT_MAX_LENGTH ) ); + $xml_testcase->testcase(Bugzilla::Testopia::TestCase->new({ 'action' => entity_replace_testopia($twig_testcase->field('action')), 'alias' => $alias, - 'arguments' => entity_replace_xml($twig_testcase->field('arguments')), + 'arguments' => entity_replace_xml($twig_testcase->field('arguments'),STRIP_NONE), 'author_id' => $author_id, 'blocks' => undef, 'breakdown' => entity_replace_testopia($twig_testcase->field('breakdown')), @@ -470,9 +435,9 @@ sub parse() 'isautomated' => ( uc $twig_testcase->att('automated') ) eq AUTOMATIC, 'plans' => undef, 'priority_id' => $priority_ids{$twig_testcase->att('priority')}, - 'requirement' => entity_replace_xml($twig_testcase->field('requirement')), + 'requirement' => $requirement, 'setup' => entity_replace_testopia($twig_testcase->field('setup')), - 'script' => entity_replace_xml($twig_testcase->field('script')), + 'script' => entity_replace_xml($twig_testcase->field('script'),STRIP_NONE), 'summary' => $summary, })); foreach my $twig_testplan_reference ( $twig_testcase->children(TESTPLAN_REFERENCE) ) @@ -484,7 +449,11 @@ sub parse() . $twig_testplan_reference->att('type') . "' in test case '" . $twig_testcase->field('summary') . "'." ); } - elsif ( ! $xml_testcase->testplan->add($twig_testplan_reference->att('type'),entity_replace_xml($testplan_reference)) ) + elsif ( length($testplan_reference) > Bugzilla::Testopia::TestPlan->NAME_MAX_LENGTH ) + { + $self->error("Length of Test Plan name '" . $testplan_reference . "' for test case '" . $summary . "' must be " . Bugzilla::Testopia::TestCase->REQUIREMENT_MAX_LENGTH . " characters or less."); + } + elsif ( ! $xml_testcase->testplan->add($twig_testplan_reference->att('type'),entity_replace_xml($testplan_reference,STRIP_BOTH)) ) { $self->error("Do not know how to handle test plan of type '" . $twig_testplan_reference->att('type') @@ -493,11 +462,11 @@ sub parse() } } # Keep track of this testcase's alias. Used during verification to insure aliases are unique. - $self->testcase_aliases(entity_replace_xml($twig_testcase->field('summary')),$alias) if ( defined $alias ); + $self->testcase_aliases(entity_replace_xml($twig_testcase->field('summary'),STRIP_BOTH),$alias) if ( defined $alias ); # Keep track of this testcase's category. To create a category at this time would require # getting the product from the Test Plan that this Test Case is associated with. The category # will created when each Test Case is stored. - $xml_testcase->category(entity_replace_xml($twig_testcase->field('categoryname'))); + $xml_testcase->category(entity_replace_xml($twig_testcase->field('categoryname'),STRIP_BOTH)); my @attachments = $twig_testcase->children('attachment'); foreach my $twig_attachments (@attachments) @@ -518,11 +487,11 @@ sub parse() $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')), + 'description' => entity_replace_xml($twig_attachments->field('description'),STRIP_BOTH), + 'filename' => entity_replace_xml($twig_attachments->field('filename'),STRIP_BOTH), 'submitter_id' => $submitter_id, - 'mime_type' => entity_replace_xml($twig_attachments->field('mimetype')), - 'contents' => entity_replace_xml($twig_attachments->field('data')) + 'mime_type' => entity_replace_xml($twig_attachments->field('mimetype'),STRIP_BOTH), + 'contents' => entity_replace_xml($twig_attachments->field('data'),STRIP_BOTH) }); $xml_testcase->add_attachment($attachment); } @@ -530,19 +499,21 @@ sub parse() my @tags = $twig_testcase->children('tag'); foreach my $twig_tag ( @tags ) { - $xml_testcase->add_tag(entity_replace_xml($twig_tag->text())); + my $tag = entity_replace_xml($twig_tag->text(),STRIP_BOTH); + $self->error("Length of tag '" . $tag . "' in test case '" . $summary . "' must be " . Bugzilla::Testopia::TestCase->TAG_MAX_LENGTH . " characters or less.") if ( defined($tag) && ( length($tag) > Bugzilla::Testopia::TestCase->TAG_MAX_LENGTH ) ); + $xml_testcase->add_tag($tag); } my @components = $twig_testcase->children('component'); foreach my $twig_component ( @components ) { - my $results = $xml_testcase->add_component(entity_replace_xml($twig_component->children_text(PCDATA)),$twig_component->att('product')); + my $results = $xml_testcase->add_component(entity_replace_xml($twig_component->children_text(PCDATA),STRIP_BOTH),$twig_component->att('product')); $self->error($results) if ( $results ne "" ); } foreach my $twig_blocks ( $twig_testcase->children(BLOCKS) ) { - if ( ! $xml_testcase->blocks->add($twig_blocks->att('type'),entity_replace_xml($twig_blocks->children_text(PCDATA))) ) + if ( ! $xml_testcase->blocks->add($twig_blocks->att('type'),entity_replace_xml($twig_blocks->children_text(PCDATA),STRIP_BOTH)) ) { $self->error("Do not know how to handle a blocking test case of type '" . $twig_blocks->att('type') . "' in test case '" . $xml_testcase->testcase->summary() . "'.") } @@ -550,9 +521,9 @@ sub parse() foreach my $twig_dependson ( $twig_testcase->children(DEPENDSON) ) { - if ( ! $xml_testcase->dependson->add($twig_dependson->att('type'),entity_replace_xml($twig_dependson->children_text(PCDATA))) ) + if ( ! $xml_testcase->dependson->add($twig_dependson->att('type'),entity_replace_xml($twig_dependson->children_text(PCDATA),STRIP_BOTH)) ) { - $self->error("Do not know how to handle dependency of type '" . $twig_dependson->att('type') . "' in test case '" . entity_replace_xml($xml_testcase->testcase->summary()) . "'.") + $self->error("Do not know how to handle dependency of type '" . $twig_dependson->att('type') . "' in test case '" . entity_replace_xml($xml_testcase->testcase->summary(),STRIP_BOTH) . "'.") } } } @@ -623,8 +594,14 @@ sub parse() # Store new categories. foreach my $category ( @{$self->categories} ) { + # Make sure category still does not exist. We don't check for uniqueness above so + # the same category could be defined multiple times. + if ( ! $category->check_name($category->name()) ) + { $category->store(); - print "Created category '" . $category->name() . "': " . $category->description() . "\n"; + my $product_name = Bugzilla::Testopia::Product->new($category->product_id())->name(); + print "Created category '" . $category->name() . "': " . $category->description() . " for product " . $product_name . ".\n"; + } } # Store new testplans. @@ -673,4 +650,14 @@ sub parse() $twig->purge; } +=head1 SEE ALSO + +Testopia::(TestPlan, TestCase, TestRun, Category, Build, Environment) + +=head1 AUTHOR + +David Koenig + +=cut + 1; diff --git a/webtools/testopia/Bugzilla/Testopia/XmlTestCase.pm b/webtools/testopia/Bugzilla/Testopia/XmlTestCase.pm index 85b3f2f7af4..61a793f7a48 100644 --- a/webtools/testopia/Bugzilla/Testopia/XmlTestCase.pm +++ b/webtools/testopia/Bugzilla/Testopia/XmlTestCase.pm @@ -258,6 +258,14 @@ sub get_testcase_ids() return @return_testcase_id; } +=head2 store + +Saves a imported Test Case. This method insures that all Test Case attributes not stored +in the Test Case object are created. The attributes include the Test Plan, tags, compoents, +attachments and categories. + +=cut + sub store() { my ($self, @new_testplans) = @_; @@ -359,20 +367,49 @@ sub store() return $error_message; } +=head2 store_relationships + +Save the dependson and blocks relationships between Test Cases. This method can only be +called after the Test Cases being imported have been stored. The dependson and blocks +relationships use the Test Case identifier which is created only after the Test Case has +been stored. + +=cut + sub store_relationships() { my ($self, @new_testcases) = @_; - my $blocks = join(' ',$self->get_testcase_ids("blocks",@new_testcases)); - my $dependson = join(' ',$self->get_testcase_ids("dependson",@new_testcases)); + # Hashes are used because the entires in blocks and dependson must be unique. + my %blocks = (); + foreach my $block ( $self->get_testcase_ids("blocks",@new_testcases) ) + { + $blocks{$block}++; + } + my $blocks_size = keys( %blocks ); + my %dependson = (); + foreach my $dependson ( $self->get_testcase_ids("dependson",@new_testcases) ) + { + $dependson{$dependson}++; + } + my $dependson_size = keys( %dependson ); + - if ( $blocks ne "" || $dependson ne "" ) + if ( ( $blocks_size > 0 ) || ( $dependson_size > 0 ) ) { # Need to add the current blocks and dependson from the Test Case; otherwise, they will # be removed. - $blocks .= $self->testcase->blocked_list_uncached(); - $dependson .= $self->testcase->dependson_list_uncached(); - $self->testcase->update_deps($dependson,$blocks); + foreach my $block ( split(/ /,$self->testcase->blocked_list_uncached()) ) + { + $blocks{$block}++; + } + foreach my $dependson ( split(/ /,$self->testcase->dependson_list_uncached()) ) + { + $dependson{$dependson}++; + } + my @blocks = keys(%blocks); + my @dependson = keys(%dependson); + $self->testcase->update_deps( join(' ',@dependson ),join(' ',@blocks) ); } } diff --git a/webtools/testopia/template/en/default/testopia/case/csv.case.tmpl b/webtools/testopia/Bugzilla/WebService/Component.pm similarity index 100% rename from webtools/testopia/template/en/default/testopia/case/csv.case.tmpl rename to webtools/testopia/Bugzilla/WebService/Component.pm diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/Build.pm b/webtools/testopia/Bugzilla/WebService/Testopia/Build.pm index 2840cdec865..e9f66fd82c6 100644 --- a/webtools/testopia/Bugzilla/WebService/Testopia/Build.pm +++ b/webtools/testopia/Bugzilla/WebService/Testopia/Build.pm @@ -23,6 +23,94 @@ use base qw(Bugzilla::WebService); use Bugzilla::Testopia::Build; +sub get +{ + my $self = shift; + my ($build_id) = @_; + + $self->login; + + #Result is a test plan hash map + my $build = new Bugzilla::Testopia::Build($build_id); + + if (not defined $build) + { + $self->logout; + die "Build, " . $build_id . ", not found"; + } + + $self->logout; + + return $build; +} + +sub create +{ + my $self = shift; + my ($new_values) = @_; # Required: name, product_id + + $self->login; + + my $build = new Bugzilla::Testopia::Build($new_values); + + my $name = $$new_values{name}; + + if (defined($name) && $build->check_name($name)) + { + die "Build name, " . $name . ", already exists"; + } + + my $result = $build->store(); + + $self->logout; + + # Result is new build id + return $result; +} + +sub update +{ + my $self =shift; + my ($build_id, $new_values) = @_; # Modifiable: name, description, milestone + + $self->login; + + my $build = new Bugzilla::Testopia::Build($build_id); + + if (not defined $build) + { + $self->logout; + die "Build, " . $build_id . ", not found"; + } + + my $name = $$new_values{name}; + + if (defined($name) && $build->check_name($name)) + { + die "Build name, " . $name . ", already exists"; + } + + if (!defined($name)) + { + $name = $build->name(); + } + + my $description = (defined($$new_values{description}) ? $$new_values{description} : $build->description()); + + my $milestone = (defined($$new_values{milestone}) ? $$new_values{milestone} : $build->milestone()); + + my $result = $build->update($name, + $description, + $milestone); + + $build = new Bugzilla::Testopia::Build($build_id); + + $self->logout; + + # Result is modified build, otherwise an exception will be thrown + return $build; +} + sub lookup_name_by_id { my $self = shift; diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/Environment.pm b/webtools/testopia/Bugzilla/WebService/Testopia/Environment.pm new file mode 100644 index 00000000000..372051f1e36 --- /dev/null +++ b/webtools/testopia/Bugzilla/WebService/Testopia/Environment.pm @@ -0,0 +1,171 @@ +# -*- 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 +# Dallas Harken + +package Bugzilla::WebService::Testopia::Environment; + +use strict; + +use base qw(Bugzilla::WebService); + +use Bugzilla::Testopia::Environment; +use Bugzilla::Testopia::Search; +use Bugzilla::Testopia::Table; + +# Utility method called by the list method +sub _list +{ + my ($query) = @_; + + my $cgi = Bugzilla->cgi; + + $cgi->param("current_tab", "environment"); + + foreach (keys(%$query)) + { + $cgi->param($_, $$query{$_}); + } + + my $search = Bugzilla::Testopia::Search->new($cgi); + + # Result is an array of environment hash maps + return Bugzilla::Testopia::Table->new('environment', + 'tr_xmlrpc.cgi', + $cgi, + undef, + $search->query() + )->list(); +} + +sub get +{ + my $self = shift; + my ($environment_id) = @_; + + $self->login; + + #Result is a environment hash map + my $environment = new Bugzilla::Testopia::Environment($environment_id); + + if (not defined $environment) + { + $self->logout; + die "Environment, " . $environment_id . ", not found"; + } + + if (not $environment->canview) + { + $self->logout; + die "User Not Authorized"; + } + + $self->logout; + + return $environment; +} + +sub list +{ + my $self = shift; + my ($query) = @_; + + $self->login; + + my $list = _list($query); + + $self->logout; + + return $list; +} + +sub create +{ + my $self =shift; + my ($new_values) = @_; + + $self->login; + + my $environment = new Bugzilla::Testopia::Environment($new_values); + + my $result = $environment->store(); + + $self->logout; + + # Result is new environment id + return $result; +} + +sub update +{ + my $self =shift; + my ($environment_id, $new_values) = @_; + + $self->login; + + my $environment = new Bugzilla::Testopia::Environment($environment_id); + + if (not defined $environment) + { + $self->logout; + die "Environment, " . $environment_id . ", not found"; + } + + if (not $environment->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $environment->update($new_values); + + $environment = new Bugzilla::Testopia::Environment($environment_id); + + $self->logout; + + # Result is modified environment, otherwise an exception will be thrown + return $environment; +} + +sub get_runs +{ + my $self = shift; + my ($environment_id) = @_; + + $self->login; + + my $environment = new Bugzilla::Testopia::Environment($environment_id); + + if (not defined $environment) + { + $self->logout; + die "Environment, " . $environment_id . ", not found"; + } + + if (not $environment->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $environment->runs(); + + $self->logout; + + # Result is list of test runs for the given environment + return $result; +} + +1; \ No newline at end of file diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/TestCase.pm b/webtools/testopia/Bugzilla/WebService/Testopia/TestCase.pm index 6fc93d4fa8b..d147202f859 100644 --- a/webtools/testopia/Bugzilla/WebService/Testopia/TestCase.pm +++ b/webtools/testopia/Bugzilla/WebService/Testopia/TestCase.pm @@ -20,89 +20,10 @@ package Bugzilla::WebService::Testopia::TestCase; use strict; use base qw(Bugzilla::WebService); use Bugzilla::User; -use Bugzilla::Util qw(detaint_natural); use Bugzilla::Testopia::TestCase; use Bugzilla::Testopia::Search; use Bugzilla::Testopia::Table; - -# Convert string field values to their respective integer id's -sub _convert_to_ids -{ - my ($hash) = @_; - - if (defined($$hash{"author"})) - { - $$hash{"author_id"} = login_to_id($$hash{"author"}); - } - delete $$hash{"author"}; - - if (defined($$hash{"case_status"})) - { - $$hash{"case_status_id"} = Bugzilla::Testopia::TestCase::lookup_status_by_name($$hash{"case_status"}); - } - delete $$hash{"case_status"}; - - if (defined($$hash{"category"})) - { - $$hash{"category_id"} = Bugzilla::Testopia::TestCase::lookup_category_by_name($$hash{"category"}); - } - delete $$hash{"category"}; - - if (defined($$hash{"default_tester"})) - { - $$hash{"default_tester_id"} = login_to_id($$hash{"default_tester"}); - } - delete $$hash{"default_tester"}; - - if (defined($$hash{"priority"})) - { - $$hash{"priority_id"} = Bugzilla::Testopia::TestCase::lookup_priority_by_value($$hash{"priority"}); - } - delete $$hash{"priority"}; - } - -# Convert fields with integer id's to their respective string values -sub _convert_to_strings -{ - my ($hash) = @_; - - $$hash{"author"} = ""; - if (defined($$hash{"author_id"})) - { - $$hash{"author"} = new Bugzilla::User($$hash{"author_id"})->login; - } - delete $$hash{"author_id"}; - - $$hash{"case_status"} = ""; - if (defined($$hash{"case_status_id"})) - { - $$hash{"case_status"} = Bugzilla::Testopia::TestCase->lookup_status($$hash{"case_status_id"}); - } - delete $$hash{"case_status_id"}; - - $$hash{"category"} = ""; - if (defined($$hash{"category_id"})) - { - $$hash{"category"} = Bugzilla::Testopia::TestCase->lookup_category($$hash{"category_id"}); - } - delete $$hash{"category_id"}; - - $$hash{"default_tester"} = ""; - if (defined($$hash{"default_tester_id"})) - { - $$hash{"default_tester"} = new Bugzilla::User($$hash{"default_tester_id"})->login; - } - delete $$hash{"default_tester_id"}; - - $$hash{"priority"} = ""; - if (defined($$hash{"priority_id"})) - { - $$hash{"priority"} = Bugzilla::Testopia::TestCase->lookup_priority($$hash{"priority_id"}); - } - delete $$hash{"priority_id"}; - } - # Utility method called by the list method sub _list { @@ -110,8 +31,6 @@ sub _list my $cgi = Bugzilla->cgi; - $cgi->param("viewall", 1); - $cgi->param("current_tab", "case"); foreach (keys(%$query)) @@ -135,42 +54,38 @@ sub get my $self = shift; my ($test_case_id) = @_; - Bugzilla->login; + $self->login; - # We can detaint immediately if what we get passed is fully numeric. - # We leave bug alias checks to Bugzilla::Testopia::TestCase::new. + my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canview) + { + $self->logout; + die "User Not Authorized"; + } - if ($test_case_id =~ /^[0-9]+$/) { - detaint_natural($test_case_id); - } + $self->logout; #Result is a test case hash map - my $testcase = new Bugzilla::Testopia::TestCase($test_case_id); - - _convert_to_strings($testcase); - - Bugzilla->logout; - - return $testcase; + return $test_case; } sub list { - Bugzilla->login; - my $self = shift; my ($query) = @_; - - _convert_to_ids($query); + + $self->login; my $list = _list($query); - foreach (@$list) - { - _convert_to_strings($_); - } - - Bugzilla->logout; + $self->logout; return $list; } @@ -180,16 +95,16 @@ sub create my $self =shift; my ($new_values) = @_; - Bugzilla->login; + $self->login; - _convert_to_ids($new_values); - my $test_case = new Bugzilla::Testopia::TestCase($new_values); - Bugzilla->logout; + my $result = $test_case->store(); + $self->logout; + # Result is new test plan id - return $test_case->store(); + return $result } sub update @@ -197,18 +112,30 @@ sub update my $self =shift; my ($test_case_id, $new_values) = @_; - Bugzilla->login; + $self->login; my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); - _convert_to_ids($new_values); + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } - $test_case->update($new_values); + if (not $test_case->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_case->update($new_values); + + $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + $self->logout; - Bugzilla->logout; - - # Result is zero on success, otherwise an exception will be thrown - return 0; + # Result is modified test case on success, otherwise an exception will be thrown + return $test_case; } sub get_text @@ -216,20 +143,25 @@ sub get_text my $self =shift; my ($test_case_id) = @_; - Bugzilla->login; + $self->login; my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canview) + { + $self->logout; + die "User Not Authorized"; + } + my $doc = $test_case->text(); - $$doc{"author"} = ""; - if (defined($$doc{"author_id"})) - { - $$doc{"author"} = new Bugzilla::User($$doc{"author_id"})->login; - } - delete $$doc{"author_id"}; - - Bugzilla->logout; + $self->logout; #Result is the latest test case doc hash map return $doc; @@ -238,20 +170,257 @@ sub get_text sub store_text { my $self =shift; - my ($test_case_id, $author, $action, $effect) = @_; + my ($test_case_id, $author_id, $action, $effect, $setup, $breakdown) = @_; - Bugzilla->login; + $self->login; - my $author_id = login_to_id($author); - my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); - my $version = $test_case->store_text($test_case_id, $author_id, $action, $effect); + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } - Bugzilla->logout; + if (not $test_case->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $version = $test_case->store_text($test_case_id, $author_id, $action, $effect, $setup, $breakdown); + + $self->logout; # Result is new test case doc version on success, otherwise an exception will be thrown return $version; } +sub get_plans +{ + my $self = shift; + my ($test_case_id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_case->plans(); + + $self->logout; + + # Result is list of test plans for the given test case + return $result; +} + +sub add_component +{ + my $self =shift; + my ($test_case_id, $component_id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_case->add_component($component_id); + + $self->logout; + + # Result 0 on success, otherwise an exception will be thrown + return 0; +} + +sub remove_component +{ + my $self =shift; + my ($test_case_id, $component_id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_case->remove_component($component_id); + + $self->logout; + + # Result 0 on success, otherwise an exception will be thrown + return 0; +} + +sub get_components +{ + my $self =shift; + my ($test_case_id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase($test_case_id); + + if (not defined $test_case) + { + $self->logout; + die "Testcase, " . $test_case_id . ", not found"; + } + + if (not $test_case->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_case->components(); + + $self->logout; + + # Result list of components otherwise an exception will be thrown + return $result; +} + +sub lookup_status_id_by_name +{ + my $self =shift; + my ($name) = @_; + + $self->login; + + my $result = Bugzilla::Testopia::TestCase::lookup_status_by_name($name); + + $self->logout; + + # Result is test case status id for the given test case status name + return $result; +} + +sub lookup_status_name_by_id +{ + my $self =shift; + my ($id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase({}); + + my $result = $test_case->lookup_status($id); + + $self->logout; + + if (!defined $result) + { + $result = 0; + }; + + # Result is test case status name for the given test case status id + return $result; +} + +sub lookup_category_id_by_name +{ + my $self =shift; + my ($name) = @_; + + $self->login; + + my $result = Bugzilla::Testopia::TestCase::lookup_category_by_name($name); + + $self->logout; + + # Result is test case category id for the given test case category name + return $result; +} + +sub lookup_category_name_by_id +{ + my $self =shift; + my ($id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase({}); + + my $result = $test_case->lookup_category($id); + + $self->logout; + + if (!defined $result) + { + $result = 0; + }; + + # Result is test case category name for the given test case category id + return $result; +} + +sub lookup_priority_id_by_name +{ + my $self =shift; + my ($name) = @_; + + $self->login; + + my $result = Bugzilla::Testopia::TestCase::lookup_priority_by_value($name); + + $self->logout; + + # Result is test case priority id for the given test case priority name + return $result; +} + +sub lookup_priority_name_by_id +{ + my $self =shift; + my ($id) = @_; + + $self->login; + + my $test_case = new Bugzilla::Testopia::TestCase({}); + + my $result = $test_case->lookup_priority($id); + + $self->logout; + + if (!defined $result) + { + $result = 0; + }; + + # Result is test case priority name for the given test case priority id + return $result; +} + 1; \ No newline at end of file diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/TestCaseRun.pm b/webtools/testopia/Bugzilla/WebService/Testopia/TestCaseRun.pm index 06217a195a9..1463222facd 100644 --- a/webtools/testopia/Bugzilla/WebService/Testopia/TestCaseRun.pm +++ b/webtools/testopia/Bugzilla/WebService/Testopia/TestCaseRun.pm @@ -18,57 +18,13 @@ package Bugzilla::WebService::Testopia::TestCaseRun; use strict; + use base qw(Bugzilla::WebService); -use Bugzilla::Util qw(detaint_natural); -use Bugzilla::Testopia::TestCaseRun; + use Bugzilla::User; use Bugzilla::Testopia::Search; use Bugzilla::Testopia::Table; - -# Convert string field values to their respective integer id's -sub _convert_to_ids -{ - my ($hash) = @_; - - if (defined($$hash{"assignee"})) - { - $$hash{"assignee"} = login_to_id($$hash{"assignee"}); - } - - if (defined($$hash{"testedby"})) - { - $$hash{"testedby"} = login_to_id($$hash{"testedby"}); - } - - if (defined($$hash{"case_run_status"})) - { - $$hash{"case_run_status_id"} = Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($$hash{"case_run_status"}); - } - delete $$hash{"case_run_status"}; -} - -# Convert fields with integer id's to their respective string values -sub _convert_to_strings -{ - my ($hash) = @_; - - if (defined($$hash{"assignee"})) - { - $$hash{"assignee"} = new Bugzilla::User($$hash{"assignee"})->login; - } - - if (defined($$hash{"testedby"})) - { - $$hash{"testedby"} = new Bugzilla::User($$hash{"testedby"})->login; - } - - $$hash{"case_run_status"} = ""; - if (defined($$hash{"case_run_status_id"})) - { - $$hash{"case_run_status"} = Bugzilla::Testopia::TestCaseRun->lookup_status($$hash{"case_run_status_id"}); - } - delete $$hash{"case_run_status_id"}; -} +use Bugzilla::Testopia::TestCaseRun; # Utility method called by the list method sub _list @@ -100,21 +56,24 @@ sub get my $self = shift; my ($test_case_run_id) = @_; - Bugzilla->login; - - # We can detaint immediately if what we get passed is fully numeric. - # We leave bug alias checks to Bugzilla::Testopia::TestCaseRun::new. - - if ($test_case_run_id =~ /^[0-9]+$/) { - detaint_natural($test_case_run_id); - } + $self->login; #Result is a test case run hash map my $test_case_run = new Bugzilla::Testopia::TestCaseRun($test_case_run_id); + + if (not defined $test_case_run) + { + $self->logout; + die "TestcaseRun, " . $test_case_run_id . ", not found"; + } + + if (not $test_case_run->canview) + { + $self->logout; + die "User Not Authorized"; + } - _convert_to_strings($test_case_run); - - Bugzilla->logout; + $self->logout; return $test_case_run; @@ -122,21 +81,14 @@ sub get sub list { - Bugzilla->login; - my $self = shift; my ($query) = @_; - - _convert_to_ids($query); + + $self->login; my $list = _list($query); - foreach (@$list) - { - _convert_to_strings($_); - } - - Bugzilla->logout; + $self->logout; return $list; } @@ -146,44 +98,128 @@ sub create my $self =shift; my ($new_values) = @_; - Bugzilla->login; + $self->login; - _convert_to_ids($new_values); - my $test_case_run = new Bugzilla::Testopia::TestCaseRun($new_values); - Bugzilla->logout; + my $result = $test_case_run->store(); + $self->logout; + # Result is new test case run id - return $test_case_run->store(); + return $result; } sub update { my $self =shift; - my ($run_id, $case_id, $build_id, $new_values) = @_; + my ($run_id, $case_id, $build_id, $environment_id, $new_values) = @_; - Bugzilla->login; + $self->login; - my $test_case_run_id = Bugzilla::Testopia::TestCaseRun::lookup_case_run_id($run_id, $case_id, $build_id); - - my $test_case_run = new Bugzilla::Testopia::TestCaseRun($test_case_run_id); + my $test_case_run = new Bugzilla::Testopia::TestCaseRun($case_id, + $run_id, + $build_id, + $environment_id + ); - _convert_to_ids($new_values); + if (not defined $test_case_run) + { + $self->logout; + die "TestCaseRun for build_id = " . $build_id . + ", case_id = " . $case_id . + ", environment_id = " . $environment_id . + ", run_id = " . $run_id . + ", not found"; + } + + if (not $test_case_run->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + # Check to see what has changed then use set methods - $$new_values{build_id} = $build_id; # Needed by TestCaseRun's update member function - - if (not defined $$new_values{environment_id}) + if (defined($$new_values{assignee})) { - $$new_values{environment_id} = $test_case_run->environment; # Needed by TestCaseRun's update member function + $test_case_run->set_assignee($$new_values{assignee}); + } + + if (defined($$new_values{build_id})) + { + $test_case_run->set_build($$new_values{build_id}); + } + + if (defined($$new_values{environment_id})) + { + $test_case_run->set_environment($$new_values{environment_id}); + } + + if (defined($$new_values{case_run_status_id})) + { + $test_case_run->set_status($$new_values{case_run_status_id}); + } + + if (defined($$new_values{notes})) + { + $test_case_run->append_note($$new_values{notes}); } - $test_case_run->update($new_values); + # Remove assignee user object and replace with just assignee id + if (ref($$test_case_run{assignee}) eq 'Bugzilla::User') + { + $$test_case_run{assignee} = $$test_case_run{assignee}->id(); + } + + $self->logout; + + #Remove attributes we do not want to publish + delete $$test_case_run{bugs}; + delete $$test_case_run{build}; + delete $$test_case_run{case}; + delete $$test_case_run{environment}; + delete $$test_case_run{run}; - Bugzilla->logout; + # Result is modified test case run on success, otherwise an exception will be thrown + return $test_case_run; +} + +sub lookup_status_id_by_name +{ + my $self =shift; + my ($name) = @_; + + $self->login; + + my $result = Bugzilla::Testopia::TestCaseRun::lookup_status_by_name($name); + + $self->logout; + + # Result is test case run status id for the given test case run status name + return $result; +} + +sub lookup_status_name_by_id +{ + my $self =shift; + my ($id) = @_; + + $self->login; + + my $test_case_run = new Bugzilla::Testopia::TestCaseRun({}); + + my $result = $test_case_run->lookup_status($id); + + $self->logout; + + if (!defined $result) + { + $result = 0; + }; - # Result is zero on success, otherwise an exception will be thrown - return 0; + # Result is test case run status name for the given test case run status id + return $result; } 1; diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/TestPlan.pm b/webtools/testopia/Bugzilla/WebService/Testopia/TestPlan.pm index 8ca83adacf2..d38c0663c8a 100644 --- a/webtools/testopia/Bugzilla/WebService/Testopia/TestPlan.pm +++ b/webtools/testopia/Bugzilla/WebService/Testopia/TestPlan.pm @@ -133,9 +133,11 @@ sub update my $result = $test_plan->update($new_values); + $test_plan = new Bugzilla::Testopia::TestPlan($test_plan_id); + $self->logout; - # Result is zero on success, otherwise an exception will be thrown + # Result is modified test plan, otherwise an exception will be thrown return $test_plan; } @@ -222,7 +224,36 @@ sub get_categories $self->logout; - # Result is list of test runs for the given test plan + # Result is list of categories for the given test plan + return $result; +} + +sub get_builds +{ + my $self =shift; + my ($test_plan_id) = @_; + + $self->login; + + my $test_plan = new Bugzilla::Testopia::TestPlan($test_plan_id); + + if (not defined $test_plan) + { + $self->logout; + die "Testplan, " . $test_plan_id . ", not found"; + } + + if (not $test_plan->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_plan->product->builds(); + + $self->logout; + + # Result is list of builds for the given test plan return $result; } diff --git a/webtools/testopia/Bugzilla/WebService/Testopia/TestRun.pm b/webtools/testopia/Bugzilla/WebService/Testopia/TestRun.pm index 23769ba137e..13c6c8c53c1 100644 --- a/webtools/testopia/Bugzilla/WebService/Testopia/TestRun.pm +++ b/webtools/testopia/Bugzilla/WebService/Testopia/TestRun.pm @@ -21,51 +21,12 @@ use strict; use base qw(Bugzilla::WebService); -use Bugzilla::Util qw(detaint_natural); use Bugzilla::Product; use Bugzilla::User; use Bugzilla::Testopia::TestRun; use Bugzilla::Testopia::Search; use Bugzilla::Testopia::Table; -# Convert string field values to their respective integer id's -sub _convert_to_ids -{ - my ($hash) = @_; - - if (defined($$hash{"manager"})) - { - $$hash{"manager_id"} = login_to_id($$hash{"manager"}); - } - delete $$hash{"manager"}; - - if (defined($$hash{"environment"})) - { - $$hash{"environment_id"} = Bugzilla::Testopia::TestRun::lookup_environment_by_name($$hash{"environment"}); - } - delete $$hash{"environment"}; -} - -# Convert fields with integer id's to their respective string values -sub _convert_to_strings -{ - my ($hash) = @_; - - $$hash{"manager"} = ""; - if (defined($$hash{"manager_id"})) - { - $$hash{"manager"} = new Bugzilla::User($$hash{"manager_id"})->login; - } - delete $$hash{"manager_id"}; - - $$hash{"environment"} = ""; - if (defined($$hash{"environment_id"})) - { - $$hash{"environment"} = Bugzilla::Testopia::TestRun->lookup_environment($$hash{"environment_id"}); - } - delete $$hash{"environment_id"}; -} - # Utility method called by the list method sub _list { @@ -73,8 +34,6 @@ sub _list my $cgi = Bugzilla->cgi; - $cgi->param("viewall", 1); - $cgi->param("current_tab", "run"); foreach (keys(%$query)) @@ -98,42 +57,38 @@ sub get my $self = shift; my ($test_run_id) = @_; - Bugzilla->login; - - # We can detaint immediately if what we get passed is fully numeric. - # We leave bug alias checks to Bugzilla::Testopia::TestRun::new. - - if ($test_run_id =~ /^[0-9]+$/) { - detaint_natural($test_run_id); - } + $self->login; #Result is a test run hash map - my $testrun = new Bugzilla::Testopia::TestRun($test_run_id); + my $test_run = new Bugzilla::Testopia::TestRun($test_run_id); + + if (not defined $test_run) + { + $self->logout; + die "Testrun, " . $test_run_id . ", not found"; + } + + if (not $test_run->canview) + { + $self->logout; + die "User Not Authorized"; + } - _convert_to_strings($testrun); + $self->logout; - Bugzilla->logout; - - return $testrun; + return $test_run; } sub list { - Bugzilla->login; - my $self = shift; my ($query) = @_; - - _convert_to_ids($query); + + $self->login; my $list = _list($query); - foreach (@$list) - { - _convert_to_strings($_); - } - - Bugzilla->logout; + $self->logout; return $list; } @@ -143,16 +98,16 @@ sub create my $self =shift; my ($new_values) = @_; - Bugzilla->login; + $self->login; - _convert_to_ids($new_values); - my $test_run = new Bugzilla::Testopia::TestRun($new_values); - Bugzilla->logout; + my $result = $test_run->store(); + + $self->logout; # Result is new test run id - return $test_run->store(); + return $result } sub update @@ -160,18 +115,154 @@ sub update my $self =shift; my ($test_run_id, $new_values) = @_; - Bugzilla->login; + $self->login; my $test_run = new Bugzilla::Testopia::TestRun($test_run_id); - _convert_to_ids($new_values); + if (not defined $test_run) + { + $self->logout; + die "Testrun, " . $test_run_id . ", not found"; + } - $test_run->update($new_values); + if (not $test_run->canedit) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_run->update($new_values); + + $test_run = new Bugzilla::Testopia::TestRun($test_run_id); - Bugzilla->logout; + $self->logout; - # Result is zero on success, otherwise an exception will be thrown - return 0; + # Result is modified test run on success, otherwise an exception will be thrown + return $test_run; +} + +sub get_test_cases +{ + my $self =shift; + my ($test_run_id) = @_; + + $self->login; + + my $test_run = new Bugzilla::Testopia::TestRun($test_run_id); + + if (not defined $test_run) + { + $self->logout; + die "Testrun, " . $test_run_id . ", not found"; + } + + if (not $test_run->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_run->cases(); + + $self->logout; + + # Result is list of test cases for the given test run + return $result; +} + +sub get_test_case_runs +{ + my $self =shift; + my ($test_run_id) = @_; + + $self->login; + + my $test_run = new Bugzilla::Testopia::TestRun($test_run_id); + + if (not defined $test_run) + { + $self->logout; + die "Testrun, " . $test_run_id . ", not found"; + } + + if (not $test_run->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_run->caseruns(); + + $self->logout; + + # Result is list of test case runs for the given test run + return $result; +} + +sub get_test_plan +{ + my $self =shift; + my ($test_run_id) = @_; + + $self->login; + + my $test_run = new Bugzilla::Testopia::TestRun($test_run_id); + + if (not defined $test_run) + { + $self->logout; + die "Testrun, " . $test_run_id . ", not found"; + } + + if (not $test_run->canview) + { + $self->logout; + die "User Not Authorized"; + } + + my $result = $test_run->plan(); + + $self->logout; + + # Result is test plan for the given test run + return $result; +} + +sub lookup_environment_id_by_name +{ + my $self =shift; + my ($name) = @_; + + $self->login; + + my $result = Bugzilla::Testopia::TestRun::lookup_environment_by_name($name); + + $self->logout; + + # Result is test run environment id for the given test run environment name + return $result; +} + +sub lookup_environment_name_by_id +{ + my $self =shift; + my ($id) = @_; + + $self->login; + + my $test_run = new Bugzilla::Testopia::TestRun({}); + + my $result = $test_run->lookup_environment($id); + + $self->logout; + + if (!defined $result) + { + $result = 0; + }; + + # Result is test run environment name for the given test run environment id + return $result; } 1; \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/case/list.csv.tmpl b/webtools/testopia/template/en/default/testopia/case/list.csv.tmpl index 14cddf7a9fb..ad62af77f1a 100644 --- a/webtools/testopia/template/en/default/testopia/case/list.csv.tmpl +++ b/webtools/testopia/template/en/default/testopia/case/list.csv.tmpl @@ -25,10 +25,9 @@ [% colsepchar = user.settings.csv_colsepchar.value %] -[% PROCESS testopia/case/csv.header.tmpl %] +[% PROCESS testopia/export/csv.caseheader.tmpl %] [% FOREACH test_case = table.list %] - [% PROCESS testopia/case/csv.case.tmpl case=test_case %] - -[% END %] + [% PROCESS testopia/export/csv.case.tmpl case=test_case %] +[% END %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/case/list.html.tmpl b/webtools/testopia/template/en/default/testopia/case/list.html.tmpl index ae3accbb941..1c656fe3444 100644 --- a/webtools/testopia/template/en/default/testopia/case/list.html.tmpl +++ b/webtools/testopia/template/en/default/testopia/case/list.html.tmpl @@ -197,13 +197,16 @@ found. [% END %] +[% IF table.list_count >0 %]
+[% END %] [%############################################################################%] [%# Page Footer #%] diff --git a/webtools/testopia/template/en/default/testopia/case/list.xml.tmpl b/webtools/testopia/template/en/default/testopia/case/list.xml.tmpl new file mode 100644 index 00000000000..5844f86cfab --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/case/list.xml.tmpl @@ -0,0 +1,29 @@ +[%# 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): David Koenig + #%] + +[%# Testopia Show Test Case XML export template #%] + +[% PROCESS testopia/export/xml.header.tmpl -%] + +[% FOREACH test_case = table.list %] + [%+ PROCESS testopia/export/xml.case.tmpl case=test_case %] +[% END %] + +[%- PROCESS testopia/export/xml.footer.tmpl %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/case/show.csv.tmpl b/webtools/testopia/template/en/default/testopia/case/show.csv.tmpl index 8c2bb380b6c..d0823a4bfea 100644 --- a/webtools/testopia/template/en/default/testopia/case/show.csv.tmpl +++ b/webtools/testopia/template/en/default/testopia/case/show.csv.tmpl @@ -27,6 +27,6 @@ [% colsepchar = user.settings.csv_colsepchar.value %] -[% PROCESS testopia/case/csv.header.tmpl %] +[% PROCESS testopia/export/csv.caseheader.tmpl %] -[% PROCESS testopia/case/csv.case.tmpl%] \ No newline at end of file +[% PROCESS testopia/export/csv.case.tmpl %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/case/show.html.tmpl b/webtools/testopia/template/en/default/testopia/case/show.html.tmpl index b1f34cbd7a1..17845445083 100644 --- a/webtools/testopia/template/en/default/testopia/case/show.html.tmpl +++ b/webtools/testopia/template/en/default/testopia/case/show.html.tmpl @@ -305,8 +305,9 @@
diff --git a/webtools/testopia/template/en/default/testopia/case/show.xml.tmpl b/webtools/testopia/template/en/default/testopia/case/show.xml.tmpl new file mode 100644 index 00000000000..e453cc055c9 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/case/show.xml.tmpl @@ -0,0 +1,26 @@ +[%# 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): David Koenig + #%] + +[%# Testopia Show Test Case XML export template #%] + +[% PROCESS testopia/export/xml.header.tmpl %] + [%+ PROCESS testopia/export/xml.case.tmpl %] + +[% PROCESS testopia/export/xml.footer.tmpl %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/export/csv.case.tmpl b/webtools/testopia/template/en/default/testopia/export/csv.case.tmpl new file mode 100644 index 00000000000..68560732312 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/export/csv.case.tmpl @@ -0,0 +1,87 @@ +[%# 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 + # David Koenig + #%] + +[%# Testopia Test Case CSV row export template #%] + +[% PROCESS global/variables.none.tmpl %] + +[% colsepchar = user.settings.csv_colsepchar.value %] + +[% FOREACH column = displaycolumns %] + [% SWITCH column %] + [% CASE 'action' %] + [% case.text.action FILTER csv %] + [% CASE 'author_id' %] + [% case.author.email FILTER csv %] + [% CASE 'blocks' %] + [% case.blocked_list FILTER csv %] + [% CASE 'break_down' %] + [% case.text.breakdown FILTER csv %] + [% CASE 'case_status_id' %] + [% case.status FILTER csv %] + [% CASE 'category_id' %] + [% case.category.name FILTER csv %] + [% CASE 'components' %] + [% FILTER csv %] + [% FOREACH component = case.components %] + [% component.name %](product=[% component.product_name %]) + [% IF component != case.components.last %] + [% colsepchar %] + [% END %] + [% END %] + [% END %] + [% CASE 'default_tester_id' %] + [% case.default_tester.email FILTER csv %] + [% CASE 'depends_on' %] + [% case.dependson_list FILTER csv %] + [% CASE 'expected_results' %] + [% case.text.effect FILTER csv %] + [% CASE 'isautomated' %] + [% case.isautomated ? "YES" : "NO" FILTER csv %] + [% CASE 'plans' %] + [% FILTER csv %] + [% FOREACH plan = case.plans %] + [% plan.id %] + [% IF plan != case.plans.last %] + [% colsepchar %] + [% END %] + [% END %] + [% END %] + [% CASE 'priority_id' %] + [% case.priority FILTER csv %] + [% CASE 'set_up' %] + [% case.text.setup FILTER csv %] + [% CASE 'tags' %] + [% FILTER csv %] + [% FOREACH tag = case.tags %] + [% tag.name %] + [% IF tag != case.tags.last %] + [% colsepchar %] + [% END %] + [% END %] + [% END %] + [% CASE DEFAULT %] + [% case.$column FILTER csv %] + [% END %] + [% IF column != displaycolumns.last %] + [% colsepchar %] + [% END %] +[% END %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/export/csv.caseheader.tmpl b/webtools/testopia/template/en/default/testopia/export/csv.caseheader.tmpl new file mode 100644 index 00000000000..df016afdae9 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/export/csv.caseheader.tmpl @@ -0,0 +1,37 @@ +[%# 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 + # David Koenig + #%] + +[%# Testopia Test Case CSV column header export template #%] + +[% PROCESS global/variables.none.tmpl %] + +[% colsepchar = user.settings.csv_colsepchar.value %] + +[% FOREACH column = displaycolumns %] + [% IF column == 'case_id' %] + [% column FILTER csv %] + [% ELSE %] + [% column FILTER remove('_id') FILTER csv %] + [% END %] + [% IF column != displaycolumns.last %] + [% colsepchar %] + [% END %] +[% END %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/export/xml.case.tmpl b/webtools/testopia/template/en/default/testopia/export/xml.case.tmpl new file mode 100644 index 00000000000..c14c883be25 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/export/xml.case.tmpl @@ -0,0 +1,85 @@ +[%# 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): David Koenig + #%] + +[%# Testopia Test Case XML export template #%] + +[% PROCESS global/variables.none.tmpl %] + + +[% IF case.text.action %] + [% case.text.action FILTER xml %] +[% END %] +[% IF case.alias %] + [% case.alias FILTER xml %] +[% END %] +[% IF case.arguments %] + [% case.arguments FILTER xml %] +[% END %] +[% IF case.blocked %] + [% FOREACH blocked_test_case = case.blocked %] + [% blocked_test_case.summary FILTER xml %] + [% END %] +[% END %] +[% IF case.text.breakdown %] + [% case.text.breakdown FILTER xml %] +[% END %] +[% IF case.category.name %] + [% case.category.name FILTER xml %] +[% END %] +[% IF case.components %] + [% FOREACH component = case.components %] + [% component.name FILTER xml %] + [% END %] +[% END %] +[% IF case.default_tester.email %] + [% case.default_tester.email FILTER xml %] +[% END %] +[% IF case.dependson %] + [% FOREACH dependson_test_case = case.dependson %] + [% dependson_test_case.summary FILTER xml %] + [% END %] +[% END %] +[% IF case.text.effect %] + [% case.text.effect FILTER xml %] +[% END %] +[% IF case.requirement %] + [% case.requirement FILTER xml %] +[% END %] +[% IF case.script %] + +[% END %] +[% IF case.text.setup %] + [% case.text.setup FILTER xml %] +[% END %] +[% IF case.summary %] + [% case.summary FILTER xml %] +[% END %] +[% IF case.tags %] + [% FOREACH tag = case.tags %] + [% tag.name FILTER xml %] + [% END %] +[% END %] +[% IF case.plans %] + [% FOREACH test_plan = case.plans %] + [% test_plan.name FILTER xml %] + [% END %] +[% END %] + + \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/export/xml.footer.tmpl b/webtools/testopia/template/en/default/testopia/export/xml.footer.tmpl new file mode 100644 index 00000000000..d961014d49d --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/export/xml.footer.tmpl @@ -0,0 +1,23 @@ +[%# 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): David Koenig + #%] + +[%# Testopia XML export footer template #%] + + \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/export/xml.header.tmpl b/webtools/testopia/template/en/default/testopia/export/xml.header.tmpl new file mode 100644 index 00000000000..0467d2587c2 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/export/xml.header.tmpl @@ -0,0 +1,25 @@ +[%# 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): David Koenig + #%] + +[%# Testopia XML export header template #%] + + + + \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/plan/show.csv.tmpl b/webtools/testopia/template/en/default/testopia/plan/show.csv.tmpl new file mode 100644 index 00000000000..ad62af77f1a --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/plan/show.csv.tmpl @@ -0,0 +1,33 @@ +[%# 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 + # David Koenig + #%] + +[%# Testopia Test Case list CSV export template #%] + +[% PROCESS global/variables.none.tmpl %] + +[% colsepchar = user.settings.csv_colsepchar.value %] + +[% PROCESS testopia/export/csv.caseheader.tmpl %] + +[% FOREACH test_case = table.list %] + [% PROCESS testopia/export/csv.case.tmpl case=test_case %] + +[% END %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/plan/show.html.tmpl b/webtools/testopia/template/en/default/testopia/plan/show.html.tmpl index f9d96b62a24..adfadbb01ce 100644 --- a/webtools/testopia/template/en/default/testopia/plan/show.html.tmpl +++ b/webtools/testopia/template/en/default/testopia/plan/show.html.tmpl @@ -275,6 +275,20 @@ [% END %] + +[% IF case_table.list_count >0 %] +
+ +
+[% END %] + [%##### Footer #####%] [% PROCESS global/footer.html.tmpl %] diff --git a/webtools/testopia/template/en/default/testopia/plan/show.xml.tmpl b/webtools/testopia/template/en/default/testopia/plan/show.xml.tmpl new file mode 100644 index 00000000000..0b36f34a2e5 --- /dev/null +++ b/webtools/testopia/template/en/default/testopia/plan/show.xml.tmpl @@ -0,0 +1,31 @@ +[%# 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): David Koenig + #%] + +[%# Testopia Test Case list XML export template #%] + +[% PROCESS global/variables.none.tmpl %] + +[% PROCESS testopia/export/xml.header.tmpl -%] + +[% FOREACH test_case = table.list %] + [%+ PROCESS testopia/export/xml.case.tmpl case=test_case %] +[% END %] + +[%- PROCESS testopia/export/xml.footer.tmpl %] \ No newline at end of file diff --git a/webtools/testopia/template/en/default/testopia/case/csv.header.tmpl b/webtools/testopia/testopia/img/xml.png similarity index 100% rename from webtools/testopia/template/en/default/testopia/case/csv.header.tmpl rename to webtools/testopia/testopia/img/xml.png diff --git a/webtools/testopia/testopia/patch-2.22 b/webtools/testopia/testopia/patch-2.22 index a68551f8d1c..442d36294dd 100644 --- a/webtools/testopia/testopia/patch-2.22 +++ b/webtools/testopia/testopia/patch-2.22 @@ -92,7 +92,7 @@ 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 @@ +@@ -1039,6 +1039,492 @@ version => {TYPE => 'decimal(3,2)', NOTNULL => 1}, ], }, @@ -125,6 +125,8 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + ], + INDEXES => [ + category_name_idx => ['name'], ++ category_product_id_name_idx => {FIELDS => [qw(product_id name)], ++ TYPE => 'UNIQUE'}, + ], + }, + @@ -192,6 +194,8 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + case_run_shortkey_idx => ['sortkey'], + case_run_build_idx => [qw(case_run_id build_id)], + case_run_env_idx => [qw(case_run_id environment_id)], ++ case_run_build_env_idx => {FIELDS => [qw(run_id case_id build_id environment_id)], ++ TYPE => 'UNIQUE'}, + ], + }, + @@ -507,6 +511,11 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + name => {TYPE => 'varchar(255)'}, + description => {TYPE => 'TEXT'}, + ], ++ INDEXES => [ ++ build_name_idx => ['name'], ++ build_product_id_name_idx => {FIELDS => [qw(product_id name)], ++ TYPE => 'UNIQUE'}, ++ ], + }, + + test_attachment_data => { diff --git a/webtools/testopia/testopia/patch-2.22.1 b/webtools/testopia/testopia/patch-2.22.1 index 8da17baa61d..2b17aa4e82f 100644 --- a/webtools/testopia/testopia/patch-2.22.1 +++ b/webtools/testopia/testopia/patch-2.22.1 @@ -92,7 +92,7 @@ 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 @@ +@@ -1039,6 +1039,492 @@ version => {TYPE => 'decimal(3,2)', NOTNULL => 1}, ], }, @@ -125,6 +125,8 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + ], + INDEXES => [ + category_name_idx => ['name'], ++ category_product_id_name_idx => {FIELDS => [qw(product_id name)], ++ TYPE => 'UNIQUE'}, + ], + }, + @@ -192,6 +194,8 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + case_run_shortkey_idx => ['sortkey'], + case_run_build_idx => [qw(case_run_id build_id)], + case_run_env_idx => [qw(case_run_id environment_id)], ++ case_run_build_env_idx => {FIELDS => [qw(run_id case_id build_id environment_id)], ++ TYPE => 'UNIQUE'}, + ], + }, + @@ -507,6 +511,11 @@ Index: /bmo-2.22/Bugzilla/DB/Schema.pm + name => {TYPE => 'varchar(255)'}, + description => {TYPE => 'TEXT'}, + ], ++ INDEXES => [ ++ build_name_idx => ['name'], ++ build_product_id_name_idx => {FIELDS => [qw(product_id name)], ++ TYPE => 'UNIQUE'}, ++ ], + }, + + test_attachment_data => { diff --git a/webtools/testopia/tr_csv2xml.pl b/webtools/testopia/tr_csv2xml.pl index d84014735a5..875613e381a 100644 --- a/webtools/testopia/tr_csv2xml.pl +++ b/webtools/testopia/tr_csv2xml.pl @@ -188,13 +188,19 @@ sub remove_field_list s/\342\200\235/”/g; s/\302\251/©/g; s/\031/'/g; - s/\221/'/g; - s/\222/'/g; - s/\224/'/g; + s/\221/&8216;/g; # left single quotation mark + s/\222/&8217;/g; # right single quotation mark + s/\223/&8220;/g; # left double quotation mark + s/\224/&8221;/g; # right double quotation mark s/\226/-/g; - s/\341/à/g; # small letter a with grave - s/\344/ä/g; # small letter a with diaeresis - s/\351/è/g; # small letter e with grave + s/\337/ß/g; # beta + s/\341/à/g; # small letter a with acute accent + s/\342/á/g; # small letter a with grave accent + s/\344/ä/g; # small letter a with tilde + s/\346/å/g; # small letter a with umlaut + s/\347/æ/g; # small ae + s/\350/ç/g; # small letter c cedilla + s/\351/è/g; # small letter e with acute accent s/\364/ô/g; # small letter o with circumflex $line_count += 1; @@ -290,7 +296,7 @@ sub remove_field_list my $double_quote_index = $comma_index+1; while ( $double_quote_index<=$#chars ) { - last if ( $chars[$double_quote_index] =~ m/\S/ ); + last if ( $chars[$double_quote_index] =~ m/\S/ && $chars[$double_quote_index] ne ',' ); $double_quote_index++; } # Is the next non-white space character a comma followed by a double quote? If yes then we @@ -318,6 +324,13 @@ sub remove_field_list } } + # + # This check is for empty fields, i.e. "field1",,"field2". + # + elsif ( $char eq "," && ! $in_quote_field ) + { + push (@fields,""); + } else { if ( $in_quote_field ) @@ -440,40 +453,40 @@ map_TCDB_users(\%tcdb_user); # Process the $field_list variable which comes from the first line of the CSV file. # # Format of the first line should be in the form: -# "Testcase Name","Attributes","Priority","Description","Status","Folder","Creator", -# "Owner","ResDetails","Build","InstanceID","Long Description","Pass/Fail Definition", -# "Setup Steps","Cleanup Steps","Steps" +# "Testcase Name","Attributes","Priority","Description","Folder","Creator","Owner", +# "Pass/Fail Definition","Setup Steps","Cleanup Steps","Steps" # # Fields currently used if they exist are: # attributes - split apart at each comma to become a tag. # category - category for test case. # cleanupsteps - added to Break Down section. # component - component for test case. -# description - summary unless testcasename is defined. added to Action section. +# description - summary unless testcasename is defined. added to Action section if -tcdb flag +# used. # environment - split apart at each comma to become a tag. # folder - only processed if -tcdb option is supplied. split apart at each '/'. based on each # teams input one field becomes the category and others tags. each team defines which # sub folders they want to use. -# longdescription - added to Action section. +# longdescription - added to Action section if -tcdb flag used. # owner (required) - in TCDB this is a ID that is mapped to a email address from the file # tcdbUsers. # passfaildefinition - added to Expected Results section. # priority - becomes the priority. I just a number P is prepended. -# resdetails - added to Action section. +# resdetails - added to Action section if -tcdb flag used. # setupsteps - added to Set Up section. # steps - added to Action section. # testcasename - becomes the summary. if testcasename is not supplied the description # is the summary. if testcasename and description are both null a error is -# generated. +# generated. added to Action section if -tcdb flag used. # # 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. # # The field_list returned from remove_field_list() will have: -# Change to lower case. +# Changed to lower case. # Remove spaces. -# Remove all "'s -# Remove all /'s.' +# Remove all "s. +# Remove all /s. # # More sources for the CSV's other than TCDB, transform some of the column names. @@ -558,7 +571,14 @@ foreach my $line (@{$csv->lines()}) { { my @folder = split(/\\/,$line->folder()); print XMLOUTPUT " " . fix_entities($folder[4]) . "\n" if ( defined( $folder[4] ) ); - print XMLOUTPUT " " . fix_entities($folder[5]) . "\n" if ( defined( $folder[5] ) ); + if ( defined($fields{'category'}) ) + { + print XMLOUTPUT " " . fix_entities($folder[5]) . "\n" if ( defined( $folder[5] ) ); + } + else + { + print XMLOUTPUT " " . fix_entities($folder[5]) . "\n" if ( defined( $folder[5] ) ); + } my $fieldstart = 6; while ( defined $folder[$fieldstart] ) { @@ -606,25 +626,28 @@ foreach my $line (@{$csv->lines()}) { print XMLOUTPUT "\n"; } print XMLOUTPUT " "; - if ( defined($fields{'testcasename'}) && ( $line->testcasename() ne "") ) + if ( $tcdb ) { - print XMLOUTPUT "[TCDB Test Case Name]\n" if ( $tcdb ); - print XMLOUTPUT fix_entities($line->testcasename()); - } - if ( defined($fields{'description'}) && ( $line->description() ne "") ) - { - print XMLOUTPUT "\n\n[TCDB Description]\n" if ( $tcdb ); - print XMLOUTPUT fix_entities($line->description()); - } - if ( defined($fields{'longdescription'}) && ( $line->longdescription() ne "") ) - { - print XMLOUTPUT "\n\n[TCDB Long Description]\n" if ( $tcdb ); - print XMLOUTPUT fix_entities($line->longdescription()); - } - if ( defined($fields{'resdetails'}) && ( $line->resdetails() ne "") ) - { - print XMLOUTPUT "\n\n[TCDB Resolution Details]\n" if ( $tcdb ); - print XMLOUTPUT fix_entities($line->resdetails()); + if ( defined($fields{'testcasename'}) && ( $line->testcasename() ne "") ) + { + print XMLOUTPUT "[TCDB Test Case Name]\n"; + print XMLOUTPUT fix_entities($line->testcasename()); + } + if ( defined($fields{'description'}) && ( $line->description() ne "") ) + { + print XMLOUTPUT "\n\n[TCDB Description]\n"; + print XMLOUTPUT fix_entities($line->description()); + } + if ( defined($fields{'longdescription'}) && ( $line->longdescription() ne "") ) + { + print XMLOUTPUT "\n\n[TCDB Long Description]\n"; + print XMLOUTPUT fix_entities($line->longdescription()); + } + if ( defined($fields{'resdetails'}) && ( $line->resdetails() ne "") ) + { + print XMLOUTPUT "\n\n[TCDB Resolution Details]\n"; + print XMLOUTPUT fix_entities($line->resdetails()); + } } if ( defined($fields{'steps'}) && ( $line->steps() ne "") ) { diff --git a/webtools/testopia/tr_install.pl b/webtools/testopia/tr_install.pl index 2e7526d08bd..173c4bd5b0d 100644 --- a/webtools/testopia/tr_install.pl +++ b/webtools/testopia/tr_install.pl @@ -366,6 +366,10 @@ sub UpdateDB { $dbh->bz_drop_index('test_runs', 'run_id_2'); $dbh->bz_drop_index('test_runs', 'test_run_plan_id_run_id__idx'); + $dbh->bz_add_index('test_builds', 'build_name_idx', ['name']); + $dbh->bz_add_index('test_builds', 'build_product_id_name_idx', {FIELDS => [qw(product_id name)], TYPE => 'UNIQUE'}); + $dbh->bz_add_index('test_case_categories', 'category_product_id_name_idx', {FIELDS => [qw(product_id name)], TYPE => 'UNIQUE'}); + $dbh->bz_add_index('test_case_runs', 'case_run_build_env_idx', {FIELDS => [qw(run_id case_id build_id environment_id)], TYPE => 'UNIQUE'}); $dbh->bz_add_index('test_case_tags', 'case_tags_user_idx', [qw(tag_id userid)]); $dbh->bz_add_index('test_cases', 'test_case_requirement_idx', ['requirement']); $dbh->bz_add_index('test_runs', 'test_run_plan_id_run_id_idx', [qw(plan_id run_id)]); diff --git a/webtools/testopia/tr_list_cases.cgi b/webtools/testopia/tr_list_cases.cgi index 7357ff79438..18e8b1ca601 100755 --- a/webtools/testopia/tr_list_cases.cgi +++ b/webtools/testopia/tr_list_cases.cgi @@ -328,7 +328,7 @@ else { my $disp = "inline"; # We set CSV files to be downloaded, as they are designed for importing # into other programs. - if ($format->{'extension'} eq "csv") + if ( $format->{'extension'} eq "csv" || $format->{'extension'} eq "xml" ) { $disp = "attachment"; $vars->{'displaycolumns'} = \@Bugzilla::Testopia::Constants::TESTCASE_EXPORT; diff --git a/webtools/testopia/tr_show_case.cgi b/webtools/testopia/tr_show_case.cgi index 827c9284630..31e54270065 100755 --- a/webtools/testopia/tr_show_case.cgi +++ b/webtools/testopia/tr_show_case.cgi @@ -434,7 +434,7 @@ sub export { my $disp = "inline"; # We set CSV files to be downloaded, as they are designed for importing # into other programs. - if ($format->{'extension'} eq "csv") + if ( $format->{'extension'} eq "csv" || $format->{'extension'} eq "xml" ) { $disp = "attachment"; $vars->{'displaycolumns'} = \@Bugzilla::Testopia::Constants::TESTCASE_EXPORT; diff --git a/webtools/testopia/tr_show_plan.cgi b/webtools/testopia/tr_show_plan.cgi index 0b2a8c4b61c..f17cbd7ec30 100755 --- a/webtools/testopia/tr_show_plan.cgi +++ b/webtools/testopia/tr_show_plan.cgi @@ -60,6 +60,13 @@ unless ($plan_id){ exit; } validate_test_id($plan_id, 'plan'); + +my $format = $template->get_format("testopia/plan/show", scalar $cgi->param('format'), scalar $cgi->param('ctype')); +unless ( $format->{'extension'} eq "html" ){ + export($plan_id); + exit; +} + push @{$::vars->{'style_urls'}}, 'testopia/css/default.css'; my $serverpush = support_server_push($cgi); @@ -445,3 +452,34 @@ sub display { $template->process("testopia/plan/show.html.tmpl", $vars) || ThrowTemplateError($template->error()); } + +sub export { + my ($plan_id) = @_; + my $casequery = new Bugzilla::CGI($cgi); + + $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->view_count > $case_query_limit; + $vars->{'table'} = $table; + + my $disp = "inline"; + # We set CSV files to be downloaded, as they are designed for importing + # into other programs. + if ( $format->{'extension'} eq "csv" || $format->{'extension'} eq "xml" ) + { + $disp = "attachment"; + $vars->{'displaycolumns'} = \@Bugzilla::Testopia::Constants::TESTCASE_EXPORT; + } + + # Suggest a name for the bug list if the user wants to save it as a file. + my @time = localtime(time()); + my $date = sprintf "%04d-%02d-%02d", 1900+$time[5],$time[4]+1,$time[3]; + my $filename = "testcases-$date.$format->{extension}"; + print $cgi->header(-type => $format->{'ctype'}, + -content_disposition => "$disp; filename=$filename"); + + $template->process($format->{'template'}, $vars) || + ThrowTemplateError($template->error()); +} + diff --git a/webtools/testopia/tr_xmlrpc.cgi b/webtools/testopia/tr_xmlrpc.cgi index dea778dd32b..d99eeee81e4 100755 --- a/webtools/testopia/tr_xmlrpc.cgi +++ b/webtools/testopia/tr_xmlrpc.cgi @@ -46,8 +46,10 @@ 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', + 'Environment' => 'Bugzilla::WebService::Testopia::Environment', 'Build' => 'Bugzilla::WebService::Testopia::Build', + 'Component' => 'Bugzilla::WebService::Component', + 'User' => 'Bugzilla::WebService::User', }) ->handle;