9 use MogileFS::Util qw(error_code);
16 find_mogclient_or_skip();
18 # use mogadm to init it,
19 # mogstored on temp dir,
20 # register mogstored temp dir,
25 my $sto = eval { temp_store(); };
29 plan skip_all => "Can't create temporary test database: $@";
36 my ($hostA_ip, $hostB_ip, $hostC_ip) = (qw/127.0.1.1 127.0.1.2 127.0.1.3/);
40 $mogroot{1} = File::Temp::tempdir( CLEANUP => 1 );
41 $mogroot{2} = File::Temp::tempdir( CLEANUP => 1 );
42 $mogroot{3} = File::Temp::tempdir( CLEANUP => 1 );
43 my $dev2host = { 1 => 1, 2 => 1,
46 foreach (sort { $a <=> $b } keys %$dev2host) {
47 my $root = $mogroot{$dev2host->{$_}};
48 mkdir("$root/dev$_") or die "Failed to create dev$_ dir: $!";
51 my $ms1 = create_mogstored($hostA_ip, $mogroot{1});
52 ok($ms1, "got mogstored1");
53 my $ms2 = create_mogstored($hostB_ip, $mogroot{2});
54 ok($ms2, "got mogstored2");
56 while (! -e "$mogroot{1}/dev1/usage" &&
57 ! -e "$mogroot{2}/dev4/usage") {
58 print "Waiting on usage...\n";
62 my $tmptrack = create_temp_tracker($sto);
65 my $mogc = MogileFS::Client->new(
67 hosts => [ "127.0.0.1:7001" ],
69 my $be = $mogc->{backend}; # gross, reaching inside of MogileFS::Client
71 my $lasttime = 1167609600; # Mon Jan 1 00:00:00 UTC 2007
73 my $timestamp = $dbh->selectrow_array("SELECT ".$sto->unix_timestamp);
74 # FIXME: Some databases might be pedantic about the FROM
75 # but having it on others means that if the table has no rows
76 # we won't get any results!
77 my $rv = $timestamp > $lasttime;
78 $lasttime = $timestamp;
80 }), "Store provides sane unix_timestamp");
82 # test some basic commands to backend
83 ok($be->do_request("test", {}), "test ping worked");
84 ok(!$be->do_request("test", {crash => 1}), "crash didn't");
85 ok($be->do_request("test", {}), "test ping again worked");
88 ok($tmptrack->mogadm("domain", "add", "todie"), "created todie domain");
89 ok($tmptrack->mogadm("domain", "delete", "todie"), "delete todie domain");
90 ok(!$tmptrack->mogadm("domain", "delete", "todie"), "didn't delete todie domain again");
92 ok($tmptrack->mogadm("domain", "add", "hasclass"), "created hasclass domain");
93 ok($tmptrack->mogadm("class", "add", "hasclass", "nodel"), "created nodel class");
94 ok(!$tmptrack->mogadm("domain", "delete", "hasclass"), "didn't delete hasclass domain");
95 ok($tmptrack->mogadm("class", "delete", "hasclass", "nodel"), "created nodel class");
96 ok($tmptrack->mogadm("domain", "delete", "hasclass"), "didn't delete hasclass domain");
98 ok($tmptrack->mogadm("domain", "add", "testdom"), "created test domain");
99 ok($tmptrack->mogadm("class", "add", "testdom", "1copy", "--mindevcount=1"), "created 1copy class in testdom");
100 ok($tmptrack->mogadm("class", "add", "testdom", "2copies", "--mindevcount=2"), "created 2copies class in testdom");
101 ok($tmptrack->mogadm("class", "add", "testdom", "poltest", "--replpolicy=MultipleHosts(3)"),
102 "created a specific policy class");
104 ok($tmptrack->mogadm("host", "add", "hostA", "--ip=$hostA_ip", "--status=alive"), "created hostA");
105 ok($tmptrack->mogadm("host", "add", "hostB", "--ip=$hostB_ip", "--status=alive"), "created hostB");
107 ok($tmptrack->mogadm("device", "add", "hostA", 1), "created dev1 on hostA");
108 ok($tmptrack->mogadm("device", "add", "hostA", 2), "created dev2 on hostA");
109 ok($tmptrack->mogadm("device", "add", "hostB", 3), "created dev3 on hostB");
110 ok($tmptrack->mogadm("device", "add", "hostB", 4), "created dev4 on hostB");
112 #ok($tmptrack->mogadm("device", "mark", "hostA", 1, "alive"), "dev1 alive");
113 #ok($tmptrack->mogadm("device", "mark", "hostA", 2, "alive"), "dev2 alive");
114 #ok($tmptrack->mogadm("device", "mark", "hostB", 3, "alive"), "dev3 alive");
115 #ok($tmptrack->mogadm("device", "mark", "hostB", 4, "alive"), "dev4 alive");
119 my $was = $be->{timeout}; # can't use local on phash :(
121 ok($be->do_request("clear_cache", {}), "waited for monitor")
122 or die "Failed to wait for monitor";
123 ok($be->do_request("clear_cache", {}), "waited for monitor")
124 or die "Failed to wait for monitor";
125 $be->{timeout} = $was;
129 my $fh = $mogc->new_file('no_content', "2copies");
130 die "Error: " . $mogc->errstr unless $fh;
131 ok(close($fh), "closed file");
135 my $fh = $mogc->new_file('no_content', "2copies");
136 die "Error: " . $mogc->errstr unless $fh;
137 ok(close($fh), "closed file");
140 # wait for it to replicate
142 my @urls = $mogc->get_paths("no_content");
145 diag("no_content still only on $nloc devices");
149 }), "replicated to 2 paths");
152 my $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
153 return $to_repl_rows == 0;
154 }), "no more files to replicate");
157 ok($mogc->delete("no_content"), "deleted no_content")
158 or die "Error: " . $mogc->errstr;
160 # create two sample files
161 my $data = "My test file.\n" x 1024;
162 foreach my $k (qw(file1 file2)) {
163 my $fh = $mogc->new_file($k, "2copies");
164 ok($fh, "got filehandle") or
165 die "Error: " . $mogc->errstr;
167 ok(close($fh), "closed file");
171 ok($mogc->delete("file2"), "deleted file2")
172 or die "Error: " . $mogc->errstr;
174 # verify we can't delete the domain now
175 ok(!$tmptrack->mogadm("domain", "delete", "testdom"), "can't delete domain in use");
177 # wait for it to replicate
180 @urls = $mogc->get_paths("file1");
183 diag("file1 still only on $nloc devices");
187 }), "replicated to 2 paths");
190 my $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
191 return $to_repl_rows == 0;
192 }), "no more files to replicate");
194 my $p1 = MogPath->new($urls[0]);
195 my $p2 = MogPath->new($urls[1]);
196 isnt($p1->host, $p2->host, "host1 and host2 are different");
197 my $path1 = $mogroot{$dev2host->{$p1->device}} . $p1->path;
198 my $path2 = $mogroot{$dev2host->{$p2->device}} . $p2->path;
199 is(-s $path1, length($data), "right length on disk for path1");
200 is(-s $path2, length($data), "right length on disk for path2");
202 ok(unlink($path1), "deleted path $path1");
203 my $dead_url = $urls[0];
205 @urls = $mogc->get_paths("file1");
206 isnt($urls[0], $dead_url, "didn't return dead url first (try $_)");
209 # Tests for updateclass command
211 my $fh = $mogc->new_file('file1copy', "1copy");
212 ok($fh, "got filehandle") or
213 die "Error: " . $mogc->errstr;
214 print $fh 'EXAMPLE DATA';
215 ok(close($fh), "closed file");
217 is scalar($mogc->get_paths("file1copy")), 1, 'File is on 1 device';
219 $mogc->update_class('2copies');
221 # wait for it to replicate
223 my @urls = $mogc->get_paths("file1copy");
226 diag("no_content still only on $nloc devices");
230 }), "replicated to 2 paths");
232 ok($mogc->delete("file1copy"), "deleted updateclass testfile file1copy")
233 or die "Error: " . $mogc->errstr;
236 ok($be->do_request("rename", {
238 to_key => "file1renamed",
240 }), "renamed file1 to file1renamed");
242 ok($be->do_request("delete", {
243 key => "file1renamed",
245 }), "deleted file1renamed");
247 # create a couple hundred files now
249 diag("Creating $n_files files...");
250 for my $n (1..$n_files) {
251 my $fh = $mogc->new_file("manyhundred_$n", "2copies")
252 or die "Failed to create manyhundred_$n: " . $mogc->errstr;
253 my $data = "File number $n.\n" x 512;
255 close($fh) or die "Failed to close manyhundred_$n";
256 diag("created $n/$n_files") if $n % 10 == 0;
258 pass("Created a ton of files");
260 # wait for replication to go down
266 $to_repl_rows = $dbh->selectrow_array("SELECT COUNT(*) FROM file_to_replicate");
267 last if ! $to_repl_rows;
268 diag("Files to replicate: $to_repl_rows");
271 die "Failed to replicate all $n_files files" if $to_repl_rows;
272 pass("Replicated all $n_files files");
275 # now let's delete a host, which should fail hard, because there are still devices attached to it
277 die "Can't delete an active host" if
278 $tmptrack->mogadm("host", "delete", "hostB");
279 pass("didn't delete hostB");
282 # create a new host and device, for when we start killing some devices
283 my $ms3 = create_mogstored($hostC_ip, $mogroot{3});
284 ok($ms3, "got mogstored3");
285 ok($tmptrack->mogadm("host", "add", "hostC", "--ip=$hostC_ip", "--status=alive"), "created hostC");
286 ok($tmptrack->mogadm("device", "add", "hostC", 5), "created dev5 on hostC");
287 ok($tmptrack->mogadm("device", "add", "hostC", 6), "created dev6 on hostC");
289 ok($tmptrack->mogadm("device", "mark", "hostB", 3, "dead"), "marked device B/3 dead");
290 ok($tmptrack->mogadm("device", "mark", "hostB", 4, "dead"), "marked device B/4 dead");
294 my $sth = $dbh->prepare("SELECT devid, COUNT(*) FROM file_on GROUP BY devid");
296 while (my ($devid, $ct) = $sth->fetchrow_array) {
299 diag("Replication update: " . join(", ", map { "dev$_: " . sprintf("%3d", ($has{$_}||0)) } (1..6)));
300 return 0 if $has{3} || $has{4};
301 return $has{1} && $has{1} && $has{5} && $has{6};
302 }), "files replicated to hostC from hostB");
305 # hosts are no longer able to be nuked even if they have deleted devices.
306 # this saves us from some subtle bugs.
307 #ok($tmptrack->mogadm("host", "delete", "hostB"), "killed hostB");
309 # delete them all, see if they go away.
310 for my $n (1..$n_files) {
311 my $rv = $mogc->delete("manyhundred_$n")
312 or die "Failed to delete manyhundred_$n";
314 pass("deleted all $n_files files");
318 foreach my $hn (1, 3) {
319 my @lfiles = `find $mogroot{$hn} -type f -name '*.fid'`;
320 push @files, @lfiles;
321 diag("files on host $hn = " . scalar(@lfiles));
324 }), "and they're gone from filesystem");
326 foreach my $t (qw(file file_on file_to_delete)) {
328 return $dbh->selectrow_array("SELECT COUNT(*) FROM $t") == 0;
329 }), "table $t is empty");
332 # Test some broken client modes.
334 my $c = IO::Socket::INET->new(PeerAddr => '127.0.0.1:7001',
336 die "Failed to connect to test tracker" unless $c;
337 # Pretend to upload a file, then tell the server weird things.
338 # Not trying to be defensable to all sorts of things, but ensuring we're
339 # safe against double close, bad destdev, etc.
340 print $c "create_open "
341 . "domain=testdom&fid=0&class=&multi_dest=1&key=fufufu\n";
344 ok($res =~ m/fid=(\d+)/, "bare create_open worked");
346 # Pretend we uploaded something.
347 print $c "create_close "
348 . "domain=testdom&fid=$fidid&devid=4&size=0&key=fufufu"
349 . "&path=http://127.0.1.2:7500/dev4/0/000/000/0000000$fidid.fid\n";
351 ok($res2 =~ m/invalid_destdev/, "cannot upload to unlisted destdev");
353 # TODO: test double closing, etc.
357 my ($tries, $code) = @_;
359 return 1 if $code->();