Skip to content

Commit

Permalink
Add integration test for SIGTERM handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mneudert committed Aug 16, 2024
1 parent c1848cf commit 78826a9
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 1 deletion.
55 changes: 55 additions & 0 deletions config/environment/test.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<?php

use Piwik\Container\Container;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Request;
use Piwik\Tests\Framework\Mock\FakeAccess;
use Piwik\Tests\Framework\Mock\FakeChangesModel;
use Piwik\Tests\Framework\Mock\TestConfig;
use Piwik\Tests\Integration\CronArchiveProcessSignalTest;

return array(

Expand Down Expand Up @@ -125,6 +128,58 @@
}
})),

array('CronArchive.init.start', \Piwik\Di::value(function () {
if ('1' !== getenv(CronArchiveProcessSignalTest::ENV_TRIGGER)) {
return;
}

for ($i = 0; $i < 10; $i++) {
$doStart = (bool) Option::get(CronArchiveProcessSignalTest::OPTION_START);

if ($doStart) {
break;
}

sleep(1);
}

if (!$doStart) {
echo 'Waiting for start option took too long!';
exit(127);
}
})),

array('CronArchive.alterArchivingRequestUrl', \Piwik\Di::value(function (&$url) {
if ('1' !== getenv(CronArchiveProcessSignalTest::ENV_TRIGGER)) {
return;
}

$url .= '&' . CronArchiveProcessSignalTest::ENV_TRIGGER . '=1';
})),

array('API.CoreAdminHome.archiveReports', \Piwik\Di::value(function () {
$request = Request::fromRequest();

if (!$request->getBoolParameter(CronArchiveProcessSignalTest::ENV_TRIGGER, false)) {
return;
}

for ($i = 0; $i < 10; $i++) {
$doStart = (bool) Option::get(CronArchiveProcessSignalTest::OPTION_ARCHIVE);

if ($doStart) {
break;
}

sleep(1);
}

if (!$doStart) {
echo 'Waiting for archive option took too long!';
exit(127);
}
})),

array('Updater.checkForUpdates', \Piwik\DI::value(function () {
try {
@\Piwik\Filesystem::deleteAllCacheOnUpdate();
Expand Down
1 change: 0 additions & 1 deletion core/CliMulti.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ public function runAsSuperUser($runAsSuperUser = true)
public function kill(): void
{
$this->wasKilled = true;

foreach ($this->processes as $process) {
if ($process instanceof ProcessSymfony) {
$process->stop(0);
Expand Down
143 changes: 143 additions & 0 deletions tests/PHPUnit/Integration/CronArchiveProcessSignalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?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\Tests\Integration;

use Piwik\CliMulti\CliPhp;
use Piwik\CliMulti\ProcessSymfony;
use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\DataAccess\Model;
use Piwik\Db;
use Piwik\Option;
use Piwik\Plugins\CoreConsole\FeatureFlags\CliMultiProcessSymfony;
use Piwik\Plugins\FeatureFlags\FeatureFlagManager;
use Piwik\Tests\Fixtures\OneVisit;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;

/**
* @group Archiver
* @group CronArchive
* @group CronArchiveProcessSignal
*/
class CronArchiveProcessSignalTest extends IntegrationTestCase
{
public const ENV_TRIGGER = 'MATOMO_TEST_CRON_ARCHIVE_PROCESS_SIGNAL';

public const OPTION_ARCHIVE = 'CronArchiveProcessSignalTest.archive';
public const OPTION_START = 'CronArchiveProcessSignalTest.start';

/**
* @var OneVisit
*/
public static $fixture;

public function setUp(): void
{
parent::setUp();
}

public function testSigterm(): void
{
if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
$this->markTestSkipped('signal test cannot run without ext-pcntl');
}

$cliPhp = new CliPhp();
$phpBinary = $cliPhp->findPhpBinary();

$featureFlag = new CliMultiProcessSymfony();
$featureFlagManager = StaticContainer::get(FeatureFlagManager::class);
$isFeatureAlreadyActive = $featureFlagManager->isFeatureActive(get_class($featureFlag));

try {
if (!$isFeatureAlreadyActive) {
// activate FeatureFlag for instance outside of the testing environment
// only required if it was not already activated
$exitCode = ProcessSymfony::fromShellCommandline(sprintf(
'exec %s %s/console featureflag:enable %s',
$phpBinary,
PIWIK_INCLUDE_PATH,
$featureFlag->getName()
))->run();

self::assertSame(0, $exitCode);
}

// exec is mandatory to send signals to the process
// not using array notation because "$phpBinary" can contain parameters
$process = ProcessSymfony::fromShellCommandline(sprintf(
'exec %s %s/tests/PHPUnit/proxy/console core:archive',
$phpBinary,
PIWIK_INCLUDE_PATH
));

$process->setEnv([self::ENV_TRIGGER => '1']);
$process->setTimeout(null);
$process->start();

self::assertTrue($process->isRunning());
self::assertNotNull($process->getPid());

Option::set(self::OPTION_START, true);

$dataAccessModel = new Model();

for ($i = 0; $i < 10; $i++) {
$invalidationsInProgress = $dataAccessModel->getInvalidationsInProgress(self::$fixture->idSite);

if ([] !== $invalidationsInProgress) {
break;
}

sleep(1);
}

self::assertNotEmpty($invalidationsInProgress);
self::assertSame(4, $this->getArchiveInvalidationCount(self::$fixture->idSite));

//Option::set(self::OPTION_ARCHIVE, true);

self::assertTrue($process->isRunning());

$process->stop(10, SIGTERM);

self::assertFalse($process->isRunning());
self::assertSame(0, $process->getExitCode());

$invalidationsInProgress = $dataAccessModel->getInvalidationsInProgress(self::$fixture->idSite);

self::assertEmpty($invalidationsInProgress);
self::assertSame(4, $this->getArchiveInvalidationCount(self::$fixture->idSite));
} finally {
if (!$isFeatureAlreadyActive) {
// deactivate FeatureFlag for instance outside of the testing environment
// only required if it was not already activated
ProcessSymfony::fromShellCommandline(sprintf(
'exec %s %s/console featureflag:disable %s',
$phpBinary,
PIWIK_INCLUDE_PATH,
$featureFlag->getName()
))->run();
}
}
}

private function getArchiveInvalidationCount(int $idSite): int
{
return Db::fetchOne(
'SELECT COUNT(*) FROM ' . Common::prefixTable('archive_invalidations') . ' WHERE idsite = ?',
[
$idSite
]
);
}
}

CronArchiveProcessSignalTest::$fixture = new OneVisit();

0 comments on commit 78826a9

Please sign in to comment.