Build on wheezy, and presumably precise
[invirt/third/libt4.git] / rsm_tester.pl
1 #!/usr/bin/perl -w
2
3 use POSIX ":sys_wait_h";
4 use Getopt::Std;
5 use strict;
6
7
8 my @pid;
9 my @logs = ();
10 my @views = (); #expected views
11 my %in_views; #the number of views a node is expected to be present
12 my @p;
13 my $t;
14 my $always_kill = 0;
15
16 use sigtrap 'handler' => \&killprocess, 'HUP', 'INT', 'ABRT', 'QUIT', 'TERM';
17
18 sub paxos_log {
19   my $port = shift;
20   return "paxos-$port.log";
21 }
22
23 sub mydie {
24   my ($s) = @_;
25   killprocess() if ($always_kill);
26   die $s;
27 }
28
29 sub killprocess {
30   print "killprocess: forcestop all spawned processes...@pid \n";
31   kill 9, @pid;
32 }
33
34 sub cleanup {
35   kill 9, @pid;
36   unlink(@logs);
37   sleep 2;
38 }
39
40 sub spawn {
41   my ($p, @a) = @_;
42   my $aa = join("-", @a);
43   if (my $pid = fork) {
44 # parent
45     push( @logs, "$p-$aa.log" );
46     if( $p =~ /config_server/ ) {
47       push( @logs, paxos_log($a[1]) );
48     }
49     if( $p =~ /lock_server/ ) {
50       push( @logs, paxos_log($a[1]) );
51     }
52     return $pid;
53   } elsif (defined $pid) {
54 # child
55     open(STDOUT, ">>$p-$aa.log")
56       or mydie "Couln't redirect stout\n";
57     open(STDERR, ">&STDOUT")
58       or mydie "Couln't redirect stderr\n";
59     $| = 1;
60     print "$p @a\n";
61     exec "$p @a" 
62       or mydie "Cannot start new $p @a $!\n";
63   } else {
64     mydie "Cannot  fork: $!\n";
65   }
66 }
67
68 sub randports {
69
70   my $num = shift;
71   my @p = ();
72   for( my $i = 0; $i < $num; $i++ ) {
73     push( @p, int(rand(54000))+10000 );
74   }
75   my @sp = sort { $a <=> $b } @p;
76   return @sp;
77 }
78
79 sub print_config {
80   my @ports = @_;
81   open( CONFIG, ">config" ) or mydie( "Couldn't open config for writing" );
82   foreach my $p (@ports) {
83     printf CONFIG "%05d\n", $p;
84   }
85   close( CONFIG );
86 }
87
88 sub spawn_ls {
89   my $master = shift;
90   my $port = shift;
91   return spawn( "./lock_server", $master, $port );
92 }
93
94 sub spawn_config {
95   my $master = shift;
96   my $port = shift;
97   return spawn( "./config_server", $master, $port );
98 }
99
100 sub check_views {
101
102   my $l = shift;
103   my $v = shift;
104   my $last_v = shift;
105
106   open( LOG, "<$l" ) 
107     or mydie( "Failed: couldn't read $l" );
108   my @log = <LOG>;
109   close(LOG);
110
111   my @vs = @{$v};
112
113   my $i = 0;
114   my @last_view;
115   foreach my $line (@log) {
116     if( $line =~ /^done (\d+) ([\d\s]+)$/ ) {
117
118       my $num = $1;
119       my @view = split( /\s+/, $2 );
120       @last_view = @view;
121
122       if( $i > $#vs ) {
123 # let there be extra views
124         next;
125       }
126
127       my $e = $vs[$i];
128       my @expected = @{$e};
129
130       if( @expected != @view ) {
131         mydie( "Failed: In log $l at view $num is (@view), but expected $i (@expected)" );
132       }
133
134       $i++;
135     }
136   }
137
138   if( $i <= $#vs ) {
139     mydie( "Failed: In log $l, not enough views seen!" );
140   }
141
142   if( defined $last_v ) {
143     my @last_exp_v = @{$last_v};
144     if( @last_exp_v != @last_view ) {
145       mydie( "Failed: In log $l last view didn't match, got view @last_view, but expected @last_exp_v" );
146     }
147   }
148
149 }
150
151 sub get_num_views {
152
153   my $log = shift;
154   my $including = shift;
155   my $nv = `grep "done " $log | grep "$including" | wc -l`;
156   chomp $nv;
157   return $nv;
158
159 }
160
161 sub wait_for_view_change {
162
163   my $log = shift;
164   my $num_views = shift;
165   my $including = shift;
166   my $timeout = shift;
167
168   my $start = time();
169   while( (get_num_views( $log, $including ) < $num_views) and
170       ($start + $timeout > time()) ) {
171                 my $lastv = `grep done  $log | tail -n 1`;
172                 chomp $lastv;
173     print "   Waiting for $including to be present in >=$num_views views in $log (Last view: $lastv)\n";
174     sleep 1;
175   }
176
177   if( get_num_views( $log, $including ) < $num_views) {
178     mydie( "Failed: Timed out waiting for $including to be in >=$num_views in log $log" );
179   }else{
180     print "   Done: $including is in >=$num_views views in $log\n";
181   }
182 }
183
184 sub waitpid_to {
185   my $pid = shift;
186   my $to = shift;
187
188   my $start = time();
189   my $done_pid;
190   do {
191     sleep 1;
192     $done_pid = waitpid($pid, POSIX::WNOHANG);
193   } while( $done_pid <= 0 and (time() - $start) < $to );
194
195   if( $done_pid <= 0 ) {
196     kill 9,$pid;
197     mydie( "Failed: Timed out waiting for process $pid\n" );
198   } else {
199     return 1;
200   }
201
202 }
203
204 sub wait_and_check_expected_view($) {
205   my $v = shift;
206   push @views, $v;
207   for (my $i = 0; $i <=$#$v; $i++) {
208     $in_views{$v->[$i]}++;
209   }
210   foreach my $port (@$v) {
211     wait_for_view_change(paxos_log($port), $in_views{$port}, $port, 20);
212   }
213   foreach my $port (@$v) {
214     my $log = paxos_log($port);
215     check_views( $log, \@views );
216   }
217 }
218
219 sub start_nodes ($$){
220
221   @pid = ();
222   @logs = ();
223   @views = ();
224   for (my $i = 0; $i <= $#p; $i++) {
225     $in_views{$p[$i]} = 0;
226   }
227
228   my $n = shift;
229   my $command = shift;
230
231   for (my $i = 0; $i < $n; $i++) {
232                 if ($command eq "ls") {
233                         @pid = (@pid, spawn_ls($p[0],$p[$i]));
234                         print "Start lock_server on $p[$i]\n";
235                 }elsif ($command eq "config_server"){
236                         @pid = (@pid, spawn_config($p[0],$p[$i]));
237                         print "Start config on $p[$i]\n";
238                 }
239     sleep 1;
240
241     my @vv = @p[0..$i];
242     wait_and_check_expected_view(\@vv);
243   }
244
245 }
246
247 my %options;
248 getopts("s:k",\%options);
249 if (defined($options{s})) {
250   srand($options{s});
251 }
252 if (defined($options{k})) {
253   $always_kill = 1;
254 }
255
256 #get a sorted list of random ports
257 @p = randports(5);
258 print_config( @p[0..4] );
259
260 my @do_run = ();
261 my $NUM_TESTS = 17;
262
263 # see which tests are set
264 if( $#ARGV > -1 ) {
265   foreach my $t (@ARGV) {
266     if( $t < $NUM_TESTS && $t >= 0 ) {
267       $do_run[$t] = 1;
268     }
269   }
270 } else {
271 # turn on all tests
272   for( my $i = 0; $i < $NUM_TESTS; $i++ ) {
273     $do_run[$i] = 1;
274   }
275 }
276
277 if ($do_run[0]) {
278   print "test0: start 3-process lock server\n";
279   start_nodes(3,"ls");
280   cleanup();
281   sleep 2;
282 }
283
284 if ($do_run[1]) {
285   print "test1: start 3-process lock server, kill third server\n";
286   start_nodes(3,"ls");
287
288   print "Kill third server (PID: $pid[2]) on port $p[2]\n";
289   kill "TERM", $pid[2];
290   
291   sleep 5;
292
293   # it should go through 4 views
294   my @v4 = ($p[0], $p[1]);
295   wait_and_check_expected_view(\@v4);
296   
297   cleanup();
298   sleep 2;
299 }
300
301 if ($do_run[2]) {
302   print "test2: start 3-process lock server, kill first server\n";
303   start_nodes(3,"ls");
304   
305   print "Kill first (PID: $pid[0]) on port $p[0]\n";
306   kill "TERM", $pid[0];
307
308   sleep 5;
309
310   # it should go through 4 views
311   my @v4 = ($p[1], $p[2]);
312   wait_and_check_expected_view(\@v4);
313
314   cleanup();
315   sleep 2;
316 }
317
318
319 if ($do_run[3]) {
320
321   print "test3: start 3-process lock_server, kill a server, restart a server\n";
322   start_nodes(3,"ls");
323
324   print "Kill server (PID: $pid[2]) on port $p[2]\n";
325   kill "TERM", $pid[2];
326
327   sleep 5;
328
329   my @v4 = ($p[0], $p[1]);
330   wait_and_check_expected_view(\@v4);
331
332   print "Restart killed server on port $p[2]\n";
333   $pid[2] = spawn_ls ($p[0], $p[2]);
334
335   sleep 5;
336
337   my @v5 = ($p[0], $p[1], $p[2]);
338   wait_and_check_expected_view(\@v5);
339
340   cleanup();
341   sleep 2;
342 }
343
344 if ($do_run[4]) {
345   print "test4: 3-process lock_server, kill third server, kill second server, restart third server, kill third server again, restart second server, re-restart third server, check logs\n";
346   start_nodes(3,"ls");
347   
348   print "Kill server (PID: $pid[2]) on port $p[2]\n";
349   kill "TERM", $pid[2];
350
351   sleep 5;
352   my @v4 = ($p[0], $p[1]);
353   wait_and_check_expected_view(\@v4);
354
355   print "Kill server (PID: $pid[1]) on port $p[1]\n";
356   kill "TERM", $pid[1];
357
358   sleep 5;
359   #no view change can happen because of a lack of majority
360
361   print "Restarting server on port $p[2]\n";
362   $pid[2] = spawn_ls($p[0], $p[2]);
363
364   sleep 5;
365
366   #no view change can happen because of a lack of majority
367   foreach my $port (@p[0..2]) {
368     my $num_v = get_num_views(paxos_log($port), $port);
369     die "$num_v views in ", paxos_log($port), " : no new views should be formed due to the lack of majority\n" if ($num_v != $in_views{$port});
370   }
371
372   # kill node 3 again, 
373   print "Kill server (PID: $pid[2]) on port $p[2]\n";
374   kill "TERM", $pid[2];
375
376   sleep 5;
377
378
379   print "Restarting server on port $p[1]\n";
380   $pid[1] = spawn_ls($p[0], $p[1]);
381
382   sleep 7;
383
384   foreach my $port (@p[0..1]) {
385     $in_views{$port} = get_num_views( paxos_log($port), $port );
386     print "   Node $port is present in ", $in_views{$port}, " views in ", paxos_log($port), "\n";
387   }
388
389   print "Restarting server on port $p[2]\n";
390   $pid[2] = spawn_ls($p[0], $p[2]);
391
392   my @lastv = ($p[0],$p[1],$p[2]);
393   foreach my $port (@lastv) {
394     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
395   }
396
397 # now check the paxos logs and make sure the logs go through the right
398 # views
399
400   foreach my $port (@lastv) {
401     check_views( paxos_log($port), \@views, \@lastv);
402   }
403
404   cleanup();
405
406 }
407
408 if ($do_run[5]) {
409   print "test5: 3-process lock_server, send signal 1 to first server, kill third server, restart third server, check logs\n";
410   start_nodes(3,"ls");
411   
412   print "Sending paxos breakpoint 1 to first server on port $p[0]\n";
413   spawn("./rsm_tester", $p[0]+1, "breakpoint", 3);
414
415   sleep 1;
416
417   print "Kill third server (PID: $pid[2]) on port $p[2]\n";
418   kill "TERM", $pid[2];
419
420   sleep 5;
421   foreach my $port (@p[0..2]) {
422     my $num_v = get_num_views( paxos_log($port), $port );
423     die "$num_v views in ", paxos_log($port), " : no new views should be formed due to the lack of majority\n" if ($num_v != $in_views{$port});
424   }
425
426   print "Restarting third server on port $p[2]\n";
427   $pid[2]= spawn_ls($p[0], $p[2]);
428   my @lastv = ($p[1],$p[2]);
429   foreach my $port (@lastv) {
430     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
431   }
432         sleep 10;
433
434 # now check the paxos logs and make sure the logs go through the right
435 # views
436
437   foreach my $port (@lastv) {
438     check_views( paxos_log($port), \@views, \@lastv);
439   }
440
441   cleanup();
442
443 }
444
445 if ($do_run[6]) {
446   print "test6: 4-process lock_server, send signal 2 to first server, kill fourth server, restart fourth server, check logs\n";
447   start_nodes(4,"ls");
448   print "Sending paxos breakpoint 2 to first server on port $p[0]\n";
449   spawn("./rsm_tester", $p[0]+1, "breakpoint", 4);
450
451   sleep 1;
452
453   print "Kill fourth server (PID: $pid[3]) on port $p[3]\n";
454   kill "TERM", $pid[3];
455
456   sleep 5;
457
458   foreach my $port ($p[1],$p[2]) {
459       my $num_v = get_num_views( paxos_log($port), $port );
460       die "$num_v views in ", paxos_log($port), " : no new views should be formed due to the lack of majority\n" if ($num_v != $in_views{$port});
461   }
462
463   sleep 5;
464
465   print "Restarting fourth server on port $p[3]\n";
466   $pid[3] = spawn_ls($p[1], $p[3]);
467
468   sleep 5;
469
470   my @v5 = ($p[0],$p[1],$p[2]);
471   foreach my $port (@v5) {
472     $in_views{$port}++;
473   }
474   push @views, \@v5;
475
476   sleep 10;
477
478   # the 6th view will be (2,3)  or (1,2,3,4)
479   my @v6 = ($p[1],$p[2]);
480   foreach my $port (@v6) {
481     $in_views{$port}++;
482   }
483   foreach my $port (@v6) {
484     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 30);
485   }
486
487   # final will be (2,3,4)
488   my @lastv = ($p[1],$p[2],$p[3]);
489   foreach my $port (@lastv) {
490     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
491   }
492   foreach my $port (@lastv) {
493     check_views( paxos_log($port), \@views, \@lastv );
494   }
495   cleanup();
496
497 }
498
499 if ($do_run[7]) {
500   print "test7: 4-process lock_server, send signal 2 to first server, kill fourth server, kill other servers, restart other servers, restart fourth server, check logs\n";
501   start_nodes(4,"ls");
502   print "Sending paxos breakpoint 2 to first server on port $p[0]\n";
503   spawn("./rsm_tester", $p[0]+1, "breakpoint", 4);
504   sleep 3;
505
506   print "Kill fourth server (PID: $pid[3]) on port $p[3]\n";
507   kill "TERM", $pid[3];
508
509   sleep 5;
510
511   print "Kill third server (PID: $pid[2]) on port $p[2]\n";
512   kill "TERM", $pid[2];
513
514   print "Kill second server (PID: $pid[1]) on port $p[1]\n";
515   kill "TERM", $pid[1];
516
517   sleep 5;
518
519   print "Restarting second server on port $p[1]\n";
520   $pid[1] = spawn_ls($p[0], $p[1]);
521
522   sleep 5;
523
524   print "Restarting third server on port $p[2]\n";
525   $pid[2] = spawn_ls($p[0], $p[2]);
526
527   sleep 5;
528
529 #no view change is possible by now because there is no majority
530   foreach my $port ($p[1],$p[2]) {
531     my $num_v = get_num_views( paxos_log($port), $port );
532     die "$num_v views in ", paxos_log($port), " : no new views should be formed due to the lack of majority\n" if ($num_v != $in_views{$port});
533   }
534
535   print "Restarting fourth server on port $p[3]\n";
536   $pid[3] = spawn_ls($p[1], $p[3]);
537
538   sleep 5;
539
540   my @v5 = ($p[0], $p[1], $p[2]);
541   push @views, \@v5;
542   foreach my $port (@v5) {
543     $in_views{$port}++;
544   }
545
546   sleep 15;
547   my @lastv = ($p[1],$p[2],$p[3]);
548   foreach my $port (@lastv) {
549     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
550   }
551
552   foreach my $port (@lastv) {
553     check_views( paxos_log($port), \@views, \@lastv);
554   }
555   
556   cleanup();
557
558 }
559
560 if ($do_run[8]) {
561   print "test8: start 3-process lock service\n";
562         start_nodes(3,"ls");
563   
564   print "Start lock_tester $p[0]\n";
565   $t = spawn("./lock_tester", $p[0]);
566
567   print "   Wait for lock_tester to finish (waitpid $t)\n";
568   waitpid_to($t, 600);
569
570   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
571     mydie( "Failed lock tester for test 8" );
572   }
573
574   cleanup();
575   sleep 2;
576 }
577
578 if ($do_run[9]) {
579
580   print "test9: start 3-process rsm, kill second slave while lock_tester is running\n";
581         start_nodes(3,"ls");
582   
583   print "Start lock_tester $p[0]\n";
584   $t = spawn("./lock_tester", $p[0]);
585
586   sleep int(rand(10)+1);
587
588   print "Kill slave (PID: $pid[2]) on port $p[2]\n";
589   kill "TERM", $pid[2];
590
591   sleep 3;
592
593   # it should go through 4 views
594   my @v4 = ($p[0], $p[1]);
595   wait_and_check_expected_view(\@v4);
596
597   print "   Wait for lock_tester to finish (waitpid $t)\n";
598   waitpid_to($t, 600);
599
600   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
601     mydie( "Failed lock tester for test 9" );
602   }
603
604   cleanup();
605   sleep 2;
606 }
607
608 if ($do_run[10]) {
609
610   print "test10: start 3-process rsm, kill second slave and restarts it later while lock_tester is running\n";
611         start_nodes(3,"ls");
612   
613   print "Start lock_tester $p[0]\n";
614   $t = spawn("./lock_tester", $p[0]);
615
616   sleep int(rand(10)+1);
617
618   print "Kill slave (PID: $pid[2]) on port $p[2]\n";
619   kill "TERM", $pid[2];
620
621   sleep 3;
622
623   # it should go through 4 views
624   my @v4 = ($p[0], $p[1]);
625   wait_and_check_expected_view(\@v4);
626
627   sleep 3;
628
629   print "Restarting killed lock_server on port $p[2]\n";
630   $pid[2] = spawn_ls($p[0], $p[2]);
631   my @v5 = ($p[0],$p[1],$p[2]);
632   wait_and_check_expected_view(\@v5);
633
634   print "   Wait for lock_tester to finish (waitpid $t)\n";
635   waitpid_to($t, 600);
636
637   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
638     mydie( "Failed lock tester for test 10" );
639   }
640
641   cleanup();
642   sleep 2;
643 }
644
645
646 if ($do_run[11]) {
647
648   print "test11: start 3-process rsm, kill primary while lock_tester is running\n";
649         start_nodes(3,"ls");
650
651   print "Start lock_tester $p[0]\n";
652   $t = spawn("./lock_tester", $p[0]);
653
654   sleep int(rand(10)+1);
655
656   print "Kill primary (PID: $pid[0]) on port $p[0]\n";
657   kill "TERM", $pid[0];
658
659   sleep 3;
660
661   # it should go through 4 views
662   my @v4 = ($p[1], $p[2]);
663   wait_and_check_expected_view(\@v4);
664
665   print "   Wait for lock_tester to finish (waitpid $t)\n";
666   waitpid_to($t, 600);
667
668   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
669     mydie( "Failed lock tester for test 11" );
670   }
671
672   cleanup();
673   sleep 2;
674 }
675
676 if ($do_run[12]) {
677
678   print "test12: start 3-process rsm, kill master at break1 and restart it while lock_tester is running\n";
679   
680   start_nodes(3, "ls");
681
682   print "Start lock_tester $p[0]\n";
683   $t = spawn("./lock_tester", $p[0]);
684
685   sleep 1;
686
687   print "Kill master (PID: $pid[0]) on port $p[0] at breakpoint 1\n";
688   spawn("./rsm_tester", $p[0]+1, "breakpoint", 1);
689
690
691   sleep 1;
692
693   # it should go through 5 views
694   my @v4 = ($p[1], $p[2]);
695   wait_and_check_expected_view(\@v4);
696
697   print "Restarting killed lock_server on port $p[0]\n";
698   $pid[0] = spawn_ls($p[1], $p[0]);
699
700   sleep 3;
701
702   # the last view should include all nodes
703   my @lastv = ($p[0],$p[1],$p[2]);
704   foreach my $port (@lastv) {
705     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
706   }
707
708   foreach my $port (@lastv) {
709     check_views( paxos_log($port), \@views, \@lastv);
710   }
711
712   print "   Wait for lock_tester to finish (waitpid $t)\n";
713   waitpid_to($t, 600);
714
715   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
716     mydie( "Failed lock tester for test 12" );
717   }
718
719   cleanup();
720   sleep 2;
721 }
722
723 if ($do_run[13]) {
724
725   print "test13: start 3-process rsm, kill slave at break1 and restart it while lock_tester is running\n";
726
727   start_nodes(3, "ls");
728
729   print "Start lock_tester $p[0]\n";
730   $t = spawn("./lock_tester", $p[0]);
731
732   sleep 1;
733
734   print "Kill slave (PID: $pid[2]) on port $p[2] at breakpoint 1\n";
735   spawn("./rsm_tester", $p[2]+1, "breakpoint", 1);
736
737   sleep 1;
738
739   # it should go through 4 views
740   my @v4 = ($p[0], $p[1]);
741   wait_and_check_expected_view(\@v4);
742
743   print "Restarting killed lock_server on port $p[2]\n";
744   $pid[2] = spawn_ls($p[0], $p[2]);
745
746   sleep 3;
747
748   # the last view should include all nodes
749   my @lastv = ($p[0],$p[1],$p[2]);
750   foreach my $port (@lastv) {
751     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
752   }
753
754   foreach my $port (@lastv) {
755     check_views( paxos_log($port), \@views, \@lastv);
756   }
757
758   print "   Wait for lock_tester to finish (waitpid $t)\n";
759   waitpid_to($t, 600);
760
761   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
762     mydie( "Failed lock tester for test 13" );
763   }
764
765   cleanup();
766   sleep 2;
767 }
768
769 if ($do_run[14]) {
770
771   print "test14: start 5-process rsm, kill slave break1, kill slave break2\n";
772
773   start_nodes(5, "ls");
774
775   print "Start lock_tester $p[0]\n";
776   $t = spawn("./lock_tester", $p[0]);
777
778   sleep 1;
779
780   print "Kill slave (PID: $pid[4]) on port $p[4] at breakpoint 1\n";
781   spawn("./rsm_tester", $p[4]+1, "breakpoint", 1);
782
783
784   print "Kill slave (PID: $pid[3]) on port $p[3] at breakpoint 2\n";
785   spawn("./rsm_tester", $p[3]+1, "breakpoint", 2);
786
787
788   sleep 1;
789
790   # two view changes:
791
792   print "first view change wait\n";
793   my @lastv = ($p[0],$p[1],$p[2],$p[3]);
794   foreach my $port (@lastv) {
795     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
796   }
797
798   print "second view change wait\n";
799
800   @lastv = ($p[0],$p[1],$p[2]);
801   foreach my $port (@lastv) {
802     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
803   }
804
805   print "   Wait for lock_tester to finish (waitpid $t)\n";
806   waitpid_to($t, 600);
807
808   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
809     mydie( "Failed lock tester for test 14" );
810   }
811
812   cleanup();
813   sleep 2;
814 }
815
816 if ($do_run[15]) {
817
818   print "test15: start 5-process rsm, kill slave break1, kill primary break2\n";
819
820   start_nodes(5, "ls");
821
822   print "Start lock_tester $p[0]\n";
823   $t = spawn("./lock_tester", $p[0]);
824
825   sleep 1;
826
827   print "Kill slave (PID: $pid[4]) on port $p[4] at breakpoint 1\n";
828   spawn("./rsm_tester", $p[4]+1, "breakpoint", 1);
829
830
831   print "Kill primary (PID: $pid[0]) on port $p[0] at breakpoint 2\n";
832   spawn("./rsm_tester", $p[0]+1, "breakpoint", 2);
833
834   sleep 1;
835
836   # two view changes:
837
838   print "first view change wait\n";
839   my @lastv = ($p[0],$p[1],$p[2],$p[3]);
840   foreach my $port (@lastv) {
841     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
842   }
843
844   print "second view change wait\n";
845
846   @lastv = ($p[1],$p[2],$p[3]);
847   foreach my $port (@lastv) {
848     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
849   }
850
851   print "   Wait for lock_tester to finish (waitpid $t)\n";
852   waitpid_to($t, 600);
853
854   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
855     mydie( "Failed lock tester for test 15" );
856   }
857
858   cleanup();
859   sleep 2;
860 }
861
862 if ($do_run[16]) {
863
864   print "test16: start 3-process rsm, partition primary, heal it\n";
865
866   start_nodes(3, "ls");
867
868   print "Start lock_tester $p[0]\n";
869   $t = spawn("./lock_tester", $p[0]);
870
871   sleep 1;
872
873   print "Partition primary (PID: $pid[0]) on port $p[0] at breakpoint\n";
874
875   spawn("./rsm_tester", $p[0]+1, "partition", 0);
876
877   sleep 3;
878
879   print "first view change wait\n";
880   my @lastv = ($p[1],$p[2]);
881   foreach my $port (@lastv) {
882     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
883   }
884
885   sleep 1;
886
887   print "Heal partition primary (PID: $pid[0]) on port $p[0] at breakpoint\n";
888   spawn("./rsm_tester", $p[0]+1, "partition", 1);
889
890   sleep 1;
891
892   # xxx it should test that this is the 5th view!
893   print "second view change wait\n";
894   @lastv = ($p[0], $p[1],$p[2]);
895   foreach my $port (@lastv) {
896     wait_for_view_change(paxos_log($port), $in_views{$port}+1, $port, 20);
897   }
898   
899   print "   Wait for lock_tester to finish (waitpid $t)\n";
900   waitpid_to($t, 600);
901
902   if( system( "grep \"passed all tests successfully\" lock_tester-$p[0].log" ) ) {
903     mydie( "Failed lock tester for test 16" );
904   }
905
906   cleanup();
907   sleep 2;
908 }
909
910 print "tests done OK\n";
911
912 unlink("config");