Fix fail with DBICTEST_DEBUG_CONCURRENCY_LOCKS set (thinko in 69016f65)
[dbsrgits/DBIx-Class.git] / t / lib / DBICTest / Util.pm
CommitLineData
65d35121 1package DBICTest::Util;
2
3use warnings;
4use strict;
5
bbcc1fe8 6# this noop trick initializes the STDOUT, so that the TAP::Harness
7# issued IO::Select->can_read calls (which are blocking wtf wtf wtf)
8# keep spinning and scheduling jobs
9# This results in an overall much smoother job-queue drainage, since
10# the Harness blocks less
11# (ideally this needs to be addressed in T::H, but a quick patchjob
12# broke everything so tabling it for now)
13BEGIN {
14 if ($INC{'Test/Builder.pm'}) {
15 local $| = 1;
16 print "#\n";
17 }
18}
19
69016f65 20use constant DEBUG_TEST_CONCURRENCY_LOCKS =>
21 ( ($ENV{DBICTEST_DEBUG_CONCURRENCY_LOCKS}||'') =~ /^(\d+)$/ )[0]
22 ||
23 0
24;
25
8d6b1478 26use Config;
a3a17a15 27use Carp 'confess';
a446d7f8 28use Scalar::Util qw(blessed refaddr);
e1d9e578 29use DBIx::Class::_Util;
65d35121 30
31use base 'Exporter';
69016f65 32our @EXPORT_OK = qw(
33 dbg stacktrace
34 local_umask
35 visit_namespaces
36 check_customcond_args
37 DEBUG_TEST_CONCURRENCY_LOCKS
38);
39
40if (DEBUG_TEST_CONCURRENCY_LOCKS) {
41 require DBI;
42 my $oc = DBI->can('connect');
43 no warnings 'redefine';
44 *DBI::connect = sub {
45 DBICTest::Util::dbg("Connecting to $_[1]");
46 goto $oc;
47 }
48}
49
50sub dbg ($) {
51 require Time::HiRes;
52 printf STDERR "\n%.06f %5s %-78s %s\n",
53 scalar Time::HiRes::time(),
54 $$,
55 $_[0],
56 $0,
57 ;
58}
8d6b1478 59
60sub local_umask {
61 return unless defined $Config{d_umask};
62
63 die 'Calling local_umask() in void context makes no sense'
64 if ! defined wantarray;
65
66 my $old_umask = umask(shift());
67 die "Setting umask failed: $!" unless defined $old_umask;
68
69 return bless \$old_umask, 'DBICTest::Util::UmaskGuard';
70}
71{
72 package DBICTest::Util::UmaskGuard;
73 sub DESTROY {
e1d9e578 74 &DBIx::Class::_Util::detected_reinvoked_destructor;
75
8d6b1478 76 local ($@, $!);
77 eval { defined (umask ${$_[0]}) or die };
78 warn ( "Unable to reset old umask ${$_[0]}: " . ($!||'Unknown error') )
79 if ($@ || $!);
80 }
81}
82
65d35121 83sub stacktrace {
84 my $frame = shift;
85 $frame++;
86 my (@stack, @frame);
87
821edc09 88 while (@frame = CORE::caller($frame++)) {
65d35121 89 push @stack, [@frame[3,1,2]];
90 }
91
92 return undef unless @stack;
93
94 $stack[0][0] = '';
95 return join "\tinvoked as ", map { sprintf ("%s at %s line %d\n", @$_ ) } @stack;
96}
97
a3a17a15 98sub check_customcond_args ($) {
99 my $args = shift;
100
101 confess "Expecting a hashref"
102 unless ref $args eq 'HASH';
103
a446d7f8 104 for (qw(rel_name foreign_relname self_alias foreign_alias)) {
a3a17a15 105 confess "Custom condition argument '$_' must be a plain string"
106 if length ref $args->{$_} or ! length $args->{$_};
107 }
108
a446d7f8 109 confess "Current and legacy rel_name arguments do not match"
110 if $args->{rel_name} ne $args->{foreign_relname};
111
a3a17a15 112 confess "Custom condition argument 'self_resultsource' must be a rsrc instance"
113 unless defined blessed $args->{self_resultsource} and $args->{self_resultsource}->isa('DBIx::Class::ResultSource');
114
115 confess "Passed resultsource has no record of the supplied rel_name - likely wrong \$rsrc"
a446d7f8 116 unless ref $args->{self_resultsource}->relationship_info($args->{rel_name});
117
e884e5d9 118 my $struct_cnt = 0;
1adbd3fc 119
98def3ef 120 if (defined $args->{self_result_object} or defined $args->{self_rowobj} ) {
e884e5d9 121 $struct_cnt++;
98def3ef 122 for (qw(self_result_object self_rowobj)) {
a446d7f8 123 confess "Custom condition argument '$_' must be a result instance"
124 unless defined blessed $args->{$_} and $args->{$_}->isa('DBIx::Class::Row');
125 }
a3a17a15 126
98def3ef 127 confess "Current and legacy self_result_object arguments do not match"
128 if refaddr($args->{self_result_object}) != refaddr($args->{self_rowobj});
a3a17a15 129 }
130
e884e5d9 131 if (defined $args->{foreign_values}) {
132 $struct_cnt++;
1adbd3fc 133
e884e5d9 134 confess "Custom condition argument 'foreign_values' must be a hash reference"
135 unless ref $args->{foreign_values} eq 'HASH';
1adbd3fc 136 }
137
e884e5d9 138 confess "Data structures supplied on both ends of a relationship"
139 if $struct_cnt == 2;
1adbd3fc 140
a3a17a15 141 $args;
142}
143
c9abd679 144sub visit_namespaces {
145 my $args = { (ref $_[0]) ? %{$_[0]} : @_ };
146
147 my $visited_count = 1;
148
149 # A package and a namespace are subtly different things
150 $args->{package} ||= 'main';
151 $args->{package} = 'main' if $args->{package} =~ /^ :: (?: main )? $/x;
152 $args->{package} =~ s/^:://;
153
154 if ( $args->{action}->($args->{package}) ) {
155 my $ns =
156 ( ($args->{package} eq 'main') ? '' : $args->{package} )
157 .
158 '::'
159 ;
160
161 $visited_count += visit_namespaces( %$args, package => $_ ) for
162 grep
163 # this happens sometimes on %:: traversal
164 { $_ ne '::main' }
165 map
166 { $_ =~ /^(.+?)::$/ ? "$ns$1" : () }
167 do { no strict 'refs'; keys %$ns }
168 ;
169 }
170
171 return $visited_count;
172}
173
65d35121 1741;