PageRenderTime 61ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/Rose-DB-Object/t/test-lib.pl

http://rose.googlecode.com/
Perl | 442 lines | 330 code | 79 blank | 33 comment | 27 complexity | abb985bc7ec4faeeabae47f82b8ddb83 MD5 | raw file
  1. #!/usr/bin/perl
  2. use strict;
  3. use FindBin qw($Bin);
  4. use Rose::DB;
  5. BEGIN
  6. {
  7. Rose::DB->default_domain('test');
  8. #
  9. # PostgreSQL
  10. #
  11. eval { require DBD::Pg };
  12. $ENV{'PGDATESTYLE'} = 'MDY';
  13. no warnings 'uninitialized';
  14. # Many tests don't work with DBD::Pg version 2.1.x and 2.2.0
  15. unless($DBD::Pg::VERSION =~ /^2\.(?:1\.|2\.0)/)
  16. {
  17. # Main
  18. Rose::DB->register_db(
  19. domain => 'test',
  20. type => 'pg',
  21. driver => 'Pg',
  22. database => 'test',
  23. host => 'localhost',
  24. username => 'postgres',
  25. password => '',
  26. connect_options => { AutoCommit => 1 },
  27. post_connect_sql =>
  28. [
  29. 'SET default_transaction_isolation TO "read committed"',
  30. ],
  31. );
  32. # Private schema
  33. Rose::DB->register_db(
  34. domain => 'test',
  35. type => 'pg_with_schema',
  36. schema => 'rose_db_object_private',
  37. driver => 'Pg',
  38. database => 'test',
  39. host => 'localhost',
  40. username => 'postgres',
  41. password => '',
  42. connect_options => { AutoCommit => 1 },
  43. post_connect_sql =>
  44. [
  45. 'SET default_transaction_isolation TO "read committed"',
  46. ],
  47. );
  48. # Admin
  49. Rose::DB->register_db(
  50. domain => 'test',
  51. type => 'pg_admin',
  52. driver => 'Pg',
  53. database => 'test',
  54. host => 'localhost',
  55. username => 'postgres',
  56. password => '',
  57. connect_options => { AutoCommit => 1 },
  58. post_connect_sql =>
  59. [
  60. 'SET default_transaction_isolation TO "read committed"',
  61. ],
  62. );
  63. }
  64. #
  65. # MySQL
  66. #
  67. # Main
  68. Rose::DB->register_db(
  69. domain => 'test',
  70. type => 'mysql',
  71. driver => 'mysql',
  72. database => 'test',
  73. host => 'localhost',
  74. username => 'root',
  75. password => ''
  76. );
  77. # Admin
  78. Rose::DB->register_db(
  79. domain => 'test',
  80. type => 'mysql_admin',
  81. driver => 'mysql',
  82. database => 'test',
  83. host => 'localhost',
  84. username => 'root',
  85. password => ''
  86. );
  87. #
  88. # Informix
  89. #
  90. # Main
  91. Rose::DB->register_db(
  92. domain => 'test',
  93. type => 'informix',
  94. driver => 'Informix',
  95. database => 'test@test',
  96. connect_options => { AutoCommit => 1 },
  97. post_connect_sql =>
  98. [
  99. 'SET LOCK MODE TO WAIT 100',
  100. 'SET ISOLATION TO DIRTY READ',
  101. ],
  102. );
  103. # Admin
  104. Rose::DB->register_db(
  105. domain => 'test',
  106. type => 'informix_admin',
  107. driver => 'Informix',
  108. database => 'test@test',
  109. connect_options => { AutoCommit => 1 },
  110. post_connect_sql =>
  111. [
  112. 'SET LOCK MODE TO WAIT 100',
  113. 'SET ISOLATION TO DIRTY READ',
  114. ],
  115. );
  116. #
  117. # SQLite
  118. #
  119. eval
  120. {
  121. local $^W = 0;
  122. require DBD::SQLite;
  123. };
  124. (my $version = $DBD::SQLite::VERSION || 0) =~ s/_//g;
  125. unless($ENV{'RDBO_NO_SQLITE'} || $version < 1.11 || ($version >= 1.13 && $version < 1.1902))
  126. {
  127. #unlink("$Bin/sqlite.db");
  128. # Main
  129. Rose::DB->register_db(
  130. domain => 'test',
  131. type => 'sqlite',
  132. driver => 'sqlite',
  133. database => "$Bin/sqlite.db",
  134. auto_create => 0,
  135. connect_options => { AutoCommit => 1 },
  136. post_connect_sql =>
  137. [
  138. 'PRAGMA synchronous = OFF',
  139. 'PRAGMA temp_store = MEMORY',
  140. ],
  141. );
  142. # Admin
  143. Rose::DB->register_db(
  144. domain => 'test',
  145. type => 'sqlite_admin',
  146. driver => 'sqlite',
  147. database => "$Bin/sqlite.db",
  148. connect_options => { AutoCommit => 1 },
  149. post_connect_sql =>
  150. [
  151. 'PRAGMA synchronous = OFF',
  152. 'PRAGMA temp_store = MEMORY',
  153. ],
  154. );
  155. }
  156. #
  157. # Oracle
  158. #
  159. # Main
  160. Rose::DB->register_db(
  161. domain => 'test',
  162. type => 'oracle',
  163. driver => 'oracle',
  164. database => 'test@test',
  165. connect_options => { AutoCommit => 1 },
  166. );
  167. # Admin
  168. Rose::DB->register_db(
  169. domain => 'test',
  170. type => 'oracle_admin',
  171. driver => 'oracle',
  172. database => 'test@test',
  173. connect_options => { AutoCommit => 1 },
  174. );
  175. my @types = qw(pg pg_with_schema pg_admin mysql mysql_admin
  176. informix informix_admin oracle oracle_admin);
  177. unless($Rose::DB::Object::Test::NoDefaults)
  178. {
  179. foreach my $db_type (qw(PG MYSQL INFORMIX ORACLE))
  180. {
  181. if(my $dsn = $ENV{"RDBO_${db_type}_DSN"})
  182. {
  183. foreach my $type (grep { /^$db_type(?:_|$)/i } @types)
  184. {
  185. Rose::DB->modify_db(domain => 'test', type => $type, dsn => $dsn);
  186. }
  187. }
  188. if(my $user = $ENV{"RDBO_${db_type}_USER"})
  189. {
  190. foreach my $type (grep { /^$db_type(?:_|$)/i } @types)
  191. {
  192. Rose::DB->modify_db(domain => 'test', type => $type, username => $user);
  193. }
  194. }
  195. if(my $user = $ENV{"RDBO_${db_type}_PASS"})
  196. {
  197. foreach my $type (grep { /^$db_type(?:_|$)/i } @types)
  198. {
  199. Rose::DB->modify_db(domain => 'test', type => $type, password => $user);
  200. }
  201. }
  202. }
  203. }
  204. }
  205. package main;
  206. my %Have_DB;
  207. sub get_db
  208. {
  209. my($type) = shift;
  210. if((defined $Have_DB{$type} && !$Have_DB{$type}) || !get_dbh($type))
  211. {
  212. return undef;
  213. }
  214. return Rose::DB->new($type);
  215. }
  216. sub get_dbh
  217. {
  218. my($type) = shift;
  219. my $dbh;
  220. local $@;
  221. eval
  222. {
  223. $dbh = Rose::DB->new($type)->retain_dbh()
  224. or die Rose::DB->error;
  225. };
  226. if(!$@ && $dbh)
  227. {
  228. $Have_DB{$type} = 1;
  229. return $dbh;
  230. }
  231. return $Have_DB{$type} = 0;
  232. }
  233. sub have_db
  234. {
  235. my($type) = shift;
  236. if($type =~ /^sqlite(?:_admin)$/ && $ENV{'RDBO_NO_SQLITE'})
  237. {
  238. return $Have_DB{$type} = 0;
  239. }
  240. return $Have_DB{$type} = shift if(@_);
  241. return $Have_DB{$type} if(exists $Have_DB{$type});
  242. return get_dbh($type) ? 1 : 0;
  243. }
  244. sub mysql_supports_innodb
  245. {
  246. my $db = get_db('mysql_admin') or return 0;
  247. eval
  248. {
  249. my $dbh = $db->dbh;
  250. CLEAR:
  251. {
  252. local $dbh->{'RaiseError'} = 0;
  253. local $dbh->{'PrintError'} = 0;
  254. $dbh->do('DROP TABLE rdbo_innodb_test');
  255. }
  256. $dbh->do(<<"EOF");
  257. CREATE TABLE rdbo_innodb_test
  258. (
  259. id INTEGER PRIMARY KEY
  260. )
  261. ENGINE=InnoDB
  262. EOF
  263. # MySQL will silently ignore the "ENGINE=InnoDB" part and create
  264. # a MyISAM table instead. MySQL is evil! Now we have to manually
  265. # check to make sure an InnoDB table was really created.
  266. my $db_name = $db->database;
  267. my $sth = $dbh->prepare("SHOW TABLE STATUS FROM `$db_name` LIKE ?");
  268. $sth->execute('rdbo_innodb_test');
  269. my $info = $sth->fetchrow_hashref;
  270. no warnings 'uninitialized';
  271. unless(lc $info->{'Type'} eq 'innodb' || lc $info->{'Engine'} eq 'innodb')
  272. {
  273. die "Missing InnoDB support";
  274. }
  275. $dbh->do('DROP TABLE rdbo_innodb_test');
  276. };
  277. if($@)
  278. {
  279. warn $@ unless($@ =~ /Missing InnoDB support/);
  280. return 0;
  281. }
  282. return 1;
  283. }
  284. our $PG_HAS_CHKPASS = $ENV{'PG_HAS_CHKPASS'};
  285. sub pg_has_chkpass
  286. {
  287. return $PG_HAS_CHKPASS if(defined $PG_HAS_CHKPASS);
  288. my $dbh = get_dbh('pg_admin') or return undef;
  289. eval
  290. {
  291. local $dbh->{'RaiseError'} = 1;
  292. local $dbh->{'PrintError'} = 0;
  293. $dbh->do('CREATE TABLE rose_db_object_chkpass_test (pass CHKPASS)');
  294. $dbh->do('DROP TABLE rose_db_object_chkpass_test');
  295. };
  296. return $PG_HAS_CHKPASS = $@ ? 0 : 1;
  297. }
  298. our $PG_MAX_CONNECTIONS;
  299. sub pg_max_connections
  300. {
  301. return $PG_MAX_CONNECTIONS if(defined $PG_MAX_CONNECTIONS);
  302. my $dbh = get_dbh('pg') or return 0;
  303. my @dbh = ($dbh);
  304. for(;;)
  305. {
  306. eval { $dbh = get_dbh('pg') or die; push(@dbh, $dbh) };
  307. last if($@ || @dbh > 50);
  308. }
  309. return $PG_MAX_CONNECTIONS = @dbh;
  310. }
  311. sub oracle_is_broken
  312. {
  313. return undef unless(have_db('oracle'));
  314. my $db = get_db('oracle');
  315. # This particular version of Oracle 10g on Mac OS X is broken
  316. return ($db->database_version == 100010300 && $^O =~ /darwin/i) ? 1 : 0;
  317. }
  318. our $HAVE_TEST_MEMORY_CYCLE;
  319. eval
  320. {
  321. require Test::Memory::Cycle;
  322. $HAVE_TEST_MEMORY_CYCLE = 1;
  323. };
  324. sub test_memory_cycle_ok
  325. {
  326. my($val, $msg) = @_;
  327. $HAVE_TEST_MEMORY_CYCLE ?
  328. Test::Memory::Cycle::memory_cycle_ok($val, $msg) :
  329. Test::More::ok(1, "$msg (skipped)");
  330. }
  331. my %Column_Args =
  332. (
  333. enum => [ values => [ 'a' .. 'z' ] ],
  334. );
  335. sub nonpersistent_column_definitions
  336. {
  337. my @columns;
  338. my $i = 1;
  339. foreach my $type (Rose::DB::Object::Metadata->column_type_names)
  340. {
  341. next if($type =~ /(?:chkpass| to |serial|array|\bset\b)/);
  342. push(@columns, 'np' . $i++ => { type => $type, smart_modification => 0,
  343. temp => 1, @{ $Column_Args{$type} || [] } });
  344. }
  345. return @columns;
  346. }
  347. sub modify_nonpersistent_column_values
  348. {
  349. my($object) = shift;
  350. foreach my $column ($object->meta->nonpersistent_columns)
  351. {
  352. my $method = $column->mutator_method_name;
  353. $object->$method(undef); # with smart modification off, this should be sufficient
  354. }
  355. }
  356. sub add_nonpersistent_columns_and_methods
  357. {
  358. my($class) = shift;
  359. my $meta = $class->meta;
  360. $meta->add_columns(nonpersistent_column_definitions());
  361. $meta->make_nonpersistent_column_methods();
  362. }
  363. 1;