Skip to content

Commit

Permalink
Add tests for non-symfony climulti methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mneudert committed Aug 22, 2024
1 parent 267c942 commit 8d19658
Showing 1 changed file with 115 additions and 38 deletions.
153 changes: 115 additions & 38 deletions tests/PHPUnit/Integration/CronArchiveProcessSignalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
*/
class CronArchiveProcessSignalTest extends IntegrationTestCase
{
private const METHOD_ASYNC_CLI = 'asyncCli';
private const METHOD_ASYNC_CLI_SYMFONY = 'asyncCliSymfony';
private const METHOD_CURL = 'curl';
private const METHOD_SYNC_CLI = 'syncCli';

/**
* @var CronArchiveProcessSignalFixture
Expand Down Expand Up @@ -62,13 +65,13 @@ public function testArchivingWithoutSignalWorks(string $method): void
self::$fixture->stepControl->unblockAPIArchiveReports();

// let archiving run completely
$process = $this->startArchivingProcess();
$process = $this->startArchivingProcess($method);
$process->setTimeout(30);
$process->wait();

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

$this->assertArchiveInvalidationCount($inProgress = 0, $total = 0);
$this->assertArchiveInvalidationCount(['inProgress' => 0, 'total' => 0]);

$processOutput = $process->getOutput();

Expand All @@ -79,48 +82,103 @@ public function testArchivingWithoutSignalWorks(string $method): void
self::assertStringContainsString('Archived website id 1, period = year', $processOutput);
self::assertStringContainsString('Done archiving!', $processOutput);
self::assertStringContainsString('Starting Scheduled tasks...', $processOutput);

if (self::METHOD_CURL === $method) {
self::assertStringContainsString('Execute HTTP API request:', $processOutput);
} else {
self::assertRegExp('/Running command.*\[method = ' . $method . ']/', $processOutput);
}
}

public function getArchivingWithoutSignalData(): iterable
{
yield 'symfony process' => [
'method' => self::METHOD_ASYNC_CLI_SYMFONY,
];

yield 'default process (single process)' => [
'method' => self::METHOD_SYNC_CLI,
];

yield 'default process (multi process)' => [
'method' => self::METHOD_ASYNC_CLI,
];

yield 'curl' => [
'method' => self::METHOD_CURL,
];
}

/**
* @dataProvider getSigintTestArchivingData
*
* @param array{segment: string, period: string, date: string} $blockSpec
* @param array{inProgress: int, total: int} $invalidationCountIntermediate
* @param array{inProgress: int, total: int} $invalidationCountFinal
*/
public function testSigint(string $method, array $blockSpec): void
{
public function testSigint(
string $method,
array $blockSpec,
array $invalidationCountIntermediate,
array $invalidationCountFinal
): void {
self::$fixture->stepControl->blockCronArchiveStart();
self::$fixture->stepControl->blockAPIArchiveReports($blockSpec);

$this->setUpArchivingMethod($method);

$process = $this->startArchivingProcess();
$process = $this->startArchivingProcess($method);

self::$fixture->stepControl->unblockCronArchiveStart();

$this->waitForArchivingToStart($process, $blockSpec);
$this->assertArchiveInvalidationCount($inProgress = 1, $total = 12);
$this->waitForArchivingToStart($process, $method, $blockSpec);
$this->assertArchiveInvalidationCount($invalidationCountIntermediate);

$process->signal(\SIGINT);

self::$fixture->stepControl->unblockAPIArchiveReports();

$this->waitForArchivingProcessToStop($process);
$this->assertArchivingOutput($process, $method, \SIGINT, $blockSpec);
$this->assertArchiveInvalidationCount($inProgress = 0, $total = 11);
$this->assertArchiveInvalidationCount($invalidationCountFinal);
}

public function getSigintTestArchivingData(): iterable
{
$specToday = ['segment' => '', 'period' => 'day', 'date' => self::$fixture->today];

yield 'symfony process' => [
'method' => self::METHOD_ASYNC_CLI_SYMFONY,
'blockSpec' => ['segment' => '', 'period' => 'day', 'date' => self::$fixture->today],
'blockSpec' => $specToday,
'invalidationCountIntermediate' => ['inProgress' => 1, 'total' => 12],
'invalidationCountFinal' => ['inProgress' => 0, 'total' => 11],
];

yield 'default process (single process)' => [
'method' => self::METHOD_SYNC_CLI,
'blockSpec' => $specToday,
'invalidationCountIntermediate' => ['inProgress' => 1, 'total' => 12],
'invalidationCountFinal' => ['inProgress' => 0, 'total' => 11],
];

// empty day segment will always run as a single process
// so we use a non-empty segment for testing asyncCli
yield 'default process (multi process)' => [
'method' => self::METHOD_ASYNC_CLI,
'blockSpec' => [
'segment' => CronArchiveProcessSignalFixture::TEST_SEGMENT_CH,
'period' => 'day',
'date' => self::$fixture->today,
],
'invalidationCountIntermediate' => ['inProgress' => 2, 'total' => 11],
'invalidationCountFinal' => ['inProgress' => 0, 'total' => 9],
];

yield 'curl' => [
'method' => self::METHOD_CURL,
'blockSpec' => $specToday,
'invalidationCountIntermediate' => ['inProgress' => 1, 'total' => 12],
'invalidationCountFinal' => ['inProgress' => 0, 'total' => 11],
];
}

Expand All @@ -136,18 +194,18 @@ public function testSigterm(string $method, array $blockSpec): void

$this->setUpArchivingMethod($method);

$process = $this->startArchivingProcess();
$process = $this->startArchivingProcess($method);

self::$fixture->stepControl->unblockCronArchiveStart();

$this->waitForArchivingToStart($process, $blockSpec);
$this->assertArchiveInvalidationCount($inProgress = 1, $total = 12);
$this->waitForArchivingToStart($process, $method, $blockSpec);
$this->assertArchiveInvalidationCount(['inProgress' => 1, 'total' => 12]);

$process->signal(\SIGTERM);

$this->waitForArchivingProcessToStop($process);
$this->assertArchivingOutput($process, $method, \SIGTERM, $blockSpec);
$this->assertArchiveInvalidationCount($inProgress = 0, $total = 12);
$this->assertArchiveInvalidationCount(['inProgress' => 0, 'total' => 12]);
}

public function getSigtermTestArchivingData(): iterable
Expand All @@ -158,18 +216,19 @@ public function getSigtermTestArchivingData(): iterable
];
}

