Files
piratepoet/mailpoet/tests/integration/Automation/Integrations/MailPoet/Hooks/CreateAutomationRunHookTest.php
2024-08-12 12:25:42 +02:00

117 lines
4.9 KiB
PHP

<?php declare(strict_types = 1);
namespace MailPoet\Test\Automation\Integrations\MailPoet\Hooks;
use Codeception\Stub\Expected;
use DateTimeImmutable;
use MailPoet\Automation\Engine\Data\Automation;
use MailPoet\Automation\Engine\Data\AutomationRun;
use MailPoet\Automation\Engine\Data\StepRunArgs;
use MailPoet\Automation\Engine\Data\Subject;
use MailPoet\Automation\Engine\Data\SubjectEntry;
use MailPoet\Automation\Engine\Storage\AutomationRunStorage;
use MailPoet\Automation\Integrations\MailPoet\Hooks\CreateAutomationRunHook;
use MailPoet\Automation\Integrations\MailPoet\Subjects\SubscriberSubject;
use MailPoet\Test\DataFactories;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetTest;
class CreateAutomationRunHookTest extends MailPoetTest {
private const TEST_SUBSCRIBER_ID = 123;
public function testWithoutPreviousRuns(): void {
$service = $this->diContainer->get(CreateAutomationRunHook::class);
// with run once args
$args = $this->getStepRunArgs(true);
$this->assertFalse($service->createAutomationRun(false, $args));
$this->assertTrue($service->createAutomationRun(true, $args));
// without run once args
$args = $this->getStepRunArgs(false);
$this->assertFalse($service->createAutomationRun(false, $args));
$this->assertTrue($service->createAutomationRun(true, $args));
}
public function testWithPreviousRuns(): void {
$service = $this->diContainer->get(CreateAutomationRunHook::class);
// with run once args
$args = $this->getStepRunArgs(true);
$this->createAutomationRun($args->getAutomation());
$this->assertFalse($service->createAutomationRun(false, $args));
$this->assertFalse($service->createAutomationRun(true, $args));
// without run once args
$args = $this->getStepRunArgs(false);
$this->createAutomationRun($args->getAutomation());
$this->assertFalse($service->createAutomationRun(false, $args));
$this->assertTrue($service->createAutomationRun(true, $args));
}
public function testItAcquiresLock(): void {
$service = $this->diContainer->get(CreateAutomationRunHook::class);
$args = $this->getStepRunArgs(true);
$this->assertFalse($service->createAutomationRun(false, $args));
$this->assertTrue($service->createAutomationRun(true, $args));
// next run should be blocked by the lock
$this->assertFalse($service->createAutomationRun(true, $args));
// check lock
$wp = $this->diContainer->get(WPFunctions::class);
$subject = array_values($args->getAutomationRun()->getSubjects(SubscriberSubject::KEY))[0];
$key = sprintf('mailpoet:run-once-per-subscriber:[%s][%s]', $args->getAutomation()->getId(), $subject->getHash());
$lock = $wp->getTransient($key);
$timeout = new DateTimeImmutable('@' . $wp->getOption("_transient_timeout_$key"));
$this->assertIsString($lock);
$this->assertNotEmpty($lock);
$this->assertGreaterThan(new DateTimeImmutable('+10 seconds'), $timeout);
$this->assertLessThan(new DateTimeImmutable('+2 minutes'), $timeout);
}
public function testItVerifiesLock(): void {
$wp = $this->diContainer->get(WPFunctions::class);
$args = $this->getStepRunArgs(true);
$subject = array_values($args->getAutomationRun()->getSubjects(SubscriberSubject::KEY))[0];
$key = sprintf('mailpoet:run-once-per-subscriber:[%s][%s]', $args->getAutomation()->getId(), $subject->getHash());
$service = $this->getServiceWithOverrides(CreateAutomationRunHook::class, [
'automationRunStorage' => $this->make(AutomationRunStorage::class, [
'getCountByAutomationAndSubject' => Expected::once(function () use ($wp, $key): int {
// simulate that another process caused a locking race condition
$wp->setTransient($key, 'lock-value-from-another-process', MINUTE_IN_SECONDS);
return 0;
}),
]),
]);
// run will be blocked by the lock due to a lock value mismatch
$this->assertFalse($service->createAutomationRun(true, $args));
}
private function getStepRunArgs(bool $runOncePerSubscriber): StepRunArgs {
$automation = (new DataFactories\Automation())
->withMeta('mailpoet:run-once-per-subscriber', $runOncePerSubscriber)
->withSomeoneSubscribesTrigger()
->withDelayAction()
->create();
$subject = new Subject(SubscriberSubject::KEY, ['subscriber_id' => self::TEST_SUBSCRIBER_ID]);
$automationRun = new AutomationRun($automation->getId(), 1, '', [$subject]);
$trigger = array_values($automation->getTriggers())[0];
$subscriberEntry = new SubjectEntry($this->diContainer->get(SubscriberSubject::class), $subject);
return new StepRunArgs($automation, $automationRun, $trigger, [$subscriberEntry], 1);
}
private function createAutomationRun(Automation $automation): AutomationRun {
return (new DataFactories\AutomationRun())
->withAutomation($automation)
->withSubject(new Subject(SubscriberSubject::KEY, ['subscriber_id' => self::TEST_SUBSCRIBER_ID]))
->create();
}
}