Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Unit tests for the update checker.
  19   *
  20   * @package   core_plugin
  21   * @category  test
  22   * @copyright 2012, 2015 David Mudrak <david@moodle.com>
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  use core\update\testable_checker;
  29  use core\update\testable_checker_cron_executed;
  30  
  31  global $CFG;
  32  require_once (__DIR__.'/fixtures/testable_update_checker.php');
  33  
  34  /**
  35   * Tests of the basic API of the available update checker.
  36   */
  37  class core_update_checker_testcase extends advanced_testcase {
  38  
  39      public function test_core_available_update() {
  40          $provider = testable_checker::instance();
  41          $this->assertInstanceOf('\core\update\checker', $provider);
  42  
  43          $provider->fake_current_environment(2012060102.00, '2.3.2 (Build: 20121012)', '2.3', array());
  44          $updates = $provider->get_update_info('core');
  45          $this->assertCount(2, $updates);
  46  
  47          $provider->fake_current_environment(2012060103.00, '2.3.3 (Build: 20121212)', '2.3', array());
  48          $updates = $provider->get_update_info('core');
  49          $this->assertCount(1, $updates);
  50  
  51          $provider->fake_current_environment(2012060103.00, '2.3.3 (Build: 20121212)', '2.3', array());
  52          $updates = $provider->get_update_info('core', array('minmaturity' => MATURITY_STABLE));
  53          $this->assertNull($updates);
  54      }
  55  
  56      /**
  57       * If there are no fetched data yet, the first cron should fetch them.
  58       *
  59       * @expectedException \core\update\testable_checker_cron_executed
  60       */
  61      public function test_cron_initial_fetch() {
  62          $provider = testable_checker::instance();
  63          $provider->fakerecentfetch = null;
  64          $provider->fakecurrenttimestamp = -1;
  65          $provider->cron();
  66      }
  67  
  68      /**
  69       * If there is a fresh fetch available, no cron execution is expected.
  70       */
  71      public function test_cron_has_fresh_fetch() {
  72          $provider = testable_checker::instance();
  73          $provider->fakerecentfetch = time() - 23 * HOURSECS; // Fetched 23 hours ago.
  74          $provider->fakecurrenttimestamp = -1;
  75          $provider->cron();
  76          $this->assertTrue(true); // We should get here with no exception thrown.
  77      }
  78  
  79      /**
  80       * If there is an outdated fetch, the cron execution is expected.
  81       *
  82       * @expectedException \core\update\testable_checker_cron_executed
  83       */
  84      public function test_cron_has_outdated_fetch() {
  85          $provider = testable_checker::instance();
  86          $provider->fakerecentfetch = time() - 49 * HOURSECS; // Fetched 49 hours ago.
  87          $provider->fakecurrenttimestamp = -1;
  88          $provider->cron();
  89      }
  90  
  91      /**
  92       * The first cron after 01:42 AM today should fetch the data.
  93       *
  94       * @see testable_checker::cron_execution_offset()
  95       */
  96      public function test_cron_offset_execution_not_yet() {
  97          $provider = testable_checker::instance();
  98          $provider->fakecurrenttimestamp = mktime(1, 40, 02); // 01:40:02 AM today
  99          $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS;
 100          $provider->cron();
 101          $this->assertTrue(true); // We should get here with no exception thrown.
 102      }
 103  
 104      /**
 105       * The first cron after 01:42 AM today should fetch the data and then
 106       * it is supposed to wait next 24 hours.
 107       *
 108       * @see testable_checker::cron_execution_offset()
 109       */
 110      public function test_cron_offset_execution() {
 111          $provider = testable_checker::instance();
 112  
 113          // The cron at 01:45 should fetch the data.
 114          $provider->fakecurrenttimestamp = mktime(1, 45, 02); // 01:45:02 AM today
 115          $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS - 1;
 116          $executed = false;
 117          try {
 118              $provider->cron();
 119          } catch (testable_checker_cron_executed $e) {
 120              $executed = true;
 121          }
 122          $this->assertTrue($executed, 'Cron should be executed at 01:45:02 but it was not.');
 123  
 124          // Another cron at 06:45 should still consider data as fresh enough.
 125          $provider->fakerecentfetch = $provider->fakecurrenttimestamp;
 126          $provider->fakecurrenttimestamp = mktime(6, 45, 03); // 06:45:03 AM
 127          $executed = false;
 128          try {
 129              $provider->cron();
 130          } catch (testable_checker_cron_executed $e) {
 131              $executed = true;
 132          }
 133          $this->assertFalse($executed, 'Cron should not be executed at 06:45:03 but it was.');
 134  
 135          // The next scheduled execution should happen the next day.
 136          $provider->fakecurrenttimestamp = $provider->fakerecentfetch + 24 * HOURSECS + 1;
 137          $executed = false;
 138          try {
 139              $provider->cron();
 140          } catch (testable_checker_cron_executed $e) {
 141              $executed = true;
 142          }
 143          $this->assertTrue($executed, 'Cron should be executed the next night but it was not.');
 144      }
 145  
 146      public function test_compare_responses_both_empty() {
 147          $provider = testable_checker::instance();
 148          $old = array();
 149          $new = array();
 150          $cmp = $provider->compare_responses($old, $new);
 151          $this->assertInternalType('array', $cmp);
 152          $this->assertEmpty($cmp);
 153      }
 154  
 155      public function test_compare_responses_old_empty() {
 156          $provider = testable_checker::instance();
 157          $old = array();
 158          $new = array(
 159              'updates' => array(
 160                  'core' => array(
 161                      array(
 162                          'version' => 2012060103
 163                      )
 164                  )
 165              )
 166          );
 167          $cmp = $provider->compare_responses($old, $new);
 168          $this->assertInternalType('array', $cmp);
 169          $this->assertNotEmpty($cmp);
 170          $this->assertTrue(isset($cmp['core'][0]['version']));
 171          $this->assertEquals(2012060103, $cmp['core'][0]['version']);
 172      }
 173  
 174      public function test_compare_responses_no_change() {
 175          $provider = testable_checker::instance();
 176          $old = $new = array(
 177              'updates' => array(
 178                  'core' => array(
 179                      array(
 180                          'version' => 2012060104
 181                      ),
 182                      array(
 183                          'version' => 2012120100
 184                      )
 185                  ),
 186                  'mod_foo' => array(
 187                      array(
 188                          'version' => 2011010101
 189                      )
 190                  )
 191              )
 192          );
 193          $cmp = $provider->compare_responses($old, $new);
 194          $this->assertInternalType('array', $cmp);
 195          $this->assertEmpty($cmp);
 196      }
 197  
 198      public function test_compare_responses_new_and_missing_update() {
 199          $provider = testable_checker::instance();
 200          $old = array(
 201              'updates' => array(
 202                  'core' => array(
 203                      array(
 204                          'version' => 2012060104
 205                      )
 206                  ),
 207                  'mod_foo' => array(
 208                      array(
 209                          'version' => 2011010101
 210                      )
 211                  )
 212              )
 213          );
 214          $new = array(
 215              'updates' => array(
 216                  'core' => array(
 217                      array(
 218                          'version' => 2012060104
 219                      ),
 220                      array(
 221                          'version' => 2012120100
 222                      )
 223                  )
 224              )
 225          );
 226          $cmp = $provider->compare_responses($old, $new);
 227          $this->assertInternalType('array', $cmp);
 228          $this->assertNotEmpty($cmp);
 229          $this->assertCount(1, $cmp);
 230          $this->assertCount(1, $cmp['core']);
 231          $this->assertEquals(2012120100, $cmp['core'][0]['version']);
 232      }
 233  
 234      public function test_compare_responses_modified_update() {
 235          $provider = testable_checker::instance();
 236          $old = array(
 237              'updates' => array(
 238                  'mod_foo' => array(
 239                      array(
 240                          'version' => 2011010101
 241                      )
 242                  )
 243              )
 244          );
 245          $new = array(
 246              'updates' => array(
 247                  'mod_foo' => array(
 248                      array(
 249                          'version' => 2011010102
 250                      )
 251                  )
 252              )
 253          );
 254          $cmp = $provider->compare_responses($old, $new);
 255          $this->assertInternalType('array', $cmp);
 256          $this->assertNotEmpty($cmp);
 257          $this->assertCount(1, $cmp);
 258          $this->assertCount(1, $cmp['mod_foo']);
 259          $this->assertEquals(2011010102, $cmp['mod_foo'][0]['version']);
 260      }
 261  
 262      /**
 263       * @expectedException \core\update\checker_exception
 264       */
 265      public function test_compare_responses_invalid_format() {
 266          $provider = testable_checker::instance();
 267          $broken = array(
 268              'status' => 'ERROR' // No 'updates' key here.
 269          );
 270          $cmp = $provider->compare_responses($broken, $broken);
 271      }
 272  
 273      public function test_is_same_release_explicit() {
 274          $provider = testable_checker::instance();
 275          $this->assertTrue($provider->is_same_release('2.3dev (Build: 20120323)', '2.3dev (Build: 20120323)'));
 276          $this->assertTrue($provider->is_same_release('2.3dev (Build: 20120323)', '2.3dev (Build: 20120330)'));
 277          $this->assertFalse($provider->is_same_release('2.3dev (Build: 20120529)', '2.3 (Build: 20120601)'));
 278          $this->assertFalse($provider->is_same_release('2.3dev', '2.3 dev'));
 279          $this->assertFalse($provider->is_same_release('2.3.1', '2.3'));
 280          $this->assertFalse($provider->is_same_release('2.3.1', '2.3.2'));
 281          $this->assertTrue($provider->is_same_release('2.3.2+', '2.3.2')); // Yes, really!
 282          $this->assertTrue($provider->is_same_release('2.3.2 (Build: 123456)', '2.3.2+ (Build: 123457)'));
 283          $this->assertFalse($provider->is_same_release('3.0 Community Edition', '3.0 Enterprise Edition'));
 284          $this->assertTrue($provider->is_same_release('3.0 Community Edition', '3.0 Community Edition (Build: 20290101)'));
 285      }
 286  
 287      public function test_is_same_release_implicit() {
 288          $provider = testable_checker::instance();
 289          $provider->fake_current_environment(2012060102.00, '2.3.2 (Build: 20121012)', '2.3', array());
 290          $this->assertTrue($provider->is_same_release('2.3.2'));
 291          $this->assertTrue($provider->is_same_release('2.3.2+'));
 292          $this->assertTrue($provider->is_same_release('2.3.2+ (Build: 20121013)'));
 293          $this->assertFalse($provider->is_same_release('2.4dev (Build: 20121012)'));
 294      }
 295  }