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 core;
18
 
19
/**
20
 * Unit tests for session manager class.
21
 *
22
 * @package    core
23
 * @category   test
24
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
class session_manager_test extends \advanced_testcase {
28
    public function test_start() {
29
        $this->resetAfterTest();
30
        // Session must be started only once...
31
        \core\session\manager::start();
32
        $this->assertDebuggingCalled('Session was already started!', DEBUG_DEVELOPER);
33
    }
34
 
35
    public function test_init_empty_session() {
36
        global $SESSION, $USER;
37
        $this->resetAfterTest();
38
 
39
        $user = $this->getDataGenerator()->create_user();
40
 
41
        $SESSION->test = true;
42
        $this->assertTrue($GLOBALS['SESSION']->test);
43
        $this->assertTrue($_SESSION['SESSION']->test);
44
 
45
        \core\session\manager::set_user($user);
46
        $this->assertSame($user, $USER);
47
        $this->assertSame($user, $GLOBALS['USER']);
48
        $this->assertSame($user, $_SESSION['USER']);
49
 
50
        \core\session\manager::init_empty_session();
51
 
52
        $this->assertInstanceOf('stdClass', $SESSION);
53
        $this->assertEmpty((array)$SESSION);
54
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
55
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
56
 
57
        $this->assertInstanceOf('stdClass', $USER);
58
        $this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);
59
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
60
        $this->assertSame($GLOBALS['USER'], $USER);
61
 
62
        // Now test how references work.
63
 
64
        $GLOBALS['SESSION'] = new \stdClass();
65
        $GLOBALS['SESSION']->test = true;
66
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
67
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
68
 
69
        $SESSION = new \stdClass();
70
        $SESSION->test2 = true;
71
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
72
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
73
 
74
        $_SESSION['SESSION'] = new \stdClass();
75
        $_SESSION['SESSION']->test3 = true;
76
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
77
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
78
 
79
        $GLOBALS['USER'] = new \stdClass();
80
        $GLOBALS['USER']->test = true;
81
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
82
        $this->assertSame($GLOBALS['USER'], $USER);
83
 
84
        $USER = new \stdClass();
85
        $USER->test2 = true;
86
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
87
        $this->assertSame($GLOBALS['USER'], $USER);
88
 
89
        $_SESSION['USER'] = new \stdClass();
90
        $_SESSION['USER']->test3 = true;
91
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
92
        $this->assertSame($GLOBALS['USER'], $USER);
93
    }
94
 
95
    public function test_set_user() {
96
        global $USER;
97
        $this->resetAfterTest();
98
 
99
        $this->assertEquals(0, $USER->id);
100
 
101
        $user = $this->getDataGenerator()->create_user();
102
        $this->assertObjectHasProperty('description', $user);
103
        $this->assertObjectHasProperty('password', $user);
104
 
105
        \core\session\manager::set_user($user);
106
 
107
        $this->assertEquals($user->id, $USER->id);
108
        $this->assertObjectNotHasProperty('description', $user);
109
        $this->assertObjectNotHasProperty('password', $user);
110
        $this->assertObjectHasProperty('sesskey', $user);
111
        $this->assertSame($user, $GLOBALS['USER']);
112
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
113
        $this->assertSame($GLOBALS['USER'], $USER);
114
    }
115
 
116
    public function test_login_user() {
117
        global $USER;
118
        $this->resetAfterTest();
119
 
120
        $this->assertEquals(0, $USER->id);
121
 
122
        $user = $this->getDataGenerator()->create_user();
123
 
124
        @\core\session\manager::login_user($user); // Ignore header error messages.
125
        $this->assertEquals($user->id, $USER->id);
126
 
127
        $this->assertObjectNotHasProperty('description', $user);
128
        $this->assertObjectNotHasProperty('password', $user);
129
        $this->assertSame($user, $GLOBALS['USER']);
130
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
131
        $this->assertSame($GLOBALS['USER'], $USER);
132
    }
133
 
134
    public function test_terminate_current() {
135
        global $USER, $SESSION;
136
        $this->resetAfterTest();
137
 
138
        $this->setAdminUser();
139
        \core\session\manager::terminate_current();
140
        $this->assertEquals(0, $USER->id);
141
 
142
        $this->assertInstanceOf('stdClass', $SESSION);
143
        $this->assertEmpty((array)$SESSION);
144
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
145
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
146
 
147
        $this->assertInstanceOf('stdClass', $USER);
148
        $this->assertEqualsCanonicalizing(array('id' => 0, 'mnethostid' => 1), (array)$USER);
149
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
150
        $this->assertSame($GLOBALS['USER'], $USER);
151
    }
152
 
153
    public function test_write_close() {
154
        global $USER;
155
        $this->resetAfterTest();
156
 
157
        // Just make sure no errors and $USER->id is kept
158
        $this->setAdminUser();
159
        $userid = $USER->id;
160
        \core\session\manager::write_close();
161
        $this->assertSame($userid, $USER->id);
162
 
163
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
164
        $this->assertSame($GLOBALS['USER'], $USER);
165
    }
166
 
167
    public function test_session_exists() {
168
        global $CFG, $DB;
169
        $this->resetAfterTest();
170
 
171
        $this->assertFalse(\core\session\manager::session_exists('abc'));
172
 
173
        $user = $this->getDataGenerator()->create_user();
174
        $guest = guest_user();
175
 
176
        // The file handler is used by default, so let's fake the data somehow.
177
        $sid = md5('hokus');
178
        mkdir("$CFG->dataroot/sessions/", $CFG->directorypermissions, true);
179
        touch("$CFG->dataroot/sessions/sess_$sid");
180
 
181
        $this->assertFalse(\core\session\manager::session_exists($sid));
182
 
183
        $record = new \stdClass();
184
        $record->userid = 0;
185
        $record->sid = $sid;
186
        $record->timecreated = time();
187
        $record->timemodified = $record->timecreated;
188
        $record->id = $DB->insert_record('sessions', $record);
189
 
190
        $this->assertTrue(\core\session\manager::session_exists($sid));
191
 
192
        $record->timecreated = time() - $CFG->sessiontimeout - 100;
193
        $record->timemodified = $record->timecreated + 10;
194
        $DB->update_record('sessions', $record);
195
 
196
        $this->assertTrue(\core\session\manager::session_exists($sid));
197
 
198
        $record->userid = $guest->id;
199
        $DB->update_record('sessions', $record);
200
 
201
        $this->assertTrue(\core\session\manager::session_exists($sid));
202
 
203
        $record->userid = $user->id;
204
        $DB->update_record('sessions', $record);
205
 
206
        $this->assertFalse(\core\session\manager::session_exists($sid));
207
 
208
        $CFG->sessiontimeout = $CFG->sessiontimeout + 3000;
209
 
210
        $this->assertTrue(\core\session\manager::session_exists($sid));
211
    }
212
 
213
    public function test_touch_session() {
214
        global $DB;
215
        $this->resetAfterTest();
216
 
217
        $sid = md5('hokus');
218
        $record = new \stdClass();
219
        $record->state        = 0;
220
        $record->sid          = $sid;
221
        $record->sessdata     = null;
222
        $record->userid       = 2;
223
        $record->timecreated  = time() - 60*60;
224
        $record->timemodified = time() - 30;
225
        $record->firstip      = $record->lastip = '10.0.0.1';
226
        $record->id = $DB->insert_record('sessions', $record);
227
 
228
        $now = time();
229
        \core\session\manager::touch_session($sid);
230
        $updated = $DB->get_field('sessions', 'timemodified', array('id'=>$record->id));
231
 
232
        $this->assertGreaterThanOrEqual($now, $updated);
233
        $this->assertLessThanOrEqual(time(), $updated);
234
    }
235
 
236
    public function test_kill_session() {
237
        global $DB, $USER;
238
        $this->resetAfterTest();
239
 
240
        $this->setAdminUser();
241
        $userid = $USER->id;
242
 
243
        $sid = md5('hokus');
244
        $record = new \stdClass();
245
        $record->state        = 0;
246
        $record->sid          = $sid;
247
        $record->sessdata     = null;
248
        $record->userid       = $userid;
249
        $record->timecreated  = time() - 60*60;
250
        $record->timemodified = time() - 30;
251
        $record->firstip      = $record->lastip = '10.0.0.1';
252
        $DB->insert_record('sessions', $record);
253
 
254
        $record->userid       = 0;
255
        $record->sid          = md5('pokus');
256
        $DB->insert_record('sessions', $record);
257
 
258
        $this->assertEquals(2, $DB->count_records('sessions'));
259
 
260
        \core\session\manager::kill_session($sid);
261
 
262
        $this->assertEquals(1, $DB->count_records('sessions'));
263
        $this->assertFalse($DB->record_exists('sessions', array('sid'=>$sid)));
264
 
265
        $this->assertSame($userid, $USER->id);
266
    }
267
 
268
    public function test_kill_user_sessions() {
269
        global $DB, $USER;
270
        $this->resetAfterTest();
271
 
272
        $this->setAdminUser();
273
        $userid = $USER->id;
274
 
275
        $sid = md5('hokus');
276
        $record = new \stdClass();
277
        $record->state        = 0;
278
        $record->sid          = $sid;
279
        $record->sessdata     = null;
280
        $record->userid       = $userid;
281
        $record->timecreated  = time() - 60*60;
282
        $record->timemodified = time() - 30;
283
        $record->firstip      = $record->lastip = '10.0.0.1';
284
        $DB->insert_record('sessions', $record);
285
 
286
        $record->sid          = md5('hokus2');
287
        $DB->insert_record('sessions', $record);
288
 
289
        $record->userid       = 0;
290
        $record->sid          = md5('pokus');
291
        $DB->insert_record('sessions', $record);
292
 
293
        $this->assertEquals(3, $DB->count_records('sessions'));
294
 
295
        \core\session\manager::kill_user_sessions($userid);
296
 
297
        $this->assertEquals(1, $DB->count_records('sessions'));
298
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $userid)));
299
 
300
        $record->userid       = $userid;
301
        $record->sid          = md5('pokus3');
302
        $DB->insert_record('sessions', $record);
303
 
304
        $record->userid       = $userid;
305
        $record->sid          = md5('pokus4');
306
        $DB->insert_record('sessions', $record);
307
 
308
        $record->userid       = $userid;
309
        $record->sid          = md5('pokus5');
310
        $DB->insert_record('sessions', $record);
311
 
312
        $this->assertEquals(3, $DB->count_records('sessions', array('userid' => $userid)));
313
 
314
        \core\session\manager::kill_user_sessions($userid, md5('pokus5'));
315
 
316
        $this->assertEquals(1, $DB->count_records('sessions', array('userid' => $userid)));
317
        $this->assertEquals(1, $DB->count_records('sessions', array('userid' => $userid, 'sid' => md5('pokus5'))));
318
    }
319
 
320
    public function test_apply_concurrent_login_limit() {
321
        global $DB;
322
        $this->resetAfterTest();
323
 
324
        $user1 = $this->getDataGenerator()->create_user();
325
        $user2 = $this->getDataGenerator()->create_user();
326
        $guest = guest_user();
327
 
328
        $record = new \stdClass();
329
        $record->state        = 0;
330
        $record->sessdata     = null;
331
        $record->userid       = $user1->id;
332
        $record->timemodified = time();
333
        $record->firstip      = $record->lastip = '10.0.0.1';
334
 
335
        $record->sid = md5('hokus1');
336
        $record->timecreated = 20;
337
        $DB->insert_record('sessions', $record);
338
        $record->sid = md5('hokus2');
339
        $record->timecreated = 10;
340
        $DB->insert_record('sessions', $record);
341
        $record->sid = md5('hokus3');
342
        $record->timecreated = 30;
343
        $DB->insert_record('sessions', $record);
344
 
345
        $record->userid = $user2->id;
346
        $record->sid = md5('pokus1');
347
        $record->timecreated = 20;
348
        $DB->insert_record('sessions', $record);
349
        $record->sid = md5('pokus2');
350
        $record->timecreated = 10;
351
        $DB->insert_record('sessions', $record);
352
        $record->sid = md5('pokus3');
353
        $record->timecreated = 30;
354
        $DB->insert_record('sessions', $record);
355
 
356
        $record->timecreated = 10;
357
        $record->userid = $guest->id;
358
        $record->sid = md5('g1');
359
        $DB->insert_record('sessions', $record);
360
        $record->sid = md5('g2');
361
        $DB->insert_record('sessions', $record);
362
        $record->sid = md5('g3');
363
        $DB->insert_record('sessions', $record);
364
 
365
        $record->userid = 0;
366
        $record->sid = md5('nl1');
367
        $DB->insert_record('sessions', $record);
368
        $record->sid = md5('nl2');
369
        $DB->insert_record('sessions', $record);
370
        $record->sid = md5('nl3');
371
        $DB->insert_record('sessions', $record);
372
 
373
        set_config('limitconcurrentlogins', 0);
374
        $this->assertCount(12, $DB->get_records('sessions'));
375
 
376
        \core\session\manager::apply_concurrent_login_limit($user1->id);
377
        \core\session\manager::apply_concurrent_login_limit($user2->id);
378
        \core\session\manager::apply_concurrent_login_limit($guest->id);
379
        \core\session\manager::apply_concurrent_login_limit(0);
380
        $this->assertCount(12, $DB->get_records('sessions'));
381
 
382
        set_config('limitconcurrentlogins', -1);
383
 
384
        \core\session\manager::apply_concurrent_login_limit($user1->id);
385
        \core\session\manager::apply_concurrent_login_limit($user2->id);
386
        \core\session\manager::apply_concurrent_login_limit($guest->id);
387
        \core\session\manager::apply_concurrent_login_limit(0);
388
        $this->assertCount(12, $DB->get_records('sessions'));
389
 
390
        set_config('limitconcurrentlogins', 2);
391
 
392
        \core\session\manager::apply_concurrent_login_limit($user1->id);
393
        $this->assertCount(11, $DB->get_records('sessions'));
394
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
395
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
396
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
397
 
398
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
399
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
400
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
401
        set_config('limitconcurrentlogins', 2);
402
        \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
403
        $this->assertCount(10, $DB->get_records('sessions'));
404
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
405
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
406
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
407
 
408
        \core\session\manager::apply_concurrent_login_limit($guest->id);
409
        \core\session\manager::apply_concurrent_login_limit(0);
410
        $this->assertCount(10, $DB->get_records('sessions'));
411
 
412
        set_config('limitconcurrentlogins', 1);
413
 
414
        \core\session\manager::apply_concurrent_login_limit($user1->id, md5('grrr'));
415
        $this->assertCount(9, $DB->get_records('sessions'));
416
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
417
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
418
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
419
 
420
        \core\session\manager::apply_concurrent_login_limit($user1->id);
421
        $this->assertCount(9, $DB->get_records('sessions'));
422
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 20)));
423
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 30)));
424
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user1->id, 'timecreated' => 10)));
425
 
426
        \core\session\manager::apply_concurrent_login_limit($user2->id, md5('pokus2'));
427
        $this->assertCount(8, $DB->get_records('sessions'));
428
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
429
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
430
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
431
 
432
        \core\session\manager::apply_concurrent_login_limit($user2->id);
433
        $this->assertCount(8, $DB->get_records('sessions'));
434
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 20)));
435
        $this->assertFalse($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 30)));
436
        $this->assertTrue($DB->record_exists('sessions', array('userid' => $user2->id, 'timecreated' => 10)));
437
 
438
        \core\session\manager::apply_concurrent_login_limit($guest->id);
439
        \core\session\manager::apply_concurrent_login_limit(0);
440
        $this->assertCount(8, $DB->get_records('sessions'));
441
    }
442
 
443
    public function test_kill_all_sessions() {
444
        global $DB, $USER;
445
        $this->resetAfterTest();
446
 
447
        $this->setAdminUser();
448
        $userid = $USER->id;
449
 
450
        $sid = md5('hokus');
451
        $record = new \stdClass();
452
        $record->state        = 0;
453
        $record->sid          = $sid;
454
        $record->sessdata     = null;
455
        $record->userid       = $userid;
456
        $record->timecreated  = time() - 60*60;
457
        $record->timemodified = time() - 30;
458
        $record->firstip      = $record->lastip = '10.0.0.1';
459
        $DB->insert_record('sessions', $record);
460
 
461
        $record->sid          = md5('hokus2');
462
        $DB->insert_record('sessions', $record);
463
 
464
        $record->userid       = 0;
465
        $record->sid          = md5('pokus');
466
        $DB->insert_record('sessions', $record);
467
 
468
        $this->assertEquals(3, $DB->count_records('sessions'));
469
 
470
        \core\session\manager::kill_all_sessions();
471
 
472
        $this->assertEquals(0, $DB->count_records('sessions'));
473
        $this->assertSame(0, $USER->id);
474
    }
475
 
476
    public function test_gc() {
477
        global $CFG, $DB, $USER;
478
        $this->resetAfterTest();
479
 
480
        $this->setAdminUser();
481
        $adminid = $USER->id;
482
        $this->setGuestUser();
483
        $guestid = $USER->id;
484
        $this->setUser(0);
485
 
486
        $CFG->sessiontimeout = 60*10;
487
 
488
        $record = new \stdClass();
489
        $record->state        = 0;
490
        $record->sid          = md5('hokus1');
491
        $record->sessdata     = null;
492
        $record->userid       = $adminid;
493
        $record->timecreated  = time() - 60*60;
494
        $record->timemodified = time() - 30;
495
        $record->firstip      = $record->lastip = '10.0.0.1';
496
        $r1 = $DB->insert_record('sessions', $record);
497
 
498
        $record->sid          = md5('hokus2');
499
        $record->userid       = $adminid;
500
        $record->timecreated  = time() - 60*60;
501
        $record->timemodified = time() - 60*20;
502
        $r2 = $DB->insert_record('sessions', $record);
503
 
504
        $record->sid          = md5('hokus3');
505
        $record->userid       = $guestid;
506
        $record->timecreated  = time() - 60*60*60;
507
        $record->timemodified = time() - 60*20;
508
        $r3 = $DB->insert_record('sessions', $record);
509
 
510
        $record->sid          = md5('hokus4');
511
        $record->userid       = $guestid;
512
        $record->timecreated  = time() - 60*60*60;
513
        $record->timemodified = time() - 60*10*5 - 60;
514
        $r4 = $DB->insert_record('sessions', $record);
515
 
516
        $record->sid          = md5('hokus5');
517
        $record->userid       = 0;
518
        $record->timecreated  = time() - 60*5;
519
        $record->timemodified = time() - 60*5;
520
        $r5 = $DB->insert_record('sessions', $record);
521
 
522
        $record->sid          = md5('hokus6');
523
        $record->userid       = 0;
524
        $record->timecreated  = time() - 60*60;
525
        $record->timemodified = time() - 60*10 -10;
526
        $r6 = $DB->insert_record('sessions', $record);
527
 
528
        $record->sid          = md5('hokus7');
529
        $record->userid       = 0;
530
        $record->timecreated  = time() - 60*60;
531
        $record->timemodified = time() - 60*9;
532
        $r7 = $DB->insert_record('sessions', $record);
533
 
534
        \core\session\manager::gc();
535
 
536
        $this->assertTrue($DB->record_exists('sessions', array('id'=>$r1)));
537
        $this->assertFalse($DB->record_exists('sessions', array('id'=>$r2)));
538
        $this->assertTrue($DB->record_exists('sessions', array('id'=>$r3)));
539
        $this->assertFalse($DB->record_exists('sessions', array('id'=>$r4)));
540
        $this->assertFalse($DB->record_exists('sessions', array('id'=>$r5)));
541
        $this->assertFalse($DB->record_exists('sessions', array('id'=>$r6)));
542
        $this->assertTrue($DB->record_exists('sessions', array('id'=>$r7)));
543
    }
544
 
545
    /**
546
     * Test loginas.
547
     * @copyright  2103 Rajesh Taneja <rajesh@moodle.com>
548
     */
