1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\CoreAdminHome\tests\Integration\Commands;
use Piwik\CliMulti\ProcessSymfony;
use Piwik\Plugins\CoreAdminHome\Tasks;
use Piwik\Plugins\CoreAdminHome\tests\Fixtures\RunScheduledTasksProcessSignal as RunScheduledTasksProcessSignalFixture;
use Piwik\Plugins\CoreConsole\FeatureFlags\SystemSignals;
use Piwik\Scheduler\Task;
use Piwik\Tests\Framework\Fixture;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
/**
* @group Core
* @group CoreAdminHome
* @group RunScheduledTasksProcessSignal
*/
class RunScheduledTasksProcessSignalTest extends IntegrationTestCase
{
/**
* @var RunScheduledTasksProcessSignalFixture
*/
public static $fixture;
public function setUp(): void
{
if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
$this->markTestSkipped('signal test cannot run without ext-pcntl');
}
parent::setUp();
$environment = self::$fixture->getTestEnvironment();
$environment->overrideConfig(
'FeatureFlags',
(new SystemSignals())->getName() . '_feature',
'enabled'
);
$environment->save();
self::$fixture->stepControl->reset();
}
/**
* @dataProvider getScheduledTasksStoppedData
*/
public function testScheduledTasksStopped(int $signal): void
{
self::$fixture->stepControl->blockScheduledTasks();
$process = $this->startScheduledTasks();
// wait until scheduled tasks are running
$result = self::$fixture->stepControl->waitForSuccess(static function () use ($process): bool {
return false !== strpos($process->getOutput(), 'Scheduler: executing task');
}, $timeoutInSeconds = 30);
self::assertTrue($result, 'Scheduled tasks did not start');
$this->sendSignalToProcess($process, $signal);
self::$fixture->stepControl->unblockScheduledTasks();
$this->waitForProcessToStop($process);
$processOutput = $process->getOutput();
$expectedExecutedTask = Task::getTaskName(Tasks::class, 'invalidateOutdatedArchives', null);
$expectedSkippedTask = Task::getTaskName(Tasks::class, 'purgeOutdatedArchives', null);
self::assertStringContainsString('executing task ' . $expectedExecutedTask, $processOutput);
self::assertStringNotContainsString('executing task ' . $expectedSkippedTask, $processOutput);
self::assertStringContainsString(
'Received system signal to stop scheduled tasks: ' . $signal,
$processOutput
);
self::assertStringContainsString('Scheduler: Aborting due to received signal', $processOutput);
}
public function getScheduledTasksStoppedData(): iterable
{
yield 'stop using sigint' => [\SIGINT];
yield 'stop using sigterm' => [\SIGTERM];
}
private function sendSignalToProcess(ProcessSymfony $process, int $signal): void
{
$process->signal($signal);
$result = self::$fixture->stepControl->waitForSuccess(
static function () use ($process, $signal): bool {
return false !== strpos(
$process->getOutput(),
'Received system signal to stop scheduled tasks: ' . $signal
);
}
);
self::assertTrue($result, 'Process did not acknowledge signal');
}
private function startScheduledTasks(): ProcessSymfony
{
// exec is mandatory to send signals to the process
// not using array notation because "Fixture::getCliCommandBase" contains parameters
$process = ProcessSymfony::fromShellCommandline(sprintf(
'exec %s scheduled-tasks:run -vvv --force',
Fixture::getCliCommandBase()
));
$process->setEnv([RunScheduledTasksProcessSignalFixture::ENV_TRIGGER => '1']);
$process->setTimeout(null);
$process->start();
self::assertTrue($process->isRunning());
self::assertNotNull($process->getPid());
return $process;
}
private function waitForProcessToStop(ProcessSymfony $process): void
{
$result = self::$fixture->stepControl->waitForSuccess(static function () use ($process): bool {
return !$process->isRunning();
});
self::assertTrue($result, 'Archiving process did not stop');
self::assertSame(0, $process->getExitCode());
}
}
RunScheduledTasksProcessSignalTest::$fixture = new RunScheduledTasksProcessSignalFixture();
|