1--TEST--
2FPM: bug76601 children should not ignore signals during concurrent reloads
3--SKIPIF--
4<?php
5include "skipif.inc";
6if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
7?>
8--FILE--
9<?php
10
11require_once "tester.inc";
12
13$cfg = <<<EOT
14[global]
15error_log = {{FILE:LOG}}
16pid = {{FILE:PID}}
17; some value twice greater than tester->getLogLines() timeout
18process_control_timeout=10
19[unconfined]
20listen = {{ADDR}}
21; spawn children immediately after reload
22pm = static
23pm.max_children = 10
24EOT;
25
26$code = <<<EOT
27<?php
28/* empty */
29EOT;
30
31/*
32 * If a child miss SIGQUIT then reload process should stuck
33 * for at least process_control_timeout that is set greater
34 * than timout in log reading functions.
35 *
36 * Alternative way is to set log_level=debug and filter result of
37 * $tester->getLogLines(2000) for lines containing SIGKILL
38 *
39 *     [22-Oct-2019 03:28:19.532703] DEBUG: pid 21315, fpm_pctl_kill_all(), line 161: [pool unconfined] sending signal 9 SIGKILL to child 21337
40 *     [22-Oct-2019 03:28:19.533471] DEBUG: pid 21315, fpm_children_bury(), line 259: [pool unconfined] child 21337 exited on signal 9 (SIGKILL) after 1.003055 seconds from start
41 *
42 * but it has less probability of failure detection. Additionally it requires more
43 * $tester->expectLogNotice() around last reload due to presence of debug messages.
44 */
45
46$tester = new FPM\Tester($cfg, $code);
47$tester->start();
48$tester->expectLogStartNotices();
49
50/* Vary interval between concurrent reload requests
51    since performance of test instance is not known in advance */
52$max_interval = 25000;
53$step = 1000;
54$pid = $tester->getPid();
55for ($interval = 0; $interval < $max_interval; $interval += $step) {
56    exec("kill -USR2 $pid", $out, $killExitCode);
57    if ($killExitCode) {
58        echo "ERROR: master process is dead\n";
59        break;
60    }
61    usleep($interval);
62}
63echo "Reached interval $interval us with $step us steps\n";
64$tester->expectLogNotice('Reloading in progress ...');
65/* Consume mix of 'Reloading in progress ...' and 'reloading: .*' */
66$skipped = $tester->getLogLines(2000);
67
68$tester->signal('USR2');
69$tester->expectLogNotice('Reloading in progress ...');
70/* When a child ignores SIGQUIT, the following expectation fails due to timeout. */
71if (!$tester->expectLogNotice('reloading: .*')) {
72    /* for troubleshooting */
73    echo "Skipped messages\n";
74    echo implode('', $skipped);
75}
76$tester->expectLogNotice('using inherited socket fd=\d+, "127.0.0.1:\d+"');
77$tester->expectLogStartNotices();
78
79$tester->terminate();
80$tester->expectLogTerminatingNotices();
81$tester->close();
82
83?>
84Done
85--EXPECT--
86Reached interval 25000 us with 1000 us steps
87Done
88--CLEAN--
89<?php
90require_once "tester.inc";
91FPM\Tester::clean();
92?>
93