Add unit tests [PREMIUM-4]

This commit is contained in:
Alexey Stoletniy
2017-05-04 09:25:34 +03:00
parent 8d15ef6d06
commit 0474985866
9 changed files with 460 additions and 22 deletions

View File

@@ -55,7 +55,10 @@ class ServicesChecker {
$premium_plugin_active = License::getLicense();
$result = Setting::getValue(Bridge::PREMIUM_KEY_STATE_SETTING_NAME);
if(empty($result['state']) || $result['state'] == Bridge::PREMIUM_KEY_VALID) {
if(empty($result['state'])) {
return false;
}
if($result['state'] == Bridge::PREMIUM_KEY_VALID) {
return true;
}

View File

@@ -9,6 +9,8 @@ if(!defined('ABSPATH')) exit;
class Bridge {
const API_KEY_STATE_SETTING_NAME = 'mta.mailpoet_api_key_state';
const PREMIUM_KEY_SETTING_NAME = 'premium.premium_key';
const PREMIUM_KEY_STATE_SETTING_NAME = 'premium.premium_key_state';
const MAILPOET_KEY_VALID = 'valid';
@@ -40,7 +42,7 @@ class Bridge {
}
static function isPremiumKeySpecified() {
$key = Setting::getValue(self::PREMIUM_KEY_STATE_SETTING_NAME);
$key = Setting::getValue(self::PREMIUM_KEY_SETTING_NAME);
return !empty($key);
}
@@ -106,7 +108,7 @@ class Bridge {
$update_settings = false;
if(!empty($result['code']) && isset($state_map[$result['code']])) {
if($result['code'] == self::PREMIUM_KEY_VALID
if($state_map[$result['code']] == self::PREMIUM_KEY_VALID
&& !empty($result['data']['expire_at'])
) {
$key_state = self::PREMIUM_KEY_EXPIRING;

View File

@@ -11,13 +11,13 @@ class ServicesTest extends MailPoetTest {
$this->data = array('key' => '1234567890abcdef');
}
function testItRespondsWithErrorIfNoKeyIsGiven() {
function testItRespondsWithErrorIfNoMSSKeyIsGiven() {
$response = $this->services_endpoint->verifyMailPoetKey(array('key' => ''));
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
expect($response->errors[0]['message'])->equals('Please specify a key.');
}
function testItRespondsWithSuccessIfKeyIsValid() {
function testItRespondsWithSuccessIfMSSKeyIsValid() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkKey' => array('state' => Bridge::MAILPOET_KEY_VALID)),
@@ -27,7 +27,7 @@ class ServicesTest extends MailPoetTest {
expect($response->status)->equals(APIResponse::STATUS_OK);
}
function testItRespondsWithErrorIfKeyIsInvalid() {
function testItRespondsWithErrorIfMSSKeyIsInvalid() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkKey' => array('state' => Bridge::MAILPOET_KEY_INVALID)),
@@ -37,7 +37,7 @@ class ServicesTest extends MailPoetTest {
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
}
function testItRespondsWithErrorIfKeyIsExpiring() {
function testItRespondsWithErrorIfMSSKeyIsExpiring() {
$date = new DateTime;
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
@@ -52,7 +52,7 @@ class ServicesTest extends MailPoetTest {
expect($response->data['message'])->contains($date->format('Y-m-d'));
}
function testItRespondsWithErrorIfServiceIsUnavailable() {
function testItRespondsWithErrorIfServiceIsUnavailableDuringMSSCheck() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkKey' => array('code' => Bridge::CHECK_ERROR_UNAVAILABLE)),
@@ -62,4 +62,88 @@ class ServicesTest extends MailPoetTest {
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
expect($response->errors[0]['message'])->contains((string)Bridge::CHECK_ERROR_UNAVAILABLE);
}
function testItRespondsWithErrorIfMSSCheckThrowsAnException() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkKey' => function() { throw new \Exception('test'); }),
$this
);
$response = $this->services_endpoint->verifyMailPoetKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
expect($response->errors[0]['message'])->equals('test');
}
function testItRespondsWithErrorIfNoPremiumKeyIsGiven() {
$response = $this->services_endpoint->verifyPremiumKey(array('key' => ''));
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
expect($response->errors[0]['message'])->equals('Please specify a key.');
}
function testItRespondsWithSuccessIfPremiumKeyIsValid() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => array('state' => Bridge::PREMIUM_KEY_VALID)),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_OK);
}
function testItRespondsWithErrorIfPremiumKeyIsInvalid() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => array('state' => Bridge::PREMIUM_KEY_INVALID)),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
}
function testItRespondsWithErrorIfPremiumKeyIsUsed() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => array('state' => Bridge::PREMIUM_KEY_USED)),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
}
function testItRespondsWithErrorIfPremiumKeyIsExpiring() {
$date = new DateTime;
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => array(
'state' => Bridge::PREMIUM_KEY_EXPIRING,
'data' => array('expire_at' => $date->format('c'))
)),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_OK);
expect($response->data['message'])->contains($date->format('Y-m-d'));
}
function testItRespondsWithErrorIfServiceIsUnavailableDuringPremiumCheck() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => array('code' => Bridge::CHECK_ERROR_UNAVAILABLE)),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
expect($response->errors[0]['message'])->contains((string)Bridge::CHECK_ERROR_UNAVAILABLE);
}
function testItRespondsWithErrorIfPremiumCheckThrowsAnException() {
$this->services_endpoint->bridge = Stub::make(
new Bridge(),
array('checkPremiumKey' => function() { throw new \Exception('test'); }),
$this
);
$response = $this->services_endpoint->verifyPremiumKey($this->data);
expect($response->status)->equals(APIResponse::STATUS_NOT_FOUND);
expect($response->errors[0]['message'])->equals('test');
}
}