549
    public function test_loginas() {
550
        global $USER, $SESSION;
551
        $this->resetAfterTest();
552
 
553
        // Set current user as Admin user and save it for later use.
554
        $this->setAdminUser();
555
        $adminuser = $USER;
556
        $adminsession = $SESSION;
557
        $user = $this->getDataGenerator()->create_user();
558
        $_SESSION['extra'] = true;
559
 
560
        // Try admin loginas this user in system context.
561
        $this->assertObjectNotHasProperty('realuser', $USER);
562
        \core\session\manager::loginas($user->id, \context_system::instance());
563
 
564
        $this->assertSame($user->id, $USER->id);
565
        $this->assertEquals(\context_system::instance(), $USER->loginascontext);
566
        $this->assertSame($adminuser->id, $USER->realuser);
567
        $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
568
        $this->assertSame($GLOBALS['USER'], $USER);
569
        $this->assertNotSame($adminuser, $_SESSION['REALUSER']);
570
        $this->assertEquals($adminuser, $_SESSION['REALUSER']);
571
 
572
        $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
573
        $this->assertSame($GLOBALS['SESSION'], $SESSION);
574
        $this->assertNotSame($adminsession, $_SESSION['REALSESSION']);
575
        $this->assertEquals($adminsession, $_SESSION['REALSESSION']);
576
 
577
        $this->assertArrayNotHasKey('extra', $_SESSION);
578
 
579
        // Set user as current user and login as admin user in course context.
580
        \core\session\manager::init_empty_session();
581
        $this->setUser($user);
582
        $this->assertNotEquals($adminuser->id, $USER->id);
583
        $course = $this->getDataGenerator()->create_course();
584
        $coursecontext = \context_course::instance($course->id);
585
 
586
        // Catch event triggered.
587
        $sink = $this->redirectEvents();
588
        \core\session\manager::loginas($adminuser->id, $coursecontext);
589
        $events = $sink->get_events();
590
        $sink->close();
591
        $event = array_pop($events);
592
 
593
        $this->assertSame($adminuser->id, $USER->id);
594
        $this->assertSame($coursecontext, $USER->loginascontext);
595
        $this->assertSame($user->id, $USER->realuser);
596
 
597
        // Test event captured has proper information.
598
        $this->assertInstanceOf('\core\event\user_loggedinas', $event);
599
        $this->assertSame($user->id, $event->objectid);
600
        $this->assertSame($adminuser->id, $event->relateduserid);
601
        $this->assertSame($course->id, $event->courseid);
602
        $this->assertEquals($coursecontext, $event->get_context());
603
        $oldfullname = fullname($user, true);
604
        $newfullname = fullname($adminuser, true);
605
    }
