2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for core indicators.
22 * @copyright 2017 David MonllaĆ³ {@link http://www.davidmonllao.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die();
28 require_once(__DIR__
. '/../../analytics/tests/fixtures/test_target_shortname.php');
29 require_once(__DIR__
. '/../../admin/tool/log/store/standard/tests/fixtures/event.php');
30 require_once(__DIR__
. '/../../lib/enrollib.php');
33 * Unit tests for core indicators.
37 * @copyright 2017 David MonllaĆ³ {@link http://www.davidmonllao.com}
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class core_analytics_indicators_testcase
extends advanced_testcase
{
43 * Test all core indicators.
45 * Single method as it is significantly faster (from 13s to 5s) than having separate
46 * methods because of preventResetByRollback.
50 public function test_core_indicators() {
52 $this->preventResetByRollback();
53 $this->resetAfterTest(true);
54 $this->setAdminuser();
56 set_config('enabled_stores', 'logstore_standard', 'tool_log');
57 set_config('buffersize', 0, 'logstore_standard');
59 $user1 = $this->getDataGenerator()->create_user();
60 $user2 = $this->getDataGenerator()->create_user();
62 // Test any access after end.
64 'startdate' => mktime(0, 0, 0, 10, 24, 2015),
65 'enddate' => mktime(0, 0, 0, 10, 24, 2016)
67 $course = $this->getDataGenerator()->create_course($params);
68 $coursecontext = \context_course
::instance($course->id
);
69 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
71 $indicator = new \core\analytics\indicator\any_access_after_end
();
73 $sampleids = array($user1->id
=> $user1->id
, $user2->id
=> $user2->id
);
74 $data = array($user1->id
=> array(
75 'context' => $coursecontext,
79 $data[$user2->id
] = $data[$user1->id
];
80 $data[$user2->id
]['user'] = $user2;
81 $indicator->add_sample_data($data);
83 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere');
84 $this->assertEquals($indicator::get_min_value(), $values[$user1->id
][0]);
85 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
87 \logstore_standard\event\unittest_executed
::create(
88 array('context' => $coursecontext, 'userid' => $user1->id
))->trigger();
89 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere');
90 $this->assertEquals($indicator::get_max_value(), $values[$user1->id
][0]);
91 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
93 // Test any access before start.
95 'startdate' => 9999999998,
96 'enddate' => 9999999999
98 // Resetting $course var.
99 $course = $this->getDataGenerator()->create_course($params);
100 $coursecontext = \context_course
::instance($course->id
);
101 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
103 $indicator = new \core\analytics\indicator\any_access_before_start
();
105 $sampleids = array($user1->id
=> $user1->id
, $user2->id
=> $user2->id
);
106 $data = array($user1->id
=> array(
107 'context' => $coursecontext,
111 $data[$user2->id
] = $data[$user1->id
];
112 $data[$user2->id
]['user'] = $user2;
113 $indicator->add_sample_data($data);
115 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere');
116 $this->assertEquals($indicator::get_min_value(), $values[$user1->id
][0]);
117 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
119 \logstore_standard\event\unittest_executed
::create(
120 array('context' => $coursecontext, 'userid' => $user1->id
))->trigger();
121 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere');
122 $this->assertEquals($indicator::get_max_value(), $values[$user1->id
][0]);
123 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
125 // Test any write action.
126 $course1 = $this->getDataGenerator()->create_course();
127 $coursecontext1 = \context_course
::instance($course1->id
);
128 $course2 = $this->getDataGenerator()->create_course();
129 $coursecontext2 = \context_course
::instance($course2->id
);
130 $this->getDataGenerator()->enrol_user($user1->id
, $course2->id
);
132 $indicator = new \core\analytics\indicator\any_write_action
();
134 $sampleids = array($user1->id
=> $user1->id
, $user2->id
=> $user2->id
);
135 $data = array($user1->id
=> array(
136 'context' => $coursecontext1,
137 'course' => $course1,
140 $data[$user2->id
] = $data[$user1->id
];
141 $data[$user2->id
]['user'] = $user2;
142 $indicator->add_sample_data($data);
144 list($values, $unused) = $indicator->calculate($sampleids, 'user');
145 $this->assertEquals($indicator::get_min_value(), $values[$user1->id
][0]);
146 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
148 $beforecourseeventcreate = time();
151 \logstore_standard\event\unittest_executed
::create(
152 array('context' => $coursecontext1, 'userid' => $user1->id
))->trigger();
153 list($values, $unused) = $indicator->calculate($sampleids, 'user');
154 $this->assertEquals($indicator::get_max_value(), $values[$user1->id
][0]);
155 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
157 // Now try with course-level samples where user is not available.
158 $sampleids = array($course1->id
=> $course1->id
, $course2->id
=> $course2->id
);
160 $course1->id
=> array(
161 'context' => $coursecontext1,
162 'course' => $course1,
164 $course2->id
=> array(
165 'context' => $coursecontext2,
166 'course' => $course2,
169 $indicator->clear_sample_data();
170 $indicator->add_sample_data($data);
172 // Limited by time to avoid previous logs interfering as other logs
173 // have been generated by the system.
174 list($values, $unused) = $indicator->calculate($sampleids, 'course', $beforecourseeventcreate);
175 $this->assertEquals($indicator::get_max_value(), $values[$course1->id
][0]);
176 $this->assertEquals($indicator::get_min_value(), $values[$course2->id
][0]);
178 // Test any write action in the course.
179 $course1 = $this->getDataGenerator()->create_course();
180 $coursecontext1 = \context_course
::instance($course1->id
);
181 $activity1 = $this->getDataGenerator()->create_module('forum', array('course' => $course1->id
));
182 $activity1context = \context_module
::instance($activity1->cmid
);
183 $course2 = $this->getDataGenerator()->create_course();
184 $coursecontext2 = \context_course
::instance($course2->id
);
185 $this->getDataGenerator()->enrol_user($user1->id
, $course2->id
);
187 $indicator = new \core\analytics\indicator\any_write_action_in_course
();
189 $sampleids = array($user1->id
=> $user1->id
, $user2->id
=> $user2->id
);
190 $data = array($user1->id
=> array(
191 'context' => $coursecontext1,
192 'course' => $course1,
195 $data[$user2->id
] = $data[$user1->id
];
196 $data[$user2->id
]['user'] = $user2;
197 $indicator->add_sample_data($data);
199 list($values, $unused) = $indicator->calculate($sampleids, 'user');
200 $this->assertEquals($indicator::get_min_value(), $values[$user1->id
][0]);
201 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
203 $beforecourseeventcreate = time();
206 \logstore_standard\event\unittest_executed
::create(
207 array('context' => $activity1context, 'userid' => $user1->id
))->trigger();
208 list($values, $unused) = $indicator->calculate($sampleids, 'user');
209 $this->assertEquals($indicator::get_max_value(), $values[$user1->id
][0]);
210 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
212 // Now try with course-level samples where user is not available.
213 $sampleids = array($course1->id
=> $course1->id
, $course2->id
=> $course2->id
);
215 $course1->id
=> array(
216 'context' => $coursecontext1,
217 'course' => $course1,
219 $course2->id
=> array(
220 'context' => $coursecontext2,
221 'course' => $course2,
224 $indicator->clear_sample_data();
225 $indicator->add_sample_data($data);
227 // Limited by time to avoid previous logs interfering as other logs
228 // have been generated by the system.
229 list($values, $unused) = $indicator->calculate($sampleids, 'course', $beforecourseeventcreate);
230 $this->assertEquals($indicator::get_max_value(), $values[$course1->id
][0]);
231 $this->assertEquals($indicator::get_min_value(), $values[$course2->id
][0]);
233 // Test read actions.
234 $course = $this->getDataGenerator()->create_course();
235 $coursecontext = \context_course
::instance($course->id
);
236 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
238 $indicator = new \core\analytics\indicator\read_actions
();
240 $sampleids = array($user1->id
=> $user1->id
, $user2->id
=> $user2->id
);
241 $data = array($user1->id
=> array(
242 'context' => $coursecontext,
246 $data[$user2->id
] = $data[$user1->id
];
247 $data[$user2->id
]['user'] = $user2;
248 $indicator->add_sample_data($data);
250 // More or less 4 weeks duration.
251 $startdate = time() - (WEEKSECS
* 2);
252 $enddate = time() +
(WEEKSECS
* 2);
254 $this->setAdminUser();
255 list($values, $unused) = $indicator->calculate($sampleids, 'user');
256 $this->assertNull($values[$user1->id
][0]);
257 $this->assertNull($values[$user1->id
][1]);
258 $this->assertNull($values[$user1->id
][0]);
259 $this->assertNull($values[$user2->id
][1]);
261 // Zero score for 0 accesses.
262 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
263 $this->assertEquals($indicator::get_min_value(), $values[$user1->id
][0]);
264 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
266 // 1/3 score for more than 0 accesses.
267 \core\event\course_viewed
::create(
268 array('context' => $coursecontext, 'userid' => $user1->id
))->trigger();
269 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
270 $this->assertEquals(-0.33, $values[$user1->id
][0]);
271 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
273 // 2/3 score for more than 1 access per week.
274 for ($i = 0; $i < 12; $i++
) {
275 \core\event\course_viewed
::create(
276 array('context' => $coursecontext, 'userid' => $user1->id
))->trigger();
278 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
279 $this->assertEquals(0.33, $values[$user1->id
][0]);
280 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
282 // 100% score for tons of accesses during this period (3 logs per access * 4 weeks * 10 accesses).
283 for ($i = 0; $i < (3 * 10 * 4); $i++
) {
284 \core\event\course_viewed
::create(
285 array('context' => $coursecontext, 'userid' => $user1->id
))->trigger();
287 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
288 $this->assertEquals($indicator::get_max_value(), $values[$user1->id
][0]);
289 $this->assertEquals($indicator::get_min_value(), $values[$user2->id
][0]);
291 set_config('enabled_stores', '', 'tool_log');
292 get_log_manager(true);