BEGIN {
if
(
$INC
{
'Test/Builder.pm'
}) {
local
$| = 1;
print
"#\n"
;
}
}
use
constant
DEBUG_TEST_CONCURRENCY_LOCKS
=>
( (
$ENV
{DBICTEST_DEBUG_CONCURRENCY_LOCKS}||
''
) =~ /^(\d+)$/ )[0]
||
0
;
our
@EXPORT_OK
=
qw(
dbg stacktrace
local_umask
visit_namespaces
check_customcond_args
await_flock DEBUG_TEST_CONCURRENCY_LOCKS
)
;
if
(DEBUG_TEST_CONCURRENCY_LOCKS) {
my
$oc
= DBI->can(
'connect'
);
no
warnings
'redefine'
;
*DBI::connect
=
sub
{
DBICTest::Util::dbg(
"Connecting to $_[1]"
);
goto
$oc
;
}
}
sub
dbg ($) {
printf
STDERR
"\n%.06f %5s %-78s %s\n"
,
scalar
Time::HiRes::
time
(),
$$,
$_
[0],
$0,
;
}
my
$lock_timeout_minutes
= 15;
my
$wait_step_seconds
= 0.25;
sub
await_flock ($$) {
my
(
$fh
,
$locktype
) =
@_
;
my
(
$res
,
$tries
);
while
(
! (
$res
=
flock
(
$fh
,
$locktype
| LOCK_NB ) )
and
++
$tries
<=
$lock_timeout_minutes
* 60 /
$wait_step_seconds
) {
select
(
undef
,
undef
,
undef
,
$wait_step_seconds
);
unless
(
$tries
% 10 ) {
select
( (
select
(\
*STDOUT
), $|=1 )[0] );
print
"#\n"
;
}
}
return
$res
;
}
sub
local_umask {
return
unless
defined
$Config
{d_umask};
die
'Calling local_umask() in void context makes no sense'
if
!
defined
wantarray
;
my
$old_umask
=
umask
(
shift
());
die
"Setting umask failed: $!"
unless
defined
$old_umask
;
return
bless
\
$old_umask
,
'DBICTest::Util::UmaskGuard'
;
}
{
sub
DESTROY {
&DBIx::Class::_Util::detected_reinvoked_destructor
;
local
($@, $!);
eval
{
defined
(
umask
${
$_
[0]}) or
die
};
warn
(
"Unable to reset old umask ${$_[0]}: "
. ($!||
'Unknown error'
) )
if
($@ || $!);
}
}
sub
stacktrace {
my
$frame
=
shift
;
$frame
++;
my
(
@stack
,
@frame
);
while
(
@frame
=
caller
(
$frame
++)) {
push
@stack
, [
@frame
[3,1,2]];
}
return
undef
unless
@stack
;
$stack
[0][0] =
''
;
return
join
"\tinvoked as "
,
map
{
sprintf
(
"%s at %s line %d\n"
,
@$_
) }
@stack
;
}
sub
check_customcond_args ($) {
my
$args
=
shift
;
confess
"Expecting a hashref"
unless
ref
$args
eq
'HASH'
;
for
(
qw(rel_name foreign_relname self_alias foreign_alias)
) {
confess
"Custom condition argument '$_' must be a plain string"
if
length
ref
$args
->{
$_
} or !
length
$args
->{
$_
};
}
confess
"Current and legacy rel_name arguments do not match"
if
$args
->{rel_name} ne
$args
->{foreign_relname};
confess
"Custom condition argument 'self_resultsource' must be a rsrc instance"
unless
defined
blessed
$args
->{self_resultsource} and
$args
->{self_resultsource}->isa(
'DBIx::Class::ResultSource'
);
confess
"Passed resultsource has no record of the supplied rel_name - likely wrong \$rsrc"
unless
ref
$args
->{self_resultsource}->relationship_info(
$args
->{rel_name});
my
$struct_cnt
= 0;
if
(
defined
$args
->{self_result_object} or
defined
$args
->{self_rowobj} ) {
$struct_cnt
++;
for
(
qw(self_result_object self_rowobj)
) {
confess
"Custom condition argument '$_' must be a result instance"
unless
defined
blessed
$args
->{
$_
} and
$args
->{
$_
}->isa(
'DBIx::Class::Row'
);
}
confess
"Current and legacy self_result_object arguments do not match"
if
refaddr(
$args
->{self_result_object}) != refaddr(
$args
->{self_rowobj});
}
if
(
defined
$args
->{foreign_values}) {
$struct_cnt
++;
confess
"Custom condition argument 'foreign_values' must be a hash reference"
unless
ref
$args
->{foreign_values} eq
'HASH'
;
}
confess
"Data structures supplied on both ends of a relationship"
if
$struct_cnt
== 2;
$args
;
}
sub
visit_namespaces {
my
$args
= { (
ref
$_
[0]) ? %{
$_
[0]} :
@_
};
my
$visited_count
= 1;
$args
->{
package
} ||=
'main'
;
$args
->{
package
} =
'main'
if
$args
->{
package
} =~ /^ :: (?: main )? $/x;
$args
->{
package
} =~ s/^:://;
if
(
$args
->{action}->(
$args
->{
package
}) ) {
my
$ns
=
( (
$args
->{
package
} eq
'main'
) ?
''
:
$args
->{
package
} )
.
'::'
;
$visited_count
+= visit_namespaces(
%$args
,
package
=>
$_
)
for
grep
{
$_
ne
'::main'
}
map
{
$_
=~ /^(.+?)::$/ ?
"$ns$1"
: () }
do
{
no
strict
'refs'
;
keys
%$ns
}
;
}
return
$visited_count
;
}
1;