606
 
607
    public function test_is_loggedinas() {
608
        $this->resetAfterTest();
609
 
610
        $user1 = $this->getDataGenerator()->create_user();
611
        $user2 = $this->getDataGenerator()->create_user();
612
 
613
        $this->assertFalse(\core\session\manager::is_loggedinas());
614
 
615
        $this->setUser($user1);
616
        \core\session\manager::loginas($user2->id, \context_system::instance());
617
 
618
        $this->assertTrue(\core\session\manager::is_loggedinas());
619
    }
620
 
621
    public function test_get_realuser() {
622
        $this->resetAfterTest();
623
 
624
        $user1 = $this->getDataGenerator()->create_user();
625
        $user2 = $this->getDataGenerator()->create_user();
626
 
627
        $this->setUser($user1);
628
        $normal = \core\session\manager::get_realuser();
629
        $this->assertSame($GLOBALS['USER'], $normal);
630
 
631
        \core\session\manager::loginas($user2->id, \context_system::instance());
632
 
633
        $real = \core\session\manager::get_realuser();
634
 
635
        unset($real->password);
636
        unset($real->description);
637
        unset($real->sesskey);
638
        unset($user1->password);
639
        unset($user1->description);
640
        unset($user1->sesskey);
641
 
642
        $this->assertEquals($real, $user1);
643
        $this->assertSame($_SESSION['REALUSER'], $real);
644
    }
