@@ -131,6 +131,157 @@ protected function restore_to_new_course($backupid, $userid = 2) {
131131 return $ this ->restore_course ($ backupid , 0 , $ userid );
132132 }
133133
134+ /**
135+ * Restore a course.
136+ *
137+ * @param int $backupid The backup ID.
138+ * @param int $courseid The course ID to restore in, or 0.
139+ * @param int $userid The ID of the user performing the restore.
140+ * @param int $target THe target of the restore.
141+ *
142+ * @return stdClass The updated course object.
143+ */
144+ protected function async_restore_course ($ backupid , $ courseid , $ userid , $ target ) {
145+ global $ DB ;
146+
147+ if (!$ courseid ) {
148+ $ target = backup::TARGET_NEW_COURSE ;
149+ $ categoryid = $ DB ->get_field_sql ("SELECT MIN(id) FROM {course_categories} " );
150+ $ courseid = restore_dbops::create_new_course ('Tmp ' , 'tmp ' , $ categoryid );
151+ }
152+
153+ $ rc = new restore_controller ($ backupid , $ courseid , backup::INTERACTIVE_NO , backup::MODE_ASYNC , $ userid , $ target );
154+ $ target == backup::TARGET_NEW_COURSE ?: $ rc ->get_plan ()->get_setting ('overwrite_conf ' )->set_value (true );
155+ $ this ->assertTrue ($ rc ->execute_precheck ());
156+
157+ $ restoreid = $ rc ->get_restoreid ();
158+ $ rc ->destroy ();
159+
160+ // Create the adhoc task.
161+ $ asynctask = new \core \task \asynchronous_restore_task ();
162+ $ asynctask ->set_blocking (false );
163+ $ asynctask ->set_custom_data (array ('backupid ' => $ restoreid ));
164+ \core \task \manager::queue_adhoc_task ($ asynctask );
165+
166+ // We are expecting trace output during this test.
167+ $ this ->expectOutputRegex ("/ $ restoreid/ " );
168+
169+ // Execute adhoc task.
170+ $ now = time ();
171+ $ task = \core \task \manager::get_next_adhoc_task ($ now );
172+ $ this ->assertInstanceOf ('\\core \\task \\asynchronous_restore_task ' , $ task );
173+ $ task ->execute ();
174+ \core \task \manager::adhoc_task_complete ($ task );
175+
176+ $ course = $ DB ->get_record ('course ' , array ('id ' => $ rc ->get_courseid ()));
177+
178+ return $ course ;
179+ }
180+
181+ /**
182+ * Restore a course to an existing course.
183+ *
184+ * @param int $backupid The backup ID.
185+ * @param int $courseid The course ID to restore in.
186+ * @param int $userid The ID of the user performing the restore.
187+ * @param int $target The type of restore we are performing.
188+ * @return stdClass The updated course object.
189+ */
190+ protected function async_restore_to_existing_course ($ backupid , $ courseid ,
191+ $ userid = 2 , $ target = backup::TARGET_CURRENT_ADDING ) {
192+ return $ this ->async_restore_course ($ backupid , $ courseid , $ userid , $ target );
193+ }
194+
195+ /**
196+ * Restore a course to a new course.
197+ *
198+ * @param int $backupid The backup ID.
199+ * @param int $userid The ID of the user performing the restore.
200+ * @return stdClass The new course object.
201+ */
202+ protected function async_restore_to_new_course ($ backupid , $ userid = 2 ) {
203+ return $ this ->async_restore_course ($ backupid , 0 , $ userid , 0 );
204+ }
205+
206+ public function test_async_restore_existing_idnumber_in_new_course () {
207+ $ this ->resetAfterTest ();
208+
209+ $ dg = $ this ->getDataGenerator ();
210+ $ c1 = $ dg ->create_course (['idnumber ' => 'ABC ' ]);
211+ $ backupid = $ this ->backup_course ($ c1 ->id );
212+ $ c2 = $ this ->async_restore_to_new_course ($ backupid );
213+
214+ // The ID number is set empty.
215+ $ this ->assertEquals ('' , $ c2 ->idnumber );
216+ }
217+
218+ public function test_async_restore_course_info_in_existing_course () {
219+ global $ DB ;
220+ $ this ->resetAfterTest ();
221+ $ dg = $ this ->getDataGenerator ();
222+
223+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_shortname ' ));
224+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_fullname ' ));
225+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_startdate ' ));
226+
227+ $ startdate = mktime (12 , 0 , 0 , 7 , 1 , 2016 ); // 01-Jul-2016.
228+
229+ // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
230+ $ c1 = $ dg ->create_course (['shortname ' => 'SN ' , 'fullname ' => 'FN ' , 'summary ' => 'DESC ' , 'summaryformat ' => FORMAT_MOODLE ,
231+ 'startdate ' => $ startdate ]);
232+ $ chat1 = $ dg ->create_module ('chat ' , ['name ' => 'First ' , 'course ' => $ c1 ->id , 'chattime ' => $ c1 ->startdate + 1 * WEEKSECS ]);
233+ $ c2 = $ dg ->create_course (['shortname ' => 'A ' , 'fullname ' => 'B ' , 'summary ' => 'C ' , 'summaryformat ' => FORMAT_PLAIN ,
234+ 'startdate ' => $ startdate + 2 * WEEKSECS ]);
235+ $ chat2 = $ dg ->create_module ('chat ' , ['name ' => 'Second ' , 'course ' => $ c2 ->id , 'chattime ' => $ c2 ->startdate + 1 * WEEKSECS ]);
236+ $ backupid = $ this ->backup_course ($ c1 ->id );
237+
238+ // The information is restored but adapted because names are already taken.
239+ $ c2 = $ this ->async_restore_to_existing_course ($ backupid , $ c2 ->id );
240+ $ this ->assertEquals ('SN_1 ' , $ c2 ->shortname );
241+ $ this ->assertEquals ('FN copy 1 ' , $ c2 ->fullname );
242+ $ this ->assertEquals ('DESC ' , $ c2 ->summary );
243+ $ this ->assertEquals (FORMAT_MOODLE , $ c2 ->summaryformat );
244+ $ this ->assertEquals ($ startdate , $ c2 ->startdate );
245+
246+ // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
247+ // Their dates are exactly the same as they were in the original modules.
248+ $ restoredchat1 = $ DB ->get_record ('chat ' , ['name ' => 'First ' , 'course ' => $ c2 ->id ]);
249+ $ restoredchat2 = $ DB ->get_record ('chat ' , ['name ' => 'Second ' , 'course ' => $ c2 ->id ]);
250+ $ this ->assertEquals ($ chat1 ->chattime , $ restoredchat1 ->chattime );
251+ $ this ->assertEquals ($ chat2 ->chattime , $ restoredchat2 ->chattime );
252+ }
253+
254+ public function test_async_restore_course_info_in_existing_course_delete_first () {
255+ global $ DB ;
256+ $ this ->resetAfterTest ();
257+ $ dg = $ this ->getDataGenerator ();
258+
259+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_shortname ' ));
260+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_fullname ' ));
261+ $ this ->assertEquals (1 , get_config ('restore ' , 'restore_merge_course_startdate ' ));
262+
263+ $ startdate = mktime (12 , 0 , 0 , 7 , 1 , 2016 ); // 01-Jul-2016.
264+
265+ // Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
266+ $ c1 = $ dg ->create_course (['shortname ' => 'SN ' , 'fullname ' => 'FN ' , 'summary ' => 'DESC ' , 'summaryformat ' => FORMAT_MOODLE ,
267+ 'startdate ' => $ startdate ]);
268+ $ chat1 = $ dg ->create_module ('chat ' , ['name ' => 'First ' , 'course ' => $ c1 ->id , 'chattime ' => $ c1 ->startdate + 1 * WEEKSECS ]);
269+ $ c2 = $ dg ->create_course (['shortname ' => 'A ' , 'fullname ' => 'B ' , 'summary ' => 'C ' , 'summaryformat ' => FORMAT_PLAIN ,
270+ 'startdate ' => $ startdate + 2 * WEEKSECS ]);
271+ $ chat2 = $ dg ->create_module ('chat ' , ['name ' => 'Second ' , 'course ' => $ c2 ->id , 'chattime ' => $ c2 ->startdate + 1 * WEEKSECS ]);
272+ $ backupid = $ this ->backup_course ($ c1 ->id );
273+
274+ // The information is restored and the existing course settings is modified.
275+ $ c2 = $ this ->async_restore_to_existing_course ($ backupid , $ c2 ->id , 2 , backup::TARGET_CURRENT_DELETING );
276+ $ this ->assertEquals (FORMAT_MOODLE , $ c2 ->summaryformat );
277+
278+ // Now course2 should have a new forum with the original forum deleted.
279+ $ restoredchat1 = $ DB ->get_record ('chat ' , ['name ' => 'First ' , 'course ' => $ c2 ->id ]);
280+ $ restoredchat2 = $ DB ->get_record ('chat ' , ['name ' => 'Second ' , 'course ' => $ c2 ->id ]);
281+ $ this ->assertEquals ($ chat1 ->chattime , $ restoredchat1 ->chattime );
282+ $ this ->assertEmpty ($ restoredchat2 );
283+ }
284+
134285 public function test_restore_existing_idnumber_in_new_course () {
135286 $ this ->resetAfterTest ();
136287
0 commit comments