From: <pau...@us...> - 2007-06-23 09:03:27
|
Revision: 971 http://svn.sourceforge.net/everydevel/?rev=971&view=rev Author: paul_the_nomad Date: 2007-06-23 02:03:25 -0700 (Sat, 23 Jun 2007) Log Message: ----------- Tests for update nodeball. Inclusion of callback for update to allow more flexible updating such as use of workspacing. Modified Paths: -------------- trunk/ebase/lib/Everything/Storage/Nodeball.pm trunk/ebase/lib/Everything/Storage/Test/Nodeball.pm Property Changed: ---------------- trunk/ebase/ Property changes on: trunk/ebase ___________________________________________________________________ Name: svk:merge - 16c2b9cb-492b-4d64-9535-64d4e875048d:/wip/ebase:1024 a6810612-c0f9-0310-9d3e-a9e4af8c5745:/ebase/offline:17930 + 16c2b9cb-492b-4d64-9535-64d4e875048d:/wip/ebase:1025 a6810612-c0f9-0310-9d3e-a9e4af8c5745:/ebase/offline:17930 Modified: trunk/ebase/lib/Everything/Storage/Nodeball.pm =================================================================== --- trunk/ebase/lib/Everything/Storage/Nodeball.pm 2007-06-23 09:02:38 UTC (rev 970) +++ trunk/ebase/lib/Everything/Storage/Nodeball.pm 2007-06-23 09:03:25 UTC (rev 971) @@ -671,11 +671,6 @@ $self->write_node_to_nodeball( $nodeball, 'ME' ); # create ME file my $group = $nodeball->selectNodegroupFlat; foreach ( @$group ) { - - if ( $$_{type}{title} eq 'dbtable' ) { - $self->write_sql_table_to_nodeball( $$_{title} ); - } - $self->write_node_to_nodeball( $_ ); } @@ -743,17 +738,29 @@ +=head2 C<build_new_nodes> + +Iterates through the nodes in the current nodeball and turns them into +Everything::Node objects that aren't in the NodeBase (i.e. they are +not stored in the database). + +Takes an optional subroutine references which is passed to +make_node_iterator so that the nodes may be selected. + +Returns a list. + +=cut + sub build_new_nodes { my ( $self ) = @_; my $select_cb ||= sub { 1 }; - my $iterator = $self->make_node_iterator(); + my $iterator = $self->make_node_iterator( $select_cb ); my @nodes; - while ( my $xmlnode = $iterator->() ) { + while ( my $xmlnode = $iterator->( $select_cb ) ) { my $node = xml2node( $xmlnode->get_raw_xml, 'nofinal' ); - print "@$node\n"; push @nodes, @$node; } @@ -761,28 +768,27 @@ } -sub get_conflicting_nodes { - my ( $self ) = @_; - - -} - sub update_node_to_nodebase { my ( $self, $node, $handle_conflict_cb ) = @_; my $oldnode = $node->existingNodeMatches(); ## default behaviour is to clobber nodes - $handle_conflict_cb ||= sub{ $oldnode->updateFromImport( $node, -1 ) }; + $handle_conflict_cb ||= sub { $oldnode->updateFromImport( $node, -1 ) }; + if ($oldnode) { - if ( $oldnode->conflictsWith( $node ) ){ - $handle_conflict_cb->(); - } else { - $oldnode->updateFromImport( $node, -1 ); + if ( $oldnode->conflictsWith($node) ) { + $handle_conflict_cb->( $self, $node ); + } + else { + $oldnode->updateFromImport( $node, -1 ); + } + } + else { + $node->insert(-1); + } - - } @@ -941,21 +947,31 @@ return; } -=head2 C<update_nodeball> +=head2 C<update_nodebase_from_nodeball> -We already have this nodeball in the system, and we need to figure out which -files to add, remove, and update. +We already have this nodeball in the system, and we are going to +update it. This does not delete nodes in the existing nodeball and not +in the new one, it simply removes them from the nodeball in the +nodebase. Takes an optional second argument of the nodeball directory +and an optional third argument which is a call back that updates an +indiviudal node to the nodebase. It is passed the nodeball object and +a node object as arguments. It defaults to calling +update_node_to_nodebase. =cut -sub update_nodeball { - my ( $self, $dir ) = @_; +sub update_nodebase_from_nodeball { + my ( $self, $dir, $update_node_cb ) = @_; my $DB = $self->get_nodebase || Everything::Exception::NoNodeBase->throw("No nodebase here!"); $dir ||= $self->get_nodeball_dir; + $update_node_cb ||= sub { my ( $nodeball, $node ) = @_; + $nodeball->update_node_to_nodebase( $node ); + }; + my $NEWBALLXML = $self->nodeball_xml; my $vars = $self->nodeball_vars; @@ -969,17 +985,18 @@ my @nodes = $self->build_new_nodes; # list of new nodes foreach my $N (@nodes) { - print "$N\n"; - $self->update_node_to_nodebase( $N ); + + $update_node_cb->( $self, $N ); } - fixNodes(0); + $self->fix_node_references(0); #insert the new nodeball my $nodelist = xml2node( $NEWBALLXML, 'nofinal' ); + $OLDBALL->updateFromImport( $$nodelist[0], -1 ); - fixNodes(1); + $self->fix_node_references(1); } @@ -1112,6 +1129,12 @@ my $volume; my $save_title; my $save_dir; + + + if ( $$node{type}{title} eq 'dbtable' ) { + $self->write_sql_table_to_nodeball( $$node{title} ); + } + if ( ! $filepath ) { $save_title = $$node{title}; $save_dir = $$node{type}{title}; Modified: trunk/ebase/lib/Everything/Storage/Test/Nodeball.pm =================================================================== --- trunk/ebase/lib/Everything/Storage/Test/Nodeball.pm 2007-06-23 09:02:38 UTC (rev 970) +++ trunk/ebase/lib/Everything/Storage/Test/Nodeball.pm 2007-06-23 09:03:25 UTC (rev 971) @@ -489,23 +489,121 @@ } -sub test_update_nodebase_from_nodeball : Test(6) { +sub test_build_new_nodes : Test(2) { my $self = shift; + my $instance = $self->{instance}; - can_ok( $self->{class}, 'update_nodeball' ) - || return 'update_nodeball not implemented.'; + my $mock = Test::MockObject->new; + $mock->set_always( get_raw_xml => 'some xml' ); + + my @xmlnodes = ( $mock, $mock ); + no strict 'refs'; + local *{ $self->{class} . '::make_node_iterator' }; + *{ $self->{class} . '::make_node_iterator' } = sub { sub { shift @xmlnodes } }; + my @xml2node_args = (); + local *{ $self->{class} . '::xml2node' }; + *{ $self->{class} . '::xml2node' } = sub { push @xml2node_args, $_[0], $_[1]; return [ $mock ] }; + use strict 'refs'; + + my @nodes = $instance->build_new_nodes; + + is_deeply ( \@nodes, [ $mock, $mock ], '...returns a list of node objects.'); + is_deeply ( \@xml2node_args, ['some xml', 'nofinal', 'some xml', 'nofinal' ], '...calls xml2node with nofinal argument.'); +} + +sub test_update_node_to_nodebase :Test(9) { + my $self = shift; my $instance = $self->{instance}; + my $node = Test::MockObject->new; + my $oldnode = Test::MockObject->new; - local $TODO = "Analyse, break down and fix update nodeball."; + $oldnode->set_true('updateFromImport'); + $oldnode->set_series(conflictsWith => 1, 0); - my $mock = Test::MockObject->new; - ok( undef, '...reads XML nodeball.' ); - ok( undef, - '...finds nodes in old nodeball that have been modified since install.' + $node->set_series( existingNodeMatches => $oldnode, undef ); + $node->set_true('insert'); + + $instance->update_node_to_nodebase( $node ); + + my ( $method, $args ) = $node->next_call; + + is( $method, 'existingNodeMatches', '....checks to see whether a node is matching.'); + + ( $method, $args ) = $oldnode->next_call; + is($method, 'conflictsWith', '...tries to see whether an importing node is conflicting.'); + is($args->[1], $node, '...with the new node as an argument.'); + + ( $method, $args ) = $oldnode->next_call; + is($method, 'updateFromImport', '...calls the nodes updateFromImport method.'); + is($args->[1], $node, '...with the new node as an argument.'); + is($args->[2], -1, '...and the superuser.'); + + $instance->update_node_to_nodebase( $node ); + + ( $method, $args ) = $node->next_call; + + is( $method, 'existingNodeMatches', '....checks to see whether a node is matching.'); + + ( $method, $args ) = $oldnode->next_call; + + ( $method, $args ) = $node->next_call; + is($method, 'insert', '...calls the nodes insert method.'); + is($args->[1], -1, '...and the superuser.'); + +} + +sub test_update_nodebase_from_nodeball : Test(11) { + my $self = shift; + + can_ok( $self->{class}, 'update_nodebase_from_nodeball' ) + || return 'update_nodeball not implemented.'; + + my $instance = + Test::MockObject::Extends::InsideOut->new( $self->{instance} ); + + $instance->set_always( nodeball_xml => 'some xml' ); + $instance->set_always( -nodeball_vars => { title => 'foobar' } ); + $instance->set_true( 'insert_sql_tables', 'update_node_to_nodebase', + 'fix_node_references' ); + + my $mock = $self->{mock}; + $mock->set_always( getNode => $mock ); + $mock->set_true('updateFromImport'); + $instance->set_nodebase($mock); + $instance->set_list( 'build_new_nodes' => $mock, $mock ); + + $instance->update_nodebase_from_nodeball; + + my ( $method, $args ) = $instance->next_call; + is( $method, 'nodeball_xml', '...reads XML nodeball.' ); + + ( $method, $args ) = $instance->next_call; + is( $method, 'insert_sql_tables', '...tries to insert all sql tables.' ); + ( $method, $args ) = $instance->next_call; + is( $method, 'build_new_nodes', + '...turns all new nodes into node objects.' ); + ( $method, $args ) = $instance->next_call; + is( $method, 'update_node_to_nodebase', +'...inserts/updates the node into the nodebase according to the algorithm.' ); - ok( undef, '...workspaces updated new nodes if possibole.' ); - ok( undef, '...if not then asks for instructions.' ); - ok( undef, '...updates nodeball data.' ); + is( $$args[1], $mock, '...calls with the newly created node object.' ); + + ( $method, $args ) = $instance->next_call; + is( $method, 'update_node_to_nodebase', +'...inserts/updates the node into the nodebase according to the algorithm.' + ); + is( $$args[1], $mock, '...calls with the newly created node object.' ); + + ( $method, $args ) = $instance->next_call; + is( $method, 'fix_node_references', '...fixes references.' ); + + ( $method, $args ) = $mock->next_call(2); + is( $method, 'updateFromImport', + '...calls updateFromImport against the old nodeball.' ); + + ( $method, $args ) = $instance->next_call; + is( $method, 'fix_node_references', '...and finally fixes references.' ); + } sub test_check_named_tables : Test(3) { @@ -592,29 +690,39 @@ } -sub test_export_nodeball : Test(7) { +sub test_export_nodeball_to_directory : Test(4) { my $self = shift; - local $TODO = "Methods to export a nodeball stored in a nodebase."; - can_ok( $self->{class}, 'export_nodeball' ); + my $instance= Test::MockObject::Extends::InsideOut->new( $self->{instance} ); + my $mock = $self->{mock}; + $mock->set_always( getNode => $mock ); + $mock->set_always( 'selectNodegroupFlat' => [$mock, $mock, $mock] ); + $instance->set_nodebase( $mock ); + $instance->set_true('write_node_to_nodeball'); + can_ok( $self->{class}, 'export_nodeball_to_directory' ); + + my @toXMLReturns = ('me file contents', 'data'); - local *Everything::XML::Node; + local *Everything::XML::Node::toXML; *Everything::XML::Node::toXML = sub { shift @toXMLReturns }; ### calls update_nodeball_from_nodebase; - ok( undef, '.... read nodeball data.' ); + $instance->export_nodeball_to_directory('nodeballname', 'tmpdir'); + my ($method, $args) = $mock->next_call; + is( "$method..$$args[1]$$args[2]", 'getNode..nodeballnamenodeball', '.... read nodeball data.' ); - ok( undef, '....create ME file and put nodeball data into it.' ); + ($method, $args) = $instance->next_call; + is( "$method$$args[1]$$args[2]", "write_node_to_nodeball${mock}ME", '....create ME file and put nodeball data into it.' ); - ok( undef, '...create table sql files.' ); + my $nodedata; + for (1..3) { + ($method, $args) = $instance->next_call; + $nodedata .= "$method$$args[1]"; + } + is( $nodedata, "write_node_to_nodeball$mock" x 3, '...export each node in the nodeball group as xml.' ); - ok( undef, '...export each node in the nodeball group as xml.' ); - - ok( undef, '...compress nodeball and name it .nbz file.' ); - - ok( undef, '...clean up working directory.' ); } sub test_remove_nodeball : Test( 5 ) { @@ -852,14 +960,14 @@ use strict 'refs'; my ($not_in_ME, $not_in_nodeball) = $instance->check_nodeball_integrity; - use Data::Dumper; diag Dumper $not_in_ME, $not_in_nodeball; + my @sorted = sort { $a->{title} cmp $b->{title} } @$not_in_ME; is($sorted[0]->{title}, 'Create a new user', '...not in ME when titles same but types are different.'); is($sorted[1]->{title}, 'thingo', '...not in ME when title not presnet.'); @sorted = sort { $a->{title} cmp $b->{title} } @$not_in_nodeball; is($sorted[0]->{title}, 'Create a new user', '...not in nodeball when titles same but types are different.'); - is($sorted[1]->{title}, 'Duplicates Found', '...not in nodeball when title not presnet.'); + is($sorted[1]->{title}, 'Duplicates Found', '...not in nodeball when title not present.'); } @@ -1070,4 +1178,43 @@ ); } + + +package Test::MockObject::Extends::InsideOut; + +use SUPER; +use base 'Test::MockObject::Extends'; + +our $AUTOLOAD; + +sub new { + my ( $class, $fake_class ) = @_; + + return Test::MockObject->new() unless defined $fake_class; + + my $parent_class = $class->get_class($fake_class); + $class->check_class_loaded($parent_class); + my $self = { _oio => $fake_class }; + + bless $self, $class->gen_package($parent_class); +} + +sub gen_package { + my ( $class, $parent ) = @_; + my $package = $class->SUPER($parent); + + eval qq|package $package; +use overload + '\${}' => sub { return shift()->{_oio} }, +|; + + die "Can't overload scalar dereferencing, $@" if $@; + no strict 'refs'; + + *{ $package . '::DESTROY' } = + sub { shift()->{_oio}->DESTROY }; + + return $package; +} + 1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |