Merge branch 'MDL-38190-master' of git://github.com/sammarshallou/moodle
Conflicts: backup/import.php theme/bootstrapbase/style/moodle.css
This commit is contained in:
+13
-5
@@ -89,11 +89,6 @@ if (!($bc = backup_ui::load_controller($backupid))) {
|
||||
}
|
||||
$backup = new backup_ui($bc);
|
||||
$backup->process();
|
||||
if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
$backup->execute();
|
||||
} else {
|
||||
$backup->save_controller();
|
||||
}
|
||||
|
||||
$PAGE->set_title($heading.': '.$backup->get_stage_name());
|
||||
$PAGE->set_heading($heading);
|
||||
@@ -104,6 +99,19 @@ echo $OUTPUT->header();
|
||||
if ($backup->enforce_changed_dependencies()) {
|
||||
debugging('Your settings have been altered due to unmet dependencies', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
// Display an extra progress bar so that we can show the progress first.
|
||||
echo html_writer::start_div('', array('id' => 'executionprogress'));
|
||||
echo $renderer->progress_bar($backup->get_progress_bar());
|
||||
$backup->get_controller()->set_progress(new core_backup_display_progress());
|
||||
$backup->execute();
|
||||
echo html_writer::end_div();
|
||||
echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
|
||||
} else {
|
||||
$backup->save_controller();
|
||||
}
|
||||
|
||||
echo $renderer->progress_bar($backup->get_progress_bar());
|
||||
echo $backup->display($renderer);
|
||||
$backup->destroy();
|
||||
|
||||
@@ -64,6 +64,11 @@ class backup_controller extends backup implements loggable {
|
||||
protected $destination; // Destination chain object (fs_moodle, fs_os, db, email...)
|
||||
protected $logger; // Logging chain object (moodle, inline, fs, db, syslog)
|
||||
|
||||
/**
|
||||
* @var core_backup_progress Progress reporting object.
|
||||
*/
|
||||
protected $progress;
|
||||
|
||||
protected $checksum; // Cache @checksumable results for lighter @is_checksum_correct() uses
|
||||
|
||||
/**
|
||||
@@ -109,6 +114,10 @@ class backup_controller extends backup implements loggable {
|
||||
// Default logger chain (based on interactive/execution)
|
||||
$this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->backupid);
|
||||
|
||||
// By default there is no progress reporter. Interfaces that wish to
|
||||
// display progress must set it.
|
||||
$this->progress = new core_backup_null_progress();
|
||||
|
||||
// Instantiate the output_controller singleton and active it if interactive and inmediate
|
||||
$oc = output_controller::get_instance();
|
||||
if ($this->interactive == backup::INTERACTIVE_YES && $this->execution == backup::EXECUTION_INMEDIATE) {
|
||||
@@ -302,6 +311,25 @@ class backup_controller extends backup implements loggable {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public function get_progress() {
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the progress reporter.
|
||||
*
|
||||
* @param core_backup_progress $progress Progress reporting object
|
||||
*/
|
||||
public function set_progress(core_backup_progress $progress) {
|
||||
$this->progress = $progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the backup
|
||||
* @return void Throws and exception of completes
|
||||
|
||||
@@ -57,6 +57,11 @@ class restore_controller extends backup implements loggable {
|
||||
|
||||
protected $logger; // Logging chain object (moodle, inline, fs, db, syslog)
|
||||
|
||||
/**
|
||||
* @var core_backup_progress Progress reporting object.
|
||||
*/
|
||||
protected $progress;
|
||||
|
||||
protected $checksum; // Cache @checksumable results for lighter @is_checksum_correct() uses
|
||||
|
||||
/**
|
||||
@@ -101,6 +106,10 @@ class restore_controller extends backup implements loggable {
|
||||
// Default logger chain (based on interactive/execution)
|
||||
$this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->restoreid);
|
||||
|
||||
// By default there is no progress reporter. Interfaces that wish to
|
||||
// display progress must set it.
|
||||
$this->progress = new core_backup_null_progress();
|
||||
|
||||
// Instantiate the output_controller singleton and active it if interactive and inmediate
|
||||
$oc = output_controller::get_instance();
|
||||
if ($this->interactive == backup::INTERACTIVE_YES && $this->execution == backup::EXECUTION_INMEDIATE) {
|
||||
@@ -300,6 +309,25 @@ class restore_controller extends backup implements loggable {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public function get_progress() {
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the progress reporter.
|
||||
*
|
||||
* @param core_backup_progress $progress Progress reporting object
|
||||
*/
|
||||
public function set_progress(core_backup_progress $progress) {
|
||||
$this->progress = $progress;
|
||||
}
|
||||
|
||||
public function execute_plan() {
|
||||
// Basic/initial prevention against time/memory limits
|
||||
set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
|
||||
|
||||
+20
-1
@@ -90,11 +90,25 @@ if ($backup->get_stage() == backup_ui::STAGE_CONFIRMATION) {
|
||||
|
||||
// If it's the final stage process the import
|
||||
if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Display an extra progress bar so that we can show the current stage.
|
||||
echo html_writer::start_div('', array('id' => 'executionprogress'));
|
||||
echo $renderer->progress_bar($backup->get_progress_bar());
|
||||
|
||||
// Start the progress display - we split into 2 chunks for backup and restore.
|
||||
$progress = new core_backup_display_progress();
|
||||
$progress->start_progress('', 2);
|
||||
$backup->get_controller()->set_progress($progress);
|
||||
|
||||
// First execute the backup
|
||||
$backup->execute();
|
||||
$backup->destroy();
|
||||
unset($backup);
|
||||
|
||||
// Note that we've done that progress.
|
||||
$progress->progress(1);
|
||||
|
||||
// Check whether the backup directory still exists. If missing, something
|
||||
// went really wrong in backup, throw error. Note that backup::MODE_IMPORT
|
||||
// backups don't store resulting files ever
|
||||
@@ -106,6 +120,7 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
// Prepare the restore controller. We don't need a UI here as we will just use what
|
||||
// ever the restore has (the user has just chosen).
|
||||
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_YES, backup::MODE_IMPORT, $USER->id, $restoretarget);
|
||||
$rc->set_progress($progress);
|
||||
// Convert the backup if required.... it should NEVER happed
|
||||
if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
|
||||
$rc->convert();
|
||||
@@ -140,8 +155,12 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
// Delete the temp directory now
|
||||
fulldelete($tempdestination);
|
||||
|
||||
// All progress complete. Hide progress area.
|
||||
$progress->end_progress();
|
||||
echo html_writer::end_div();
|
||||
echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
|
||||
|
||||
// Display a notification and a continue button
|
||||
echo $OUTPUT->header();
|
||||
if ($warnings) {
|
||||
echo $OUTPUT->box_start();
|
||||
echo $OUTPUT->notification(get_string('warning'), 'notifywarning');
|
||||
|
||||
@@ -157,6 +157,11 @@ class backup_final_task extends backup_task {
|
||||
$this->built = true;
|
||||
}
|
||||
|
||||
public function get_weight() {
|
||||
// The final task takes ages, so give it 20 times the weight of a normal task.
|
||||
return 20;
|
||||
}
|
||||
|
||||
// Protected API starts here
|
||||
|
||||
/**
|
||||
|
||||
+20
-12
@@ -44,18 +44,6 @@ if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
|
||||
}
|
||||
|
||||
$outcome = $restore->process();
|
||||
if (!$restore->is_independent()) {
|
||||
if ($restore->get_stage() == restore_ui::STAGE_PROCESS && !$restore->requires_substage()) {
|
||||
try {
|
||||
$restore->execute();
|
||||
} catch(Exception $e) {
|
||||
$restore->cleanup();
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$restore->save_controller();
|
||||
}
|
||||
}
|
||||
$heading = $course->fullname;
|
||||
|
||||
$PAGE->set_title($heading.': '.$restore->get_stage_name());
|
||||
@@ -67,6 +55,26 @@ echo $OUTPUT->header();
|
||||
if (!$restore->is_independent() && $restore->enforce_changed_dependencies()) {
|
||||
debugging('Your settings have been altered due to unmet dependencies', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
if (!$restore->is_independent()) {
|
||||
if ($restore->get_stage() == restore_ui::STAGE_PROCESS && !$restore->requires_substage()) {
|
||||
try {
|
||||
// Display an extra progress bar so that we can show the progress first.
|
||||
echo html_writer::start_div('', array('id' => 'executionprogress'));
|
||||
echo $renderer->progress_bar($restore->get_progress_bar());
|
||||
$restore->get_controller()->set_progress(new core_backup_display_progress());
|
||||
$restore->execute();
|
||||
echo html_writer::end_div();
|
||||
echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
|
||||
} catch(Exception $e) {
|
||||
$restore->cleanup();
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$restore->save_controller();
|
||||
}
|
||||
}
|
||||
|
||||
echo $renderer->progress_bar($restore->get_progress_bar());
|
||||
echo $restore->display($renderer);
|
||||
$restore->destroy();
|
||||
|
||||
@@ -71,6 +71,9 @@ require_once($CFG->dirroot . '/backup/util/loggers/error_log_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/file_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/database_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/output_indented_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_null_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_display_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/settings/setting_dependency.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/settings/base_setting.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/settings/backup_setting.class.php');
|
||||
|
||||
@@ -60,6 +60,9 @@ require_once($CFG->dirroot . '/backup/util/loggers/error_log_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/file_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/database_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/loggers/output_indented_logger.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_null_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_display_progress.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/factories/backup_factory.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/factories/restore_factory.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/helper/backup_helper.class.php');
|
||||
|
||||
@@ -87,6 +87,16 @@ class backup_plan extends base_plan implements loggable {
|
||||
return $this->controller->get_logger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public function get_progress() {
|
||||
return $this->controller->get_progress();
|
||||
}
|
||||
|
||||
public function is_excluding_activities() {
|
||||
return $this->excludingdactivities;
|
||||
}
|
||||
|
||||
@@ -158,12 +158,33 @@ abstract class base_plan implements checksumable, executable {
|
||||
if (!$this->built) {
|
||||
throw new base_plan_exception('base_plan_not_built');
|
||||
}
|
||||
|
||||
// Calculate the total weight of all tasks and start progress tracking.
|
||||
$progress = $this->get_progress();
|
||||
$totalweight = 0;
|
||||
foreach ($this->tasks as $task) {
|
||||
$totalweight += $task->get_weight();
|
||||
}
|
||||
$progress->start_progress($this->get_name(), $totalweight);
|
||||
|
||||
// Build and execute all tasks.
|
||||
foreach ($this->tasks as $task) {
|
||||
$task->build();
|
||||
$task->execute();
|
||||
}
|
||||
|
||||
// Finish progress tracking.
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public abstract function get_progress();
|
||||
|
||||
/**
|
||||
* Destroy all circular references. It helps PHP 5.2 a lot!
|
||||
*/
|
||||
|
||||
@@ -67,6 +67,17 @@ abstract class base_task implements checksumable, executable, loggable {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weight of this task, an approximation of the amount of time
|
||||
* it will take. By default this value is 1. It can be increased for longer
|
||||
* tasks.
|
||||
*
|
||||
* @return int Weight
|
||||
*/
|
||||
public function get_weight() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function get_setting($name) {
|
||||
// First look in task settings
|
||||
$result = null;
|
||||
@@ -111,6 +122,16 @@ abstract class base_task implements checksumable, executable, loggable {
|
||||
return $this->plan->get_logger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public function get_progress() {
|
||||
return $this->plan->get_progress();
|
||||
}
|
||||
|
||||
public function log($message, $level, $a = null, $depth = null, $display = false) {
|
||||
backup_helper::log($message, $level, $a, $depth, $display, $this->get_logger());
|
||||
}
|
||||
@@ -149,6 +170,13 @@ abstract class base_task implements checksumable, executable, loggable {
|
||||
if ($this->executed) {
|
||||
throw new base_task_exception('base_task_already_executed', $this->name);
|
||||
}
|
||||
|
||||
// Starts progress based on the weight of this task and number of steps.
|
||||
$progress = $this->get_progress();
|
||||
$progress->start_progress($this->get_name(), count($this->steps), $this->get_weight());
|
||||
$done = 0;
|
||||
|
||||
// Execute all steps.
|
||||
foreach ($this->steps as $step) {
|
||||
$result = $step->execute();
|
||||
// If step returns array, it will be forwarded to plan
|
||||
@@ -156,11 +184,16 @@ abstract class base_task implements checksumable, executable, loggable {
|
||||
if (is_array($result) and !empty($result)) {
|
||||
$this->add_result($result);
|
||||
}
|
||||
$done++;
|
||||
$progress->progress($done);
|
||||
}
|
||||
// Mark as executed if any step has been executed
|
||||
if (!empty($this->steps)) {
|
||||
$this->executed = true;
|
||||
}
|
||||
|
||||
// Finish progress for this task.
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -94,6 +94,16 @@ class restore_plan extends base_plan implements loggable {
|
||||
return $this->controller->get_logger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the progress reporter, which can be used to report progress within
|
||||
* the backup or restore process.
|
||||
*
|
||||
* @return core_backup_progress Progress reporting object
|
||||
*/
|
||||
public function get_progress() {
|
||||
return $this->controller->get_progress();
|
||||
}
|
||||
|
||||
public function get_info() {
|
||||
return $this->controller->get_info();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
class mock_base_plan extends base_plan {
|
||||
public function build() {
|
||||
}
|
||||
|
||||
public function get_progress() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Progress handler that uses a standard Moodle progress bar to display
|
||||
* progress. The Moodle progress bar cannot show indeterminate progress,
|
||||
* so we do extra output in addition to the bar.
|
||||
*
|
||||
* @package core_backup
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_backup_display_progress extends core_backup_progress {
|
||||
/**
|
||||
* @var int Number of wibble states (state0...stateN-1 classes in CSS)
|
||||
*/
|
||||
const WIBBLE_STATES = 13;
|
||||
|
||||
/**
|
||||
* @var progress_bar Current progress bar.
|
||||
*/
|
||||
private $bar;
|
||||
|
||||
private $lastwibble, $currentstate = 0, $direction = 1;
|
||||
|
||||
/**
|
||||
* @var bool True to display names
|
||||
*/
|
||||
protected $displaynames = false;
|
||||
|
||||
/**
|
||||
* Constructs the progress reporter. This will output HTML code for the
|
||||
* progress bar, and an indeterminate wibbler below it.
|
||||
*
|
||||
* @param bool $startnow If true, outputs HTML immediately.
|
||||
*/
|
||||
public function __construct($startnow = true) {
|
||||
if ($startnow) {
|
||||
$this->start_html();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the progress section names do not display because (in backup)
|
||||
* these are usually untranslated and incomprehensible. To make them
|
||||
* display, call this method.
|
||||
*
|
||||
* @param bool $displaynames True to display names
|
||||
*/
|
||||
public function set_display_names($displaynames = true) {
|
||||
$this->displaynames = $displaynames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts to output progress.
|
||||
*
|
||||
* Called in constructor and in update_progress if required.
|
||||
*
|
||||
* @throws coding_exception If already started
|
||||
*/
|
||||
public function start_html() {
|
||||
if ($this->bar) {
|
||||
throw new coding_exception('Already started');
|
||||
}
|
||||
$this->bar = new progress_bar();
|
||||
$this->bar->create();
|
||||
echo html_writer::start_div('wibbler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes output. (Progress can begin again later if there are more
|
||||
* calls to update_progress.)
|
||||
*
|
||||
* Automatically called from update_progress when progress finishes.
|
||||
*/
|
||||
public function end_html() {
|
||||
// Finish progress bar.
|
||||
$this->bar->update_full(100, '');
|
||||
$this->bar = null;
|
||||
|
||||
// End wibbler div.
|
||||
echo html_writer::end_div();
|
||||
}
|
||||
|
||||
public function update_progress() {
|
||||
// If finished...
|
||||
if (!$this->is_in_progress_section()) {
|
||||
if ($this->bar) {
|
||||
$this->end_html();
|
||||
}
|
||||
} else {
|
||||
if (!$this->bar) {
|
||||
$this->start_html();
|
||||
}
|
||||
// In case of indeterminate or small progress, update the wibbler
|
||||
// (up to once per second).
|
||||
if (time() != $this->lastwibble) {
|
||||
$this->lastwibble = time();
|
||||
echo html_writer::div('', 'wibble state' . $this->currentstate);
|
||||
|
||||
// Go on to next colour.
|
||||
$this->currentstate += $this->direction;
|
||||
if ($this->currentstate < 0 || $this->currentstate >= self::WIBBLE_STATES) {
|
||||
$this->direction = -$this->direction;
|
||||
$this->currentstate += 2 * $this->direction;
|
||||
}
|
||||
}
|
||||
|
||||
// Get progress.
|
||||
list ($min, $max) = $this->get_progress_proportion_range();
|
||||
|
||||
// Update progress bar.
|
||||
$message = '';
|
||||
if ($this->displaynames) {
|
||||
$message = $this->get_current_description();
|
||||
}
|
||||
$this->bar->update_full($min * 100, $message);
|
||||
|
||||
// Flush output.
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Progress handler that ignores progress entirely.
|
||||
*
|
||||
* @package core_backup
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_backup_null_progress extends core_backup_progress {
|
||||
public function update_progress() {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Base class for handling progress information during a backup and restore.
|
||||
*
|
||||
* Subclasses should generally override the current_progress function which
|
||||
* summarises all progress information.
|
||||
*
|
||||
* @package core_backup
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class core_backup_progress {
|
||||
/**
|
||||
* @var int Constant indicating that the number of progress calls is unknown.
|
||||
*/
|
||||
const INDETERMINATE = -1;
|
||||
|
||||
/**
|
||||
* @var int The number of seconds that can pass without progress() calls.
|
||||
*/
|
||||
const TIME_LIMIT_WITHOUT_PROGRESS = 120;
|
||||
|
||||
/**
|
||||
* @var int Time of last progress call.
|
||||
*/
|
||||
protected $lastprogresstime;
|
||||
|
||||
/**
|
||||
* @var int Number of progress calls (restricted to ~ 1/second).
|
||||
*/
|
||||
protected $count;
|
||||
|
||||
/**
|
||||
* @var array Array of progress descriptions for each stack level.
|
||||
*/
|
||||
protected $descriptions = array();
|
||||
|
||||
/**
|
||||
* @var array Array of maximum progress values for each stack level.
|
||||
*/
|
||||
protected $maxes = array();
|
||||
|
||||
/**
|
||||
* @var array Array of current progress values.
|
||||
*/
|
||||
protected $currents = array();
|
||||
|
||||
/**
|
||||
* @var int Array of counts within parent progress entry (ignored for first)
|
||||
*/
|
||||
protected $parentcounts = array();
|
||||
|
||||
/**
|
||||
* Marks the start of an operation that will display progress.
|
||||
*
|
||||
* This can be called multiple times for nested progress sections. It must
|
||||
* be paired with calls to end_progress.
|
||||
*
|
||||
* The progress maximum may be INDETERMINATE if the current operation has
|
||||
* an unknown number of steps. (This is default.)
|
||||
*
|
||||
* Calling this function will always result in a new display, so this
|
||||
* should not be called exceedingly frequently.
|
||||
*
|
||||
* When it is complete by calling end_progress, each start_progress section
|
||||
* automatically adds progress to its parent, as defined by $parentcount.
|
||||
*
|
||||
* @param string $description Description to display
|
||||
* @param int $max Maximum value of progress for this section
|
||||
* @param int $parentcount How many progress points this section counts for
|
||||
* @throws coding_exception If max is invalid
|
||||
*/
|
||||
public function start_progress($description, $max = self::INDETERMINATE,
|
||||
$parentcount = 1) {
|
||||
if ($max != self::INDETERMINATE && $max <= 0) {
|
||||
throw new coding_exception(
|
||||
'start_progress() max value cannot be zero or negative');
|
||||
}
|
||||
if ($parentcount < 1) {
|
||||
throw new coding_exception(
|
||||
'start_progress() parent progress count must be at least 1');
|
||||
}
|
||||
if (!empty($this->descriptions)) {
|
||||
$prevmax = end($this->maxes);
|
||||
if ($prevmax !== self::INDETERMINATE) {
|
||||
$prevcurrent = end($this->currents);
|
||||
if ($prevcurrent + $parentcount > $prevmax) {
|
||||
throw new coding_exception(
|
||||
'start_progress() parent progress would exceed max');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($parentcount != 1) {
|
||||
throw new coding_exception(
|
||||
'start_progress() progress count must be 1 when no parent');
|
||||
}
|
||||
}
|
||||
$this->descriptions[] = $description;
|
||||
$this->maxes[] = $max;
|
||||
$this->currents[] = 0;
|
||||
$this->parentcounts[] = $parentcount;
|
||||
$this->update_progress();
|
||||
$lastprogresstime = $this->get_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of an operation that will display progress.
|
||||
*
|
||||
* This must be paired with each start_progress call.
|
||||
*
|
||||
* If there is a parent progress section, its progress will be increased
|
||||
* automatically to reflect the end of the child section.
|
||||
*
|
||||
* @throws coding_exception If progress hasn't been started
|
||||
*/
|
||||
public function end_progress() {
|
||||
if (!count($this->descriptions)) {
|
||||
throw new coding_exception('end_progress() without start_progress()');
|
||||
}
|
||||
array_pop($this->descriptions);
|
||||
array_pop($this->maxes);
|
||||
array_pop($this->currents);
|
||||
$parentcount = array_pop($this->parentcounts);
|
||||
if (!empty($this->descriptions)) {
|
||||
$lastmax = end($this->maxes);
|
||||
if ($lastmax != self::INDETERMINATE) {
|
||||
$lastvalue = end($this->currents);
|
||||
$this->currents[key($this->currents)] = $lastvalue + $parentcount;
|
||||
}
|
||||
}
|
||||
$this->update_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that progress has occurred.
|
||||
*
|
||||
* The progress value should indicate the total progress so far, from 0
|
||||
* to the value supplied for $max (inclusive) in start_progress.
|
||||
*
|
||||
* You do not need to call this function for every value. It is OK to skip
|
||||
* values. It is also OK to call this function as often as desired; it
|
||||
* doesn't do anything if called more than once per second.
|
||||
*
|
||||
* It must be INDETERMINATE if start_progress was called with $max set to
|
||||
* INDETERMINATE. Otherwise it must not be indeterminate.
|
||||
*
|
||||
* @param int $progress Progress so far
|
||||
* @throws coding_exception If progress value is invalid
|
||||
*/
|
||||
public function progress($progress = self::INDETERMINATE) {
|
||||
// Ignore too-frequent progress calls (more than once per second).
|
||||
$now = $this->get_time();
|
||||
if ($now === $this->lastprogresstime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check we are inside a progress section.
|
||||
$max = end($this->maxes);
|
||||
if ($max === false) {
|
||||
throw new coding_exception(
|
||||
'progress() without start_progress');
|
||||
}
|
||||
|
||||
// Check and apply new progress.
|
||||
if ($progress === self::INDETERMINATE) {
|
||||
// Indeterminate progress.
|
||||
if ($max !== self::INDETERMINATE) {
|
||||
throw new coding_exception(
|
||||
'progress() INDETERMINATE, expecting value');
|
||||
}
|
||||
} else {
|
||||
// Determinate progress.
|
||||
$current = end($this->currents);
|
||||
if ($max === self::INDETERMINATE) {
|
||||
throw new coding_exception(
|
||||
'progress() with value, expecting INDETERMINATE');
|
||||
} else if ($progress < 0 || $progress > $max) {
|
||||
throw new coding_exception(
|
||||
'progress() value out of range');
|
||||
} else if ($progress < $current) {
|
||||
throw new coding_Exception(
|
||||
'progress() value may not go backwards');
|
||||
}
|
||||
$this->currents[key($this->currents)] = $progress;
|
||||
}
|
||||
|
||||
// Update progress.
|
||||
$this->count++;
|
||||
$this->lastprogresstime = $now;
|
||||
set_time_limit(self::TIME_LIMIT_WITHOUT_PROGRESS);
|
||||
$this->update_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets time (this is provided so that unit tests can override it).
|
||||
*
|
||||
* @return int Current system time
|
||||
*/
|
||||
protected function get_time() {
|
||||
return time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever new progress should be displayed.
|
||||
*/
|
||||
protected abstract function update_progress();
|
||||
|
||||
/**
|
||||
* @return bool True if currently inside a progress section
|
||||
*/
|
||||
public function is_in_progress_section() {
|
||||
return !empty($this->descriptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Current progress section description
|
||||
*/
|
||||
public function get_current_description() {
|
||||
$description = end($this->descriptions);
|
||||
if ($description === false) {
|
||||
throw new coding_exception('Not inside progress section');
|
||||
}
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains current progress in a way suitable for drawing a progress bar.
|
||||
*
|
||||
* Progress is returned as a minimum and maximum value. If there is no
|
||||
* indeterminate progress, these values will be identical. If there is
|
||||
* intermediate progress, these values can be different. (For example, if
|
||||
* the top level progress sections is indeterminate, then the values will
|
||||
* always be 0.0 and 1.0.)
|
||||
*
|
||||
* @return array Minimum and maximum possible progress proportions
|
||||
*/
|
||||
public function get_progress_proportion_range() {
|
||||
// If there is no progress underway, we must have finished.
|
||||
if (empty($this->currents)) {
|
||||
return array(1.0, 1.0);
|
||||
}
|
||||
$count = count($this->currents);
|
||||
$min = 0.0;
|
||||
$max = 1.0;
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
// Get max value at that section - if it's indeterminate we can tell
|
||||
// no more.
|
||||
$sectionmax = $this->maxes[$i];
|
||||
if ($sectionmax === self::INDETERMINATE) {
|
||||
return array($min, $max);
|
||||
}
|
||||
|
||||
// Special case if current value is max (this should only happen
|
||||
// just before ending a section).
|
||||
$sectioncurrent = $this->currents[$i];
|
||||
if ($sectioncurrent === $sectionmax) {
|
||||
return array($max, $max);
|
||||
}
|
||||
|
||||
// Using the current value at that section, we know we are somewhere
|
||||
// between 'current' and the next 'current' value which depends on
|
||||
// the parentcount of the nested section (if any).
|
||||
$newmin = ($sectioncurrent / $sectionmax) * ($max - $min) + $min;
|
||||
$nextcurrent = $sectioncurrent + 1;
|
||||
if ($i + 1 < $count) {
|
||||
$weight = $this->parentcounts[$i + 1];
|
||||
$nextcurrent = $sectioncurrent + $weight;
|
||||
}
|
||||
$newmax = ($nextcurrent / $sectionmax) * ($max - $min) + $min;
|
||||
$min = $newmin;
|
||||
$max = $newmax;
|
||||
}
|
||||
|
||||
// If there was nothing indeterminate, we use the min value as current.
|
||||
return array($min, $min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains current indeterminate progress in a way suitable for adding to
|
||||
* the progress display.
|
||||
*
|
||||
* This returns the number of indeterminate calls (at any level) during the
|
||||
* lifetime of this progress reporter, whether or not there is a current
|
||||
* indeterminate step. (The number will not be ridiculously high because
|
||||
* progress calls are limited to one per second.)
|
||||
*
|
||||
* @return int Number of indeterminate progress calls
|
||||
*/
|
||||
public function get_progress_count() {
|
||||
return $this->count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the progress classes.
|
||||
*
|
||||
* @package core_backup
|
||||
* @category phpunit
|
||||
* @copyright 2013 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Include all the needed stuff.
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
|
||||
|
||||
/**
|
||||
* Progress tests.
|
||||
*/
|
||||
class backup_progress_testcase extends basic_testcase {
|
||||
|
||||
/**
|
||||
* Tests for basic use with simple numeric progress.
|
||||
*/
|
||||
public function test_basic() {
|
||||
$progress = new core_backup_mock_progress();
|
||||
|
||||
// Check values of empty progress things.
|
||||
$this->assertFalse($progress->is_in_progress_section());
|
||||
|
||||
// Start progress counting, check basic values and check that update
|
||||
// gets called.
|
||||
$progress->start_progress('hello', 10);
|
||||
$this->assertTrue($progress->was_update_called());
|
||||
$this->assertTrue($progress->is_in_progress_section());
|
||||
$this->assertEquals('hello', $progress->get_current_description());
|
||||
|
||||
// Check numeric position and indeterminate count.
|
||||
$this->assert_min_max(0.0, 0.0, $progress);
|
||||
$this->assertEquals(0, $progress->get_progress_count());
|
||||
|
||||
// Make some progress and check that the time limit gets added.
|
||||
$progress->step_time();
|
||||
$progress->progress(2);
|
||||
$this->assertTrue($progress->was_update_called());
|
||||
$this->assertEquals(120, ini_get('max_execution_time'));
|
||||
|
||||
// Check the new value.
|
||||
$this->assert_min_max(0.2, 0.2, $progress);
|
||||
|
||||
// Do another progress run at same time, it should be ignored.
|
||||
$progress->progress(3);
|
||||
$this->assertFalse($progress->was_update_called());
|
||||
$this->assert_min_max(0.2, 0.2, $progress);
|
||||
|
||||
// End the section. This should cause an update.
|
||||
$progress->end_progress();
|
||||
$this->assertTrue($progress->was_update_called());
|
||||
|
||||
// Because there are no sections left open, it thinks we finished.
|
||||
$this->assert_min_max(1.0, 1.0, $progress);
|
||||
|
||||
// There was 1 progress call.
|
||||
$this->assertEquals(1, $progress->get_progress_count());
|
||||
|
||||
// Clear the time limit, otherwise phpunit complains.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests progress that is nested and/or indeterminate.
|
||||
*/
|
||||
public function test_nested() {
|
||||
// Outer progress goes from 0 to 10.
|
||||
$progress = new core_backup_mock_progress();
|
||||
$progress->start_progress('hello', 10);
|
||||
|
||||
// Get up to 4, check position.
|
||||
$progress->step_time();
|
||||
$progress->progress(4);
|
||||
$this->assert_min_max(0.4, 0.4, $progress);
|
||||
$this->assertEquals('hello', $progress->get_current_description());
|
||||
|
||||
// Now start indeterminate progress.
|
||||
$progress->start_progress('world');
|
||||
$this->assert_min_max(0.4, 0.5, $progress);
|
||||
$this->assertEquals('world', $progress->get_current_description());
|
||||
|
||||
// Do some indeterminate progress and count it (once per second).
|
||||
$progress->step_time();
|
||||
$progress->progress();
|
||||
$this->assertEquals(2, $progress->get_progress_count());
|
||||
$progress->progress();
|
||||
$this->assertEquals(2, $progress->get_progress_count());
|
||||
$progress->step_time();
|
||||
$progress->progress();
|
||||
$this->assertEquals(3, $progress->get_progress_count());
|
||||
$this->assert_min_max(0.4, 0.5, $progress);
|
||||
|
||||
// Exit the indeterminate section.
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.5, 0.5, $progress);
|
||||
|
||||
$progress->step_time();
|
||||
$progress->progress(7);
|
||||
$this->assert_min_max(0.7, 0.7, $progress);
|
||||
|
||||
// Enter a numbered section (this time with a range of 5).
|
||||
$progress->start_progress('frogs', 5);
|
||||
$this->assert_min_max(0.7, 0.7, $progress);
|
||||
$progress->step_time();
|
||||
$progress->progress(1);
|
||||
$this->assert_min_max(0.72, 0.72, $progress);
|
||||
$progress->step_time();
|
||||
$progress->progress(3);
|
||||
$this->assert_min_max(0.76, 0.76, $progress);
|
||||
|
||||
// Now enter another indeterminate section.
|
||||
$progress->start_progress('and');
|
||||
$this->assert_min_max(0.76, 0.78, $progress);
|
||||
|
||||
// Make some progress, should increment indeterminate count.
|
||||
$progress->step_time();
|
||||
$progress->progress();
|
||||
$this->assertEquals(7, $progress->get_progress_count());
|
||||
|
||||
// Enter numbered section, won't make any difference to values.
|
||||
$progress->start_progress('zombies', 2);
|
||||
$progress->step_time();
|
||||
$progress->progress(1);
|
||||
$this->assert_min_max(0.76, 0.78, $progress);
|
||||
$this->assertEquals(8, $progress->get_progress_count());
|
||||
|
||||
// Leaving it will make no difference too.
|
||||
$progress->end_progress();
|
||||
|
||||
// Leaving the indeterminate section will though.
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.78, 0.78, $progress);
|
||||
|
||||
// Leave the two numbered sections.
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.8, 0.8, $progress);
|
||||
$progress->end_progress();
|
||||
$this->assertFalse($progress->is_in_progress_section());
|
||||
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the feature for 'weighting' nested progress.
|
||||
*/
|
||||
public function test_nested_weighted() {
|
||||
$progress = new core_backup_mock_progress();
|
||||
$progress->start_progress('', 10);
|
||||
|
||||
// First nested child has 2 units of its own and is worth 1 unit.
|
||||
$progress->start_progress('', 2);
|
||||
$progress->step_time();
|
||||
$progress->progress(1);
|
||||
$this->assert_min_max(0.05, 0.05, $progress);
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.1, 0.1, $progress);
|
||||
|
||||
// Next child has 2 units of its own but is worth 3 units.
|
||||
$progress->start_progress('weighted', 2, 3);
|
||||
$progress->step_time();
|
||||
$progress->progress(1);
|
||||
$this->assert_min_max(0.25, 0.25, $progress);
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.4, 0.4, $progress);
|
||||
|
||||
// Next indeterminate child is worth 6 units.
|
||||
$progress->start_progress('', core_backup_progress::INDETERMINATE, 6);
|
||||
$progress->step_time();
|
||||
$progress->progress();
|
||||
$this->assert_min_max(0.4, 1.0, $progress);
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(1.0, 1.0, $progress);
|
||||
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* I had some issues with real use in backup/restore, this test is intended
|
||||
* to be similar.
|
||||
*/
|
||||
public function test_realistic() {
|
||||
$progress = new core_backup_mock_progress();
|
||||
$progress->start_progress('parent', 100);
|
||||
$progress->start_progress('child', 1);
|
||||
$progress->progress(1);
|
||||
$this->assert_min_max(0.01, 0.01, $progress);
|
||||
$progress->end_progress();
|
||||
$this->assert_min_max(0.01, 0.01, $progress);
|
||||
|
||||
// Clear the time limit, otherwise phpunit complains.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for any exceptions due to invalid calls.
|
||||
*/
|
||||
public function test_exceptions() {
|
||||
$progress = new core_backup_mock_progress();
|
||||
|
||||
// Check errors when empty.
|
||||
try {
|
||||
$progress->progress();
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
|
||||
}
|
||||
try {
|
||||
$progress->end_progress();
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
|
||||
}
|
||||
try {
|
||||
$progress->get_current_description();
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~Not inside progress~', $e->getMessage()));
|
||||
}
|
||||
try {
|
||||
$progress->start_progress('', 1, 7);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~must be 1~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// Check invalid start (0).
|
||||
try {
|
||||
$progress->start_progress('hello', 0);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~cannot be zero or negative~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// Indeterminate when value expected.
|
||||
$progress->start_progress('hello', 10);
|
||||
try {
|
||||
$progress->progress(core_backup_progress::INDETERMINATE);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~expecting value~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// Value when indeterminate expected.
|
||||
$progress->start_progress('hello');
|
||||
try {
|
||||
$progress->progress(4);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~expecting INDETERMINATE~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// Illegal values.
|
||||
$progress->start_progress('hello', 10);
|
||||
try {
|
||||
$progress->progress(-2);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
|
||||
}
|
||||
try {
|
||||
$progress->progress(11);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// You are allowed two with the same value...
|
||||
$progress->progress(4);
|
||||
$progress->step_time();
|
||||
$progress->progress(4);
|
||||
$progress->step_time();
|
||||
|
||||
// ...but not to go backwards.
|
||||
try {
|
||||
$progress->progress(3);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~backwards~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// When you go forward, you can't go further than there is room.
|
||||
try {
|
||||
$progress->start_progress('', 1, 7);
|
||||
$this->fail();
|
||||
} catch (coding_exception $e) {
|
||||
$this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
|
||||
}
|
||||
|
||||
// Clear the time limit, otherwise phpunit complains.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current progress values are as expected.
|
||||
*
|
||||
* @param number $min Expected min progress
|
||||
* @param number $max Expected max progress
|
||||
* @param core_backup_mock_progress $progress
|
||||
*/
|
||||
private function assert_min_max($min, $max, core_backup_mock_progress $progress) {
|
||||
$this->assertEquals(array($min, $max),
|
||||
$progress->get_progress_proportion_range());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class that records when update_progress is called and allows time
|
||||
* stepping.
|
||||
*/
|
||||
class core_backup_mock_progress extends core_backup_progress {
|
||||
private $updatecalled = false;
|
||||
private $time = 1;
|
||||
|
||||
/**
|
||||
* Checks if update was called since the last call to this function.
|
||||
*
|
||||
* @return boolean True if update was called
|
||||
*/
|
||||
public function was_update_called() {
|
||||
if ($this->updatecalled) {
|
||||
$this->updatecalled = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Steps the current time by 1 second.
|
||||
*/
|
||||
public function step_time() {
|
||||
$this->time++;
|
||||
}
|
||||
|
||||
protected function update_progress() {
|
||||
$this->updatecalled = true;
|
||||
}
|
||||
|
||||
protected function get_time() {
|
||||
return $this->time;
|
||||
}
|
||||
}
|
||||
@@ -542,6 +542,21 @@ body.tag .managelink {padding: 5px;}
|
||||
.path-backup .fitemtitle .iconlarge.icon-post { padding-left: 6px; }
|
||||
.path-backup.dir-rtl .fitemtitle .iconlarge.icon-post { padding-right: 6px; padding-right: 0; }
|
||||
.path-backup .fitem .smallicon { vertical-align: text-bottom; }
|
||||
.path-backup .wibbler { width: 500px; margin: 0 auto 10px; border-bottom: 1px solid black; border-right: 1px solid black; border-left: 1px solid black; position: relative; min-height: 4px;}
|
||||
.path-backup .wibbler .wibble { position: absolute; left: 0; right: 0; top: 0; height: 4px; }
|
||||
.path-backup .wibbler .state0 { background: #eee; }
|
||||
.path-backup .wibbler .state1 { background: #ddd; }
|
||||
.path-backup .wibbler .state2 { background: #ccc; }
|
||||
.path-backup .wibbler .state3 { background: #bbb; }
|
||||
.path-backup .wibbler .state4 { background: #aaa; }
|
||||
.path-backup .wibbler .state5 { background: #999; }
|
||||
.path-backup .wibbler .state6 { background: #888; }
|
||||
.path-backup .wibbler .state7 { background: #777; }
|
||||
.path-backup .wibbler .state8 { background: #666; }
|
||||
.path-backup .wibbler .state9 { background: #555; }
|
||||
.path-backup .wibbler .state10 { background: #444; }
|
||||
.path-backup .wibbler .state11 { background: #333; }
|
||||
.path-backup .wibbler .state12 { background: #222; }
|
||||
|
||||
/**
|
||||
* Web Service
|
||||
|
||||
@@ -162,3 +162,58 @@
|
||||
background-color: #eee;
|
||||
padding: 3px;
|
||||
}
|
||||
.path-backup .wibbler {
|
||||
width: 500px;
|
||||
margin: 0 auto 10px;
|
||||
border-bottom: 1px solid black;
|
||||
border-right: 1px solid black;
|
||||
border-left: 1px solid black;
|
||||
position: relative;
|
||||
min-height: 4px;
|
||||
}
|
||||
.path-backup .wibbler .wibble {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 4px;
|
||||
}
|
||||
.path-backup .wibbler .state0 {
|
||||
background: #eee;
|
||||
}
|
||||
.path-backup .wibbler .state1 {
|
||||
background: #ddd;
|
||||
}
|
||||
.path-backup .wibbler .state2 {
|
||||
background: #ccc;
|
||||
}
|
||||
.path-backup .wibbler .state3 {
|
||||
background: #bbb;
|
||||
}
|
||||
.path-backup .wibbler .state4 {
|
||||
background: #aaa;
|
||||
}
|
||||
.path-backup .wibbler .state5 {
|
||||
background: #999;
|
||||
}
|
||||
.path-backup .wibbler .state6 {
|
||||
background: #888;
|
||||
}
|
||||
.path-backup .wibbler .state7 {
|
||||
background: #777;
|
||||
}
|
||||
.path-backup .wibbler .state8 {
|
||||
background: #666;
|
||||
}
|
||||
.path-backup .wibbler .state9 {
|
||||
background: #555;
|
||||
}
|
||||
.path-backup .wibbler .state10 {
|
||||
background: #444;
|
||||
}
|
||||
.path-backup .wibbler .state11 {
|
||||
background: #333;
|
||||
}
|
||||
.path-backup .wibbler .state12 {
|
||||
background: #222;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user