645
 
646
    /**
647
     * Session lock info on pages.
648
     *
649
     * @return array
650
     */
651
    public function pages_sessionlocks() {
652
        return [
653
            [
654
                'url'      => '/good.php',
655
                'start'    => 1500000001.000,
656
                'gained'   => 1500000002.000,
657
                'released' => 1500000003.000,
658
                'wait'     => 1.0,
659
                'held'     => 1.0
660
            ],
661
            [
662
                'url'      => '/bad.php?wait=5',
663
                'start'    => 1500000003.000,
664
                'gained'   => 1500000005.000,
665
                'released' => 1500000007.000,
666
                'held'     => 2.0,
667
                'wait'     => 2.0
668
            ]
669
        ];
670
    }
671
 
672
    /**
673
     * Test to get recent session locks.
674
     */
675
    public function test_get_recent_session_locks() {
676
        global $CFG;
677
 
678
        $this->resetAfterTest();
679
        $CFG->debugsessionlock = 5;
680
        $pages = $this->pages_sessionlocks();
681
        // Recent session locks must be empty at first.
682
        $recentsessionlocks = \core\session\manager::get_recent_session_locks();
683
        $this->assertEmpty($recentsessionlocks);
684
 
685
        // Add page to the recentsessionlocks array.
686
        \core\session\manager::update_recent_session_locks($pages[0]);
687
        $recentsessionlocks = \core\session\manager::get_recent_session_locks();
688
        // Make sure we are getting the first page we added.
689
        $this->assertEquals($pages[0], $recentsessionlocks[0]);
690
        // There should be 1 page in the array.
691
        $this->assertCount(1, $recentsessionlocks);
692
 
693
        // Add second page to the recentsessionlocks array.
694
        \core\session\manager::update_recent_session_locks($pages[1]);
695
        $recentsessionlocks = \core\session\manager::get_recent_session_locks();
696
        // Make sure we are getting the second page we added.
697
        $this->assertEquals($pages[1], $recentsessionlocks[1]);
698
        // There should be 2 pages in the array.
699
        $this->assertCount(2, $recentsessionlocks);
700
    }