View File

@@ -56,4 +56,27 @@ class MenuTest extends MailPoetTest {
$menu->checkMailPoetAPIKey($checker);
expect($menu->mp_api_key_valid)->false();
}
function testItChecksPremiumKey() {
$renderer = Stub::make(new Renderer());
$assets_url = '';
$menu = new Menu($renderer, $assets_url);
$_REQUEST['page'] = 'mailpoet-newsletters';
$checker = Stub::make(
new ServicesChecker(),
array('isPremiumKeyValid' => true),
$this
);
$menu->checkPremiumKey($checker);
expect($menu->premium_key_valid)->true();
$checker = Stub::make(
new ServicesChecker(),
array('isPremiumKeyValid' => false),
$this
);
$menu->checkPremiumKey($checker);
expect($menu->premium_key_valid)->false();
}
}

View File

@@ -6,13 +6,13 @@ use MailPoet\Models\Setting;
use MailPoet\Services\Bridge;
class ServicesCheckerTest extends MailPoetTest {
function testItDoesNotCheckKeyIfMPSendingServiceIsDisabled() {
function testItDoesNotCheckMSSKeyIfMPSendingServiceIsDisabled() {
$this->disableMailPoetSendingMethod();
$result = ServicesChecker::checkMailPoetAPIKeyValid();
expect($result)->null();
}
function testItChecksKeyValidity() {
function testItChecksMSSKeyValidity() {
$this->setMailPoetSendingMethod();
Setting::setValue(
Bridge::API_KEY_STATE_SETTING_NAME,
@@ -49,6 +49,65 @@ class ServicesCheckerTest extends MailPoetTest {
expect($result)->true();
}
function testItDoesNotCheckPremiumKeyIfPremiumKeyIsNotSpecified() {
$this->clearPremiumKey();
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->null();
}
function testItChecksPremiumKeyValidity() {
$this->fillPremiumKey();
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array('state' => Bridge::PREMIUM_KEY_VALID)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->true();
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array('state' => Bridge::PREMIUM_KEY_INVALID)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->false();
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array('state' => Bridge::PREMIUM_KEY_USED)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->false();
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array(
'state' => Bridge::PREMIUM_KEY_EXPIRING,
'data' => array('expire_at' => date('c'))
)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->true();
// unexpected state should be treated as invalid
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array(
'state' => 'unexpected'
)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->false();
// empty state should be treated as invalid
Setting::setValue(
Bridge::PREMIUM_KEY_STATE_SETTING_NAME,
array(
'state' => ''
)
);
$result = ServicesChecker::isPremiumKeyValid();
expect($result)->false();
}
private function setMailPoetSendingMethod() {
Setting::setValue(
@@ -68,4 +127,12 @@ class ServicesCheckerTest extends MailPoetTest {
)
);
}
private function clearPremiumKey() {
Setting::setValue(Bridge::PREMIUM_KEY_SETTING_NAME, '');
}
private function fillPremiumKey() {
Setting::setValue(Bridge::PREMIUM_KEY_SETTING_NAME, '123457890abcdef');
}
}

View File

@@ -0,0 +1,195 @@
<?php
use Carbon\Carbon;
use Codeception\Util\Stub;
use MailPoet\Cron\CronHelper;
use MailPoet\Cron\Workers\PremiumKeyCheck;
use MailPoet\Mailer\Mailer;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Setting;
use MailPoet\Services\Bridge;
class PremiumKeyCheckTest extends MailPoetTest {
function _before() {
$this->worker = new PremiumKeyCheck(microtime(true));
}
function testItConstructs() {
expect($this->worker->timer)->notEmpty();
}
function testItThrowsExceptionWhenExecutionLimitIsReached() {
try {
$sskeycheck = new PremiumKeyCheck(microtime(true) - CronHelper::DAEMON_EXECUTION_LIMIT);
self::fail('Maximum execution time limit exception was not thrown.');
} catch(\Exception $e) {
expect($e->getMessage())->equals('Maximum execution time has been reached.');
}
}
function testItSchedulesPremiumKeyCheck() {
expect(SendingQueue::where('type', PremiumKeyCheck::TASK_TYPE)->findMany())->isEmpty();
PremiumKeyCheck::schedule();
expect(SendingQueue::where('type', PremiumKeyCheck::TASK_TYPE)->findMany())->notEmpty();
}
function testItDoesNotSchedulePremiumKeyCheckTwice() {
expect(count(SendingQueue::where('type', PremiumKeyCheck::TASK_TYPE)->findMany()))->equals(0);
PremiumKeyCheck::schedule();
expect(count(SendingQueue::where('type', PremiumKeyCheck::TASK_TYPE)->findMany()))->equals(1);
PremiumKeyCheck::schedule();
expect(count(SendingQueue::where('type', PremiumKeyCheck::TASK_TYPE)->findMany()))->equals(1);
}
function testItCanGetScheduledQueues() {
expect(PremiumKeyCheck::getScheduledQueues())->isEmpty();
$this->createScheduledQueue();
expect(PremiumKeyCheck::getScheduledQueues())->notEmpty();
}
function testItCanGetRunningQueues() {
expect(PremiumKeyCheck::getRunningQueues())->isEmpty();
$this->createRunningQueue();
expect(PremiumKeyCheck::getRunningQueues())->notEmpty();
}
function testItCanGetAllDueQueues() {
expect(PremiumKeyCheck::getAllDueQueues())->isEmpty();
// scheduled for now
$this->createScheduledQueue();
// running
$this->createRunningQueue();
// scheduled in the future (should not be retrieved)
$queue = $this->createScheduledQueue();
$queue->scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'))->addDays(7);
$queue->save();
// completed (should not be retrieved)
$queue = $this->createRunningQueue();
$queue->status = SendingQueue::STATUS_COMPLETED;
$queue->save();
expect(count(PremiumKeyCheck::getAllDueQueues()))->equals(2);
}
function testItCanGetFutureQueues() {
expect(PremiumKeyCheck::getFutureQueues())->isEmpty();
$queue = $this->createScheduledQueue();
$queue->scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'))->addDays(7);
$queue->save();
expect(count(PremiumKeyCheck::getFutureQueues()))->notEmpty();
}
function testItFailsToProcessWithoutMailPoetMethodSetUp() {
expect($this->worker->process())->false();
}
function testItFailsToProcessWithoutQueues() {
$this->fillPremiumKey();
expect($this->worker->process())->false();
}
function testItProcesses() {
$this->worker->bridge = Stub::make(
new Bridge,
array('checkPremiumKey' => array('code' => Bridge::PREMIUM_KEY_VALID)),
$this
);
$this->fillPremiumKey();
$this->createScheduledQueue();
$this->createRunningQueue();
expect($this->worker->process())->true();
}
function testItPreparesPremiumKeyCheckQueue() {
$queue = $this->createScheduledQueue();
$this->worker->prepareQueue($queue);
expect($queue->status)->null();
}
function testItProcessesPremiumKeyCheckQueue() {
$this->worker->bridge = Stub::make(
new Bridge,
array('checkPremiumKey' => array('code' => Bridge::PREMIUM_KEY_VALID)),
$this
);
$this->fillPremiumKey();
$queue = $this->createRunningQueue();
$this->worker->prepareQueue($queue);
$this->worker->processQueue($queue);
expect($queue->status)->equals(SendingQueue::STATUS_COMPLETED);
}
function testItReschedulesCheckOnException() {
$this->worker->bridge = Stub::make(
new Bridge,
array('checkPremiumKey' => function () { throw new \Exception(); }),
$this
);
$this->fillPremiumKey();
$queue = $this->createRunningQueue();
$scheduled_at = $queue->scheduled_at;
$this->worker->prepareQueue($queue);
$this->worker->processQueue($queue);
expect($scheduled_at < $queue->scheduled_at)->true();
}
function testItReschedulesCheckOnError() {
$this->worker->bridge = Stub::make(
new Bridge,
array('checkPremiumKey' => array('code' => Bridge::CHECK_ERROR_UNAVAILABLE)),
$this
);
$this->fillPremiumKey();
$queue = $this->createRunningQueue();
$scheduled_at = $queue->scheduled_at;
$this->worker->prepareQueue($queue);
$this->worker->processQueue($queue);
expect($scheduled_at < $queue->scheduled_at)->true();
}
function testItCalculatesNextRunDateWithinNextWeekBoundaries() {
$current_date = Carbon::createFromTimestamp(current_time('timestamp'));
$next_run_date = PremiumKeyCheck::getNextRunDate();
$difference = $next_run_date->diffInDays($current_date);
// Subtract days left in the current week
$difference -= (Carbon::DAYS_PER_WEEK - $current_date->format('N'));
expect($difference)->lessOrEquals(7);
expect($difference)->greaterOrEquals(0);
}
private function fillPremiumKey() {
Setting::setValue(
Bridge::PREMIUM_KEY_SETTING_NAME,
'123457890abcdef'
);
}
private function createScheduledQueue() {
$queue = SendingQueue::create();
$queue->type = PremiumKeyCheck::TASK_TYPE;
$queue->status = SendingQueue::STATUS_SCHEDULED;
$queue->scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'));
$queue->newsletter_id = 0;
$queue->save();
return $queue;
}
private function createRunningQueue() {
$queue = SendingQueue::create();
$queue->type = PremiumKeyCheck::TASK_TYPE;
$queue->status = null;
$queue->scheduled_at = Carbon::createFromTimestamp(current_time('timestamp'));
$queue->newsletter_id = 0;
$queue->save();
return $queue;
}
function _after() {
ORM::raw_execute('TRUNCATE ' . Setting::$_table);
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
}
}

View File

@@ -11,12 +11,6 @@ use MailPoet\Services\Bridge;
class SendingServiceKeyCheckTest extends MailPoetTest {
function _before() {
$this->emails = array(
'soft_bounce@example.com',
'hard_bounce@example.com',
'good_address@example.com'
);
$this->sskeycheck = new SendingServiceKeyCheck(microtime(true));
}
@@ -99,6 +93,11 @@ class SendingServiceKeyCheckTest extends MailPoetTest {
}
function testItProcesses() {
$this->sskeycheck->bridge = Stub::make(
new Bridge,
array('checkKey' => array('code' => Bridge::MAILPOET_KEY_VALID)),
$this
);
$this->setMailPoetSendingMethod();
$this->createScheduledQueue();
$this->createRunningQueue();

View File

@@ -15,6 +15,9 @@ class BridgeTest extends MailPoetTest {
$this->expiring_key = '402' . $this->valid_key;
$this->uncheckable_key = '503' . $this->valid_key;
$this->expiring_premium_key = 'expiring' . $this->valid_key;
$this->used_premium_key = '402' . $this->valid_key;
$this->bridge = new Bridge();
$this->bridge->api = new MailPoet\Services\Bridge\MockAPI('key');
@@ -31,13 +34,19 @@ class BridgeTest extends MailPoetTest {
expect(Bridge::isMPSendingServiceEnabled())->false();
}
function testItChecksIfPremiumKeyIsSpecified() {
expect(Bridge::isPremiumKeySpecified())->false();
$this->fillPremiumKey();
expect(Bridge::isPremiumKeySpecified())->true();
}
function testItInstantiatesDefaultAPI() {
$this->bridge->api = null;
$this->bridge->initApi(null);
expect($this->bridge->api instanceof API)->true();
}
function testItChecksValidKey() {
function testItChecksMSSKey() {
$result = $this->bridge->checkKey($this->valid_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::MAILPOET_KEY_VALID);
@@ -52,7 +61,7 @@ class BridgeTest extends MailPoetTest {
expect($result['data']['expire_at'])->notEmpty();
}
function testItReturnsErrorStateOnEmptyAPIResponseCode() {
function testItReturnsErrorStateOnEmptyAPIResponseCodeDuringMSSCheck() {
$api = Stub::make(new API(null), array('checkKey' => array()), $this);
$this->bridge->api = $api;
$result = $this->bridge->checkKey($this->valid_key);
@@ -60,6 +69,33 @@ class BridgeTest extends MailPoetTest {
expect($result['state'])->equals(Bridge::MAILPOET_KEY_CHECK_ERROR);
}
function testItChecksPremiumKey() {
$result = $this->bridge->checkPremiumKey($this->valid_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::PREMIUM_KEY_VALID);
$result = $this->bridge->checkPremiumKey($this->invalid_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::PREMIUM_KEY_INVALID);
$result = $this->bridge->checkPremiumKey($this->used_premium_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::PREMIUM_KEY_USED);
$result = $this->bridge->checkPremiumKey($this->expiring_premium_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::PREMIUM_KEY_EXPIRING);
expect($result['data']['expire_at'])->notEmpty();
}
function testItReturnsErrorStateOnEmptyAPIResponseCodeDuringPremiumCheck() {
$api = Stub::make(new API(null), array('checkPremiumKey' => array()), $this);
$this->bridge->api = $api;
$result = $this->bridge->checkPremiumKey($this->valid_key);
expect($result)->notEmpty();
expect($result['state'])->equals(Bridge::PREMIUM_KEY_CHECK_ERROR);
}
function testItUpdatesSubscriberCount() {
// it performs update if the key is valid or expiring
$result = array();
@@ -75,7 +111,7 @@ class BridgeTest extends MailPoetTest {
expect($updated)->null();
}
function testItInvalidatesKey() {
function testItInvalidatesMSSKey() {
Setting::setValue(
Bridge::API_KEY_STATE_SETTING_NAME,
array('state' => Bridge::MAILPOET_KEY_VALID)
@@ -85,6 +121,25 @@ class BridgeTest extends MailPoetTest {
expect($value)->equals(array('state' => Bridge::MAILPOET_KEY_INVALID));
}
function testItChecksKeysOnSettingsSave() {
$api = Stub::make(
new API(null),
array(
'checkKey' => Stub::once(function() { return array(); }),
'checkPremiumKey' => Stub::once(function() { return array(); })
),
$this
);
$this->bridge->api = $api;
$settings = array();
$settings[Mailer::MAILER_CONFIG_SETTING_NAME]['mailpoet_api_key'] = $this->valid_key;
$settings['premium']['premium_key'] = $this->valid_key;
$this->setMailPoetSendingMethod();
$this->bridge->onSettingsSave($settings);
}
private function setMailPoetSendingMethod() {
Setting::setValue(
Mailer::MAILER_CONFIG_SETTING_NAME,
@@ -95,6 +150,13 @@ class BridgeTest extends MailPoetTest {
);
}
private function fillPremiumKey() {
Setting::setValue(
Bridge::PREMIUM_KEY_SETTING_NAME,
'123457890abcdef'
);
}
function _after() {
ORM::raw_execute('TRUNCATE ' . Setting::$_table);
}

View File

@@ -21,7 +21,7 @@ class MockAPI {
function checkPremiumKey() {
// if a key begins with these codes, return them
$regex = '/^(401|402|503)/';
$regex = '/^(expiring|401|402|503)/';
$code = preg_match($regex, $this->api_key, $m) ? $m[1] : 200;
return $this->processPremiumResponse($code);
}
@@ -57,12 +57,15 @@ class MockAPI {
private function processPremiumResponse($code) {
switch($code) {
case 200:
case 'expiring':
// a special case of a valid key
$code = 200;
$body = array(
'expire_at' => Carbon::createFromTimestamp(current_time('timestamp'))
->addMonth()->format('c')
);
break;
case 200:
case 401:
case 402:
default: