Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

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