701
 
702
    /**
703
     * Test to update recent session locks.
704
     */
705
    public function test_update_recent_session_locks() {
706
        global $CFG;
707
 
708
        $this->resetAfterTest();
709
        $CFG->debugsessionlock = 5;
710
        $pages = $this->pages_sessionlocks();
711
 
712
        \core\session\manager::update_recent_session_locks($pages[0]);
713
        \core\session\manager::update_recent_session_locks($pages[1]);
714
        $recentsessionlocks = \core\session\manager::get_recent_session_locks();
715
        // There should be 2 pages in the array.
716
        $this->assertCount(2, $recentsessionlocks);
717
        // Make sure the last page is added at the end of the array.
718
        $this->assertEquals($pages[1], end($recentsessionlocks));
719
 
720
    }
721
 
722
    /**
723
     * Test to get session lock info.
724
     */
725
    public function test_get_session_lock_info() {
726
        global $PERF;
727
 
728
        $this->resetAfterTest();
729
 
730
        $pages = $this->pages_sessionlocks();
731
        $PERF->sessionlock = $pages[0];
732
        $sessionlock = \core\session\manager::get_session_lock_info();
733
        $this->assertEquals($pages[0], $sessionlock);
734
    }
735
 
736
    /**
737
     * Session lock info on some pages to serve as history.
738
     *
739
     * @return array
740
     */
