Refactored XML import to support the new objects.

git-svn-id: svn://10.0.0.236/trunk@233957 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ghendricks%novell.com
2007-09-05 17:09:47 +00:00
parent 5af756623a
commit 4942faa12a
4 changed files with 781 additions and 761 deletions

View File

@@ -209,7 +209,7 @@ sub _check_tester{
sub _check_automated{
my ($invocant, $isactive) = @_;
$isactive = trim($isactive);
ThrowCodeError('bad_arg', {argument => 'isactive', function => 'set_isactive'}) unless ($isactive =~ /(1|0)/);
ThrowCodeError('bad_arg', {argument => 'isautomated', function => 'set_automated'}) unless ($isactive =~ /(1|0)/);
return $isactive;
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,64 @@
#
# Contributor(s): David Koenig <dkoenig@novell.com>
package Bugzilla::Testopia::XmlReferences;
use constant IGNORECASE => "ignorecase";
use strict;
sub new {
my ($invocant,$ignorecase,$fields) = @_;
my $class = ref($invocant) || $invocant;
my $self = {};
bless($self, $class);
$self->{IGNORECASE} = $ignorecase;
for my $field ( split(/ /, $fields) ) {
$field = uc $field if ( $self->{IGNORECASE} );
$self->{$field} = [];
}
return $self;
}
sub add {
my ($self, $type, $object) = @_;
$type = uc $type if ( $self->{IGNORECASE} );
return 0 if ( ! exists $self->{$type} );
push @{$self->{$type}}, $object;
}
sub display {
my ($self) = @_;
print "display() self=" . $self . "\n";
foreach my $key (keys %$self) {
if ( defined $self->{$key} ) {
print "display() key=$key value=" . $self->{$key} . "\n";
}
else {
print "display() key=$key value=undefined\n";
}
}
}
sub get {
my ($self, $type) = @_;
$type = uc $type if ( $self->{IGNORECASE} );
return 0 if ( ! exists $self->{$type} );
return $self->{$type};
}
1;
__END__
=head1 NAME
Bugzilla::Testopia::XmlReferences - Testopia XmlReferences object
@@ -31,71 +89,56 @@ are stored here and processed as needed.
=head1 SYNOPSIS
use Bugzilla::Testopia::XmlReferences;
use Bugzilla::Testopia::XmlReferences;
$xml_testcase->blocks(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
$xml_testcase->dependson(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
$xml_testcase->testplan(Bugzilla::Testopia::XmlReferences->new(IGNORECASE, XMLREFERENCES_FIELDS));
=head1 METHODS
=over
=item C<new(IGNORECASE, XMLREFERENCES_FIELDS)>
Description: Creates a new reference.
Params: Constants - IGNORECASE
Returns: Blessed XmlReferences object.
=item C<add($type, $object)>
Description: Add a new object reeference of the supplied type.
Params: type - dependson, blocks, plan
object - case or plan
Returns: Nothing.
=item C<display()>
Description: displays the cureent references on the screen.
Params: none.
Returns: Nothing.
=item C<get($type)>
Description: Returns the references of the specified type.
Params: type
Returns: references.
=back
=cut
=head1 SEE ALSO
package Bugzilla::Testopia::XmlReferences;
Testopia::(TestPlan, TestCase, XmlTestCase, Xml)
use constant IGNORECASE => "ignorecase";
=head1 AUTHOR
use strict;
sub new
{
my ($invocant,$ignorecase,$fields) = @_;
my $class = ref($invocant) || $invocant;
my $self = {};
bless($self, $class);
$self->{IGNORECASE} = $ignorecase;
for my $field ( split(/ /, $fields) )
{
$field = uc $field if ( $self->{IGNORECASE} );
$self->{$field} = [];
}
return $self;
}
sub add
{
my ($self, $type, $object) = @_;
$type = uc $type if ( $self->{IGNORECASE} );
return 0 if ( ! exists $self->{$type} );
push @{$self->{$type}}, $object;
}
sub display
{
my ($self) = @_;
print "display() self=" . $self . "\n";
foreach my $key (keys %$self)
{
if ( defined $self->{$key} )
{
print "display() key=$key value=" . $self->{$key} . "\n";
}
else
{
print "display() key=$key value=undefined\n";
}
}
}
sub get
{
my ($self, $type) = @_;
$type = uc $type if ( $self->{IGNORECASE} );
return 0 if ( ! exists $self->{$type} );
return $self->{$type};
}
1;
David Koenig <dkoenig@novell.com>

View File

@@ -10,29 +10,15 @@
# 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 Original Code is the Bugzilla Testopia 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.
# The Initial Developer of the Original Code is Greg Hendricks.
# Portions created by Greg Hendricks are Copyright (C) 2006
# Novell. All Rights Reserved.
#
# Contributor(s): David Koenig <dkoenig@novell.com>
=head1 NAME
Bugzilla::Testopia::XmlTestCase - Testopia XmlTestCase 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
=head1 SYNOPSIS
use Bugzilla::Testopia::XmlTestCase;
=cut
# Jeff Dayley <jedayley@novell.com>
# Greg Hendricks <ghendricks@novell.com>
package Bugzilla::Testopia::XmlTestCase;
#use fields qw(testplans testcases tags categories builds);
@@ -54,48 +40,33 @@ use Bugzilla::User;
use Bugzilla::Util;
use Class::Struct;
#
# The XmlTestCase structure stores data for the verfication processing. The database is not updated
# until a verfication pass is made through the XML data. Some of the TestCase class references are
# database references that will not be valid until the class has been stored in the database. This
# structure stores these references to be used during verfication and writting to the database.
#
struct
(
struct(
'Bugzilla::Testopia::XmlTestCase',
{
attachments => '@',
blocks => 'Bugzilla::Testopia::XmlReferences',
category => '$',
component_ids => '@',
dependson => 'Bugzilla::Testopia::XmlReferences',
tags => '@',
testcase => 'Bugzilla::Testopia::TestCase',
testplan => 'Bugzilla::Testopia::XmlReferences',
attachments => '@',
blocks => 'Bugzilla::Testopia::XmlReferences',
category => '$',
component_ids => '@',
dependson => 'Bugzilla::Testopia::XmlReferences',
tags => '@',
testcase => '$',
testplan => 'Bugzilla::Testopia::XmlReferences',
}
);
sub add_attachment()
{
my ($self,$tag) = @_;
sub add_attachment(){
my ($self,$attachment) = @_;
push @{$self->attachments}, $tag;
push @{$self->attachments}, $attachment;
}
sub add_tag()
{
sub add_tag(){
my ($self,$tag) = @_;
push @{$self->tags}, $tag;
}
=head2 get_available_products
Returns a list of products. This is the same code as Bugzilla::Testopia::TestPlan->get_available_products
without view restrictions.
=cut
sub get_available_products {
my $dbh = Bugzilla->dbh;
@@ -107,8 +78,7 @@ sub get_available_products {
return $products;
}
sub add_component()
{
sub add_component {
my ($self,$component,$component_product) = @_;
my $component_id = "";
my $product_id = "";
@@ -117,10 +87,8 @@ sub add_component()
# Find the product identifier.
my $products_ref = get_available_products();
foreach my $product (@$products_ref)
{
if ( $component_product eq $product->{name} )
{
foreach my $product (@$products_ref){
if ( $component_product eq $product->{name} ){
$product_id = $product->{id};
last;
}
@@ -130,10 +98,8 @@ sub add_component()
# Find the component identifier for the product's componet
my $product = Bugzilla::Testopia::Product->new($product_id);
my $components_ref = $product->components;
foreach my $product_component ( @$components_ref )
{
if ( $component eq $product_component->name )
{
foreach my $product_component ( @$components_ref ) {
if ( $component eq $product_component->name ) {
$component_id = $product_component->id;
last;
}
@@ -146,8 +112,7 @@ sub add_component()
return "";
}
sub debug_display()
{
sub debug_display {
my ($self) = @_;
my $display_variable = "";
@@ -157,11 +122,9 @@ sub debug_display()
$testcase_id = $self->testcase->id() if ( $self->testcase->id() );
print STDERR " ID " . $testcase_id . "\n";
print STDERR " Action\n";
if ( defined $text{'action'} )
{
if ( defined $text{'action'} ){
my @results = split(/\n/,$text{'action'});
foreach my $result (@results)
{
foreach my $result (@results){
print STDERR " $result\n";
}
}
@@ -176,11 +139,9 @@ sub debug_display()
print STDERR " Category " . $self->category . "\n";
print STDERR " Depends On " . $self->dependson->display() . "\n";
print STDERR " Expected Results\n";
if ( defined $text{'effect'} )
{
if ( defined $text{'effect'} ){
my @results = split(/\n/,$text{'effect'});
foreach my $result (@results)
{
foreach my $result (@results){
print STDERR " $result\n";
}
}
@@ -201,14 +162,12 @@ sub debug_display()
print STDERR " Script Arguments " . $self->testcase->arguments() . "\n";
print STDERR " Status " . $self->testcase->status() . "\n";
foreach my $tag (@{$self->tags})
{
foreach my $tag (@{$self->tags}){
print STDERR " Tag " . $tag . "\n";
}
my @attachments = @{$self->testcase->attachments()};
foreach my $attachment (@attachments)
{
foreach my $attachment (@attachments) {
my %submitter = %{$self->testcase->submitter()};
$author_login = $author{"login"};
print STDERR " Attachment " . $attachment->description() . "\n";
@@ -218,40 +177,33 @@ sub debug_display()
}
}
sub get_testcase_ids()
{
sub get_testcase_ids {
my ($self, $field, @new_testcases) = @_;
my $error_message = "";
my @testcase_id = @{$self->$field->get(uc $Bugzilla::Testopia::Xml::DATABASE_ID)};
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} )
{
foreach my $testcase (@new_testcases)
{
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} ) {
foreach my $testcase (@new_testcases) {
push @testcase_id, $testcase->testcase->id() if ( $testcase->testcase->summary() eq $testcase_summary );
}
}
#TODO Testplans using Database_Description
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} )
{
foreach my $testcase_summary ( @{$self->$field->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} ) {
$error_message .= "\n" if ( $error_message ne "" );
$error_message .= "Have not implemented code for $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION lookup for blocking test case " . $testcase_summary . "' for Test Case '". $self->testcase->summary . "'.";
}
return $error_message if ( $error_message ne "" );
my @return_testcase_id;
foreach my $testcase_id (@testcase_id)
{
foreach my $testcase_id (@testcase_id) {
my $testcase = Bugzilla::Testopia::TestCase->new($testcase_id);
if ( ! defined($testcase) )
{
if ( ! defined($testcase) ) {
$error_message .= "\n" if ( $error_message ne "" );
$error_message .= "Could not find blocking Test Case '" . $testcase_id . "' for Test Case '". $self->testcase->summary . "'.";
}
else
{
else {
push @return_testcase_id, $testcase->id();
}
}
@@ -260,16 +212,7 @@ 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()
{
sub store {
my ($self, @new_testplans) = @_;
my $error_message = "";
my @testplan_id = @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::DATABASE_ID)};
@@ -278,17 +221,14 @@ sub store()
# array to find the actual test plan id. The new_testplans array contains all test plans created
# from the XML.
# Order of looping does not matter, number of test plans associated to each test case should be small.
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} )
{
foreach my $testplan (@new_testplans)
{
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::XML_DESCRIPTION)} ) {
foreach my $testplan (@new_testplans) {
push @testplan_id, $testplan->id() if ( $testplan->name() eq $testplan_name );
}
}
#TODO Testplans using Database_Description
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} )
{
foreach my $testplan_name ( @{$self->testplan->get(uc $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION)} ) {
$error_message .= "\n" if ( $error_message ne "" );
$error_message .= "Have not implemented code for $Bugzilla::Testopia::Xml::DATABASE_DESCRIPTION lookup of test plan " . $testplan_name . "' for Test Case '". $self->testcase->summary . "'.";
}
@@ -299,16 +239,13 @@ sub store()
# Verify that each testplan exists.
my @testplan;
foreach my $testplan_id (@testplan_id)
{
foreach my $testplan_id (@testplan_id) {
my $testplan = Bugzilla::Testopia::TestPlan->new($testplan_id);
if ( ! defined($testplan) )
{
if ( ! defined($testplan) ) {
$error_message .= "\n" if ( $error_message ne "" );
$error_message .= "Could not find Test Plan '" . $testplan_id . "' for Test Case '". $self->testcase->summary . "'.";
$error_message .= "Could not find Test Plan '" . $testplan_id . "' for Test Case '". $self->testcase->{'summary'} . "'.";
}
else
{
else {
push @testplan, $testplan;
}
}
@@ -316,90 +253,70 @@ sub store()
# Verify that each testplan has the testcase's category associated to it. If the category does not
# exist it will be created.
foreach my $testplan (@testplan)
{
foreach my $testplan (@testplan) {
my $category = $testplan->product->categories->[0];
my $categoryid = check_case_category($self->category) if ( defined($category) );
if ( ! defined($categoryid) )
{
my $new_category = Bugzilla::Testopia::Category->new({
my $categoryid = check_case_category($self->category, $testplan->product_id) if ( defined($category) );
if ( ! defined($categoryid) ) {
my $new_category = Bugzilla::Testopia::Category->create({
product_id => $testplan->product_id,
name => $self->category,
description => "FIX ME. Created during Test Plan import."
});
$categoryid = $new_category->store();
$categoryid = $new_category->id;
}
$self->testcase->{'category_id'} = $categoryid if ( ! defined($self->testcase->{'category_id'}) );
}
my $case_id = $self->testcase->store();
$self->testcase->{'case_id'} = $case_id;
foreach my $attachment ( @{$self->attachments} )
{
$attachment->{'case_id'} = $case_id;
$attachment->store();
my $case = Bugzilla::Testopia::TestCase($self->testcase);
$self->testcase->{'case_id'} = $case->id;
foreach my $attachment ( @{$self->attachments} ) {
$attachment->{'case_id'} = $case->id;
$attachment = Bugzilla::Testopia::Attachment->create($attachment);
}
foreach my $asciitag ( @{$self->tags} )
{
my $classtag = Bugzilla::Testopia::TestTag->new({'tag_name' => $asciitag});
my $tagid = $classtag->store;
$self->testcase->add_tag($tagid);
foreach my $asciitag ( @{$self->tags} ) {
$case->add_tag($asciitag);
}
# Link the testcase to each of it's testplans.
foreach my $testplan ( @testplan )
{
$self->testcase->link_plan($testplan->id(),$case_id)
foreach my $testplan ( @testplan ) {
$case->link_plan($testplan->id(),$case->id)
}
# Code below requires the testplans to be linked into testcases before being run.
foreach my $component_id ( @{$self->component_ids} )
{
$self->testcase->add_component($component_id);
foreach my $component_id ( @{$self->component_ids} ) {
$case->add_component($component_id);
}
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()
{
sub store_relationships {
my ($self, @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) )
{
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) )
{
foreach my $dependson ( $self->get_testcase_ids("dependson",@new_testcases) ) {
$dependson{$dependson}++;
}
my $dependson_size = keys( %dependson );
if ( ( $blocks_size > 0 ) || ( $dependson_size > 0 ) )
{
my $dependson_size = keys( %dependson );
if ( ( $blocks_size > 0 ) || ( $dependson_size > 0 ) ) {
# Need to add the current blocks and dependson from the Test Case; otherwise, they will
# be removed.
foreach my $block ( split(/ /,$self->testcase->blocked_list_uncached()) )
{
foreach my $block ( split(/ /,$self->testcase->blocked_list_uncached()) ) {
$blocks{$block}++;
}
foreach my $dependson ( split(/ /,$self->testcase->dependson_list_uncached()) )
{
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) );
@@ -407,3 +324,161 @@ sub store_relationships()
}
1;
__END__
=head1 NAME
Bugzilla::Testopia::XmlTestCase
=head1 DESCRIPTION
The XmlTestCase structure stores data for the verfication processing. The database is not updated
until a verfication pass is made through the XML data. Some of the TestCase class references are
database references that will not be valid until the class has been stored in the database. This
structure stores these references to be used during verfication and writting to the database.
=head1 SYNOPSIS
$testcase = Bugzilla::Testopia::XMLTestcase->new($case_hash_ref);
$testcase->store();
=head1 FILEDS
=over
=item C<attachments>
Array - List of attachment hashes that will be used to create Testopia::Attachment objects
for this test case.
=item C<blocks>
Testopia::XMLReferences Object representing the test cases that this tests case blocks.
=item C<category>
Testopia::Category object representing the category this case will belong to.
=item C<component_ids>
List of Bugzilla::Component ids that will be attached to this test case.
=item C<dependson>
Testopia::XMLReferences Object representing the test cases that this tests case depends on.
=item C<tags>
Array of strings - tags to apply to this test case.
=item C<testcase>
Hash representation of the test case that will be created.
=item C<testplan>
Bugzilla::Testopia::XmlReferences of plans to link to this test case
=back
=head1 METHODS
=over
=item C<add_attachment()>
Description: Adds an attachment to the list for later inclusion
Params: attachment - hash representing the Testopia::Attachment to add.
Returns: Nothing.
=item C<add_component()>
Description: Adds a component to the list for later inclusion
Params: component_id - id of component to add.
product_id - id of the product this component belongs to.
Returns: Nothing.
=item C<add_tag()>
Description: Adds a tag for later inclusion.
Params: string - tag name
Returns: Nothing.
=item C<debug_display()>
Description: Prints debug information to STDERR
Params: None.
Returns: Nothing.
=item C<get_test_case_ids()>
Description: Gets a list of the newly created testcases for use in setting up relationships
Params: field - dependson or blocks.
cases - array of test cases newly created by store.
Returns: A list of case ids.
=item C<store()>
Description: 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.
Params: test_plans - list of plans to link the newly created cases to.
Returns: error - if the store was not successful, an error message is returned.
=item C<store_relationships>
Description: 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.
Params: test_cases - array of newly created case objects.
Returns: nothing.
=back
=head1 FUNCTIONS
=over
=item C<get_available_products()>
Description: Returns a list of products. This is the same code as Bugzilla::Testopia::TestPlan->get_available_products
without view restrictions.
Params: None.
Returns: A array of product information.
=back
=head1 SEE ALSO
=over
L<Bugzilla::Testopia::TestCase>
L<Bugzilla::Testopia::Xml>
L<Bugzilla::Testopia::XmlReferences>
=back
=head1 AUTHOR
David Koenig <dkoenig@novell.com>