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