741
    public function sessionlock_history() {
742
        return [
743
            [
744
                'url'      => '/good.php',
745
                'start'    => 1500000001.000,
746
                'gained'   => 1500000001.100,
747
                'released' => 1500000001.500,
748
                'wait'     => 0.1
749
            ],
750
            [
751
                // This bad request doesn't release the session for 10 seconds.
752
                'url'      => '/bad.php',
753
                'start'    => 1500000012.000,
754
                'gained'   => 1500000012.200,
755
                'released' => 1500000020.200,
756
                'wait'     => 0.2
757
            ],
758
            [
759
                // All subsequent requests are blocked and need to wait.
760
                'url'      => '/good.php?id=1',
761
                'start'    => 1500000012.900,
762
                'gained'   => 1500000020.200,
763
                'released' => 1500000022.000,
764
                'wait'     => 7.29
765
            ],
766
            [
767
                'url'      => '/good.php?id=2',
768
                'start'    => 1500000014.000,
769
                'gained'   => 1500000022.000,
770
                'released' => 1500000025.000,
771
                'wait'     => 8.0
772
            ],
773
            [
774
                'url'      => '/good.php?id=3',
775
                'start'    => 1500000015.000,
776
                'gained'   => 1500000025.000,
777
                'released' => 1500000026.000,
778
                'wait'     => 10.0
779
            ],
780
            [
781
                'url'      => '/good.php?id=4',
782
                'start'    => 1500000016.000,
783
                'gained'   => 1500000026.000,
784
                'released' => 1500000027.000,
785
                'wait'     => 10.0
786
            ]
787
        ];
788
    }
