@@ -43,6 +43,7 @@ use warnings;
43
43
use Cwd qw( realpath) ;
44
44
use Data::Dumper;
45
45
use Date::Format qw( time2str) ;
46
+ use Time::HiRes qw( usleep) ;
46
47
47
48
use lib ' .' ;
48
49
use base qw( Cassandane::Cyrus::TestCase) ;
@@ -296,6 +297,63 @@ sub test_proc_services
296
297
}
297
298
}
298
299
300
+ sub test_proc_crashed_services
301
+ {
302
+ my ($self ) = @_ ;
303
+
304
+ # no clients => no service daemons => no processes
305
+ my @output = $self -> {instance }-> run_cyr_info(' proc' );
306
+ $self -> assert_num_equals(0, scalar @output );
307
+
308
+ # master spawns service processes when clients connect to them
309
+ my $imap_svc = $self -> {instance }-> get_service(' imap' );
310
+ my @clients ;
311
+ foreach (1..5) {
312
+ # five concurrent connections for a single user is normal,
313
+ # e.g. thunderbird does this
314
+ my $store = $imap_svc -> create_store(username => ' cassandane' );
315
+ my $imaptalk = $store -> get_client();
316
+ push @clients , $imaptalk if $imaptalk ;
317
+ }
318
+
319
+ # better have got some clients from that!
320
+ $self -> assert_num_gte(1, scalar @clients );
321
+
322
+ # five clients => five service daemons => five processes
323
+ @output = $self -> {instance }-> run_cyr_info(' proc' );
324
+ $self -> assert_num_equals(scalar @clients , scalar @output );
325
+
326
+ my @pids = sort map { (split /\s +/, $_ , 2)[0] } @output ;
327
+ $self -> assert_num_equals(scalar @clients , scalar @pids );
328
+
329
+ # crash service processes one at a time, expect proc count to decrease
330
+ while (scalar @pids ) {
331
+ my $pid = shift @pids ;
332
+ kill ' SEGV' , $pid ;
333
+ usleep 250_000;
334
+
335
+ my @cores = $self -> {instance }-> find_cores();
336
+ if (@cores ) {
337
+ # if we dumped core, there'd better only be one core file
338
+ $self -> assert_num_equals(1, scalar @cores );
339
+
340
+ # don't barf on it existing during shutdown
341
+ unlink $cores [0];
342
+ }
343
+
344
+ @output = $self -> {instance }-> run_cyr_info(' proc' );
345
+ $self -> assert_num_equals(scalar @pids , scalar @output );
346
+ }
347
+
348
+ # prevent a lot of "Connection closed by other end" noise by claiming
349
+ # and discarding the client's socket before its DESTROY is called
350
+ while (scalar @clients ) {
351
+ my $old = shift @clients ;
352
+
353
+ $old -> release_socket(1);
354
+ }
355
+ }
356
+
299
357
sub test_proc_starts
300
358
:NoStartInstances :needs_component_idled
301
359
{
0 commit comments