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 $values = $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 $values = $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 $values = $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 $values = $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 $values = $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 $values = $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 $values = $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 read actions.
179 $course = $this->getDataGenerator()->create_course();
180 $coursecontext = \context_course::instance($course->id);
181 $this->getDataGenerator()->enrol_user($user1->id, $course->id);
183 $indicator = new \core\analytics\indicator\read_actions();
185 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id);
186 $data = array($user1->id => array(
187 'context' => $coursecontext,
191 $data[$user2->id] = $data[$user1->id];
192 $data[$user2->id]['user'] = $user2;
193 $indicator->add_sample_data($data);
195 // More or less 4 weeks duration.
196 $startdate = time() - (WEEKSECS * 2);
197 $enddate = time() + (WEEKSECS * 2);
199 $this->setAdminUser();
200 $values = $indicator->calculate($sampleids, 'user');
201 $this->assertNull($values[$user1->id][0]);
202 $this->assertNull($values[$user1->id][1]);
203 $this->assertNull($values[$user1->id][0]);
204 $this->assertNull($values[$user2->id][1]);
206 // Zero score for 0 accesses.
207 $values = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
208 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]);
209 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]);
211 // 1/3 score for more than 0 accesses.
212 \core\event\course_viewed::create(
213 array('context' => $coursecontext, 'userid' => $user1->id))->trigger();
214 $values = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
215 $this->assertEquals(-0.33, $values[$user1->id][0]);
216 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]);
218 // 2/3 score for more than 1 access per week.
219 for ($i = 0; $i < 12; $i++) {
220 \core\event\course_viewed::create(
221 array('context' => $coursecontext, 'userid' => $user1->id))->trigger();
223 $values = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
224 $this->assertEquals(0.33, $values[$user1->id][0]);
225 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]);
227 // 100% score for tons of accesses during this period (3 logs per access * 4 weeks * 10 accesses).
228 for ($i = 0; $i < (3 * 10 * 4); $i++) {
229 \core\event\course_viewed::create(
230 array('context' => $coursecontext, 'userid' => $user1->id))->trigger();
232 $values = $indicator->calculate($sampleids, 'user', $startdate, $enddate);
233 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]);
234 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]);