789
 
790
    /**
791
     * Data provider for test_get_locked_page_at function.
792
     *
793
     * @return array
794
     */
795
    public function sessionlocks_info_provider(): array {
796
        return [
797
            [
798
                'url'      => null,
799
                'time'    => 1500000001.000
800
            ],
801
            [
802
                'url'      => '/bad.php',
803
                'time'    => 1500000014.000
804
            ],
805
            [
806
                'url'      => '/good.php?id=2',
807
                'time'    => 1500000022.500
808
            ],
809
        ];
810
    }
811
 
812
    /**
813
     * Test to get locked page at a speficic timestamp.
814
     *
815
     * @dataProvider sessionlocks_info_provider
816
     * @param array $url Session lock page url.
817
     * @param array $time Session lock time.
818
     */
819
    public function test_get_locked_page_at($url, $time) {
820
        global $CFG, $SESSION;
821
 
822
        $this->resetAfterTest();
823
        $CFG->debugsessionlock = 5;
824
        $SESSION->recentsessionlocks = $this->sessionlock_history();
825
 
826
        $page = \core\session\manager::get_locked_page_at($time);
827
        $this->assertEquals($url, is_array($page) ? $page['url'] : null);
828
    }
829
 
830
    /**
831
     * Test cleanup recent session locks.
832
     */
