[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/tests/tests/http/ -> api-check.php (source)

   1  <?php
   2  
   3  /**
   4   * HTTP functions related to api.yourls.org
   5   *
   6   * @group http
   7   * @group AYO
   8   * @since 0.1
   9   */
  10  class HTTP_AYO_Tests extends PHPUnit\Framework\TestCase {
  11  
  12      protected $actions, $core_version_checks;
  13  
  14      protected function setUp(): void {
  15          global $yourls_actions;
  16          $this->actions = $yourls_actions;
  17      }
  18  
  19      protected function tearDown(): void {
  20          yourls_remove_all_filters( 'is_admin' );
  21          yourls_remove_all_filters( 'shunt_yourls_http_request' );
  22          global $yourls_actions;
  23          $yourls_actions = $this->actions;
  24          yourls_delete_option('core_version_checks');
  25      }
  26  
  27      /**
  28       * Emulate successful HTTP request to api.yourls.org
  29       */
  30      public function fake_http_request_success() {
  31          $return = (object) array();
  32          $return->body = '{
  33              "latest": "1.0.1",
  34              "zipurl": "https:\/\/api.github.com\/repos\/YOURLS\/YOURLS\/zipball\/1.0.1"
  35              }';
  36          $return->success = true;
  37  
  38          return $return;
  39      }
  40  
  41      /**
  42       * Emulate failed HTTP request to api.yourls.org
  43       */
  44      public function fake_http_request_failure() {
  45          return 'cURL error 28: Connection timed out after 3000 milliseconds (GET on http://api.yourls.org/)';
  46      }
  47  
  48      /**
  49       * Emulate HTTP request to api.yourls.org with a server error
  50       */
  51      public function fake_http_request_server_error() {
  52          $return = new stdClass;
  53          $return->body = 'Error 500';
  54          $return->success = false;
  55          return $return;
  56      }
  57  
  58      /**
  59       * Check that version checking returns false if host is unreachable, and that failed attempts counter increments
  60       */
  61      public function test_api_failed_request() {
  62          yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_failure') );
  63          $this->check_and_assert();
  64      }
  65  
  66      /**
  67       * Check that version checking returns false if host errors, and that failed attempts counter increments
  68       */
  69      public function test_api_failed_request_server_error() {
  70          yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_server_error') );
  71          $this->check_and_assert();
  72      }
  73  
  74      /**
  75       * Helper function for test_api_failed_request() and test_api_failed_request_server_error()
  76       */
  77      public function check_and_assert() {
  78          $checks = yourls_get_option( 'core_version_checks' );
  79          if( !is_object( $checks ) ) {
  80              $checks = new stdClass;
  81              $checks->failed_attempts = 0;
  82          }
  83          $before_check = $checks->failed_attempts;
  84  
  85          $this->assertFalse( yourls_check_core_version() );
  86  
  87          $checks = yourls_get_option( 'core_version_checks' );
  88          $after_check = $checks->failed_attempts;
  89  
  90          $this->assertEquals( $after_check, $before_check + 1 );
  91      }
  92  
  93      /**
  94       * Check that version checking returns expected stuff and updates the relevant option
  95       *
  96       * @since 0.1
  97       */
  98      public function test_check_core_version() {
  99          yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_success') );
 100  
 101          $before = yourls_get_option( 'core_version_checks' );
 102          $check = yourls_check_core_version();
 103          $after = yourls_get_option( 'core_version_checks' );
 104  
 105          $this->assertNotSame( $before, $after );
 106          $this->assertTrue( isset( $check->latest ) );
 107          $this->assertTrue( isset( $check->zipurl ) );
 108      }
 109  
 110      /**
 111       * Check that version checking happens only when visiting the admin area
 112       *
 113       * @since 0.1
 114       */
 115      public function test_check_only_in_admin() {
 116          yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_success') );
 117  
 118          yourls_add_filter( 'is_admin', 'yourls_return_false' );
 119          $this->assertFalse( yourls_maybe_check_core_version() );
 120      }
 121  
 122      /**
 123       * Generate an object to mock last attempt of checking against api.yourls.org
 124       */
 125      public function return_case_object( $failed_attempts, $last_attempt, $version_checked ) {
 126          $checks = new stdClass();
 127          $checks->last_result     = rand_str();
 128          $checks->failed_attempts = $failed_attempts;
 129          $checks->last_attempt    = $last_attempt;
 130          $checks->version_checked = $version_checked;
 131  
 132          return $checks;
 133      }
 134  
 135      /**
 136       * Provider of various test cases for test_api_check_in_various_scenario()
 137       */
 138      public function case_scenario() {
 139  
 140          $return = array();
 141  
 142          /**
 143           * Case 0 :
 144           * - a previous check was NEVER done
 145           * Then : we DO want to check
 146           */
 147          $name = 'Case 0';
 148          $checks = '';
 149          $expected = true;
 150          $return[] = array( $name, $checks, $expected );
 151  
 152          // Now all possible cases : see https://gist.github.com/ozh/17ea830b2f688613927f
 153  
 154          /**
 155           * Case 1 : previous check
 156           * - was SUCCESSFUL,
 157           * - was performed MORE than 24 hours ago,
 158           * - and version checked DID match current version
 159           * Then : we DO want to check
 160           */
 161          $name = 'Case 1';
 162          $checks = $this->return_case_object(
 163              0,                  // 0 previously failed attempt
 164              time() - 26 * 3600, // 26 hours ago
 165              YOURLS_VERSION      // version match
 166          );
 167          $expected = true;
 168          $return[] = array( $name, $checks, $expected );
 169  
 170          /**
 171           * Case 2 : previous check
 172           * - was SUCCESSFUL,
 173           * - was performed MORE than 24 hours ago,
 174           * - and version checked DID NOT match current version
 175           * Then : we DO want to check
 176           */
 177          $name = 'Case 2';
 178          $checks = $this->return_case_object(
 179              0,                  // 0 previously failed attempt
 180              time() - 26 * 3600, // 26 hours ago
 181              rand_str()          // version mismatch
 182          );
 183          $expected = true;
 184          $return[] = array( $name, $checks, $expected );
 185  
 186          /**
 187           * Case 3 : previous check
 188           * - was SUCCESSFUL,
 189           * - was performed LESS than 24 hours ago,
 190           * - and version checked DID match current version
 191           * Then : we DON'T want to check
 192           */
 193          $name = 'Case 3';
 194          $checks = $this->return_case_object(
 195              0,                  // 0 previously failed attempt
 196              time() - 10 * 3600, // 10 hours ago
 197              YOURLS_VERSION      // version match
 198          );
 199          $expected = false;
 200          $return[] = array( $name, $checks, $expected );
 201  
 202          /**
 203           * Case 4 : previous check
 204           * - was SUCCESSFUL,
 205           * - was performed LESS than 24 hours ago,
 206           * - and version checked DID NOT match current version
 207           * Then : we DO want to check
 208           */
 209          $name = 'Case 4';
 210          $checks = $this->return_case_object(
 211              0,                  // 0 previously failed attempt
 212              time() - 10 * 3600, // 10 hours ago
 213              rand_str()          // version mismatch
 214          );
 215          $expected = true;
 216          $return[] = array( $name, $checks, $expected );
 217  
 218          /**
 219           * Case 5 : previous check
 220           * - was NOT SUCCESSFUL,
 221           * - was performed MORE than 2 hours ago,
 222           * - and version checked DID match current version
 223           * Then : we DO want to check
 224           */
 225          $name = 'Case 5';
 226          $checks = $this->return_case_object(
 227              1337,               // some previously failed attempts
 228              time() - 3 * 3600,  // 3 hours ago
 229              YOURLS_VERSION      // version match
 230          );
 231          $expected = true;
 232          $return[] = array( $name, $checks, $expected );
 233  
 234          /**
 235           * Case 6 : previous check
 236           * - was NOT SUCCESSFUL,
 237           * - was performed MORE than 2 hours ago,
 238           * - and version checked DID NOT match current version
 239           * Then : we DO want to check
 240           */
 241          $name = 'Case 6';
 242          $checks = $this->return_case_object(
 243              1337,               // some previously failed attempts
 244              time() - 3 * 3600,  // 3 hours ago
 245              rand_str()          // version mismatch
 246          );
 247          $expected = true;
 248          $return[] = array( $name, $checks, $expected );
 249  
 250          /**
 251           * Case 7 : previous check
 252           * - was NOT SUCCESSFUL,
 253           * - was performed LESS than 2 hours ago,
 254           * - and version checked DID match current version
 255           * Then : we DON'T want to check
 256           */
 257          $name = 'Case 7';
 258          $checks = $this->return_case_object(
 259              1337,               // some previously failed attempts
 260              time() - 1 * 3600,  // 1 hour ago
 261              YOURLS_VERSION      // version match
 262          );
 263          $expected = false;
 264          $return[] = array( $name, $checks, $expected );
 265  
 266          /**
 267           * Case 8 : previous check
 268           * - was NOT SUCCESSFUL,
 269           * - was performed LESS than 2 hours ago,
 270           * - and version checked DID NOT match current version
 271           * Then : we DO want to check
 272           */
 273          $name = 'Case 8';
 274          $checks = $this->return_case_object(
 275              1337,               // some previously failed attempts
 276              time() - 1 * 3600,  // 1 hour ago
 277              rand_str()          // version mismatch
 278          );
 279          $expected = true;
 280          $return[] = array( $name, $checks, $expected );
 281  
 282          return $return;
 283      }
 284  
 285      /**
 286       * Check if we should poll api.yourls.org under various circumstances
 287       *
 288       * @dataProvider case_scenario
 289       * @since 0.1
 290       */
 291      public function test_api_check_in_various_scenario( $name, $checks, $expected ) {
 292          yourls_add_filter('shunt_yourls_http_request', array($this,'fake_http_request_success') );
 293  
 294          yourls_add_filter( 'is_admin', 'yourls_return_true' );
 295          yourls_update_option( 'core_version_checks', $checks );
 296  
 297          $this->assertSame( $expected, yourls_maybe_check_core_version() );
 298      }
 299  
 300      /**
 301       *  Provide fake JSON responses from api.yourls.org and a boolean stating if they should be accepted or not
 302       */
 303      public function json_responses() {
 304          $return = array();
 305  
 306          $return['expected'] = array(
 307              (object)array(
 308                  'latest' => '1.2.3',
 309                  'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3',
 310              ),
 311              true);
 312  
 313          $return['unexpected version number format'] = array(
 314              (object)array(
 315                  'latest' => '1.2.3-something',
 316                  'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3',
 317              ),
 318              false);
 319  
 320          $return['version mismatch'] = array(
 321              (object)array(
 322                  'latest' => '1.2.3',
 323                  'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.4',
 324              ),
 325              false);
 326  
 327          $return['not github.com'] = array(
 328              (object)array(
 329                  'latest' => '1.2.3',
 330                  'zipurl' => 'https://notgithub.com/repos/YOURLS/YOURLS/zipball/1.2.3',
 331              ),
 332              false);
 333  
 334          $return['not YOURLS/YOURLS'] = array(
 335              (object)array(
 336                  'latest' => '1.2.3',
 337                  'zipurl' => 'https://api.github.com/repos/Y0URL5/YOURLS/zipball/1.2.3',
 338              ),
 339              false);
 340  
 341          $return['no version'] = array(
 342              (object)array(
 343                  'zipurl' => 'https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3',
 344              ),
 345              false);
 346  
 347          $return['no URL'] = array(
 348              (object)array(
 349                  'latest' => '1.2.3',
 350              ),
 351              false);
 352  
 353          $return['nothing 1'] = array(
 354              (object)[],
 355              false);
 356  
 357          $return['nothing 2'] = array([],
 358              false);
 359  
 360          $return['nothing 3'] = array(false,
 361              false);
 362  
 363          return $return;
 364      }
 365  
 366      /**
 367       * Validate various json responses from api.yourls.org and make sure they're legit
 368       *
 369       * @dataProvider json_responses
 370       * @since 0.1
 371       */
 372      public function test_validate_api_json_response($json, $expected) {
 373          $this->assertSame( $expected, yourls_validate_core_version_response($json) );
 374      }
 375  
 376      /**
 377       * Provide fake and true github repo URLs
 378       */
 379      public function fake_and_true_github_repo_urls() {
 380          $return = array();
 381          $return['true']       = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', true];
 382          $return['not github'] = ['https://api.g1thub.com/repos/YOURLS/YOURLS/zipball/1.2.3', false];
 383          $return['not YOURLS'] = ['https://api.github.com/repos/Y0URL5/YOURLS/zipball/1.2.3', false];
 384          $return['not URL']    = ['nope', false];
 385  
 386          return $return;
 387      }
 388  
 389      /**
 390       * Test yourls_is_valid_github_repo_url()
 391       *
 392       * @dataProvider fake_and_true_github_repo_urls
 393       */
 394      public function test_is_valid_github_repo_url($url, $expected) {
 395          $this->assertSame( yourls_is_valid_github_repo_url($url), $expected );
 396      }
 397  
 398      /**
 399       * Provide various scenarios for version reported by api.yourls.org / current version to check if notice is shown
 400       */
 401      public function new_version_scenarios() {
 402          $return = array();
 403  
 404          //            AYO       current      notice
 405          $return[] = ['1.2.3',  '1.2.2',      1];  // new version - display notice
 406          $return[] = ['1.3',    '1.2.2',      1];  // new version - display notice
 407          $return[] = ['1.8.22', '1.8.3',      1];  // new version - display notice
 408          $return[] = ['1.2.3',  '1.2.3-beta', 1];  // new version - display notice
 409          $return[] = ['1.3',    '1.22',       0];  // older version - don't display version
 410          $return[] = ['1.2.2',  '1.2.2',      0];  // same version - don't display notice
 411          $return[] = ['1.2.2',  '1.2.3',      0];  // older version - don't display version
 412          $return[] = ['99.9.9',  false,       1];  // newer version compared to actual current YOURLS version - display notice
 413          $return[] = ['0.1.1',   false,       0];  // older version compared to actual current YOURLS version - don't display notice
 414  
 415          return $return;
 416      }
 417  
 418      /**
 419       * Test various YOURLS version strings from api.yourls.org, compare them to the actual version
 420       * and make sure we display the correct update notice
 421       *
 422       * @dataProvider new_version_scenarios
 423       */
 424      public function test_new_version_notice( $api_version, $current_version, $expected ) {
 425          // fake the api response
 426          $check = (object)array(
 427              'last_result' => (object)array(
 428                  'latest' => $api_version,
 429              ),
 430          );
 431          yourls_add_option('core_version_checks', $check);
 432  
 433          // trigger yourls_core_version_notice() and check we had expected action
 434          yourls_new_core_version_notice($current_version);
 435          $this->assertSame($expected, yourls_did_action('new_core_version_notice'));
 436      }
 437  
 438      /**
 439       * Test various zipball URLs and get version number from it
 440       */
 441      function various_zipball_url_version() {
 442          $return = [];
 443  
 444          $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3', '1.2.3'];
 445          $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3-beta', '1.2.3-beta'];
 446          $return[] = ['https://api.github.com/repos/YOURLS/YOURLS/zipball/1.2.3/lol', 'lol'];
 447          $return[] = ['http://hey', ''];
 448          $return[] = ['lol', ''];
 449          $return[] = ['', ''];
 450  
 451          return $return;
 452      }
 453  
 454      /**
 455       * Test various zipball URLs and get version number from it
 456       *
 457       * @dataProvider various_zipball_url_version
 458       */
 459      public function test_get_version_from_zipball_url($url, $expected) {
 460          $this->assertSame($expected, yourls_get_version_from_zipball_url($url));
 461      }
 462  
 463  
 464      /**
 465       * test various core version JSON responses from api.yourls.org
 466       */
 467      function get_various_json_response_keys() {
 468          $return = [];
 469  
 470          $return['latest & zipurl'] = [['latest' => 'ok', 'zipurl' => 'ok'], true];
 471          $return['no latest'] = [['zipurl' => 'ok'], false];
 472          $return['no zipurl'] = [['latest' => 'ok'], false];
 473          $return['latest & other key'] = [['latest' => 'ok', 'other' => 'oops'], false];
 474          $return['zipurl & other key'] = [['zipurl' => 'ok', 'other' => 'oops'], false];
 475          $return['nothing'] = [[], false];
 476          $return['extra key'] = [['latest' => 'ok', 'zipurl' => 'ok', 'extra' => 'oops'], false];
 477          $return['not strings'] = [['latest' => [], 'zipurl' => 'ok'], false];
 478  
 479          return $return;
 480      }
 481  
 482      /**
 483       * Check yourls_validate_core_version_response_keys() works as expected
 484       * @dataProvider get_various_json_response_keys
 485       */
 486      function test_yourls_validate_core_version_response_keys($json, $expected) {
 487          $this->assertSame(yourls_validate_core_version_response_keys((object)$json), $expected);
 488      }
 489  
 490      /**
 491       * Return all possible api.yourls.org/core/version URL
 492       */
 493      function get_api_yourls_core() {
 494          return [
 495              ['https://api.yourls.org/core/version/1.1/'],
 496              ['http://api.yourls.org/core/version/1.0/'],
 497          ];
 498      }
 499  
 500      /**
 501       * Make sure https://api.yourls.org/core/version/1.[0/1]/ returns a valid JSON response
 502       *
 503       * This test may fail is the server is unreachable or the API is down.
 504       * TODO: make this test evolve as the API evolves
 505       *
 506       * @dataProvider get_api_yourls_core
 507       */
 508      function test_yourls_get_core_version_json($url) {
 509          $req = yourls_http_get($url);
 510  
 511          if ($req->status_code != 200) {
 512              $this->markTestSkipped("Unable to reach $url - test skipped");
 513          }
 514  
 515          $json = json_decode(trim($req->body));
 516          $this->assertTrue(is_object($json));
 517          $this->assertTrue(yourls_validate_core_version_response($json));
 518      }
 519  
 520  }


Generated: Wed Sep 28 05:10:02 2022 Cross-referenced by PHPXref 0.7.1