settings = SettingsController::getInstance(); $this->settings->set('db_version', MAILPOET_VERSION); // Disable cron trigger to not run tasks like migration when pinging the daemon $this->settings->set('cron_trigger', [ 'method' => 'none', ]); $this->settings->set('sender', [ 'name' => 'John Doe', 'address' => 'john.doe@example.com', ]); $this->cronHelper = new CronHelper($this->settings, new WPFunctions); } public function testItDefinesConstants() { expect(CronHelper::DAEMON_EXECUTION_LIMIT)->equals(20); expect(CronHelper::DAEMON_REQUEST_TIMEOUT)->equals(5); expect(CronHelper::DAEMON_SETTING)->equals('cron_daemon'); } public function testItCreatesDaemon() { $token = 'create_token'; $time = time(); $this->cronHelper->createDaemon($token); $daemon = $this->settings->get(CronHelper::DAEMON_SETTING); expect($daemon)->equals( [ 'token' => $token, 'status' => CronHelper::DAEMON_STATUS_ACTIVE, 'updated_at' => $time, 'run_accessed_at' => null, 'run_started_at' => null, 'run_completed_at' => null, 'last_error' => null, 'last_error_date' => null, ] ); } public function testItRestartsDaemon() { $token = 'restart_token'; $time = time(); $this->cronHelper->restartDaemon($token); $daemon = $this->settings->get(CronHelper::DAEMON_SETTING); expect($daemon)->equals( [ 'token' => $token, 'status' => CronHelper::DAEMON_STATUS_ACTIVE, 'updated_at' => $time, 'run_accessed_at' => null, 'run_started_at' => null, 'run_completed_at' => null, 'last_error' => null, 'last_error_date' => null, ] ); } public function testItLoadsDaemon() { $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); expect($this->cronHelper->getDaemon())->equals($daemon); } public function testItSavesDaemon() { // when saving daemon, 'updated_at' value should change $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); $time = time(); $this->cronHelper->saveDaemon($daemon); $daemon['updated_at'] = $time; expect($this->cronHelper->getDaemon())->equals($daemon); } public function testItUpdatesDaemonAccessedAt() { $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); $time = time(); $wp = Stub::make(new WPFunctions, [ 'wpRemotePost' => [], ]); $cronHelper = new CronHelper($this->settings, $wp); $cronHelper->accessDaemon('some_token'); $updatedDaemon = $cronHelper->getDaemon(); expect($updatedDaemon['run_accessed_at'])->greaterOrEquals($time); expect($updatedDaemon['run_accessed_at'])->lessThan($time + 2); } public function testItThrowsAnExceptionIfAccessingNonExistingDaemon() { try { $this->cronHelper->accessDaemon('some_token'); $this->fail('An exception should have been thrown.'); } catch (\LogicException $e) { expect($e->getMessage())->equals('Daemon does not exist.'); } } public function testItDetectsNotAccessibleDaemon() { $time = time(); $runStartValues = [null, $time - 20]; foreach ($runStartValues as $runStart) { $daemon = $this->getDeamonTestData(); $daemon['run_accessed_at'] = $time - 10; $daemon['run_started_at'] = $runStart; $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); expect($this->cronHelper->isDaemonAccessible())->false(); } } public function testItDetectsAccessibleDaemon() { $time = time(); $daemon = $this->getDeamonTestData(); $daemon['run_accessed_at'] = $time - 5; $daemon['run_started_at'] = $time - 4; $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); expect($this->cronHelper->isDaemonAccessible())->true(); } public function testItDetectsUnknownStateOfTheDaemon() { $time = time(); $testInputs = [ [ 'run_access' => null, 'run_start' => null, ], [ 'run_access' => $time - 4, 'run_start' => null, ], [ 'run_access' => $time - 4, 'run_start' => $time - 10, ], ]; foreach ($testInputs as $testInput) { $daemon = $this->getDeamonTestData(); $daemon['run_accessed_at'] = $testInput['run_access']; $daemon['run_started_at'] = $testInput['run_start']; $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); expect($this->cronHelper->isDaemonAccessible())->null(); } } public function testItDeactivatesDaemon() { $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); $this->cronHelper->deactivateDaemon($daemon); $daemon = $this->cronHelper->getDaemon(); expect($daemon['status'])->equals(CronHelper::DAEMON_STATUS_INACTIVE); } public function testItSavesLastError() { $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); $time = time(); $this->cronHelper->saveDaemonLastError('error'); $daemon = $this->cronHelper->getDaemon(); expect($daemon['last_error'])->equals('error'); expect($daemon['last_error_date'])->greaterOrEquals($time); } public function testItSavesRunCompletedAt() { $daemon = $this->getDeamonTestData(); $this->settings->set( CronHelper::DAEMON_SETTING, $daemon ); $this->cronHelper->saveDaemonRunCompleted(123); $daemon = $this->cronHelper->getDaemon(); expect($daemon['run_completed_at'])->equals(123); } public function testItCreatesRandomToken() { // random token is a string of 5 characters $token1 = $this->cronHelper->createToken(); $token2 = $this->cronHelper->createToken(); expect($token1)->notEquals($token2); expect(is_string($token1))->true(); expect(strlen($token1))->equals(5); } public function testItGetsSiteUrl() { // 1. do nothing when the url does not contain port $siteUrl = 'http://example.com'; expect($this->cronHelper->getSiteUrl($siteUrl))->equals($siteUrl); if (getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') $this->markTestSkipped(); // 2. when url contains valid port, try connecting to it $siteUrl = 'http://example.com:80'; expect($this->cronHelper->getSiteUrl($siteUrl))->equals($siteUrl); // 3. when url contains invalid port, try connecting to it. when connection fails, // another attempt will be made to connect to the standard port derived from URL schema $siteUrl = 'http://example.com:8080'; expect($this->cronHelper->getSiteUrl($siteUrl))->equals('http://example.com'); // 4. when connection can't be established, exception should be thrown $siteUrl = 'https://invalid:80'; try { $this->cronHelper->getSiteUrl($siteUrl); self::fail('Site URL is unreachable exception not thrown.'); } catch (\Exception $e) { expect($e->getMessage())->equals('Site URL is unreachable.'); } } public function testItGetsSubsiteUrlOnMultisiteEnvironment() { if ((boolean)getenv('MULTISITE') === true) { expect($this->cronHelper->getSiteUrl())->contains(getenv('WP_TEST_MULTISITE_SLUG')); } } public function testItEnforcesExecutionLimit() { $time = microtime(true); expect($this->cronHelper->enforceExecutionLimit($time))->null(); try { $this->cronHelper->enforceExecutionLimit($time - $this->cronHelper->getDaemonExecutionLimit()); self::fail('Execution limit exception not thrown.'); } catch (\Exception $e) { expect($e->getMessage())->equals('Maximum execution time has been reached.'); } } public function testItAllowsSettingCustomCronUrl() { $filter = function($url) { expect($url)->contains('&endpoint=cron'); return 'http://custom_cron_url'; }; add_filter('mailpoet_cron_request_url', $filter); expect($this->cronHelper->getCronUrl('sample_action'))->equals('http://custom_cron_url'); remove_filter('mailpoet_cron_request_url', $filter); } public function testItAllowsSettingCustomCronRequestArguments() { $requestArgs = [ 'blocking' => 'custom_blocking', 'sslverify' => 'custom_ssl_verify', 'timeout' => 'custom_timeout', 'user-agent' => 'custom_user_agent', ]; $filter = function($args) use ($requestArgs) { expect($args)->notEmpty(); return $requestArgs; }; $wpRemoteGetArgs = []; $wp = Stub::make(new WPFunctions, [ 'wpRemotePost' => function() use (&$wpRemoteGetArgs) { return $wpRemoteGetArgs = func_get_args(); }, ]); $wp->addFilter('mailpoet_cron_request_args', $filter); $cronHelper = new CronHelper($this->settings, $wp); $cronHelper->queryCronUrl('test'); expect($wpRemoteGetArgs[1])->equals($requestArgs); $wp->removeFilter('mailpoet_cron_request_args', $filter); } public function testItReturnsErrorMessageAsPingResponseWhenCronUrlCannotBeAccessed() { $wp = Stub::make(new WPFunctions, [ 'applyFilters' => [], ]); $cronHelper = new CronHelper($this->settings, $wp); expect($cronHelper->pingDaemon())->equals('A valid URL was not provided.'); } public function testItPingsDaemon() { if (getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') $this->markTestSkipped(); // raw response is returned expect($this->cronHelper->pingDaemon())->equals(DaemonHttpRunner::PING_SUCCESS_RESPONSE); } public function testItValidatesPingResponse() { expect($this->cronHelper->validatePingResponse('pong'))->true(); expect($this->cronHelper->validatePingResponse('something else'))->false(); } public function _after() { $this->diContainer->get(SettingsRepository::class)->truncate(); } private function getDeamonTestData() { return [ 'token' => 'some_token', 'status' => CronHelper::DAEMON_STATUS_ACTIVE, 'updated_at' => 12345678, 'run_accessed_at' => null, 'run_started_at' => null, 'run_completed_at' => null, 'last_error' => null, 'last_error_date' => null, ]; } }