Audit/simplify various ->is_* runmode specs
[dbsrgits/DBIx-Class.git] / t / lib / DBICTest / RunMode.pm
CommitLineData
4bea1fe7 1package # hide from PAUSE
39c9c72d 2 DBICTest::RunMode;
ab340f7f 3
4use strict;
5use warnings;
6
4bea1fe7 7BEGIN {
8 if ($INC{'DBIx/Class.pm'}) {
9 my ($fr, @frame) = 1;
10 while (@frame = caller($fr++)) {
11 last if $frame[1] !~ m|^t/lib/DBICTest|;
12 }
13
14 die __PACKAGE__ . " must be loaded before DBIx::Class (or modules using DBIx::Class) at $frame[1] line $frame[2]\n";
15 }
da9346a0 16
17 if ( $ENV{DBICTEST_VERSION_WARNS_INDISCRIMINATELY} ) {
18 my $ov = UNIVERSAL->can("VERSION");
19
20 require Carp;
21
22 no warnings 'redefine';
23 *UNIVERSAL::VERSION = sub {
24 Carp::carp( 'Argument "blah bleh bloh" isn\'t numeric in subroutine entry' );
25 &$ov;
26 };
27 }
4bea1fe7 28}
29
ab340f7f 30use Path::Class qw/file dir/;
fa19e5d6 31use Fcntl ':DEFAULT';
32use File::Spec ();
33use File::Temp ();
0a03f539 34use DBICTest::Util 'local_umask';
ab340f7f 35
36_check_author_makefile() unless $ENV{DBICTEST_NO_MAKEFILE_VERIFICATION};
37
9b871b00 38# PathTools has a bug where on MSWin32 it will often return / as a tmpdir.
39# This is *really* stupid and the result of having our lockfiles all over
40# the place is also rather obnoxious. So we use our own heuristics instead
41# https://rt.cpan.org/Ticket/Display.html?id=76663
42my $tmpdir;
43sub tmpdir {
85143769 44 dir ($tmpdir ||= do {
9b871b00 45
fa19e5d6 46 # works but not always
9b871b00 47 my $dir = dir(File::Spec->tmpdir);
fa19e5d6 48 my $reason_dir_unusable;
9b871b00 49
50 my @parts = File::Spec->splitdir($dir);
fa19e5d6 51 if (@parts == 2 and $parts[1] =~ /^ [ \\ \/ ]? $/x ) {
52 $reason_dir_unusable =
53 'File::Spec->tmpdir returned a root directory instead of a designated '
54 . 'tempdir (possibly https://rt.cpan.org/Ticket/Display.html?id=76663)';
55 }
56 else {
57 # make sure we can actually create and sysopen a file in this dir
58 local $@;
0a03f539 59 my $u = local_umask(0); # match the umask we use in DBICTest(::Schema)
3ba92e4a 60 my $tempfile = '<NONCREATABLE>';
fa19e5d6 61 eval {
3ba92e4a 62 $tempfile = File::Temp->new(
63 TEMPLATE => '_dbictest_writability_test_XXXXXX',
fa19e5d6 64 DIR => "$dir",
65 UNLINK => 1,
66 );
3ba92e4a 67 close $tempfile or die "closing $tempfile failed: $!\n";
68
69 sysopen (my $tempfh2, "$tempfile", O_RDWR) or die "reopening $tempfile failed: $!\n";
70 print $tempfh2 'deadbeef' x 1024 or die "printing to $tempfile failed: $!\n";
71 close $tempfh2 or die "closing $tempfile failed: $!\n";
fa19e5d6 72 1;
73 } or do {
74 chomp( my $err = $@ );
3ba92e4a 75 my @x_tests = map { (defined $_) ? ( $_ ? 1 : 0 ) : 'U' } map {(-e, -d, -f, -r, -w, -x, -o)} ("$dir", "$tempfile");
0a03f539 76 $reason_dir_unusable = sprintf <<"EOE", "$tempfile"||'', $err, scalar $>, scalar $), umask(), (stat($dir))[4,5,2], @x_tests;
fa19e5d6 77File::Spec->tmpdir returned a directory which appears to be non-writeable:
78Error encountered while testing '%s': %s
79Process EUID/EGID: %s / %s
0a03f539 80Effective umask: %o
fa19e5d6 81TmpDir UID/GID: %s / %s
82TmpDir StatMode: %o
83TmpDir X-tests: -e:%s -d:%s -f:%s -r:%s -w:%s -x:%s -o:%s
84TmpFile X-tests: -e:%s -d:%s -f:%s -r:%s -w:%s -x:%s -o:%s
85EOE
86 };
87 }
88
89 if ($reason_dir_unusable) {
9b871b00 90 # Replace with our local project tmpdir. This will make multiple runs
91 # from different runs conflict with each other, but is much better than
fa19e5d6 92 # polluting the root dir with random crap or failing outright
93 my $local_dir = _find_co_root()->subdir('t')->subdir('var');
94 $local_dir->mkpath;
95
96 warn "\n\nUsing '$local_dir' as test scratch-dir instead of '$dir': $reason_dir_unusable\n";
97 $dir = $local_dir;
9b871b00 98 }
99
85143769 100 $dir->stringify;
101 });
9b871b00 102}
103
104
ab340f7f 105# Die if the author did not update his makefile
106#
107# This is pretty heavy handed, so the check is pretty solid:
108#
109# 1) Assume that this particular module is loaded from -I <$root>/t/lib
110# 2) Make sure <$root>/Makefile.PL exists
111# 3) Make sure we can stat() <$root>/Makefile.PL
112#
113# If all of the above is satisfied
114#
115# *) die if <$root>/inc does not exist
116# *) die if no stat() results for <$root>/Makefile (covers no Makefile)
117# *) die if Makefile.PL mtime > Makefile mtime
118#
119sub _check_author_makefile {
120
121 my $root = _find_co_root()
122 or return;
123
7159a456 124 my $optdeps = file('lib/DBIx/Class/Optional/Dependencies.pm');
125
ab340f7f 126 # not using file->stat as it invokes File::stat which in turn breaks stat(_)
7159a456 127 my ($mf_pl_mtime, $mf_mtime, $optdeps_mtime) = ( map
50360f3e 128 { (stat ($root->file ($_)) )[9] || undef } # stat returns () on nonexistent files
7159a456 129 (qw|Makefile.PL Makefile|, $optdeps)
ab340f7f 130 );
131
132 return unless $mf_pl_mtime; # something went wrong during co_root detection ?
133
7159a456 134 my @fail_reasons;
ab340f7f 135
7159a456 136 if(not -d $root->subdir ('inc')) {
137 push @fail_reasons, "Missing ./inc directory";
138 }
ab340f7f 139
a256e995 140 if(not $mf_mtime) {
7159a456 141 push @fail_reasons, "Missing ./Makefile";
142 }
a256e995 143 else {
144 if($mf_mtime < $mf_pl_mtime) {
145 push @fail_reasons, "./Makefile.PL is newer than ./Makefile";
146 }
147 if($mf_mtime < $optdeps_mtime) {
148 push @fail_reasons, "./$optdeps is newer than ./Makefile";
149 }
7159a456 150 }
151
152 if (@fail_reasons) {
153 print STDERR <<'EOE';
ab340f7f 154
ab340f7f 155!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
156======================== FATAL ERROR ===========================
157!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
158
159We have a number of reasons to believe that this is a development
160checkout and that you, the user, did not run `perl Makefile.PL`
161before using this code. You absolutely _must_ perform this step,
0424d17a 162to ensure you have all required dependencies present. Not doing
dc4600b2 163so often results in a lot of wasted time for other contributors
23b2c49b 164trying to assist you with spurious "its broken!" problems.
ab340f7f 165
6e22e629 166By default DBICs Makefile.PL turns all optional dependencies into
0424d17a 167*HARD REQUIREMENTS*, in order to make sure that the entire test
168suite is executed, and no tests are skipped due to missing modules.
169If you for some reason need to disable this behavior - supply the
170--skip_author_deps option when running perl Makefile.PL
171
ab340f7f 172If you are seeing this message unexpectedly (i.e. you are in fact
dc4600b2 173attempting a regular installation be it through CPAN or manually),
174please report the situation to either the mailing list or to the
175irc channel as described in
ab340f7f 176
177http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class.pm#GETTING_HELP/SUPPORT
178
ab340f7f 179The DBIC team
180
181
7159a456 182Reasons you received this message:
ab340f7f 183
184EOE
185
7159a456 186 foreach my $r (@fail_reasons) {
187 print STDERR " * $r\n";
188 }
189 print STDERR "\n\n\n";
190
1439bf15 191 require Time::HiRes;
192 Time::HiRes::sleep(0.005);
193 print STDOUT "\nBail out!\n";
ab340f7f 194 exit 1;
195 }
196}
197
dc4600b2 198# Mimic $Module::Install::AUTHOR
199sub is_author {
200
201 my $root = _find_co_root()
202 or return undef;
203
204 return (
205 ( not -d $root->subdir ('inc') )
206 or
39c9c72d 207 ( -e $root->subdir ('inc')->subdir ($^O eq 'VMS' ? '_author' : '.author') )
dc4600b2 208 );
209}
210
39c9c72d 211sub is_smoker {
6853e2c3 212 return (
1a08c5ed 213 ( $ENV{AUTOMATED_TESTING} && ! $ENV{PERL5_CPANM_IS_RUNNING} && ! $ENV{RELEASE_TESTING} )
6853e2c3 214 or
215 __PACKAGE__->is_ci
216 );
39c9c72d 217}
218
81b29c8d 219sub is_ci {
220 return (
221 ($ENV{TRAVIS}||'') eq 'true'
222 and
1ab8de44 223 ($ENV{TRAVIS_REPO_SLUG}||'') =~ m|\w+/dbix-class$|
81b29c8d 224 )
225}
226
39c9c72d 227sub is_plain {
6853e2c3 228 return (
229 ! $ENV{RELEASE_TESTING}
230 and
231 ! $ENV{DBICTEST_RUN_ALL_TESTS}
232 and
233 ! __PACKAGE__->is_smoker
234 and
235 ! __PACKAGE__->is_author
236 )
39c9c72d 237}
238
ab340f7f 239# Try to determine the root of a checkout/untar if possible
240# or return undef
241sub _find_co_root {
242
243 my @mod_parts = split /::/, (__PACKAGE__ . '.pm');
fd3d890d 244 my $rel_path = join ('/', @mod_parts); # %INC stores paths with / regardless of OS
ab340f7f 245
246 return undef unless ($INC{$rel_path});
247
248 # a bit convoluted, but what we do here essentially is:
249 # - get the file name of this particular module
250 # - do 'cd ..' as many times as necessary to get to t/lib/../..
251
252 my $root = dir ($INC{$rel_path});
fd3d890d 253 for (1 .. @mod_parts + 2) {
ab340f7f 254 $root = $root->parent;
255 }
256
257 return (-f $root->file ('Makefile.PL') )
258 ? $root
259 : undef
260 ;
261}
262
2631;