private function assertArchiveInvalidationCount(
int $expectedInProgress,
int $expectedTotal
): void {
/**
* @param array{inProgress: int, total: int} $expectedCounts
*/
private function assertArchiveInvalidationCount(array $expectedCounts): void
{
$actualInProgress = $this->dataAccessModel->getInvalidationsInProgress(self::$fixture->idSite);
$actualTotal = (int) Db::fetchOne(
'SELECT COUNT(*) FROM ' . Common::prefixTable('archive_invalidations') . ' WHERE idsite = ?',
[self::$fixture->idSite]
);

self::assertSame($expectedTotal, $actualTotal);
self::assertCount($expectedInProgress, $actualInProgress);
self::assertSame($expectedCounts['total'], $actualTotal);
self::assertCount($expectedCounts['inProgress'], $actualInProgress);
}

/**
Expand All @@ -184,13 +243,20 @@ private function assertArchivingOutput(
$idSite = self::$fixture->idSite;
$processOutput = $process->getOutput();

self::assertRegExp('/Running command.*\[method = ' . $method . ']/', $processOutput);
if (self::METHOD_CURL === $method) {
self::assertStringContainsString('Execute HTTP API request:', $processOutput);
} else {
self::assertRegExp('/Running command.*\[method = ' . $method . ']/', $processOutput);
}

self::assertStringContainsString('Starting archiving for', $processOutput);
self::assertStringContainsString('Received system signal: ' . $signal, $processOutput);
self::assertStringContainsString('Trying to stop running cli processes...', $processOutput);
self::assertStringContainsString('Archiving will stop now because signal to abort received', $processOutput);

if (self::METHOD_CURL !== $method) {
self::assertStringContainsString('Received system signal: ' . $signal, $processOutput);
self::assertStringContainsString('Trying to stop running cli processes...', $processOutput);
}

if (\SIGINT === $signal) {
self::assertStringContainsString(sprintf(
"Archived website id %u, period = %s, date = %s, segment = '%s'",
Expand All @@ -209,31 +275,34 @@ private function assertArchivingOutput(

private function setUpArchivingMethod(string $method): void
{
if (self::METHOD_ASYNC_CLI_SYMFONY === $method) {
$featureFlag = new CliMultiProcessSymfony();
$environment = self::$fixture->getTestEnvironment();

$environment = self::$fixture->getTestEnvironment();
$environment->overrideConfig(
'FeatureFlags',
$featureFlag->getName() . '_feature',
'enabled'
);
$featureFlag = new CliMultiProcessSymfony();
$featureFlagConfigName = $featureFlag->getName() . '_feature';

$environment->save();
if (self::METHOD_ASYNC_CLI_SYMFONY === $method) {
$environment->overrideConfig('FeatureFlags', $featureFlagConfigName, 'enabled');
} else {
$environment->removeOverriddenConfig('FeatureFlags', $featureFlagConfigName);
}

$environment->forceCliMultiViaCurl = (int) (self::METHOD_CURL === $method);

$environment->save();
}

private function startArchivingProcess(): ProcessSymfony
private function startArchivingProcess(string $method): ProcessSymfony
{
$cliPhp = new CliPhp();
$phpBinary = $cliPhp->findPhpBinary();

// 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 -vvv',
'exec %s %s/tests/PHPUnit/proxy/console core:archive -vvv %s',
$phpBinary,
PIWIK_INCLUDE_PATH
PIWIK_INCLUDE_PATH,
self::METHOD_SYNC_CLI === $method ? '--concurrent-requests-per-website=1' : ''
));

$process->setEnv([CronArchiveProcessSignalFixture::ENV_TRIGGER => '1']);
Expand All @@ -259,8 +328,11 @@ private function waitForArchivingProcessToStop(ProcessSymfony $process): void
/**
* @param array{segment: string, period: string, date: string} $blockSpec
*/
private function waitForArchivingToStart(ProcessSymfony $process, array $blockSpec): void
{
private function waitForArchivingToStart(
ProcessSymfony $process,
string $method,
array $blockSpec
): void {
$segment = new Segment($blockSpec['segment'], [self::$fixture->idSite]);
$doneFlag = Rules::getDoneFlagArchiveContainsAllPlugins($segment);

Expand All @@ -283,15 +355,20 @@ private function waitForArchivingToStart(ProcessSymfony $process, array $blockSp
self::assertTrue($result, 'Invalidation did not start for: ' . json_encode($blockSpec));

$result = self::$fixture->stepControl->waitForSuccess(
static function () use ($process, $blockSpec): bool {
static function () use ($process, $method, $blockSpec): bool {
$processOutput = $process->getOutput();

$needles = [
'Running command',
'date=' . $blockSpec['date'],
'period=' . $blockSpec['period']
];

if (self::METHOD_CURL === $method) {
$needles[] = 'Execute HTTP API request';
} else {
$needles[] = 'Running command';
}

if ('' !== $blockSpec['segment']) {
$needles[] = 'segment=' . urlencode($blockSpec['segment']);
}
Expand Down

0 comments on commit 8d19658

Please sign in to comment.