1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
<?php
use PHPUnit\Framework\TestCase;
/**
* Tests for modules-available/exams/inc/exams.inc.php using the SQLite-backed DB.
*
*/
class ExamsIncTest extends TestCase
{
protected function setUp(): void
{
Database::resetSchema();
}
private function loadInc(): void
{
require_once __DIR__ . '/../../../modules-available/exams/inc/exams.inc.php';
}
public function testIsInExamModeMatchesSpecificLocationAndGlobal(): void
{
$this->loadInc();
$now = time();
// Insert an exam active now, bound to location 2
Database::exec('INSERT INTO exams (examid, lectureid, autologin, starttime, endtime, description) VALUES (1, :l, :a, :s, :e, :d)', [
'l' => 'L-1',
'a' => 'auto1',
's' => $now - 3600,
'e' => $now + 3600,
'd' => 'Exam in A'
]);
Database::exec('INSERT INTO exams_x_location (examid, locationid) VALUES (1, 2)');
// No active exam window for location 3 then
$lecture = $auto = null;
$this->assertFalse(Exams::isInExamMode([3], $lecture, $auto));
// Insert a global exam (NULL location)
Database::exec('INSERT INTO exams (examid, lectureid, autologin, starttime, endtime, description) VALUES (2, :l, :a, :s, :e, :d)', [
'l' => 'L-2',
'a' => 'auto2',
's' => $now - 1800,
'e' => $now + 1800,
'd' => 'Global Exam'
]);
Database::exec('INSERT INTO exams_x_location (examid, locationid) VALUES (2, NULL)');
$lecture = null;
$auto = null;
// Specific location match
$this->assertTrue(Exams::isInExamMode([2], $lecture, $auto));
$this->assertSame('L-1', $lecture);
$this->assertSame('auto1', $auto);
// Global match when no specific exam in list
$lecture = $auto = null;
$this->assertTrue(Exams::isInExamMode([999], $lecture, $auto));
$this->assertSame('L-2', $lecture);
$this->assertSame('auto2', $auto);
}
public function testPlausiblyInExamModeFiltersByDurationAndMachines(): void
{
$this->loadInc();
$now = time();
// Seed one ONLINE machine in location 2
Database::exec("INSERT INTO machine (machineuuid, subnetlocationid, locationid, fixedlocationid, hostname, clientip, state)
VALUES ('ex1', 2, 2, 2, 'host-ex1', '10.0.0.20', 'ONLINE')");
// Exam too long (> 1 day) but lecture bounds should limit when lecture is active -> keep
Database::exec('INSERT INTO exams (examid, lectureid, autologin, starttime, endtime, description) VALUES (10, :l, :a, :s, :e, :d)', [
'l' => 'L-keep',
's' => $now - 2 * 86400,
'e' => $now + 2 * 86400,
'd' => 'Long but bounded'
]);
Database::exec('INSERT INTO exams_x_location (examid, locationid) VALUES (10, 2)');
Database::exec('INSERT INTO sat_user (userid, firstname, lastname, email) VALUES (1, "A", "B", "a@b")');
Database::exec('INSERT INTO sat_lecture (lectureid, ownerid, displayname, starttime, endtime, isexam, isenabled)
VALUES (:id, 1, :n, :ls, :le, 1, 1)', [
'id' => 'L-keep',
'n' => 'Lecture Window',
'ls' => $now - 300,
'le' => $now + 300
]);
Database::exec('INSERT INTO sat_lecture_x_location (lectureid, locationid) VALUES (:id, 2)', ['id' => 'L-keep']);
// Exam too long and zero machines -> should be skipped
Database::exec('INSERT INTO exams (examid, lectureid, autologin, starttime, endtime, description) VALUES (11, :l, :a, :s, :e, :d)', [
'l' => 'L-skip',
's' => $now - 3 * 86400,
'e' => $now + 3 * 86400,
'd' => 'Long and no machines'
]);
Database::exec('INSERT INTO exams_x_location (examid, locationid) VALUES (11, 5)');
Database::exec('INSERT INTO sat_lecture (lectureid, ownerid, displayname, starttime, endtime, isexam, isenabled) VALUES (:id, 1, :n, :ls, :le, 1, 1)', [
'id' => 'L-skip',
'n' => 'Lecture Long',
'ls' => $now - 100000,
'le' => $now + 100000
]);
$out = Exams::plausiblyInExamMode();
$names = array_column($out, 'examtitle');
$this->assertContains('Long but bounded', $names);
$this->assertNotContains('Long and no machines', $names);
}
}
|