summaryrefslogtreecommitdiff
path: root/t/80proxy.t
diff options
context:
space:
mode:
Diffstat (limited to 't/80proxy.t')
-rw-r--r--t/80proxy.t473
1 files changed, 473 insertions, 0 deletions
diff --git a/t/80proxy.t b/t/80proxy.t
new file mode 100644
index 0000000..ab529b6
--- /dev/null
+++ b/t/80proxy.t
@@ -0,0 +1,473 @@
+#!perl -w # -*- perl -*-
+# vim:sw=4:ts=8
+
+require 5.004;
+use strict;
+
+
+use DBI;
+use Config;
+require VMS::Filespec if $^O eq 'VMS';
+require Cwd;
+
+my $haveFileSpec = eval { require File::Spec };
+my $failed_tests = 0;
+
+$| = 1;
+$^W = 1;
+
+# $\ = "\n"; # XXX Triggers bug, check this later (JW, 1998-12-28)
+
+# Can we load the modules? If not, exit the test immediately:
+# Reason is most probable a missing prerequisite.
+#
+# Is syslog available (required for the server)?
+
+eval {
+ local $SIG{__WARN__} = sub { $@ = shift };
+ require Storable;
+ require DBD::Proxy;
+ require DBI::ProxyServer;
+ require RPC::PlServer;
+ require Net::Daemon::Test;
+};
+if ($@) {
+ if ($@ =~ /^Can't locate (\S+)/) {
+ print "1..0 # Skipped: modules required for proxy are probably not installed (e.g., $1)\n";
+ exit 0;
+ }
+ die $@;
+}
+
+if ($DBI::PurePerl) {
+ # XXX temporary I hope
+ print "1..0 # Skipped: DBD::Proxy currently has a problem under DBI::PurePerl\n";
+ exit 0;
+}
+
+{
+ my $numTest = 0;
+ sub _old_Test($;$) {
+ my $result = shift; my $str = shift || '';
+ printf("%sok %d%s\n", ($result ? "" : "not "), ++$numTest, $str);
+ $result;
+ }
+ sub Test ($;$) {
+ my($ok, $msg) = @_;
+ $msg = ($msg) ? " ($msg)" : "";
+ my $line = (caller)[2];
+ ++$numTest;
+ ($ok) ? print "ok $numTest at line $line\n" : print "not ok $numTest\n";
+ warn "# failed test $numTest at line ".(caller)[2]."$msg\n" unless $ok;
+ ++$failed_tests unless $ok;
+ return $ok;
+ }
+}
+
+
+# Create an empty config file to make sure that settings aren't
+# overloaded by /etc/dbiproxy.conf
+my $config_file = "dbiproxytst.conf";
+unlink $config_file;
+(open(FILE, ">$config_file") and
+ (print FILE "{}\n") and
+ close(FILE))
+ or die "Failed to create config file $config_file: $!";
+
+my $debug = ($ENV{DBI_TRACE}||=0) ? 1 : 0;
+my $dbitracelog = "dbiproxy.dbilog";
+
+my ($handle, $port, @child_args);
+
+my $numTests = 136;
+
+if (@ARGV) {
+ $port = $ARGV[0];
+}
+else {
+
+ unlink $dbitracelog;
+ unlink "dbiproxy.log";
+ unlink "dbiproxy.truss";
+
+ # Uncommentand adjust this to isolate pure-perl client from server settings:
+ # local $ENV{DBI_PUREPERL} = 0;
+
+ # If desperate uncomment this and add '-d' after $^X below:
+ # local $ENV{PERLDB_OPTS} = "AutoTrace NonStop=1 LineInfo=dbiproxy.dbg";
+
+ # pass our @INC to children (e.g., so -Mblib passes through)
+ $ENV{PERL5LIB} = join($Config{path_sep}, @INC);
+
+ # server DBI trace level always at least 1
+ my $dbitracelevel = DBI->trace(0) || 1;
+ @child_args = (
+ #'truss', '-o', 'dbiproxy.truss',
+ $^X, 'dbiproxy', '--test', # --test must be first command line arg
+ "--dbitrace=$dbitracelevel=$dbitracelog", # must be second arg
+ '--configfile', $config_file,
+ ($dbitracelevel >= 2 ? ('--debug') : ()),
+ '--mode=single',
+ '--logfile=STDERR',
+ '--timeout=90'
+ );
+ warn " starting test dbiproxy process: @child_args\n" if DBI->trace(0);
+ ($handle, $port) = Net::Daemon::Test->Child($numTests, @child_args);
+}
+
+my $dsn = "DBI:Proxy:hostname=127.0.0.1;port=$port;debug=$debug;dsn=DBI:ExampleP:";
+
+print "Making a first connection and closing it immediately.\n";
+Test(eval { DBI->connect($dsn, '', '', { 'PrintError' => 1 }) })
+ or print "Connect error: " . $DBI::errstr . "\n";
+
+print "Making a second connection.\n";
+my $dbh;
+Test($dbh = eval { DBI->connect($dsn, '', '', { 'PrintError' => 0 }) })
+ or print "Connect error: " . $DBI::errstr . "\n";
+
+print "example_driver_path=$dbh->{example_driver_path}\n";
+Test($dbh->{example_driver_path});
+
+print "Setting AutoCommit\n";
+$@ = "old-error"; # should be preserved across DBI calls
+Test($dbh->{AutoCommit} = 1);
+Test($dbh->{AutoCommit});
+Test($@ eq "old-error", "\$@ now '$@'");
+#$dbh->trace(2);
+
+eval {
+ local $dbh->{ AutoCommit } = 1; # This breaks die!
+ die "BANG!!!\n";
+};
+Test($@ eq "BANG!!!\n", "\$@ value lost");
+
+
+print "begin_work...\n";
+Test($dbh->{AutoCommit});
+Test(!$dbh->{BegunWork});
+
+Test($dbh->begin_work);
+Test(!$dbh->{AutoCommit});
+Test($dbh->{BegunWork});
+
+$dbh->commit;
+Test(!$dbh->{BegunWork});
+Test($dbh->{AutoCommit});
+
+Test($dbh->begin_work({}));
+$dbh->rollback;
+Test($dbh->{AutoCommit});
+Test(!$dbh->{BegunWork});
+
+
+print "Doing a ping.\n";
+$_ = $dbh->ping;
+Test($_);
+Test($_ eq '2'); # ping was DBD::ExampleP's ping
+
+print "Ensure CompatMode enabled.\n";
+Test($dbh->{CompatMode});
+
+print "Trying local quote.\n";
+$dbh->{'proxy_quote'} = 'local';
+Test($dbh->quote("quote's") eq "'quote''s'");
+Test($dbh->quote(undef) eq "NULL");
+
+print "Trying remote quote.\n";
+$dbh->{'proxy_quote'} = 'remote';
+Test($dbh->quote("quote's") eq "'quote''s'");
+Test($dbh->quote(undef) eq "NULL");
+
+# XXX the $optional param is undocumented and may be removed soon
+Test($dbh->quote_identifier('foo') eq '"foo"', $dbh->quote_identifier('foo'));
+Test($dbh->quote_identifier('f"o') eq '"f""o"', $dbh->quote_identifier('f"o'));
+Test($dbh->quote_identifier('foo','bar') eq '"foo"."bar"');
+Test($dbh->quote_identifier('foo',undef,'bar') eq '"foo"."bar"');
+Test($dbh->quote_identifier(undef,undef,'bar') eq '"bar"');
+
+print "Trying commit with invalid number of parameters.\n";
+eval { $dbh->commit('dummy') };
+Test($@ =~ m/^DBI commit: invalid number of arguments:/)
+ unless $DBI::PurePerl && Test(1);
+
+print "Trying select with unknown field name.\n";
+my $cursor_e = $dbh->prepare("select unknown_field_name from ?");
+Test(defined $cursor_e);
+Test(!$cursor_e->execute('a'));
+Test($DBI::err);
+Test($DBI::err == $dbh->err);
+Test($DBI::errstr =~ m/unknown_field_name/, $DBI::errstr);
+
+Test($DBI::errstr eq $dbh->errstr);
+Test($dbh->errstr eq $dbh->func('errstr'));
+
+my $dir = Cwd::cwd(); # a dir always readable on all platforms
+$dir = VMS::Filespec::unixify($dir) if $^O eq 'VMS';
+
+print "Trying a real select.\n";
+my $csr_a = $dbh->prepare("select mode,name from ?");
+Test(ref $csr_a);
+Test($csr_a->execute($dir))
+ or print "Execute failed: ", $csr_a->errstr(), "\n";
+
+print "Repeating the select with second handle.\n";
+my $csr_b = $dbh->prepare("select mode,name from ?");
+Test(ref $csr_b);
+Test($csr_b->execute($dir));
+Test($csr_a != $csr_b);
+Test($csr_a->{NUM_OF_FIELDS} == 2);
+if ($DBI::PurePerl) {
+ $csr_a->trace(2);
+ use Data::Dumper;
+ warn Dumper($csr_a->{Database});
+}
+Test($csr_a->{Database}->{Driver}->{Name} eq 'Proxy', "Name=$csr_a->{Database}->{Driver}->{Name}");
+$csr_a->trace(0), die if $DBI::PurePerl;
+
+my($col0, $col1);
+my(@row_a, @row_b);
+
+#$csr_a->trace(2);
+print "Trying bind_columns.\n";
+Test($csr_a->bind_columns(undef, \($col0, $col1)) );
+Test($csr_a->execute($dir));
+@row_a = $csr_a->fetchrow_array;
+Test(@row_a);
+Test($row_a[0] eq $col0);
+Test($row_a[1] eq $col1);
+
+print "Trying bind_param.\n";
+Test($csr_b->bind_param(1, $dir));
+Test($csr_b->execute());
+@row_b = @{ $csr_b->fetchrow_arrayref };
+Test(@row_b);
+
+Test("@row_a" eq "@row_b");
+@row_b = $csr_b->fetchrow_array;
+Test("@row_a" ne "@row_b")
+ or printf("Expected something different from '%s', got '%s'\n", "@row_a",
+ "@row_b");
+
+print "Trying fetchrow_hashref.\n";
+Test($csr_b->execute());
+my $row_b = $csr_b->fetchrow_hashref;
+Test($row_b);
+print "row_a: @{[ @row_a ]}\n";
+print "row_b: @{[ %$row_b ]}\n";
+Test($row_b->{mode} == $row_a[0]);
+Test($row_b->{name} eq $row_a[1]);
+
+print "Trying fetchrow_hashref with FetchHashKeyName.\n";
+do {
+#local $dbh->{TraceLevel} = 9;
+local $dbh->{FetchHashKeyName} = 'NAME_uc';
+Test($dbh->{FetchHashKeyName} eq 'NAME_uc');
+my $csr_c = $dbh->prepare("select mode,name from ?");
+Test($csr_c->execute($dir), $DBI::errstr);
+$row_b = $csr_c->fetchrow_hashref;
+Test($row_b);
+print "row_b: @{[ %$row_b ]}\n";
+Test($row_b->{MODE} eq $row_a[0]);
+};
+
+print "Trying finish.\n";
+Test($csr_a->finish);
+#Test($csr_b->finish);
+Test(1);
+
+print "Forcing destructor.\n";
+$csr_a = undef; # force destruction of this cursor now
+Test(1);
+
+print "Trying fetchall_arrayref.\n";
+Test($csr_b->execute());
+my $r = $csr_b->fetchall_arrayref;
+Test($r);
+Test(@$r);
+Test($r->[0]->[0] == $row_a[0]);
+Test($r->[0]->[1] eq $row_a[1]);
+
+Test($csr_b->finish);
+
+
+print "Retrying unknown field name.\n";
+my $csr_c;
+$csr_c = $dbh->prepare("select unknown_field_name1 from ?");
+Test($csr_c);
+Test(!$csr_c->execute($dir));
+Test($DBI::errstr =~ m/Unknown field names: unknown_field_name1/)
+ or printf("Wrong error string: %s", $DBI::errstr);
+
+print "Trying RaiseError.\n";
+$dbh->{RaiseError} = 1;
+Test($dbh->{RaiseError});
+Test($csr_c = $dbh->prepare("select unknown_field_name2 from ?"));
+Test(!eval { $csr_c->execute(); 1 });
+#print "$@\n";
+Test($@ =~ m/Unknown field names: unknown_field_name2/);
+$dbh->{RaiseError} = 0;
+Test(!$dbh->{RaiseError});
+
+print "Trying warnings.\n";
+{
+ my @warn;
+ local($SIG{__WARN__}) = sub { push @warn, @_ };
+ $dbh->{PrintError} = 1;
+ Test($dbh->{PrintError});
+ Test(($csr_c = $dbh->prepare("select unknown_field_name3 from ?")));
+ Test(!$csr_c->execute());
+ Test("@warn" =~ m/Unknown field names: unknown_field_name3/);
+ $dbh->{PrintError} = 0;
+ Test(!$dbh->{PrintError});
+}
+$csr_c->finish();
+
+
+print "Trying type_info_all.\n";
+my $array = $dbh->type_info_all();
+Test($array and ref($array) eq 'ARRAY')
+ or printf("Expected ARRAY, got %s, error %s\n", DBI::neat($array),
+ $dbh->errstr());
+Test($array->[0] and ref($array->[0]) eq 'HASH');
+my $ok = 1;
+for (my $i = 1; $i < @{$array}; $i++) {
+ print "$array->[$i]\n";
+ $ok = 0 unless ($array->[$i] and ref($array->[$i]) eq 'ARRAY');
+ print "$ok\n";
+}
+Test($ok);
+
+# Test the table_info method
+# First generate a list of all subdirectories
+$dir = $haveFileSpec ? File::Spec->curdir() : ".";
+Test(opendir(DIR, $dir));
+my(%dirs, %unexpected, %missing);
+while (defined(my $file = readdir(DIR))) {
+ $dirs{$file} = 1 if -d $file;
+}
+closedir(DIR);
+my $sth = $dbh->table_info(undef, undef, undef, undef);
+Test($sth) or warn "table_info failed: ", $dbh->errstr(), "\n";
+%missing = %dirs;
+%unexpected = ();
+while (my $ref = $sth->fetchrow_hashref()) {
+ print "table_info: Found table $ref->{'TABLE_NAME'}\n";
+ if (exists($missing{$ref->{'TABLE_NAME'}})) {
+ delete $missing{$ref->{'TABLE_NAME'}};
+ } else {
+ $unexpected{$ref->{'TABLE_NAME'}} = 1;
+ }
+}
+Test(!$sth->errstr())
+ or print "Fetching table_info rows failed: ", $sth->errstr(), "\n";
+Test(keys %unexpected == 0)
+ or print "Unexpected directories: ", join(",", keys %unexpected), "\n";
+Test(keys %missing == 0)
+ or print "Missing directories: ", join(",", keys %missing), "\n";
+
+# Test the tables method
+%missing = %dirs;
+%unexpected = ();
+print "Expecting directories ", join(",", keys %dirs), "\n";
+foreach my $table ($dbh->tables()) {
+ print "tables: Found table $table\n";
+ if (exists($missing{$table})) {
+ delete $missing{$table};
+ } else {
+ $unexpected{$table} = 1;
+ }
+}
+Test(!$sth->errstr())
+ or print "Fetching table_info rows failed: ", $sth->errstr(), "\n";
+Test(keys %unexpected == 0)
+ or print "Unexpected directories: ", join(",", keys %unexpected), "\n";
+Test(keys %missing == 0)
+ or print "Missing directories: ", join(",", keys %missing), "\n";
+
+
+# Test large recordsets
+for (my $i = 0; $i <= 300; $i += 100) {
+ print "Testing the fake directories ($i).\n";
+ Test($csr_a = $dbh->prepare("SELECT name, mode FROM long_list_$i"));
+ Test($csr_a->execute(), $DBI::errstr);
+ my $ary = $csr_a->fetchall_arrayref;
+ Test(!$DBI::errstr, $DBI::errstr);
+ Test(@$ary == $i, "expected $i got ".@$ary);
+ if ($i) {
+ my @n1 = map { $_->[0] } @$ary;
+ my @n2 = reverse map { "file$_" } 1..$i;
+ Test("@n1" eq "@n2");
+ }
+ else {
+ Test(1);
+ }
+}
+
+
+# Test the RowCacheSize attribute
+Test($csr_a = $dbh->prepare("SELECT * FROM ?"));
+Test($dbh->{'RowCacheSize'} == 20);
+Test($csr_a->{'RowCacheSize'} == 20);
+Test($csr_a->execute('long_list_50'));
+Test($csr_a->fetchrow_arrayref());
+Test($csr_a->{'proxy_data'} and @{$csr_a->{'proxy_data'}} == 19);
+Test($csr_a->finish());
+
+Test($dbh->{'RowCacheSize'} = 30);
+Test($dbh->{'RowCacheSize'} == 30);
+Test($csr_a->{'RowCacheSize'} == 30);
+Test($csr_a->execute('long_list_50'));
+Test($csr_a->fetchrow_arrayref());
+Test($csr_a->{'proxy_data'} and @{$csr_a->{'proxy_data'}} == 29)
+ or print("Expected 29 records in cache, got " . @{$csr_a->{'proxy_data'}} .
+ "\n");
+Test($csr_a->finish());
+
+
+Test($csr_a->{'RowCacheSize'} = 10);
+Test($dbh->{'RowCacheSize'} == 30);
+Test($csr_a->{'RowCacheSize'} == 10);
+Test($csr_a->execute('long_list_50'));
+Test($csr_a->fetchrow_arrayref());
+Test($csr_a->{'proxy_data'} and @{$csr_a->{'proxy_data'}} == 9)
+ or print("Expected 9 records in cache, got " . @{$csr_a->{'proxy_data'}} .
+ "\n");
+Test($csr_a->finish());
+
+$dbh->disconnect;
+
+# Test $dbh->func()
+# print "Testing \$dbh->func().\n";
+# my %tables = map { $_ =~ /lib/ ? ($_, 1) : () } $dbh->tables();
+# $ok = 1;
+# foreach my $t ($dbh->func('lib', 'examplep_tables')) {
+# defined(delete $tables{$t}) or print "Unexpected table: $t\n";
+# }
+# Test(%tables == 0);
+
+if ($failed_tests) {
+ warn "Proxy: @child_args\n";
+ for my $class (qw(Net::Daemon RPC::PlServer Storable)) {
+ (my $pm = $class) =~ s/::/\//g; $pm .= ".pm";
+ my $version = eval { $class->VERSION } || '?';
+ warn sprintf "Using %-13s %-6s %s\n", $class, $version, $INC{$pm};
+ }
+ warn join(", ", map { "$_=$ENV{$_}" } grep { /^LC_|LANG/ } keys %ENV)."\n";
+ warn "More info can be found in $dbitracelog\n";
+ #system("cat $dbitracelog");
+}
+
+
+END {
+ local $?;
+ $handle->Terminate() if $handle;
+ undef $handle;
+ unlink $config_file if $config_file;
+ if (!$failed_tests) {
+ unlink 'dbiproxy.log';
+ unlink $dbitracelog if $dbitracelog;
+ }
+};
+
+1;