Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
namespace tool_recyclebin;
18
 
19
use mod_quiz\quiz_attempt;
20
use stdClass;
21
 
22
/**
23
 * Recycle bin course tests.
24
 *
25
 * @package    tool_recyclebin
26
 * @copyright  2015 University of Kent
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 */
29
class course_bin_test extends \advanced_testcase {
30
 
31
    /**
32
     * @var \stdClass $course
33
     */
34
    protected $course;
35
 
36
    /**
37
     * @var stdClass the quiz record
38
     */
39
    protected $quiz;
40
 
41
    /**
42
     * Setup for each test.
43
     */
44
    protected function setUp(): void {
45
        $this->resetAfterTest(true);
46
        $this->setAdminUser();
47
 
48
        // We want the course bin to be enabled.
49
        set_config('coursebinenable', 1, 'tool_recyclebin');
50
 
51
        $this->course = $this->getDataGenerator()->create_course();
52
        $this->quiz = $this->getDataGenerator()->get_plugin_generator('mod_quiz')->create_instance(array(
53
            'course' => $this->course->id, 'grade' => 100.0, 'sumgrades' => 1
54
        ));
55
    }
56
 
57
    /**
58
     * Check that our hook is called when an activity is deleted.
59
     */
60
    public function test_pre_course_module_delete_hook() {
61
        global $DB;
62
 
63
        // Should have nothing in the recycle bin.
64
        $this->assertEquals(0, $DB->count_records('tool_recyclebin_course'));
65
 
66
        // Delete the course module.
67
        course_delete_module($this->quiz->cmid);
68
 
69
        // Now, run the course module deletion adhoc task.
70
        \phpunit_util::run_all_adhoc_tasks();
71
 
72
        // Check the course module is now in the recycle bin.
73
        $this->assertEquals(1, $DB->count_records('tool_recyclebin_course'));
74
 
75
        // Try with the API.
76
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
77
        $this->assertEquals(1, count($recyclebin->get_items()));
78
    }
79
 
80
    /**
81
     * Test that we can restore recycle bin items.
82
     */
83
    public function test_restore() {
84
        global $DB;
85
 
86
        $startcount = $DB->count_records('course_modules');
87
 
88
        // Delete the course module.
89
        course_delete_module($this->quiz->cmid);
90
 
91
        // Try restoring.
92
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
93
        foreach ($recyclebin->get_items() as $item) {
94
            $recyclebin->restore_item($item);
95
        }
96
 
97
        // Check that it was restored and removed from the recycle bin.
98
        $this->assertEquals($startcount, $DB->count_records('course_modules'));
99
        $this->assertEquals(0, count($recyclebin->get_items()));
100
    }
101
 
102
    /**
103
     * Test that we can delete recycle bin items.
104
     */
105
    public function test_delete() {
106
        global $DB;
107
 
108
        $startcount = $DB->count_records('course_modules');
109
 
110
        // Delete the course module.
111
        course_delete_module($this->quiz->cmid);
112
 
113
        // Now, run the course module deletion adhoc task.
114
        \phpunit_util::run_all_adhoc_tasks();
115
 
116
        // Try purging.
117
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
118
        foreach ($recyclebin->get_items() as $item) {
119
            $recyclebin->delete_item($item);
120
        }
121
 
122
        // Item was deleted, so no course module was restored.
123
        $this->assertEquals($startcount - 1, $DB->count_records('course_modules'));
124
        $this->assertEquals(0, count($recyclebin->get_items()));
125
    }
126
 
127
    /**
128
     * Test the cleanup task.
129
     */
130
    public function test_cleanup_task() {
131
        global $DB;
132
 
133
        set_config('coursebinexpiry', WEEKSECS, 'tool_recyclebin');
134
 
135
        // Delete the quiz.
136
        course_delete_module($this->quiz->cmid);
137
 
138
        // Now, run the course module deletion adhoc task.
139
        \phpunit_util::run_all_adhoc_tasks();
140
 
141
        // Set deleted date to the distant past.
142
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
143
        foreach ($recyclebin->get_items() as $item) {
144
            $item->timecreated = time() - WEEKSECS;
145
            $DB->update_record('tool_recyclebin_course', $item);
146
        }
147
 
148
        // Create another module we are going to delete, but not alter the time it was placed in the recycle bin.
149
        $book = $this->getDataGenerator()->get_plugin_generator('mod_book')->create_instance(array(
150
            'course' => $this->course->id));
151
 
152
        course_delete_module($book->cmid);
153
 
154
        // Now, run the course module deletion adhoc task.
155
        \phpunit_util::run_all_adhoc_tasks();
156
 
157
        // Should have 2 items now.
158
        $this->assertEquals(2, count($recyclebin->get_items()));
159
 
160
        // Execute cleanup task.
161
        $this->expectOutputRegex("/\[tool_recyclebin\] Deleting item '\d+' from the course recycle bin/");
162
        $task = new \tool_recyclebin\task\cleanup_course_bin();
163
        $task->execute();
164
 
165
        // Should only have the book as it was not due to be deleted.
166
        $items = $recyclebin->get_items();
167
        $this->assertEquals(1, count($items));
168
        $deletedbook = reset($items);
169
        $this->assertEquals($book->name, $deletedbook->name);
170
    }
171
 
172
    /**
173
     * Provider for test_coursemodule_restore_with_userdata() and test_coursemodule_restore_without_userdata()
174
     *
175
     * Used to verify that recycle bin is immune to various settings. Provides plugin, name, value for
176
     * direct usage with set_config()
177
     */
178
    public function recycle_bin_settings_provider() {
179
        return [
180
            'backup/backup_auto_storage moodle' => [[
181
                (object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 0],
182
            ]],
183
 
184
            'backup/backup_auto_storage external' => [[
185
                (object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 1],
186
                (object)['plugin' => 'backup', 'name' => 'backup_auto_destination', 'value' => true],
187
            ]],
188
 
189
            'backup/backup_auto_storage mixed' => [[
190
                (object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 2],
191
                (object)['plugin' => 'backup', 'name' => 'backup_auto_destination', 'value' => true],
192
            ]],
193
 
194
            'restore/restore_general_users moodle' => [[
195
                (object)['plugin' => 'restore', 'name' => 'restore_general_users', 'value' => 0],
196
                (object)['plugin' => 'restore', 'name' => 'restore_general_groups', 'value' => 0],
197
            ]],
198
        ];
199
    }
200
 
201
    /**
202
     * Tests that user data is restored when module is restored.
203
     *
204
     * @dataProvider recycle_bin_settings_provider
205
     * @param array $settings array of plugin, name, value stdClass().
206
     */
207
    public function test_coursemodule_restore_with_userdata($settings) {
208
        // Force configuration changes from provider.
209
        foreach ($settings as $setting) {
210
            // Need to create a directory for backup_auto_destination.
211
            if ($setting->plugin === 'backup' && $setting->name === 'backup_auto_destination' && $setting->value === true) {
212
                $setting->value = make_request_directory();
213
            }
214
            set_config($setting->name, $setting->value, $setting->plugin);
215
        }
216
 
217
        $student = $this->getDataGenerator()->create_and_enrol($this->course, 'student');
218
        $this->setUser($student);
219
 
220
        set_config('backup_auto_users', true, 'backup');
221
        $this->create_quiz_attempt($this->quiz, $student);
222
 
223
        // Delete quiz.
224
        $cm = get_coursemodule_from_instance('quiz', $this->quiz->id);
225
        course_delete_module($cm->id);
226
        \phpunit_util::run_all_adhoc_tasks();
227
        $quizzes = get_coursemodules_in_course('quiz', $this->course->id);
228
        $this->assertEquals(0, count($quizzes));
229
 
230
        // Restore quiz.
231
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
232
        foreach ($recyclebin->get_items() as $item) {
233
            $recyclebin->restore_item($item);
234
        }
235
        $quizzes = get_coursemodules_in_course('quiz', $this->course->id);
236
        $this->assertEquals(1, count($quizzes));
237
        $cm = array_pop($quizzes);
238
 
239
        // Check if user quiz attempt data is restored.
240
        $attempts = quiz_get_user_attempts($cm->instance, $student->id);
241
        $this->assertEquals(1, count($attempts));
242
        $attempt = array_pop($attempts);
243
        $attemptobj = quiz_attempt::create($attempt->id);
244
        $this->assertEquals($student->id, $attemptobj->get_userid());
245
        $this->assertEquals(true, $attemptobj->is_finished());
246
    }
247
 
248
    /**
249
     * Test that the activity is NOT stored in bin when
250
     * in Automated backup setup settings "backup_auto_activities" is disabled.
251
     *
252
     * @dataProvider recycle_bin_settings_provider
253
     * @covers ::store_item
254
     */
255
    public function test_coursemodule_restore_with_activity_setting_disabled() {
256
 
257
        // Set the configuration to not include activities in the automated backup.
258
        set_config('backup_auto_activities', false, 'backup');
259
 
260
        // Delete the course module.
261
        course_delete_module($this->quiz->cmid);
262
 
263
        // Now, run the course module deletion adhoc task.
264
        \phpunit_util::run_all_adhoc_tasks();
265
 
266
        // Check there is no items in the recycle bin.
267
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
268
        $this->assertEquals(0, count($recyclebin->get_items()));
269
    }
270
 
271
    /**
272
     * Tests that user data is not restored when module is restored.
273
     *
274
     * @dataProvider recycle_bin_settings_provider
275
     * @param array $settings array of plugin, name, value stdClass().
276
     */
277
    public function test_coursemodule_restore_without_userdata($settings) {
278
        // Force configuration changes from provider.
279
        foreach ($settings as $setting) {
280
            // Need to create a directory for backup_auto_destination.
281
            if ($setting->plugin === 'backup' && $setting->name === 'backup_auto_destination' && $setting->value === true) {
282
                $setting->value = make_request_directory();
283
            }
284
            set_config($setting->name, $setting->value, $setting->plugin);
285
        }
286
 
287
        $student = $this->getDataGenerator()->create_and_enrol($this->course, 'student');
288
        $this->setUser($student);
289
 
290
        set_config('backup_auto_users', false, 'backup');
291
        $this->create_quiz_attempt($this->quiz, $student);
292
 
293
        // Delete quiz.
294
        $cm = get_coursemodule_from_instance('quiz', $this->quiz->id);
295
        course_delete_module($cm->id);
296
        \phpunit_util::run_all_adhoc_tasks();
297
        $quizzes = get_coursemodules_in_course('quiz', $this->course->id);
298
        $this->assertEquals(0, count($quizzes));
299
 
300
        // Restore quiz.
301
        $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
302
        foreach ($recyclebin->get_items() as $item) {
303
            $recyclebin->restore_item($item);
304
        }
305
        $quizzes = get_coursemodules_in_course('quiz', $this->course->id);
306
        $this->assertEquals(1, count($quizzes));
307
        $cm = array_pop($quizzes);
308
 
309
        // Check if user quiz attempt data is restored.
310
        $attempts = quiz_get_user_attempts($cm->instance, $student->id);
311
        $this->assertEquals(0, count($attempts));
312
    }
313
 
314
    /**
315
     * Add a question to quiz and create a quiz attempt.
316
     * @param \stdClass $quiz Quiz
317
     * @param \stdClass $student User
318
     * @throws coding_exception
319
     * @throws moodle_exception
320
     */
321
    private function create_quiz_attempt($quiz, $student) {
322
        // Add Question.
323
        $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
324
        $cat = $questiongenerator->create_question_category();
325
        $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
326
        quiz_add_quiz_question($numq->id, $quiz);
327
 
328
        // Create quiz attempt.
329
        $quizobj = \mod_quiz\quiz_settings::create($quiz->id, $student->id);
330
        $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
331
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
332
        $timenow = time();
333
        $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id);
334
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
335
        quiz_attempt_save_started($quizobj, $quba, $attempt);
336
        $attemptobj = quiz_attempt::create($attempt->id);
337
        $tosubmit = array(1 => array('answer' => '0'));
338
        $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
339
        $attemptobj = quiz_attempt::create($attempt->id);
340
        $attemptobj->process_finish($timenow, false);
341
    }
342
}