252 lines
9.5 KiB
PHP
252 lines
9.5 KiB
PHP
<?php
|
|
|
|
namespace MailPoet\Test\Cron\Workers;
|
|
|
|
use MailPoet\Cron\Workers\Bounce;
|
|
use MailPoet\Cron\Workers\Bounce\BounceTestMockAPI as MockAPI;
|
|
use MailPoet\Entities\NewsletterEntity;
|
|
use MailPoet\Entities\ScheduledTaskEntity;
|
|
use MailPoet\Entities\ScheduledTaskSubscriberEntity;
|
|
use MailPoet\Entities\SendingQueueEntity;
|
|
use MailPoet\Entities\StatisticsBounceEntity;
|
|
use MailPoet\Entities\SubscriberEntity;
|
|
use MailPoet\Mailer\Mailer;
|
|
use MailPoet\Models\ScheduledTask;
|
|
use MailPoet\Models\ScheduledTaskSubscriber;
|
|
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
|
|
use MailPoet\Services\Bridge;
|
|
use MailPoet\Services\Bridge\API;
|
|
use MailPoet\Settings\SettingsController;
|
|
use MailPoet\Settings\SettingsRepository;
|
|
use MailPoet\Statistics\StatisticsBouncesRepository;
|
|
use MailPoet\Subscribers\SubscribersRepository;
|
|
use MailPoet\Test\DataFactories\ScheduledTask as ScheduledTaskFactory;
|
|
use MailPoet\WP\Functions as WPFunctions;
|
|
use MailPoetVendor\Carbon\Carbon;
|
|
|
|
require_once('BounceTestMockAPI.php');
|
|
|
|
class BounceTest extends \MailPoetTest {
|
|
|
|
/** @var Bounce */
|
|
private $worker;
|
|
|
|
/** @var string[] */
|
|
private $emails;
|
|
|
|
/** @var SubscribersRepository */
|
|
private $subscribersRepository;
|
|
|
|
/** @var ScheduledTaskFactory */
|
|
private $scheduledTaskFactory;
|
|
|
|
public function _before() {
|
|
parent::_before();
|
|
$this->cleanup();
|
|
$this->emails = [
|
|
'soft_bounce@example.com',
|
|
'hard_bounce@example.com',
|
|
'good_address@example.com',
|
|
];
|
|
$this->subscribersRepository = $this->diContainer->get(SubscribersRepository::class);
|
|
$this->scheduledTaskFactory = new ScheduledTaskFactory();
|
|
|
|
foreach ($this->emails as $email) {
|
|
$subscriber = new SubscriberEntity();
|
|
$subscriber->setStatus(SubscriberEntity::STATUS_SUBSCRIBED);
|
|
$subscriber->setEmail($email);
|
|
$this->subscribersRepository->persist($subscriber);
|
|
}
|
|
|
|
$this->worker = new Bounce(
|
|
$this->diContainer->get(SettingsController::class),
|
|
$this->subscribersRepository,
|
|
$this->diContainer->get(SendingQueuesRepository::class),
|
|
$this->diContainer->get(StatisticsBouncesRepository::class),
|
|
$this->diContainer->get(Bridge::class)
|
|
);
|
|
|
|
$this->worker->api = new MockAPI();
|
|
$this->subscribersRepository->flush();
|
|
$this->entityManager->clear();
|
|
}
|
|
|
|
public function testItDefinesConstants() {
|
|
expect(Bounce::BATCH_SIZE)->equals(100);
|
|
}
|
|
|
|
public function testItCanInitializeBridgeAPI() {
|
|
$this->setMailPoetSendingMethod();
|
|
$worker = new Bounce(
|
|
$this->diContainer->get(SettingsController::class),
|
|
$this->subscribersRepository,
|
|
$this->diContainer->get(SendingQueuesRepository::class),
|
|
$this->diContainer->get(StatisticsBouncesRepository::class),
|
|
$this->diContainer->get(Bridge::class)
|
|
);
|
|
$worker->init();
|
|
expect($worker->api instanceof API)->true();
|
|
}
|
|
|
|
public function testItRequiresMailPoetMethodToBeSetUp() {
|
|
expect($this->worker->checkProcessingRequirements())->false();
|
|
$this->setMailPoetSendingMethod();
|
|
expect($this->worker->checkProcessingRequirements())->true();
|
|
}
|
|
|
|
public function testItDeletesAllSubscribersIfThereAreNoSubscribersToProcessWhenPreparingTask() {
|
|
// 1st run - subscribers will be processed
|
|
$task = $this->createScheduledTask();
|
|
$this->worker->prepareTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::where('task_id', $task->getId())->findMany())->notEmpty();
|
|
|
|
// 2nd run - nothing more to process, ScheduledTaskSubscriber will be cleaned up
|
|
$this->truncateEntity(SubscriberEntity::class);
|
|
$task = $this->createScheduledTask();
|
|
$this->worker->prepareTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::where('task_id', $task->getId())->findMany())->isEmpty();
|
|
}
|
|
|
|
public function testItPreparesTask() {
|
|
$task = $this->createScheduledTask();
|
|
expect(ScheduledTaskSubscriber::getUnprocessedCount($task->getId()))->isEmpty();
|
|
$result = $this->worker->prepareTaskStrategy($task, microtime(true));
|
|
expect($result)->true();
|
|
expect(ScheduledTaskSubscriber::getUnprocessedCount($task->getId()))->notEmpty();
|
|
}
|
|
|
|
public function testItDeletesAllSubscribersIfThereAreNoSubscribersToProcessWhenProcessingTask() {
|
|
// prepare subscribers
|
|
$task = $this->createScheduledTask();
|
|
$this->worker->prepareTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::where('task_id', $task->getId())->findMany())->notEmpty();
|
|
|
|
// process - no subscribers found, ScheduledTaskSubscriber will be cleaned up
|
|
$this->truncateEntity(SubscriberEntity::class);
|
|
$task = $this->createScheduledTask();
|
|
$this->worker->processTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::where('task_id', $task->getId())->findMany())->isEmpty();
|
|
}
|
|
|
|
public function testItProcessesTask() {
|
|
$task = $this->createRunningTask();
|
|
$this->worker->prepareTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::getUnprocessedCount($task->getId()))->notEmpty();
|
|
$this->worker->processTaskStrategy($task, microtime(true));
|
|
expect(ScheduledTaskSubscriber::getProcessedCount($task->getId()))->notEmpty();
|
|
}
|
|
|
|
public function testItSetsSubscriberStatusAsBounced() {
|
|
$task = $this->createRunningTask();
|
|
$this->worker->processEmails($task, $this->emails);
|
|
|
|
$subscribers = $this->subscribersRepository->findAll();
|
|
|
|
expect($subscribers[0]->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
|
|
expect($subscribers[1]->getStatus())->equals(SubscriberEntity::STATUS_BOUNCED);
|
|
expect($subscribers[2]->getStatus())->equals(SubscriberEntity::STATUS_SUBSCRIBED);
|
|
}
|
|
|
|
public function testItCreatesStatistics() {
|
|
$subscriber = $this->subscribersRepository->findOneBy(['email' => 'hard_bounce@example.com']);
|
|
// create old data that shouldn't be picked by the code
|
|
$this->assertInstanceOf(SubscriberEntity::class, $subscriber);
|
|
$oldNewsletter = $this->createNewsletter();
|
|
$oldSendingTask = $this->createSendingTask();
|
|
$oldSendingTask->setUpdatedAt(Carbon::now()->subDays(5));
|
|
$this->createSendingQueue($oldNewsletter, $oldSendingTask);
|
|
$this->createScheduledTaskSubscriber($oldSendingTask, $subscriber);
|
|
// create previous bounce task
|
|
$previousBounceTask = $this->createRunningTask();
|
|
$previousBounceTask->setStatus(ScheduledTask::STATUS_COMPLETED);
|
|
$previousBounceTask->setCreatedAt(Carbon::now()->subDays(6));
|
|
$previousBounceTask->setScheduledAt(Carbon::now()->subDays(4));
|
|
$previousBounceTask->setUpdatedAt(Carbon::now()->subDays(4));
|
|
$this->entityManager->persist($previousBounceTask);
|
|
$this->entityManager->flush();
|
|
// create data that should be used for the current bounce task run
|
|
$newsletter = $this->createNewsletter();
|
|
$sendingTask = $this->createSendingTask() ;
|
|
$sendingTask->setCreatedAt(Carbon::now()->subDays(3));
|
|
$sendingTask->setUpdatedAt(Carbon::now()->subDays(3));
|
|
$this->createSendingQueue($newsletter, $sendingTask);
|
|
$this->createScheduledTaskSubscriber($sendingTask, $subscriber);
|
|
// flush
|
|
$this->entityManager->flush();
|
|
$this->entityManager->clear();
|
|
// run the code
|
|
$this->worker->processEmails($this->createRunningTask(), $this->emails);
|
|
// test it
|
|
$statisticsRepository = $this->diContainer->get(StatisticsBouncesRepository::class);
|
|
$statistics = $statisticsRepository->findAll();
|
|
expect($statistics)->count(1);
|
|
}
|
|
|
|
private function setMailPoetSendingMethod() {
|
|
$settings = SettingsController::getInstance();
|
|
$settings->set(
|
|
Mailer::MAILER_CONFIG_SETTING_NAME,
|
|
[
|
|
'method' => 'MailPoet',
|
|
'mailpoet_api_key' => 'some_key',
|
|
]
|
|
);
|
|
}
|
|
|
|
private function createScheduledTask(): ScheduledTaskEntity {
|
|
return $this->scheduledTaskFactory->create(
|
|
'bounce',
|
|
ScheduledTaskEntity::STATUS_SCHEDULED,
|
|
Carbon::createFromTimestamp(WPFunctions::get()->currentTime('timestamp'))
|
|
);
|
|
}
|
|
|
|
private function createRunningTask(): ScheduledTaskEntity {
|
|
return $this->scheduledTaskFactory->create(
|
|
'bounce',
|
|
null,
|
|
Carbon::createFromTimestamp(WPFunctions::get()->currentTime('timestamp'))
|
|
);
|
|
}
|
|
|
|
private function createNewsletter(): NewsletterEntity {
|
|
$newsletter = new NewsletterEntity();
|
|
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
|
|
$newsletter->setSubject('Subject');
|
|
$this->entityManager->persist($newsletter);
|
|
return $newsletter;
|
|
}
|
|
|
|
private function createSendingQueue(NewsletterEntity $newsletter, ScheduledTaskEntity $task): SendingQueueEntity {
|
|
$queue = new SendingQueueEntity();
|
|
$queue->setNewsletter($newsletter);
|
|
$queue->setTask($task);
|
|
$this->entityManager->persist($queue);
|
|
return $queue;
|
|
}
|
|
|
|
private function createSendingTask(): ScheduledTaskEntity {
|
|
$task = new ScheduledTaskEntity();
|
|
$task->setType('sending');
|
|
$task->setStatus(ScheduledTaskEntity::STATUS_COMPLETED);
|
|
$this->entityManager->persist($task);
|
|
return $task;
|
|
}
|
|
|
|
private function createScheduledTaskSubscriber(ScheduledTaskEntity $task, SubscriberEntity $subscriber) {
|
|
$entity = new ScheduledTaskSubscriberEntity($task, $subscriber);
|
|
$this->entityManager->persist($entity);
|
|
return $entity;
|
|
}
|
|
|
|
public function cleanup() {
|
|
$this->diContainer->get(SettingsRepository::class)->truncate();
|
|
$this->truncateEntity(SubscriberEntity::class);
|
|
$this->truncateEntity(ScheduledTaskEntity::class);
|
|
$this->truncateEntity(ScheduledTaskSubscriberEntity::class);
|
|
$this->truncateEntity(StatisticsBounceEntity::class);
|
|
$this->truncateEntity(NewsletterEntity::class);
|
|
$this->truncateEntity(SendingQueueEntity::class);
|
|
}
|
|
}
|