diff options
author | Ozh <ozh@ozh.org> | 2022-04-15 15:59:49 +0300 |
---|---|---|
committer | Ozh <ozh@ozh.org> | 2022-04-15 15:59:49 +0300 |
commit | 6ad19996319ae361a98600437928153e6afa884e (patch) | |
tree | 0f8f996fd47d2bb20a6e1dbaf1dd005080dc6c25 | |
parent | a1ce6306c52d211ce8c674b1eef30524f8618e59 (diff) |
More checks with new version noticesayo_version_checks
WIP & ugly mess for the moment, full of var_dumps, will fix later next week
* Motivations :
* add unit tests to make sure running 1.8.3-dev will trigger a new version notice when 1.8.3 is out (I think it already works this way)
* more validation of the api core/update response
* Current problems :
* http/api-check.php tests are not dependent from each other: resetting options in setUp/tearDown as we should raises errors
* in http/api-check.php::test_api_failed_request_server_error() the yourls_get_option() returns false despite yourls_check_core_version() correct yourls_update_option(), wtf
-rw-r--r-- | includes/functions-html.php | 8 | ||||
-rw-r--r-- | includes/functions-http.php | 39 | ||||
-rw-r--r-- | includes/functions.php | 2 | ||||
-rw-r--r-- | tests/bootstrap.php | 13 | ||||
-rw-r--r-- | tests/tests/http/api-check.php | 134 |
5 files changed, 180 insertions, 16 deletions
diff --git a/includes/functions-html.php b/includes/functions-html.php index 667cbe40..2ae620f8 100644 --- a/includes/functions-html.php +++ b/includes/functions-html.php @@ -918,13 +918,16 @@ function yourls_l10n_calendar_strings() { * Display a notice if there is a newer version of YOURLS available * * @since 1.7 + * @param string $compare_with Optional, YOURLS version to compare to */ -function yourls_new_core_version_notice() { +function yourls_new_core_version_notice($compare_with = false) { + $compare_with = $compare_with ?: YOURLS_VERSION; $checks = yourls_get_option( 'core_version_checks' ); $latest = isset($checks->last_result->latest) ? yourls_sanitize_version($checks->last_result->latest) : false; - if( $latest AND version_compare( $latest, YOURLS_VERSION, '>' ) ) { + if( $latest AND version_compare( $latest, $compare_with, '>' ) ) { + yourls_do_action('new_core_version_notice', $latest); $msg = yourls_s( '<a href="%s">YOURLS version %s</a> is available. Please update!', 'http://yourls.org/download', $latest ); yourls_add_notice( $msg ); } @@ -986,4 +989,3 @@ function yourls_html_favicon() { printf( '<link rel="shortcut icon" href="%s" />', yourls_get_yourls_favicon_url(false) ); } - diff --git a/includes/functions-http.php b/includes/functions-http.php index 12e953bd..3756250d 100644 --- a/includes/functions-http.php +++ b/includes/functions-http.php @@ -328,6 +328,7 @@ function yourls_check_core_version() { if( is_string( $req ) or !$req->success ) { $checks->failed_attempts = $checks->failed_attempts + 1; yourls_update_option( 'core_version_checks', $checks ); + yourls_ut_var_dump( $checks ); if( is_string($req) ) { yourls_debug_log('Version check failed: ' . $req); } @@ -353,9 +354,11 @@ function yourls_check_core_version() { /** * Make sure response from api.yourls.org is valid * - * we should get a json object with two following properties: + * 1) we should get a json object with two following properties: * 'latest' => a string representing a YOURLS version number, eg '1.2.3' * 'zipurl' => a string for a zip package URL, from github, eg 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3' + * 2) 'latest' and version extracted from 'zipurl' should match + * 3) the object should not contain any other key * * @since 1.7.7 * @param $json JSON object to check @@ -365,8 +368,10 @@ function yourls_validate_core_version_response($json) { return ( isset($json->latest) && isset($json->zipurl) + && yourls_validate_core_version_response_keys($json) && $json->latest === yourls_sanitize_version($json->latest) && $json->zipurl === yourls_sanitize_url($json->zipurl) + && $json->latest === yourls_get_version_from_zipball_url($json->zipurl) && join('.',array_slice(explode('.',parse_url($json->zipurl, PHP_URL_HOST)), -2, 2)) === 'github.com' // this last bit get the host ('api.github.com'), explodes on '.' (['api','github','com']) and keeps the last two elements // to make sure domain is either github.com or one of its subdomain (api.github.com for instance) @@ -375,6 +380,37 @@ function yourls_validate_core_version_response($json) { } /** + * Get version number from Github zipball URL (last part of URL, really) + * @since 1.8.3 + * @param string $zipurl eg 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3' + * @return string + */ +function yourls_get_version_from_zipball_url($zipurl) { + $version = ''; + $parts = explode('/', parse_url(yourls_sanitize_url($zipurl), PHP_URL_PATH)); + // expect at least 1 slash in path, return last part + if( count($parts) > 1 ) { + $version = end($parts); + } + return $version; +} + +/** + * Check if object has only expected keys 'latest' and 'zipurl' + * @since 1.8.3 + * @param object $json + * @return bool + */ +function yourls_validate_core_version_response_keys($json) { + $keys = array('latest', 'zipurl'); + return ( + count(array_diff(array_keys((array)$json), $keys)) === 0 + && isset($json->latest) + && isset($json->zipurl) + ); +} + +/** * Determine if we want to check for a newer YOURLS version (and check if applicable) * * Currently checks are performed every 24h and only when someone is visiting an admin page. @@ -457,4 +493,3 @@ function yourls_can_http_over_ssl() { return ( $ssl_curl OR $ssl_socket ); } - diff --git a/includes/functions.php b/includes/functions.php index 62141243..55860ea2 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1267,5 +1267,5 @@ function yourls_set_url_scheme( $url, $scheme = false ) { */ function yourls_tell_if_new_version() { yourls_debug_log( 'Check for new version: '.( yourls_maybe_check_core_version() ? 'yes' : 'no' ) ); - yourls_new_core_version_notice(); + yourls_new_core_version_notice(YOURLS_VERSION); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c4320a58..aaa06693 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -48,4 +48,17 @@ yourls_get_all_options(); yourls_load_plugins(); // At this point, tests will start + +// Simplify yourls_die() when running unit tests +yourls_add_action( 'pre_yourls_die', function($params) { + printf("\n\nCalling yourls_die(). %s : %s (%s)\n\n", $params[1], $params[0], $params[2]); + echo "Last 10 Backtrace:\n"; + $trace = debug_backtrace(); + foreach( array_slice($trace, 0, 10) as $t ) { + printf("** %s:%d %s() with args\n%s\n", $t['file'], $t['line'], $t['function'], var_export($t['args'], true)); + } + + die(1); +} ); + echo "YOURLS installed, starting PHPUnit\n\n"; diff --git a/tests/tests/http/api-check.php b/tests/tests/http/api-check.php index 5455b7bf..7b714165 100644 --- a/tests/tests/http/api-check.php +++ b/tests/tests/http/api-check.php @@ -9,9 +9,20 @@ */ class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase { + protected $actions, $core_version_checks; + + protected function setUp(): void { + global $yourls_actions; + $this->actions = $yourls_actions; + $this->core_version_checks = yourls_get_option( 'core_version_checks' ); + } + protected function tearDown(): void { yourls_remove_all_filters( 'is_admin' ); yourls_remove_all_filters( 'shunt_yourls_http_request' ); + global $yourls_actions; + $yourls_actions = $this->actions; + yourls_update_option( 'core_version_checks', $this->core_version_checks ); } /** @@ -76,6 +87,7 @@ class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase { $this->assertFalse( yourls_check_core_version() ); $checks = yourls_get_option( 'core_version_checks' ); + yourls_ut_var_dump( $checks ); $after_check = $checks->failed_attempts; $this->assertEquals( $after_check, $before_check + 1 ); @@ -294,44 +306,56 @@ class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase { public function json_responses() { $return = array(); - // expected - $return[] = array( + $return['expected'] = array( (object)array( 'latest' => '1.2.3', 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), true); - // incorrect version number - $return[] = array( + $return['unexpected version number format'] = array( (object)array( 'latest' => '1.2.3-something', 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // url not part of github.com - $return[] = array( + $return['version mismatch'] = array( + (object)array( + 'latest' => '1.2.3', + 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.4', + ), + false); + + $return['url not part of github.com'] = array( (object)array( 'latest' => '1.2.3', 'zipurl' => 'https://notgithub.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // no version - $return[] = array( + $return['no version'] = array( (object)array( 'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', ), false); - // no URL - $return[] = array( + $return['no URL'] = array( (object)array( 'latest' => '1.2.3', ), false); + $return['nothing 1'] = array( + (object)[], + false); + + $return['nothing 2'] = array([], + false); + + $return['nothing 3'] = array(false, + false); + return $return; } @@ -345,4 +369,94 @@ class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase { $this->assertSame( $expected, yourls_validate_core_version_response($json) ); } + /** + * Provide various scenarios for version reported by api.yourls.org / current version + */ + public function new_version_scenarios() { + $return = array(); + + // AYO current notice + $return[] = ['1.2.3', '1.2.2', true]; // new version - display notice +/* $return[] = ['1.3', '1.2.2', true]; // new version - display notice + $return[] = ['1.3', '1.22', true]; // older version - don't display version + $return[] = ['1.8.22', '1.8.3', true]; // new version - display notice + $return[] = ['1.2.3', '1.2.3-beta', true]; // new version - display notice + $return[] = ['1.2.2', '1.2.2', false]; // same version - don't display notice + $return[] = ['1.2.2', '1.2.3', false]; // older version - don't display version + $return[] = ['99.9.9', false, false]; // newer version compared to actual current YOURLS version - display notice*/ + + return $return; + } + + /** + * Test various YOURLS version strings from api.yourls.org, compare them to the actual version + * and make sure we display the correct update notice + * + * @dataProvider new_version_scenarios + */ + public function test_new_version_notice( $api_version, $current_version, $expected ) { + // fake the api response + $check = (object)array( + 'last_result' => (object)array( + 'latest' => $api_version, + ), + ); + yourls_add_option('core_version_checks', $check); + + // trigger yourls_core_version_notice() and check we had expected action + yourls_new_core_version_notice($current_version); + $this->assertSame($expected, yourls_did_action('new_core_version_notice')); + } + + /** + * Test various zipball URLs and get version number from it + */ + function various_zipball_url_version() { + $return = []; + + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', '1.2.3']; + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3-beta', '1.2.3-beta']; + $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3/lol', 'lol']; + $return[] = ['http://hey', '']; + $return[] = ['lol', '']; + $return[] = ['', '']; + + return $return; + } + + /** + * Test various zipball URLs and get version number from it + * + * @dataProvider various_zipball_url_version + */ + public function test_get_version_from_zipball_url($url, $expected) { + $this->assertSame($expected, yourls_get_version_from_zipball_url($url)); + } + + + /** + * test various core version JSON responses from api.yourls.org + */ + function get_various_json_response_keys() { + $return = []; + + $return['latest & zipurl'] = [['latest' => 'ok', 'zipurl' => 'ok'], true]; + $return['no latest'] = [['zipurl' => 'ok'], false]; + $return['no zipurl'] = [['latest' => 'ok'], false]; + $return['latest & other key'] = [['latest' => 'ok', 'other' => 'oops'], false]; + $return['zipurl & other key'] = [['zipurl' => 'ok', 'other' => 'oops'], false]; + $return['nothing'] = [[], false]; + $return['extra key'] = [['latest' => 'ok', 'zipurl' => 'ok', 'extra' => 'oops'], false]; + + return $return; + } + + /** + * Check yourls_validate_core_version_response_keys() works as expected + * @dataProvider get_various_json_response_keys + */ + function test_yourls_validate_core_version_response_keys($json, $expected) { + $this->assertSame(yourls_validate_core_version_response_keys((object)$json), $expected); + } + } |