use strict; use Wiki::Toolkit; use Wiki::Toolkit::Store::Pg; use Wiki::Toolkit::Setup::Pg; use Wiki::Toolkit::TestConfig; use Test::More tests => 9; my $class = "Wiki::Toolkit::Store::Pg"; eval { $class->new; }; ok( $@, "Failed creation dies" ); my %config = %{$Wiki::Toolkit::TestConfig::config{Pg}}; my ($dbname, $dbuser, $dbpass, $dbhost) = @config{qw(dbname dbuser dbpass dbhost)}; SKIP: { skip "No Postgres database configured for testing", 8 unless $dbname; { my $store = eval { $class->new( dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, dbhost => $dbhost ); }; is( $@, "", "Creation doesn't die when given connection params" ); isa_ok( $store, $class ); ok( $store->dbh, "...and has set up a database handle" ); } { my $dsn = "dbi:Pg:dbname=$dbname"; $dsn .= ";host=$dbhost" if $dbhost; my $dbh = DBI->connect( $dsn, $dbuser, $dbpass ); my $store = eval { $class->new( dbh => $dbh ); }; is( $@, "", "Creation doesn't die when given a dbh" ); isa_ok( $store, $class ); ok( $store->dbh, "...and we can retrieve the database handle" ); $dbh->disconnect; } Wiki::Toolkit::Setup::Pg::cleardb({ dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, dbhost => $dbhost }); Wiki::Toolkit::Setup::Pg::setup({ dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, dbhost => $dbhost }); SKIP: { eval { require Hook::LexWrap; require Test::MockObject; }; skip "either Hook::LexWrap or Test::MockObject not installed", 2 if $@; my $store = $class->new( dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, dbhost => $dbhost ); my $wiki = Wiki::Toolkit->new( store => $store ); # Write some test data. $wiki->write_node( "Home", "This is the home node." ) or die "Couldn't setup"; # White box testing - override verify_node_checksum to first verify the # checksum and then if it's OK set up a new wiki object that sneakily # writes to the node before letting us have control back. my $temp; $temp = Hook::LexWrap::wrap( # fully qualify since we're requiring 'Wiki::Toolkit::Store::Database::verify_checksum', post => sub { undef $temp; # Don't want to wrap our sneaking-in my $node = $_[1]; my $evil_store = $class->new( dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, dbhost => $dbhost ); my $evil_wiki = Wiki::Toolkit->new( store => $evil_store ); my %node_data = $evil_wiki->retrieve_node($node); $evil_wiki->write_node($node, "foo", $node_data{checksum}) or die "Evil wiki got conflict on writing"; } ); # Now try to write to a node -- it should fail. my %node_data = $wiki->retrieve_node("Home"); ok( ! $wiki->write_node("Home", "bar", $node_data{checksum}), "write_node handles overlapping write attempts correctly" ); # Check actual real database errors croak rather than flagging conflict %node_data = $wiki->retrieve_node("Home"); my $dbh = $store->dbh; $dbh->disconnect; # Mock a database handle. Need to mock rollback() and disconnect() # as well to avoid warnings that an unmocked method has been called # (we don't actually care). my $fake_dbh = Test::MockObject->new(); $fake_dbh->mock("do", sub { die "Dave told us to"; }); $fake_dbh->set_true("rollback"); $fake_dbh->set_true("disconnect"); $store->{_dbh} = $fake_dbh; eval { $store->check_and_write_node( node => "Home", content => "This is a node.", checksum => $node_data{checksum} ); }; ok( $@ =~ /Dave told us to/, "...and croaks on database error" ); } }