MDL-44640 enrol_meta: sync when enrol method is updated
[moodle.git] / enrol / meta / tests / plugin_test.php
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/>.
17 /**
18  * Meta enrolment sync functional test.
19  *
20  * @package    enrol_meta
21  * @category   phpunit
22  * @copyright  2013 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 class enrol_meta_plugin_testcase extends advanced_testcase {
32     protected function enable_plugin() {
33         $enabled = enrol_get_plugins(true);
34         $enabled['meta'] = true;
35         $enabled = array_keys($enabled);
36         set_config('enrol_plugins_enabled', implode(',', $enabled));
37     }
39     protected function disable_plugin() {
40         $enabled = enrol_get_plugins(true);
41         unset($enabled['meta']);
42         $enabled = array_keys($enabled);
43         set_config('enrol_plugins_enabled', implode(',', $enabled));
44     }
46     protected function is_meta_enrolled($user, $enrol, $role = null) {
47         global $DB;
49         if (!$DB->record_exists('user_enrolments', array('enrolid'=>$enrol->id, 'userid'=>$user->id))) {
50             return false;
51         }
53         if ($role === null) {
54             return true;
55         }
57         return $this->has_role($user, $enrol, $role);
58     }
60     protected function has_role($user, $enrol, $role) {
61         global $DB;
63         $context = context_course::instance($enrol->courseid);
65         if ($role === false) {
66             if ($DB->record_exists('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_meta', 'itemid'=>$enrol->id))) {
67                 return false;
68             }
69         } else if (!$DB->record_exists('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'roleid'=>$role->id, 'component'=>'enrol_meta', 'itemid'=>$enrol->id))) {
70             return false;
71         }
73         return true;
74     }
76     public function test_sync() {
77         global $CFG, $DB;
79         $this->resetAfterTest(true);
81         $metalplugin = enrol_get_plugin('meta');
82         $manplugin = enrol_get_plugin('manual');
84         $user1 = $this->getDataGenerator()->create_user();
85         $user2 = $this->getDataGenerator()->create_user();
86         $user3 = $this->getDataGenerator()->create_user();
87         $user4 = $this->getDataGenerator()->create_user();
88         $user5 = $this->getDataGenerator()->create_user();
90         $course1 = $this->getDataGenerator()->create_course();
91         $course2 = $this->getDataGenerator()->create_course();
92         $course3 = $this->getDataGenerator()->create_course();
93         $course4 = $this->getDataGenerator()->create_course();
94         $manual1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
95         $manual2 = $DB->get_record('enrol', array('courseid'=>$course2->id, 'enrol'=>'manual'), '*', MUST_EXIST);
96         $manual3 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
97         $manual4 = $DB->get_record('enrol', array('courseid'=>$course4->id, 'enrol'=>'manual'), '*', MUST_EXIST);
99         $student = $DB->get_record('role', array('shortname'=>'student'));
100         $teacher = $DB->get_record('role', array('shortname'=>'teacher'));
101         $manager = $DB->get_record('role', array('shortname'=>'manager'));
103         $this->disable_plugin();
105         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
106         $this->getDataGenerator()->enrol_user($user2->id, $course1->id, $student->id);
107         $this->getDataGenerator()->enrol_user($user3->id, $course1->id, 0);
108         $this->getDataGenerator()->enrol_user($user4->id, $course1->id, $teacher->id);
109         $this->getDataGenerator()->enrol_user($user5->id, $course1->id, $manager->id);
111         $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $student->id);
112         $this->getDataGenerator()->enrol_user($user2->id, $course2->id, $teacher->id);
114         $this->assertEquals(7, $DB->count_records('user_enrolments'));
115         $this->assertEquals(6, $DB->count_records('role_assignments'));
117         set_config('syncall', 0, 'enrol_meta');
118         set_config('nosyncroleids', $manager->id, 'enrol_meta');
120         require_once($CFG->dirroot.'/enrol/meta/locallib.php');
122         enrol_meta_sync(null, false);
123         $this->assertEquals(7, $DB->count_records('user_enrolments'));
124         $this->assertEquals(6, $DB->count_records('role_assignments'));
126         $this->enable_plugin();
127         enrol_meta_sync(null, false);
128         $this->assertEquals(7, $DB->count_records('user_enrolments'));
129         $this->assertEquals(6, $DB->count_records('role_assignments'));
131         $e1 = $metalplugin->add_instance($course3, array('customint1'=>$course1->id));
132         $e2 = $metalplugin->add_instance($course3, array('customint1'=>$course2->id));
133         $e3 = $metalplugin->add_instance($course4, array('customint1'=>$course2->id));
134         $enrol1 = $DB->get_record('enrol', array('id'=>$e1));
135         $enrol2 = $DB->get_record('enrol', array('id'=>$e2));
136         $enrol3 = $DB->get_record('enrol', array('id'=>$e3));
138         enrol_meta_sync($course4->id, false);
139         $this->assertEquals(9, $DB->count_records('user_enrolments'));
140         $this->assertEquals(8, $DB->count_records('role_assignments'));
141         $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
142         $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher));
144         enrol_meta_sync(null, false);
145         $this->assertEquals(14, $DB->count_records('user_enrolments'));
146         $this->assertEquals(13, $DB->count_records('role_assignments'));
148         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
149         $this->assertTrue($this->is_meta_enrolled($user2, $enrol1, $student));
150         $this->assertFalse($this->is_meta_enrolled($user3, $enrol1));
151         $this->assertTrue($this->is_meta_enrolled($user4, $enrol1, $teacher));
152         $this->assertFalse($this->is_meta_enrolled($user5, $enrol1));
154         $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student));
155         $this->assertTrue($this->is_meta_enrolled($user2, $enrol2, $teacher));
157         $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
158         $this->assertTrue($this->is_meta_enrolled($user2, $enrol3, $teacher));
160         set_config('syncall', 1, 'enrol_meta');
161         enrol_meta_sync(null, false);
162         $this->assertEquals(16, $DB->count_records('user_enrolments'));
163         $this->assertEquals(13, $DB->count_records('role_assignments'));
165         $this->assertTrue($this->is_meta_enrolled($user3, $enrol1, false));
166         $this->assertTrue($this->is_meta_enrolled($user5, $enrol1, false));
168         $this->assertEquals(16, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
169         $this->disable_plugin();
170         $manplugin->unenrol_user($manual1, $user1->id);
171         $manplugin->unenrol_user($manual2, $user1->id);
173         $this->assertEquals(14, $DB->count_records('user_enrolments'));
174         $this->assertEquals(11, $DB->count_records('role_assignments'));
175         $this->assertEquals(14, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
177         $this->enable_plugin();
179         set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta');
180         enrol_meta_sync($course4->id, false);
181         $this->assertEquals(14, $DB->count_records('user_enrolments'));
182         $this->assertEquals(11, $DB->count_records('role_assignments'));
183         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
184         $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, $student));
185         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol3->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
187         enrol_meta_sync(null, false);
188         $this->assertEquals(14, $DB->count_records('user_enrolments'));
189         $this->assertEquals(11, $DB->count_records('role_assignments'));
190         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
191         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
192         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol1->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
193         $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, $student));
194         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol2->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
196         set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
197         enrol_meta_sync($course4->id, false);
198         $this->assertEquals(14, $DB->count_records('user_enrolments'));
199         $this->assertEquals(10, $DB->count_records('role_assignments'));
200         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
201         $this->assertTrue($this->is_meta_enrolled($user1, $enrol3, false));
202         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol3->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
204         enrol_meta_sync(null, false);
205         $this->assertEquals(14, $DB->count_records('user_enrolments'));
206         $this->assertEquals(8, $DB->count_records('role_assignments'));
207         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
208         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
209         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol1->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
210         $this->assertTrue($this->is_meta_enrolled($user1, $enrol2, false));
211         $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$enrol2->id, 'status'=>ENROL_USER_SUSPENDED, 'userid'=>$user1->id)));
213         set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
214         enrol_meta_sync($course4->id, false);
215         $this->assertEquals(13, $DB->count_records('user_enrolments'));
216         $this->assertEquals(8, $DB->count_records('role_assignments'));
217         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
218         $this->assertFalse($this->is_meta_enrolled($user1, $enrol3));
220         enrol_meta_sync(null, false);
221         $this->assertEquals(11, $DB->count_records('user_enrolments'));
222         $this->assertEquals(8, $DB->count_records('role_assignments'));
223         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
224         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
225         $this->assertFalse($this->is_meta_enrolled($user1, $enrol2));
228         // Now try sync triggered by events.
230         set_config('syncall', 1, 'enrol_meta');
232         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
233         $this->assertEquals(13, $DB->count_records('user_enrolments'));
234         $this->assertEquals(10, $DB->count_records('role_assignments'));
235         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
236         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
237         enrol_meta_sync(null, false);
238         $this->assertEquals(13, $DB->count_records('user_enrolments'));
239         $this->assertEquals(10, $DB->count_records('role_assignments'));
240         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
241         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
243         $manplugin->unenrol_user($manual1, $user1->id);
244         $this->assertEquals(11, $DB->count_records('user_enrolments'));
245         $this->assertEquals(8, $DB->count_records('role_assignments'));
246         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
247         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
248         enrol_meta_sync(null, false);
249         $this->assertEquals(11, $DB->count_records('user_enrolments'));
250         $this->assertEquals(8, $DB->count_records('role_assignments'));
251         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
252         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
254         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0);
255         $this->assertEquals(13, $DB->count_records('user_enrolments'));
256         $this->assertEquals(8, $DB->count_records('role_assignments'));
257         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
258         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
259         enrol_meta_sync(null, false);
260         $this->assertEquals(13, $DB->count_records('user_enrolments'));
261         $this->assertEquals(8, $DB->count_records('role_assignments'));
262         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
263         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
265         $manplugin->unenrol_user($manual1, $user1->id);
266         $this->assertEquals(11, $DB->count_records('user_enrolments'));
267         $this->assertEquals(8, $DB->count_records('role_assignments'));
268         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
269         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
270         enrol_meta_sync(null, false);
271         $this->assertEquals(11, $DB->count_records('user_enrolments'));
272         $this->assertEquals(8, $DB->count_records('role_assignments'));
273         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
274         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
276         set_config('syncall', 0, 'enrol_meta');
277         enrol_meta_sync(null, false);
278         $this->assertEquals(9, $DB->count_records('user_enrolments'));
279         $this->assertEquals(8, $DB->count_records('role_assignments'));
280         $this->assertEquals(9, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
281         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
283         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 0);
284         $this->assertEquals(10, $DB->count_records('user_enrolments'));
285         $this->assertEquals(8, $DB->count_records('role_assignments'));
286         $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
287         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
288         enrol_meta_sync(null, false);
289         $this->assertEquals(10, $DB->count_records('user_enrolments'));
290         $this->assertEquals(8, $DB->count_records('role_assignments'));
291         $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
292         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
294         role_assign($teacher->id, $user1->id, context_course::instance($course1->id)->id);
295         $this->assertEquals(11, $DB->count_records('user_enrolments'));
296         $this->assertEquals(10, $DB->count_records('role_assignments'));
297         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
298         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher));
299         enrol_meta_sync(null, false);
300         $this->assertEquals(11, $DB->count_records('user_enrolments'));
301         $this->assertEquals(10, $DB->count_records('role_assignments'));
302         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
303         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $teacher));
305         role_unassign($teacher->id, $user1->id, context_course::instance($course1->id)->id);
306         $this->assertEquals(10, $DB->count_records('user_enrolments'));
307         $this->assertEquals(8, $DB->count_records('role_assignments'));
308         $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
309         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
310         enrol_meta_sync(null, false);
311         $this->assertEquals(10, $DB->count_records('user_enrolments'));
312         $this->assertEquals(8, $DB->count_records('role_assignments'));
313         $this->assertEquals(10, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
314         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1, $student));
316         $manplugin->unenrol_user($manual1, $user1->id);
317         $this->assertEquals(9, $DB->count_records('user_enrolments'));
318         $this->assertEquals(8, $DB->count_records('role_assignments'));
319         $this->assertEquals(9, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
320         $this->assertFalse($this->is_meta_enrolled($user1, $enrol1));
322         set_config('syncall', 1, 'enrol_meta');
323         set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPEND, 'enrol_meta');
324         enrol_meta_sync(null, false);
325         $this->assertEquals(11, $DB->count_records('user_enrolments'));
326         $this->assertEquals(8, $DB->count_records('role_assignments'));
327         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
329         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
330         $this->assertEquals(13, $DB->count_records('user_enrolments'));
331         $this->assertEquals(10, $DB->count_records('role_assignments'));
332         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
333         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
334         enrol_meta_sync(null, false);
335         $this->assertEquals(13, $DB->count_records('user_enrolments'));
336         $this->assertEquals(10, $DB->count_records('role_assignments'));
337         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
338         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
340         $manplugin->update_user_enrol($manual1, $user1->id, ENROL_USER_SUSPENDED);
341         $this->assertEquals(13, $DB->count_records('user_enrolments'));
342         $this->assertEquals(10, $DB->count_records('role_assignments'));
343         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
344         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
345         enrol_meta_sync(null, false);
346         $this->assertEquals(13, $DB->count_records('user_enrolments'));
347         $this->assertEquals(10, $DB->count_records('role_assignments'));
348         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
349         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
351         $manplugin->unenrol_user($manual1, $user1->id);
352         $this->assertEquals(12, $DB->count_records('user_enrolments'));
353         $this->assertEquals(9, $DB->count_records('role_assignments'));
354         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
355         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
356         enrol_meta_sync(null, false);
357         $this->assertEquals(12, $DB->count_records('user_enrolments'));
358         $this->assertEquals(9, $DB->count_records('role_assignments'));
359         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
360         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
362         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
363         $this->assertEquals(13, $DB->count_records('user_enrolments'));
364         $this->assertEquals(10, $DB->count_records('role_assignments'));
365         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
366         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
367         enrol_meta_sync(null, false);
368         $this->assertEquals(13, $DB->count_records('user_enrolments'));
369         $this->assertEquals(10, $DB->count_records('role_assignments'));
370         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
371         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
373         set_config('syncall', 1, 'enrol_meta');
374         set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
375         enrol_meta_sync(null, false);
376         $this->assertEquals(13, $DB->count_records('user_enrolments'));
377         $this->assertEquals(10, $DB->count_records('role_assignments'));
378         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
380         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
381         $this->assertEquals(13, $DB->count_records('user_enrolments'));
382         $this->assertEquals(10, $DB->count_records('role_assignments'));
383         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
384         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
385         enrol_meta_sync(null, false);
386         $this->assertEquals(13, $DB->count_records('user_enrolments'));
387         $this->assertEquals(10, $DB->count_records('role_assignments'));
388         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
389         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
391         $manplugin->unenrol_user($manual1, $user1->id);
392         $this->assertEquals(12, $DB->count_records('user_enrolments'));
393         $this->assertEquals(8, $DB->count_records('role_assignments'));
394         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
395         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
396         enrol_meta_sync(null, false);
397         $this->assertEquals(12, $DB->count_records('user_enrolments'));
398         $this->assertEquals(8, $DB->count_records('role_assignments'));
399         $this->assertEquals(11, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
400         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, false));
402         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
403         $this->assertEquals(13, $DB->count_records('user_enrolments'));
404         $this->assertEquals(10, $DB->count_records('role_assignments'));
405         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
406         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
407         enrol_meta_sync(null, false);
408         $this->assertEquals(13, $DB->count_records('user_enrolments'));
409         $this->assertEquals(10, $DB->count_records('role_assignments'));
410         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
411         $this->assertTrue($this->is_meta_enrolled($user1, $enrol1, $student));
414         set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
415         enrol_meta_sync(null, false);
416         $this->assertEquals(13, $DB->count_records('user_enrolments'));
417         $this->assertEquals(10, $DB->count_records('role_assignments'));
418         $this->assertEquals(13, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
420         delete_course($course1, false);
421         $this->assertEquals(3, $DB->count_records('user_enrolments'));
422         $this->assertEquals(3, $DB->count_records('role_assignments'));
423         $this->assertEquals(3, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
424         enrol_meta_sync(null, false);
425         $this->assertEquals(3, $DB->count_records('user_enrolments'));
426         $this->assertEquals(3, $DB->count_records('role_assignments'));
427         $this->assertEquals(3, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
429         delete_course($course2, false);
430         $this->assertEquals(0, $DB->count_records('user_enrolments'));
431         $this->assertEquals(0, $DB->count_records('role_assignments'));
432         $this->assertEquals(0, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
433         enrol_meta_sync(null, false);
434         $this->assertEquals(0, $DB->count_records('user_enrolments'));
435         $this->assertEquals(0, $DB->count_records('role_assignments'));
436         $this->assertEquals(0, $DB->count_records('user_enrolments', array('status'=>ENROL_USER_ACTIVE)));
438         delete_course($course3, false);
439         delete_course($course4, false);
441     }
443     public function test_add_to_group() {
444         global $CFG, $DB;
446         require_once($CFG->dirroot.'/group/lib.php');
448         $this->resetAfterTest(true);
450         $metalplugin = enrol_get_plugin('meta');
452         $user1 = $this->getDataGenerator()->create_user();
453         $user4 = $this->getDataGenerator()->create_user();
455         $course1 = $this->getDataGenerator()->create_course();
456         $course2 = $this->getDataGenerator()->create_course();
457         $course3 = $this->getDataGenerator()->create_course();
458         $manualenrol1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
459         $manualenrol2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST);
461         $student = $DB->get_record('role', array('shortname' => 'student'));
462         $teacher = $DB->get_record('role', array('shortname' => 'teacher'));
464         $id = groups_create_group((object)array('name' => 'Group 1 in course 3', 'courseid' => $course3->id));
465         $group31 = $DB->get_record('groups', array('id' => $id), '*', MUST_EXIST);
466         $id = groups_create_group((object)array('name' => 'Group 2 in course 4', 'courseid' => $course3->id));
467         $group32 = $DB->get_record('groups', array('id' => $id), '*', MUST_EXIST);
469         $this->enable_plugin();
471         $e1 = $metalplugin->add_instance($course3, array('customint1' => $course1->id, 'customint2' => $group31->id));
472         $e2 = $metalplugin->add_instance($course3, array('customint1' => $course2->id, 'customint2' => $group32->id));
474         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $student->id);
475         $this->getDataGenerator()->enrol_user($user4->id, $course1->id, $teacher->id);
477         $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $student->id);
479         // Now make sure users are in the correct groups.
480         $this->assertTrue(groups_is_member($group31->id, $user1->id));
481         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user1->id,
482             'component' => 'enrol_meta', 'itemid' => $e1)));
483         $this->assertTrue(groups_is_member($group32->id, $user1->id));
484         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group32->id, 'userid' => $user1->id,
485             'component' => 'enrol_meta', 'itemid' => $e2)));
487         $this->assertTrue(groups_is_member($group31->id, $user4->id));
488         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user4->id,
489             'component' => 'enrol_meta', 'itemid' => $e1)));
491         // Make sure everything is the same after sync.
492         enrol_meta_sync(null, false);
493         $this->assertTrue(groups_is_member($group31->id, $user1->id));
494         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user1->id,
495             'component' => 'enrol_meta', 'itemid' => $e1)));
496         $this->assertTrue(groups_is_member($group32->id, $user1->id));
497         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group32->id, 'userid' => $user1->id,
498             'component' => 'enrol_meta', 'itemid' => $e2)));
500         $this->assertTrue(groups_is_member($group31->id, $user4->id));
501         $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $group31->id, 'userid' => $user4->id,
502             'component' => 'enrol_meta', 'itemid' => $e1)));
504         set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
506         // When user 1 is unenrolled from course1, he is removed from group31 but still present in group32.
507         enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user1->id);
508         $this->assertFalse(groups_is_member($group31->id, $user1->id));
509         $this->assertTrue(groups_is_member($group32->id, $user1->id));
510         $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1, '', true)); // He still has active enrolment.
511         // And the same after sync.
512         enrol_meta_sync(null, false);
513         $this->assertFalse(groups_is_member($group31->id, $user1->id));
514         $this->assertTrue(groups_is_member($group32->id, $user1->id));
515         $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1, '', true));
517         // Unenroll user1 from course2 and make sure he is completely unenrolled from course3.
518         enrol_get_plugin('manual')->unenrol_user($manualenrol2, $user1->id);
519         $this->assertFalse(groups_is_member($group32->id, $user1->id));
520         $this->assertFalse(is_enrolled(context_course::instance($course3->id), $user1));
522         set_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES, 'enrol_meta');
524         // When user is unenrolled in this case, he is still a member of a group (but enrolment is suspended).
525         enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user4->id);
526         $this->assertTrue(groups_is_member($group31->id, $user4->id));
527         $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user4));
528         $this->assertFalse(is_enrolled(context_course::instance($course3->id), $user4, '', true));
529         enrol_meta_sync(null, false);
530         $this->assertTrue(groups_is_member($group31->id, $user4->id));
531         $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user4));
532         $this->assertFalse(is_enrolled(context_course::instance($course3->id), $user4, '', true));
533     }
535     /**
536      * Enrol users from another course into a course where one of the members is already enrolled
537      * and is a member of the same group.
538      */
539     public function test_add_to_group_with_member() {
540         global $CFG, $DB;
542         require_once($CFG->dirroot.'/group/lib.php');
544         $this->resetAfterTest(true);
546         $metalplugin = enrol_get_plugin('meta');
548         $user1 = $this->getDataGenerator()->create_user();
549         $user2 = $this->getDataGenerator()->create_user();
551         $course1 = $this->getDataGenerator()->create_course();
552         $course2 = $this->getDataGenerator()->create_course();
553         $manualenrol1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
554         $manualenrol2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST);
556         $student = $DB->get_record('role', array('shortname' => 'student'));
558         $groupid = groups_create_group((object)array('name' => 'Grp', 'courseid' => $course2->id));
560         $this->enable_plugin();
561         set_config('unenrolaction', ENROL_EXT_REMOVED_UNENROL, 'enrol_meta');
563         // Manually enrol user1 to course2 and add him to group.
564         // Manually enrol user2 to course2 but do not add him to the group.
565         enrol_get_plugin('manual')->enrol_user($manualenrol2, $user1->id, $student->id);
566         groups_add_member($groupid, $user1->id);
567         enrol_get_plugin('manual')->enrol_user($manualenrol2, $user2->id, $student->id);
568         $this->assertTrue(groups_is_member($groupid, $user1->id));
569         $this->assertFalse(groups_is_member($groupid, $user2->id));
571         // Add instance of meta enrolment in course2 linking to course1 and enrol both users in course1.
572         $metalplugin->add_instance($course2, array('customint1' => $course1->id, 'customint2' => $groupid));
574         enrol_get_plugin('manual')->enrol_user($manualenrol1, $user1->id, $student->id);
575         enrol_get_plugin('manual')->enrol_user($manualenrol1, $user2->id, $student->id);
577         // Both users now should be members of the group.
578         $this->assertTrue(groups_is_member($groupid, $user1->id));
579         $this->assertTrue(groups_is_member($groupid, $user2->id));
581         // Ununerol both users from course1.
582         enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user1->id);
583         enrol_get_plugin('manual')->unenrol_user($manualenrol1, $user2->id);
585         // User1 should still be member of the group because he was added there manually. User2 should no longer be there.
586         $this->assertTrue(groups_is_member($groupid, $user1->id));
587         $this->assertFalse(groups_is_member($groupid, $user2->id));
589         // Assert that everything is the same after sync.
590         enrol_meta_sync();
592         $this->assertTrue(groups_is_member($groupid, $user1->id));
593         $this->assertFalse(groups_is_member($groupid, $user2->id));
595     }
597     /**
598      * Test user_enrolment_created event.
599      */
600     public function test_user_enrolment_created_event() {
601         global $DB;
603         $this->resetAfterTest();
605         $metaplugin = enrol_get_plugin('meta');
606         $user1 = $this->getDataGenerator()->create_user();
607         $course1 = $this->getDataGenerator()->create_course();
608         $course2 = $this->getDataGenerator()->create_course();
609         $student = $DB->get_record('role', array('shortname' => 'student'));
611         $e1 = $metaplugin->add_instance($course2, array('customint1' => $course1->id));
612         $enrol1 = $DB->get_record('enrol', array('id' => $e1));
614         // Enrol user and capture event.
615         $sink = $this->redirectEvents();
617         $metaplugin->enrol_user($enrol1, $user1->id, $student->id);
618         $events = $sink->get_events();
619         $sink->close();
620         $event = array_shift($events);
622         // Test Event.
623         $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id));
624         $this->assertInstanceOf('\core\event\user_enrolment_created', $event);
625         $this->assertEquals($dbuserenrolled->id, $event->objectid);
626         $this->assertEquals('user_enrolled', $event->get_legacy_eventname());
627         $expectedlegacyeventdata = $dbuserenrolled;
628         $expectedlegacyeventdata->enrol = 'meta';
629         $expectedlegacyeventdata->courseid = $course2->id;
630         $this->assertEventLegacyData($expectedlegacyeventdata, $event);
631         $this->assertEventContextNotUsed($event);
632     }
634     /**
635      * Test user_enrolment_deleted event.
636      */
637     public function test_user_enrolment_deleted_event() {
638         global $DB;
640         $this->resetAfterTest(true);
642         $metalplugin = enrol_get_plugin('meta');
643         $user1 = $this->getDataGenerator()->create_user();
644         $course1 = $this->getDataGenerator()->create_course();
645         $course2 = $this->getDataGenerator()->create_course();
646         $student = $DB->get_record('role', array('shortname'=>'student'));
648         $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
649         $enrol1 = $DB->get_record('enrol', array('id' => $e1));
651         // Enrol user.
652         $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
653         $this->assertEquals(1, $DB->count_records('user_enrolments'));
655         // Unenrol user and capture event.
656         $sink = $this->redirectEvents();
657         $metalplugin->unenrol_user($enrol1, $user1->id);
658         $events = $sink->get_events();
659         $sink->close();
660         $event = array_pop($events);
662         $this->assertEquals(0, $DB->count_records('user_enrolments'));
663         $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event);
664         $this->assertEquals('user_unenrolled', $event->get_legacy_eventname());
665         $this->assertEventContextNotUsed($event);
666     }
668     /**
669      * Test user_enrolment_updated event.
670      */
671     public function test_user_enrolment_updated_event() {
672         global $DB;
674         $this->resetAfterTest(true);
676         $metalplugin = enrol_get_plugin('meta');
677         $user1 = $this->getDataGenerator()->create_user();
678         $course1 = $this->getDataGenerator()->create_course();
679         $course2 = $this->getDataGenerator()->create_course();
680         $student = $DB->get_record('role', array('shortname'=>'student'));
682         $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
683         $enrol1 = $DB->get_record('enrol', array('id' => $e1));
685         // Enrol user.
686         $metalplugin->enrol_user($enrol1, $user1->id, $student->id);
687         $this->assertEquals(1, $DB->count_records('user_enrolments'));
689         // Updated enrolment for user and capture event.
690         $sink = $this->redirectEvents();
691         $metalplugin->update_user_enrol($enrol1, $user1->id, ENROL_USER_SUSPENDED, null, time());
692         $events = $sink->get_events();
693         $sink->close();
694         $event = array_shift($events);
696         // Test Event.
697         $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id));
698         $this->assertInstanceOf('\core\event\user_enrolment_updated', $event);
699         $this->assertEquals($dbuserenrolled->id, $event->objectid);
700         $this->assertEquals('user_enrol_modified', $event->get_legacy_eventname());
701         $expectedlegacyeventdata = $dbuserenrolled;
702         $expectedlegacyeventdata->enrol = 'meta';
703         $expectedlegacyeventdata->courseid = $course2->id;
704         $url = new \moodle_url('/enrol/editenrolment.php', array('ue' => $event->objectid));
705         $this->assertEquals($url, $event->get_url());
706         $this->assertEventLegacyData($expectedlegacyeventdata, $event);
707         $this->assertEventContextNotUsed($event);
708     }
710     /**
711      * Test that a new group with the name of the course is created.
712      */
713     public function test_enrol_meta_create_new_group() {
714         global $DB;
715         $this->resetAfterTest();
716         // Create two courses.
717         $course = $this->getDataGenerator()->create_course(array('fullname' => 'Mathematics'));
718         $course2 = $this->getDataGenerator()->create_course(array('fullname' => 'Physics'));
719         $metacourse = $this->getDataGenerator()->create_course(array('fullname' => 'All sciences'));
720         // Run the function.
721         $groupid = enrol_meta_create_new_group($metacourse->id, $course->id);
722         // Check the results.
723         $group = $DB->get_record('groups', array('id' => $groupid));
724         // The group name should match the course name.
725         $this->assertEquals('Mathematics course', $group->name);
726         // Group course id should match the course id.
727         $this->assertEquals($metacourse->id, $group->courseid);
729         // Create a group that will have the same name as the course.
730         $groupdata = new stdClass();
731         $groupdata->courseid = $metacourse->id;
732         $groupdata->name = 'Physics course';
733         groups_create_group($groupdata);
734         // Create a group for the course 2 in metacourse.
735         $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
736         $groupinfo = $DB->get_record('groups', array('id' => $groupid));
737         // Check that the group name has been changed.
738         $this->assertEquals('Physics course (2)', $groupinfo->name);
740         // Create a group for the course 2 in metacourse.
741         $groupid = enrol_meta_create_new_group($metacourse->id, $course2->id);
742         $groupinfo = $DB->get_record('groups', array('id' => $groupid));
743         // Check that the group name has been changed.
744         $this->assertEquals('Physics course (3)', $groupinfo->name);
745     }
747     /**
748      * Test that enrolment timestart-timeend is respected in meta course.
749      */
750     public function test_timeend() {
751         global $CFG, $DB;
753         $this->resetAfterTest(true);
755         $timeinfuture = time() + DAYSECS;
756         $timeinpast = time() - DAYSECS;
758         $metalplugin = enrol_get_plugin('meta');
759         $manplugin = enrol_get_plugin('manual');
761         $user1 = $this->getDataGenerator()->create_user();
762         $user2 = $this->getDataGenerator()->create_user();
763         $user3 = $this->getDataGenerator()->create_user();
764         $user4 = $this->getDataGenerator()->create_user();
765         $user5 = $this->getDataGenerator()->create_user();
767         $course1 = $this->getDataGenerator()->create_course();
768         $course2 = $this->getDataGenerator()->create_course();
769         $course3 = $this->getDataGenerator()->create_course();
770         $manual1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
772         $student = $DB->get_record('role', array('shortname' => 'student'));
774         $this->enable_plugin();
776         // Create instance of enrol_meta in course2 when there are no enrolments present.
777         $meta2id = $metalplugin->add_instance($course2, array('customint1' => $course1->id));
779         $expectedenrolments = array(
780             $user1->id => array(0, 0, ENROL_USER_ACTIVE),
781             $user2->id => array($timeinpast, 0, ENROL_USER_ACTIVE),
782             $user3->id => array(0, $timeinfuture, ENROL_USER_ACTIVE),
783             $user4->id => array($timeinpast, $timeinfuture, ENROL_USER_ACTIVE),
784             $user5->id => array(0, 0, ENROL_USER_SUSPENDED),
785         );
786         foreach ($expectedenrolments as $userid => $data) {
787             $expectedenrolments[$userid] = (object)(array('userid' => $userid) +
788                     array_combine(array('timestart', 'timeend', 'status'), $data));
789         }
791         // Enrol users manually in course 1.
792         foreach ($expectedenrolments as $e) {
793             $manplugin->enrol_user($manual1, $e->userid, $student->id, $e->timestart, $e->timeend, $e->status);
794         }
796         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $manual1->id), 'userid', 'userid, timestart, timeend, status');
797         $this->assertEquals($expectedenrolments, $enrolments);
799         // Make sure that the same enrolments are now present in course2 under meta enrolment.
800         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
801         $this->assertEquals($expectedenrolments, $enrolments);
803         // Create instance of enrol_meta in course3 and run sync.
804         $meta3id = $metalplugin->add_instance($course3, array('customint1' => $course1->id));
805         enrol_meta_sync($course3->id);
807         // Make sure that the same enrolments are now present in course3 under meta enrolment.
808         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
809         $this->assertEquals($expectedenrolments, $enrolments);
811         // Update some of the manual enrolments.
812         $expectedenrolments[$user2->id]->timestart = $timeinpast - 60;
813         $expectedenrolments[$user3->id]->timeend = $timeinfuture + 60;
814         $expectedenrolments[$user4->id]->status = ENROL_USER_SUSPENDED;
815         $expectedenrolments[$user5->id]->status = ENROL_USER_ACTIVE;
816         foreach ($expectedenrolments as $e) {
817             $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
818         }
820         // Make sure meta courses are also updated.
821         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
822         $this->assertEquals($expectedenrolments, $enrolments);
823         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
824         $this->assertEquals($expectedenrolments, $enrolments);
826         // Test meta sync. Imagine events are not working.
827         $sink = $this->redirectEvents();
828         $expectedenrolments[$user2->id]->timestart = $timeinpast;
829         $expectedenrolments[$user3->id]->timeend = $timeinfuture;
830         $expectedenrolments[$user4->id]->status = ENROL_USER_ACTIVE;
831         $expectedenrolments[$user5->id]->status = ENROL_USER_SUSPENDED;
832         foreach ($expectedenrolments as $e) {
833             $manplugin->update_user_enrol($manual1, $e->userid, $e->status, $e->timestart, $e->timeend);
834         }
836         // Make sure meta courses are updated only for the course that was synced.
837         enrol_meta_sync($course3->id);
839         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
840         $this->assertNotEquals($expectedenrolments, $enrolments);
842         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
843         $this->assertEquals($expectedenrolments, $enrolments);
845         $sink->close();
847         // Disable manual enrolment in course1 and make sure all user enrolments in course2 are suspended.
848         $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
849         $allsuspendedenrolemnts = array_combine(array_keys($expectedenrolments), array_fill(0, 5, ENROL_USER_SUSPENDED));
850         $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta2id), '', 'userid, status');
851         $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
853         $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
854         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta2id), '', 'userid, timestart, timeend, status');
855         $this->assertEquals($expectedenrolments, $enrolments);
857         // Disable events and repeat the same for course3 (testing sync):
858         $sink = $this->redirectEvents();
859         $manplugin->update_status($manual1, ENROL_INSTANCE_DISABLED);
860         enrol_meta_sync($course3->id);
861         $enrolmentstatuses = $DB->get_records_menu('user_enrolments', array('enrolid' => $meta3id), '', 'userid, status');
862         $this->assertEquals($allsuspendedenrolemnts, $enrolmentstatuses);
864         $manplugin->update_status($manual1, ENROL_INSTANCE_ENABLED);
865         enrol_meta_sync($course3->id);
866         $enrolments = $DB->get_records('user_enrolments', array('enrolid' => $meta3id), '', 'userid, timestart, timeend, status');
867         $this->assertEquals($expectedenrolments, $enrolments);
868         $sink->close();
869     }