Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

   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   * @package   core_backup
  19   * @category  test
  20   * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  namespace core_backup;
  25  
  26  use backup;
  27  use backup_controller;
  28  use restore_controller;
  29  
  30  defined('MOODLE_INTERNAL') || die();
  31  
  32  // Include all the needed stuff.
  33  global $CFG;
  34  require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
  35  require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
  36  
  37  /**
  38   * Tests for the backup and restore controller classes.
  39   *
  40   * @package   core_backup
  41   * @category  test
  42   * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  43   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  class controller_test extends \advanced_testcase {
  46  
  47      protected $moduleid;  // course_modules id used for testing
  48      protected $sectionid; // course_sections id used for testing
  49      protected $courseid;  // course id used for testing
  50      protected $userid;    // user used if for testing
  51  
  52      protected function setUp(): void {
  53          global $DB, $CFG;
  54  
  55          $this->resetAfterTest(true);
  56  
  57          $course = $this->getDataGenerator()->create_course();
  58          $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id), array('section'=>3));
  59          $coursemodule = $DB->get_record('course_modules', array('id'=>$page->cmid));
  60  
  61          $this->moduleid  = $coursemodule->id;
  62          $this->sectionid = $DB->get_field("course_sections", 'id', array("section"=>$coursemodule->section, "course"=>$course->id));
  63          $this->courseid  = $coursemodule->course;
  64          $this->userid = 2; // admin
  65  
  66          // Disable all loggers
  67          $CFG->backup_error_log_logger_level = backup::LOG_NONE;
  68          $CFG->backup_output_indented_logger_level = backup::LOG_NONE;
  69          $CFG->backup_file_logger_level = backup::LOG_NONE;
  70          $CFG->backup_database_logger_level = backup::LOG_NONE;
  71          $CFG->backup_file_logger_level_extra = backup::LOG_NONE;
  72      }
  73  
  74      /**
  75       * Test get_copy
  76       *
  77       * @covers \restore_controller::get_copy
  78       */
  79      public function test_restore_controller_get_copy() {
  80          $copydata = (object)["some" => "copydata"];
  81          $rc = new \restore_controller(1729, $this->courseid, backup::INTERACTIVE_NO, backup::MODE_COPY,
  82                  $this->userid, backup::TARGET_NEW_COURSE, null, backup::RELEASESESSION_NO, $copydata);
  83  
  84          $this->assertEquals($copydata, $rc->get_copy());
  85      }
  86  
  87      /**
  88       * Test instantiating a restore controller for a course copy without providing copy data.
  89       *
  90       * @covers \restore_controller::__construct
  91       */
  92      public function test_restore_controller_copy_without_copydata() {
  93          $this->expectException(\restore_controller_exception::class);
  94  
  95          new \restore_controller(1729, $this->courseid, backup::INTERACTIVE_NO, backup::MODE_COPY,
  96                  $this->userid, backup::TARGET_NEW_COURSE);
  97      }
  98  
  99      /*
 100       * test base_setting class
 101       */
 102      public function test_backup_controller() {
 103          // Instantiate non interactive backup_controller
 104          $bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 105              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
 106          $this->assertTrue($bc instanceof backup_controller);
 107          $this->assertEquals($bc->get_status(), backup::STATUS_AWAITING);
 108          // Instantiate interactive backup_controller
 109          $bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 110              backup::INTERACTIVE_YES, backup::MODE_GENERAL, $this->userid);
 111          $this->assertTrue($bc instanceof backup_controller);
 112          $this->assertEquals($bc->get_status(), backup::STATUS_SETTING_UI);
 113          $this->assertEquals(strlen($bc->get_backupid()), 32); // is one md5
 114  
 115          // Save and load one backup controller to check everything is in place
 116          $bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 117              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
 118          $recid = $bc->save_controller();
 119          $newbc = mock_backup_controller::load_controller($bc->get_backupid());
 120          $this->assertTrue($newbc instanceof backup_controller); // This means checksum and load worked ok
 121      }
 122  
 123      public function test_backup_controller_include_files() {
 124          // A MODE_GENERAL controller - this should include files
 125          $bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 126              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
 127          $this->assertEquals($bc->get_include_files(), 1);
 128  
 129  
 130          // The MODE_IMPORT and MODE_SAMESITE should not include files in the backup.
 131          // A MODE_IMPORT controller
 132          $bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 133              backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
 134          $this->assertEquals($bc->get_include_files(), 0);
 135  
 136          // A MODE_SAMESITE controller
 137          $bc = new mock_backup_controller(backup::TYPE_1COURSE, $this->courseid, backup::FORMAT_MOODLE,
 138              backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
 139          $this->assertEquals($bc->get_include_files(), 0);
 140      }
 141  
 142      /**
 143       * Test set kept roles method.
 144       */
 145      public function test_backup_controller_set_kept_roles() {
 146          $this->expectException(\backup_controller_exception::class);
 147  
 148          // Set up controller as a non-copy operation.
 149          $bc = new \backup_controller(backup::TYPE_1COURSE, $this->courseid, backup::FORMAT_MOODLE,
 150              backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid, backup::RELEASESESSION_YES);
 151  
 152          $bc->set_kept_roles(array(1, 3, 5));
 153      }
 154  
 155      /**
 156       * Tests the restore_controller.
 157       */
 158      public function test_restore_controller_is_executing() {
 159          global $CFG;
 160  
 161          // Make a backup.
 162          make_backup_temp_directory('');
 163          $bc = new backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 164              backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
 165          $backupid = $bc->get_backupid();
 166          $bc->execute_plan();
 167          $bc->destroy();
 168  
 169          // The progress class will get called during restore, so we can use that
 170          // to check the executing flag is true.
 171          $progress = new core_backup_progress_restore_is_executing();
 172  
 173          // Set up restore.
 174          $rc = new restore_controller($backupid, $this->courseid,
 175                  backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $this->userid,
 176                  backup::TARGET_EXISTING_ADDING);
 177          $this->assertTrue($rc->execute_precheck());
 178  
 179          // Check restore is NOT executing.
 180          $this->assertFalse(restore_controller::is_executing());
 181  
 182          // Execute restore.
 183          $rc->set_progress($progress);
 184          $rc->execute_plan();
 185  
 186          // Check restore is NOT executing afterward either.
 187          $this->assertFalse(restore_controller::is_executing());
 188          $rc->destroy();
 189  
 190          // During restore, check that executing was true.
 191          $this->assertTrue(count($progress->executing) > 0);
 192          $alltrue = true;
 193          foreach ($progress->executing as $executing) {
 194              if (!$executing) {
 195                  $alltrue = false;
 196                  break;
 197              }
 198          }
 199          $this->assertTrue($alltrue);
 200      }
 201  
 202      /**
 203       * Test prepare copy method.
 204       */
 205      public function test_restore_controller_prepare_copy() {
 206          $this->expectException(\restore_controller_exception::class);
 207  
 208          global $CFG;
 209  
 210          // Make a backup.
 211          make_backup_temp_directory('');
 212          $bc = new backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
 213              backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
 214          $backupid = $bc->get_backupid();
 215          $bc->execute_plan();
 216          $bc->destroy();
 217  
 218          // Set up restore.
 219          $rc = new restore_controller($backupid, $this->courseid,
 220              backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $this->userid,
 221              backup::TARGET_EXISTING_ADDING);
 222          $rc->prepare_copy();
 223      }
 224  
 225      /**
 226       * Test restore of deadlock causing backup.
 227       */
 228      public function test_restore_of_deadlock_causing_backup() {
 229          global $USER, $CFG;
 230          $this->preventResetByRollback();
 231  
 232          $foldername = 'deadlock';
 233          $fp = get_file_packer('application/vnd.moodle.backup');
 234          $tempdir = make_backup_temp_directory($foldername);
 235          $files = $fp->extract_to_pathname($CFG->dirroot . '/backup/controller/tests/fixtures/deadlock.mbz', $tempdir);
 236  
 237          $this->setAdminUser();
 238          $controller = new restore_controller(
 239              'deadlock',
 240              $this->courseid,
 241              backup::INTERACTIVE_NO,
 242              backup::MODE_GENERAL,
 243              $USER->id,
 244              backup::TARGET_NEW_COURSE
 245          );
 246          $this->assertTrue($controller->execute_precheck());
 247          $controller->execute_plan();
 248          $controller->destroy();
 249      }
 250  }
 251  
 252  
 253  /**
 254   * Progress class that records the result of restore_controller::is_executing calls.
 255   *
 256   * @package core_backup
 257   * @copyright 2014 The Open University
 258   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 259   */
 260  class core_backup_progress_restore_is_executing extends \core\progress\base {
 261      /** @var array Array of results from calling function */
 262      public $executing = array();
 263  
 264      public function update_progress() {
 265          $this->executing[] = restore_controller::is_executing();
 266      }
 267  }
 268  
 269  
 270  /*
 271   * helper extended @backup_controller class that makes some methods public for testing
 272   */
 273  class mock_backup_controller extends backup_controller {
 274  
 275      public function save_controller($includeobj = true, $cleanobj = false) {
 276          parent::save_controller($includeobj, $cleanobj);
 277      }
 278  }