Skip to content

Commit

Permalink
MDL-74548 backup: Unit tests for course copy refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
cameron1729 committed Jun 29, 2022
1 parent 53dd763 commit 8516a49
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 6 deletions.
13 changes: 13 additions & 0 deletions backup/controller/tests/controller_test.php
Expand Up @@ -71,6 +71,19 @@ protected function setUp(): void {
$CFG->backup_file_logger_level_extra = backup::LOG_NONE;
}

/**
* Test get_copy
*
* @covers \restore_controller::get_copy
*/
public function test_restore_controller_get_copy() {
$copydata = (object)["some" => "copydata"];
$rc = new \restore_controller(1729, $this->courseid, backup::INTERACTIVE_NO, backup::MODE_COPY,
$this->userid, backup::TARGET_NEW_COURSE, null, backup::RELEASESESSION_NO, $copydata);

$this->assertEquals($copydata, $rc->get_copy());
}

/**
* Test instantiating a restore controller for a course copy without providing copy data.
*
Expand Down
Expand Up @@ -32,8 +32,9 @@
* @copyright 2020 onward The Moodle Users Association <https://moodleassociation.org/>
* @author Matt Porritt <mattp@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \copy_helper
*/
class course_copy_test extends \advanced_testcase {
class copy_helper_test extends \advanced_testcase {

/**
*
Expand Down Expand Up @@ -143,8 +144,150 @@ protected function setUp(): void {
$CFG->backup_file_logger_level_extra = backup::LOG_NONE;
}

/**
* Test process form data with invalid data.
*
* @covers ::process_formdata
*/
public function test_process_formdata_missing_fields() {
$this->expectException(\moodle_exception::class);
\copy_helper::process_formdata(new \stdClass);
}

/**
* Test processing form data.
*
* @covers ::process_formdata
*/
public function test_process_formdata() {
$validformdata = [
'courseid' => 1729,
'fullname' => 'Taxicab Numbers',
'shortname' => 'Taxi101',
'category' => 2,
'visible' => 1,
'startdate' => 87539319,
'enddate' => 6963472309248,
'idnumber' => 1730,
'userdata' => 1
];

$roles = [
'role_one' => 1,
'role_two' => 2,
'role_three' => 0
];

$expected = (object)array_merge($validformdata, ['keptroles' => []]);
$expected->keptroles = [1, 2];
$processed = \copy_helper::process_formdata(
(object)array_merge(
$validformdata,
$roles,
['extra' => 'stuff', 'remove' => 'this'])
);

$this->assertEquals($expected, $processed);
}

/**
* Test orphaned controller cleanup.
*
* @covers ::cleanup_orphaned_copy_controllers
*/
public function test_cleanup_orphaned_copy_controllers() {
global $DB;

// Mock up the form data.
$formdata = new \stdClass;
$formdata->courseid = $this->course->id;
$formdata->fullname = 'foo';
$formdata->shortname = 'data1';
$formdata->category = 1;
$formdata->visible = 1;
$formdata->startdate = 1582376400;
$formdata->enddate = 0;
$formdata->idnumber = 123;
$formdata->userdata = 1;
$formdata->role_1 = 1;
$formdata->role_3 = 3;
$formdata->role_5 = 5;

$copies = [];
for ($i = 0; $i < 5; $i++) {
$formdata->shortname = 'data' . $i;
$copies[] = \copy_helper::create_copy($formdata);
}

// Delete one of the restore controllers. Simulates a situation where copy creation
// interrupted and the restore controller never gets created.
$DB->delete_records('backup_controllers', ['backupid' => $copies[0]['restoreid']]);

// Set a backup/restore controller pair to be in an intermediate state.
\backup_controller::load_controller($copies[2]['backupid'])->set_status(backup::STATUS_FINISHED_OK);

// Set a backup/restore controller pair to completed.
\backup_controller::load_controller($copies[3]['backupid'])->set_status(backup::STATUS_FINISHED_OK);
\restore_controller::load_controller($copies[3]['restoreid'])->set_status(backup::STATUS_FINISHED_OK);

// Set a backup/restore controller pair to have a failed backup.
\backup_controller::load_controller($copies[4]['backupid'])->set_status(backup::STATUS_FINISHED_ERR);

// Create some backup/restore controllers that are unrelated to course copies.
$bc = new \backup_controller(backup::TYPE_1COURSE, 1, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_ASYNC,
2, backup::RELEASESESSION_YES);
$rc = new \restore_controller('restore-test-1729', 1, backup::INTERACTIVE_NO, backup::MODE_ASYNC, 1, 2);
$rc->save_controller();
$unrelatedvanillacontrollers = ['backupid' => $bc->get_backupid(), 'restoreid' => $rc->get_restoreid()];

$bc = new \backup_controller(backup::TYPE_1COURSE, 1, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_ASYNC,
2, backup::RELEASESESSION_YES);
$rc = new \restore_controller('restore-test-1729', 1, backup::INTERACTIVE_NO, backup::MODE_ASYNC, 1, 2);
$bc->set_status(backup::STATUS_FINISHED_OK);
$rc->set_status(backup::STATUS_FINISHED_OK);
$unrelatedfinishedcontrollers = ['backupid' => $bc->get_backupid(), 'restoreid' => $rc->get_restoreid()];

$bc = new \backup_controller(backup::TYPE_1COURSE, 1, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_ASYNC,
2, backup::RELEASESESSION_YES);
$rc = new \restore_controller('restore-test-1729', 1, backup::INTERACTIVE_NO, backup::MODE_ASYNC, 1, 2);
$bc->set_status(backup::STATUS_FINISHED_ERR);
$rc->set_status(backup::STATUS_FINISHED_ERR);
$unrelatedfailedcontrollers = ['backupid' => $bc->get_backupid(), 'restoreid' => $rc->get_restoreid()];

// Clean up the backup_controllers table.
$records = $DB->get_records('backup_controllers', null, '', 'id, backupid, status, operation, purpose, timecreated');
\copy_helper::cleanup_orphaned_copy_controllers($records, 0);

// Retrieve them again and check.
$records = $DB->get_records('backup_controllers', null, '', 'backupid, status');

// Verify the backup associated with the deleted restore is marked as failed.
$this->assertEquals(backup::STATUS_FINISHED_ERR, $records[$copies[0]['backupid']]->status);

// Verify other controllers remain untouched.
$this->assertEquals(backup::STATUS_AWAITING, $records[$copies[1]['backupid']]->status);
$this->assertEquals(backup::STATUS_REQUIRE_CONV, $records[$copies[1]['restoreid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_OK, $records[$copies[2]['backupid']]->status);
$this->assertEquals(backup::STATUS_REQUIRE_CONV, $records[$copies[2]['restoreid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_OK, $records[$copies[3]['restoreid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_OK, $records[$copies[3]['backupid']]->status);

// Verify that the restore associated with the failed backup is also marked as failed.
$this->assertEquals(backup::STATUS_FINISHED_ERR, $records[$copies[4]['restoreid']]->status);

// Verify that the unrelated controllers remain unchanged.
$this->assertEquals(backup::STATUS_AWAITING, $records[$unrelatedvanillacontrollers['backupid']]->status);
$this->assertEquals(backup::STATUS_REQUIRE_CONV, $records[$unrelatedvanillacontrollers['restoreid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_OK, $records[$unrelatedfinishedcontrollers['backupid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_OK, $records[$unrelatedfinishedcontrollers['restoreid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_ERR, $records[$unrelatedfailedcontrollers['backupid']]->status);
$this->assertEquals(backup::STATUS_FINISHED_ERR, $records[$unrelatedfailedcontrollers['restoreid']]->status);
}

/**
* Test creating a course copy.
*
* @covers ::create_copy
*/
public function test_create_copy() {

Expand Down Expand Up @@ -197,6 +340,8 @@ public function test_create_copy() {

/**
* Test getting the current copies.
*
* @covers ::get_copies
*/
public function test_get_copies() {
global $USER;
Expand Down Expand Up @@ -267,8 +412,69 @@ public function test_get_copies() {
$this->assertEmpty($copies);
}

/**
* Test getting the current copies when they are in an invalid state.
*
* @covers ::get_copies
*/
public function test_get_copies_invalid_state() {
global $DB, $USER;

// Mock up the form data.
$formdata = new \stdClass;
$formdata->courseid = $this->course->id;
$formdata->fullname = 'foo';
$formdata->shortname = 'bar';
$formdata->category = 1;
$formdata->visible = 1;
$formdata->startdate = 1582376400;
$formdata->enddate = 0;
$formdata->idnumber = '';
$formdata->userdata = 1;
$formdata->role_1 = 1;
$formdata->role_3 = 3;
$formdata->role_5 = 5;

$formdata2 = clone ($formdata);
$formdata2->shortname = 'tree';

// Create some copies.
$copydata = \copy_helper::process_formdata($formdata);
$result = \copy_helper::create_copy($copydata);
$copydata2 = \copy_helper::process_formdata($formdata2);
$result2 = \copy_helper::create_copy($copydata2);

$copies = \copy_helper::get_copies($USER->id);

// Verify get_copies gives back both backup controllers.
$this->assertEqualsCanonicalizing([$result['backupid'], $result2['backupid']], array_column($copies, 'backupid'));

// Set one of the backup controllers to failed, this should cause it to not be present.
\backup_controller::load_controller($result['backupid'])->set_status(backup::STATUS_FINISHED_ERR);
$copies = \copy_helper::get_copies($USER->id);

// Verify there is only one backup listed, and that it is not the failed one.
$this->assertEqualsCanonicalizing([$result2['backupid']], array_column($copies, 'backupid'));

// Set the controller back to awaiting.
\backup_controller::load_controller($result['backupid'])->set_status(backup::STATUS_AWAITING);
$copies = \copy_helper::get_copies($USER->id);

// Verify both backup controllers are back.
$this->assertEqualsCanonicalizing([$result['backupid'], $result2['backupid']], array_column($copies, 'backupid'));

// Delete the restore controller for one of the copies, this should cause it to not be present.
$DB->delete_records('backup_controllers', ['backupid' => $result['restoreid']]);
$copies = \copy_helper::get_copies($USER->id);

// Verify there is only one backup listed, and that it is not the failed one.
$this->assertEqualsCanonicalizing([$result2['backupid']], array_column($copies, 'backupid'));
}

/**
* Test getting the current copies for specific course.
*
* @covers ::get_copies
*/
public function test_get_copies_course() {
global $USER;
Expand Down Expand Up @@ -299,6 +505,8 @@ public function test_get_copies_course() {

/**
* Test getting the current copies if course has been deleted.
*
* @covers ::get_copies
*/
public function test_get_copies_course_deleted() {
global $USER;
Expand Down Expand Up @@ -329,7 +537,7 @@ public function test_get_copies_course_deleted() {
$this->assertEmpty($copies);
}

/*
/**
* Test course copy.
*/
public function test_course_copy() {
Expand Down Expand Up @@ -406,7 +614,7 @@ public function test_course_copy() {
$this->assertEquals(2, count($discussions));
}

/*
/**
* Test course copy, not including any users (or data).
*/
public function test_course_copy_no_users() {
Expand Down Expand Up @@ -475,7 +683,7 @@ public function test_course_copy_no_users() {

}

/*
/**
* Test course copy, including students and their data.
*/
public function test_course_copy_students_data() {
Expand Down Expand Up @@ -544,7 +752,7 @@ public function test_course_copy_students_data() {
$this->assertEquals($this->courseusers[0], $users[$this->courseusers[0]]->id);
}

/*
/**
* Test course copy, not including any users (or data).
*/
public function test_course_copy_no_data() {
Expand Down Expand Up @@ -612,7 +820,7 @@ public function test_course_copy_no_data() {
$this->assertEquals(count($this->courseusers), count($users));
}

/*
/**
* Test instantiation with incomplete formdata.
*/
public function test_malformed_instantiation() {
Expand Down

0 comments on commit 8516a49

Please sign in to comment.