833
    public function test_cleanup_recent_session_locks() {
834
        global $CFG, $SESSION;
835
 
836
        $this->resetAfterTest();
837
        $CFG->debugsessionlock = 5;
838
 
839
        $SESSION->recentsessionlocks = $this->sessionlock_history();
840
        $this->assertCount(6, $SESSION->recentsessionlocks);
841
        \core\session\manager::cleanup_recent_session_locks();
842
        // Make sure the session history has been cleaned up and only has the latest page.
843
        $this->assertCount(1, $SESSION->recentsessionlocks);
844
        $this->assertEquals('/good.php?id=4', $SESSION->recentsessionlocks[0]['url']);
845
    }
846
 
847
    /**
848
     * Data provider for the array_session_diff function.
849
     *
850
     * @return array
851
     */
852
    public function array_session_diff_provider() {
853
        // Create an instance of this object so the comparison object's identities are the same.
854
        // Used in one of the tests below.
855
        $compareobjectb = (object) ['array' => 'b'];
856
 
857
        return [
858
            'both same objects' => [
859
                'a' => ['example' => (object) ['array' => 'a']],
860
                'b' => ['example' => (object) ['array' => 'a']],
861
                'expected' => [],
862
            ],
863
            'both same arrays' => [
864
                'a' => ['example' => ['array' => 'a']],
865
                'b' => ['example' => ['array' => 'a']],
866
                'expected' => [],
867
            ],
868
            'both the same with nested objects' => [
869
                'a' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],
870
                'b' => ['example' => (object) ['array' => 'a', 'deeper' => (object) []]],
871
                'expected' => [],
872
            ],
873
            'first array larger' => [
874
                'a' => ['x' => 1, 'y' => 2],
875
                'b' => ['x' => 1],
876
                'expected' => ['y' => 2]
877
            ],
878
            'second array larger' => [
879
                'a' => ['x' => 1],
880
                'b' => ['x' => 1, 'y' => 2],
881
                'expected' => ['y' => 2]
882
            ],
883
            'objects with different values but same keys' => [
884
                'a' => ['example' => (object) ['array' => 'a']],
885
                'b' => ['example' => $compareobjectb],
886
                'expected' => ['example' => $compareobjectb]
887
            ],
888
            'different arrays with top level indexes' => [
889
                'a' => ['x', 'y'],
890
                'b' => ['x', 'y', 'z'],
891
                'expected' => [2 => 'z']
892
            ],
893
            'different types but same values as first level' => [
894
                'a' => ['example' => (object) ['array' => 'a']],
895
                'b' => ['example' => ['array' => 'a']],
896
                'expected' => ['example' => ['array' => 'a']]
897
            ],
898
            'different types but same values nested' => [
899
                'a' => ['example' => (object) ['array' => ['a' => 'test']]],
900
                'b' => ['example' => (object) ['array' => (object) ['a' => 'test']]],
901
                // Type checking is not done further than the first level, so we expect no difference.
902
                'expected' => []
903
            ]
904
        ];
905
    }
906
 
907
    /**
908
     * Tests array diff method in various situations.
909
     *
910
     * @dataProvider array_session_diff_provider
911
     * @covers \core\session\manager::array_session_diff
912
     * @param array $a first value.
913
     * @param array $b second value to compare to $a.
914
     * @param array $expected the expected difference.
915
     */
916
    public function test_array_session_diff(array $a, array $b, array $expected) {
917
        $class = new \ReflectionClass('\core\session\manager');
918
        $method = $class->getMethod('array_session_diff');
919
 
920
        $result = $method->invokeArgs(null, [$a, $b]);
921
        $this->assertSame($expected, $result);
922
    }
923
}