Checking in changes prior to tagging of version 2.66.
[MogileFS-Server.git] / lib / MogileFS / Test.pm
blob4270268b9b30ca96a05b1db2d4f63d27aac30091
1 package MogileFS::Test;
3 use strict;
4 use warnings;
5 use DBI;
7 use FindBin qw($Bin);
8 use IO::Socket::INET;
9 use MogileFS::Server;
10 use base 'Exporter';
12 our @EXPORT = qw(&find_mogclient_or_skip &temp_store &create_mogstored &create_temp_tracker &try_for);
14 sub find_mogclient_or_skip {
16 # needed for running "make test" from project root directory, with
17 # full svn 'mogilefs' repo checked out, without installing
18 # MogileFS::Client to normal system locations...
20 # then, second path is when running "make disttest", which is another
21 # directory below.
22 foreach my $dir ("$Bin/../../api/perl/MogileFS-Client/lib",
23 "$Bin/../../../api/perl/MogileFS-Client/lib",
24 ) {
25 next unless -d $dir;
26 unshift @INC, $dir;
27 $ENV{PERL5LIB} = $dir . ($ENV{PERL5LIB} ? ":$ENV{PERL5LIB}" : "");
30 unless (eval "use MogileFS::Client; 1") {
31 warn "Can't find MogileFS::Client: $@\n";
32 Test::More::plan('skip_all' => "Can't find MogileFS::Client library, necessary for testing.");
35 unless (eval { TrackerHandle::_mogadm_exe() }) {
36 warn "Can't find mogadm utility $@\n";
37 Test::More::plan('skip_all' => "Can't find mogadm executable, necessary for testing.");
40 return 1;
43 sub temp_store {
44 my $type = $ENV{MOGTEST_DBTYPE};
45 my $host = $ENV{MOGTEST_DBHOST} || '';
46 my $port = $ENV{MOGTEST_DBPORT} || '';
47 my $user = $ENV{MOGTEST_DBUSER} || '';
48 my $pass = $ENV{MOGTEST_DBPASS} || '';
49 my $name = $ENV{MOGTEST_DBNAME} || '';
50 my $rootuser = $ENV{MOGTEST_DBROOTUSER} || '';
51 my $rootpass = $ENV{MOGTEST_DBROOTPASS} || '';
53 # default to mysql, but make sure DBD::MySQL is installed
54 unless ($type) {
55 $type = "MySQL";
56 eval "use DBD::mysql; 1" or
57 die "DBD::mysql isn't installed. Please install it or define MOGTEST_DBTYPE env. variable";
60 die "Bogus type" unless $type =~ /^\w+$/;
61 my $store = "MogileFS::Store::$type";
62 eval "use $store; 1;";
63 if ($@) {
64 die "Failed to load $store: $@\n";
66 my %opts = ( dbhost => $host, dbport => $port,
67 dbuser => $user, dbpass => $pass,
68 dbname => $name);
69 $opts{dbrootuser} = $rootuser unless $rootuser eq '';
70 $opts{dbrootpass} = $rootpass unless $rootpass eq '';
71 my $sto = $store->new_temp(%opts);
72 Mgd::set_store($sto);
73 return $sto;
77 sub create_temp_tracker {
78 my $sto = shift;
79 my $opts = shift || [];
81 my $pid = fork();
82 my $whoami = `whoami`;
83 chomp $whoami;
85 my $connect = sub {
86 return IO::Socket::INET->new(PeerAddr => "127.0.0.1:7001",
87 Timeout => 2);
90 my $conn = $connect->();
91 die "Failed: tracker already running on port 7001?\n" if $conn;
93 unless ($pid) {
94 exec("$Bin/../mogilefsd",
95 ($whoami eq "root" ? "--user=root" : ()),
96 "--skipconfig",
97 "--workers=2",
98 "--dsn=" . $sto->dsn,
99 "--dbuser=" . $sto->user,
100 "--dbpass=" . $sto->pass,
101 @$opts,
105 for (1..3) {
106 if ($connect->()) {
107 return TrackerHandle->new(pid => $pid);
109 sleep 1;
111 return undef;
114 sub create_mogstored {
115 my ($ip, $root, $daemonize) = @_;
117 my $connect = sub {
118 return IO::Socket::INET->new(PeerAddr => "$ip:7500",
119 Timeout => 2);
122 my $conn = $connect->();
123 die "Failed: tracker already running on port 7500?\n" if $conn;
124 $ENV{PERL5LIB} .= ":$Bin/../lib";
125 my @args = ("$Bin/../mogstored",
126 "--skipconfig",
127 "--httplisten=$ip:7500",
128 "--mgmtlisten=$ip:7501",
129 "--maxconns=1000", # because we're not root, put it below 1024
130 "--docroot=$root");
132 my $pid;
133 if ($daemonize) {
134 # don't set pid. since our fork fid would just
135 # go away, once perlbal daemonized itself.
136 push @args, "--daemonize";
137 system(@args) and die "Failed to start daemonized mogstored.";
138 } else {
139 $pid = fork();
140 die "failed to fork: $!" unless defined $pid;
141 unless ($pid) {
142 exec(@args);
146 for (1..12) {
147 if ($connect->()) {
148 return MogstoredHandle->new(pid => $pid, ip => $ip, root => $root);
150 select undef, undef, undef, 0.25;
152 return undef;
155 sub try_for {
156 my ($tries, $code) = @_;
157 for (1..$tries) {
158 return 1 if $code->();
159 sleep 1;
161 return 0;
164 ############################################################################
165 package ProcessHandle;
166 sub new {
167 my ($class, %args) = @_;
168 bless \%args, $class;
171 sub pid { return $_[0]{pid} }
173 sub DESTROY {
174 my $self = shift;
175 return unless $self->{pid};
176 kill 15, $self->{pid};
180 ############################################################################
182 package TrackerHandle;
183 use base 'ProcessHandle';
185 sub ipport {
186 my $self = shift;
187 return "127.0.0.1:7001";
190 my $_mogadm_exe_cache;
191 sub _mogadm_exe {
192 return $_mogadm_exe_cache if $_mogadm_exe_cache;
193 for my $dir ("$FindBin::Bin/../../utils",
194 "$FindBin::Bin/../../../utils",
195 split(/:/, $ENV{PATH}),
196 "/usr/bin",
197 "/usr/sbin",
198 "/usr/local/bin",
199 "/usr/local/sbin",
201 my $exe = $dir . '/mogadm';
202 return $_mogadm_exe_cache = $exe if -x $exe;
204 die "mogadm executable not found.\n";
207 sub mogadm {
208 my $self = shift;
209 my $rv = system(_mogadm_exe(), "--trackers=" . $self->ipport, @_);
210 return !$rv;
213 ############################################################################
214 package MogstoredHandle;
215 use base 'ProcessHandle';
217 # this space intentionally left blank. all in super class for now.
219 ############################################################################
220 package MogPath;
221 sub new {
222 my ($class, $url) = @_;
223 return bless {
224 url => $url,
225 }, $class;
228 sub host {
229 my $self = shift;
230 my ($host1) = $self->{url} =~ m!^http://(.+:\d+)!;
231 return $host1
234 sub device {
235 my $self = shift;
236 my ($dev) = $self->{url} =~ m!dev(\d+)!;
237 return $dev
240 sub path {
241 my $self = shift;
242 my $path = $self->{url};
243 $path =~ s!^http://(.+:\d+)!!;
244 return $path;