diff --git a/lib/Cron/CronHelper.php b/lib/Cron/CronHelper.php index 5672a034f7..f886ebeb5a 100644 --- a/lib/Cron/CronHelper.php +++ b/lib/Cron/CronHelper.php @@ -60,6 +60,7 @@ class CronHelper { QueueEndpoint::ACTION_RUN, $data ); + $url = str_replace(home_url(), self::getSiteUrl(), $url); $args = array( 'blocking' => false, 'sslverify' => false, @@ -70,20 +71,21 @@ class CronHelper { return wp_remote_retrieve_body($result); } - private static function getSiteUrl() { - // additional check for some sites running on a virtual machine or behind + static function getSiteUrl($site_url = false) { + // additional check for some sites running inside a virtual machine or behind // proxy where there could be different ports (e.g., host:8080 => guest:80) - - // if the site URL does not contain a port, return the URL - if(!preg_match('!^https?://.*?:\d+!', site_url())) return site_url(); - preg_match('!://(?P.*?):(?P\d+)!', site_url(), $server); - // connect to the URL with port - $fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1); - if($fp) return site_url(); - // connect to the URL without port - $fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1); - if($fp) return preg_replace('!(?=:\d+):\d+!', '$1', site_url()); - // throw an error if all connection attempts failed + $site_url = ($site_url) ? $site_url : home_url(); + $parsed_url = parse_url($site_url); + // 1. if the site URL does not contain a port, return the URL + if(empty($parsed_url['port'])) return $site_url; + // 2. connect to the URL with specified port + $fp = @fsockopen($parsed_url['host'], $parsed_url['port'], $errno, $errstr, 1); + if($fp) return $site_url; + $port = (strtolower($parsed_url['scheme']) === 'http') ? 80 : 443; + // 3. connect to the URL with default port + $fp = @fsockopen($parsed_url['host'], $port, $errno, $errstr, 1); + if($fp) return sprintf('%s://%s', $parsed_url['scheme'], $parsed_url['host']); + // 4. throw an error if all connection attempts failed throw new \Exception(__('Site URL is unreachable.')); } diff --git a/tests/unit/Cron/CronHelperTest.php b/tests/unit/Cron/CronHelperTest.php new file mode 100644 index 0000000000..d2cba2b587 --- /dev/null +++ b/tests/unit/Cron/CronHelperTest.php @@ -0,0 +1,121 @@ +equals(20); + expect(CronHelper::DAEMON_EXECUTION_TIMEOUT)->equals(35); + expect(CronHelper::DAEMON_REQUEST_TIMEOUT)->equals(2); + expect(CronHelper::DAEMON_SETTING)->equals('cron_daemon'); + } + + function testItCanCreateDaemon() { + $token = 'create_token'; + $time = time(); + CronHelper::createDaemon($token); + $daemon = Setting::getValue(CronHelper::DAEMON_SETTING); + expect($daemon)->equals( + array( + 'status' => Daemon::STATUS_STARTING, + 'token' => $token, + 'updated_at' => $time + ) + ); + } + + function testItCanRestartDaemon() { + $token = 'restart_token'; + $time = time(); + CronHelper::restartDaemon($token); + $daemon = Setting::getValue(CronHelper::DAEMON_SETTING); + expect($daemon)->equals( + array( + 'status' => Daemon::STATUS_STARTING, + 'token' => $token, + 'updated_at' => $time + ) + ); + } + + function testItLoadDaemon() { + $daemon = array( + 'status' => 'created', + 'token' => 'some_token', + 'updated_at' => '12345678' + ); + Setting::setValue( + CronHelper::DAEMON_SETTING, + $daemon + ); + expect(CronHelper::getDaemon())->equals($daemon); + } + + function testItCanSaveDaemon() { + // when saving daemon, 'updated_at' value should change + $daemon = array( + 'status' => 'created', + 'token' => 'some_token', + 'updated_at' => '12345678' + ); + Setting::setValue( + CronHelper::DAEMON_SETTING, + $daemon + ); + $time = time(); + CronHelper::saveDaemon($daemon); + $daemon['updated_at'] = $time; + expect(CronHelper::getDaemon())->equals($daemon); + } + + function testItCanCreateRandomToken() { + // random token is a string of 5 characters + $token1 = CronHelper::createToken(); + $token2 = CronHelper::createToken(); + expect($token1)->notEquals($token2); + expect(is_string($token1))->true(); + expect(strlen($token1))->equals(5); + } + + function testItCanGetSiteUrl() { + // 1. do nothing when the url does not contain port + $site_url = 'http://example.com'; + expect(CronHelper::getSiteUrl($site_url))->equals($site_url); + + if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; + + //2. when url contains valid port, try connecting to it + $site_url = 'http://example.com:80'; + expect(CronHelper::getSiteUrl($site_url))->equals($site_url); + //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 form URL schema + $site_url = 'http://example.com:8080'; + expect(CronHelper::getSiteUrl($site_url))->equals('http://example.com'); + //4. when connection can't be established, exception should be thrown + $site_url = 'https://invalid:80'; + try { + CronHelper::getSiteUrl($site_url); + self::fail('Site URL is unreachable exception not thrown.'); + } catch(Exception $e) { + expect($e->getMessage())->equals('Site URL is unreachable.'); + } + } + + function testItCanEnforceExecutionLimit() { + $time = microtime(true); + expect(CronHelper::enforceExecutionLimit($time))->null(); + try { + CronHelper::enforceExecutionLimit($time - CronHelper::DAEMON_EXECUTION_LIMIT); + self::fail('Execution limit exception not thrown.'); + } catch(Exception $e) { + expect($e->getMessage())->equals('Maximum execution time has been reached.'); + } + } + + function _after() { + ORM::raw_execute('TRUNCATE ' . Setting::$_table); + } +} \ No newline at end of file