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