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\analytics; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 require_once (__DIR__ . '/../../../analytics/tests/fixtures/test_target_shortname.php'); 22 require_once (__DIR__ . '/../../../admin/tool/log/store/standard/tests/fixtures/event.php'); 23 require_once (__DIR__ . '/../../../lib/enrollib.php'); 24 25 /** 26 * Unit tests for core indicators. 27 * 28 * @package core 29 * @category test 30 * @copyright 2017 David MonllaĆ³ {@link http://www.davidmonllao.com} 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 */ 33 class indicators_test extends \advanced_testcase { 34 35 /** 36 * Test all core indicators. 37 * 38 * Single method as it is significantly faster (from 13s to 5s) than having separate 39 * methods because of preventResetByRollback. 40 * 41 * @return void 42 */ 43 public function test_core_indicators() { 44 global $DB; 45 46 $this->preventResetByRollback(); 47 $this->resetAfterTest(true); 48 $this->setAdminuser(); 49 50 set_config('enabled_stores', 'logstore_standard', 'tool_log'); 51 set_config('buffersize', 0, 'logstore_standard'); 52 53 $user1 = $this->getDataGenerator()->create_user(); 54 $user2 = $this->getDataGenerator()->create_user(); 55 56 // Test any access after end. 57 $params = array( 58 'startdate' => mktime(0, 0, 0, 10, 24, 2015), 59 'enddate' => mktime(0, 0, 0, 10, 24, 2016) 60 ); 61 $course = $this->getDataGenerator()->create_course($params); 62 $coursecontext = \context_course::instance($course->id); 63 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 64 65 $indicator = new \core\analytics\indicator\any_access_after_end(); 66 67 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); 68 $data = array($user1->id => array( 69 'context' => $coursecontext, 70 'course' => $course, 71 'user' => $user1 72 )); 73 $data[$user2->id] = $data[$user1->id]; 74 $data[$user2->id]['user'] = $user2; 75 $indicator->add_sample_data($data); 76 77 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 78 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 79 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 80 81 \logstore_standard\event\unittest_executed::create( 82 array('context' => $coursecontext, 'userid' => $user1->id))->trigger(); 83 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 84 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 85 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 86 87 // Test any access before start. 88 $params = array( 89 'startdate' => 9999999998, 90 'enddate' => 9999999999 91 ); 92 // Resetting $course var. 93 $course = $this->getDataGenerator()->create_course($params); 94 $coursecontext = \context_course::instance($course->id); 95 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 96 97 $indicator = new \core\analytics\indicator\any_access_before_start(); 98 99 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); 100 $data = array($user1->id => array( 101 'context' => $coursecontext, 102 'course' => $course, 103 'user' => $user1 104 )); 105 $data[$user2->id] = $data[$user1->id]; 106 $data[$user2->id]['user'] = $user2; 107 $indicator->add_sample_data($data); 108 109 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 110 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 111 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 112 113 \logstore_standard\event\unittest_executed::create( 114 array('context' => $coursecontext, 'userid' => $user1->id))->trigger(); 115 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 116 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 117 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 118 119 // Test any course access. 120 $course = $this->getDataGenerator()->create_course($params); 121 $coursecontext = \context_course::instance($course->id); 122 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 123 124 $indicator = new \core\analytics\indicator\any_course_access(); 125 126 $sampleids = array($user1->id => $user1->id); 127 $data = array($user1->id => array( 128 'course' => $course, 129 'user' => $user1 130 )); 131 $indicator->add_sample_data($data); 132 $analysable = new \core_analytics\course($course); 133 134 // Min value if no user_lastaccess records. 135 $indicator->fill_per_analysable_caches($analysable); 136 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 137 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 138 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', time() - 10, time() + 10); 139 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 140 141 // Any access is enough if no time restrictions. 142 $DB->insert_record('user_lastaccess', array('userid' => $user1->id, 143 'courseid' => $course->id, 'timeaccess' => time() - 1)); 144 $indicator->fill_per_analysable_caches($analysable); 145 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere'); 146 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 147 148 // Min value if the existing records are old. 149 $indicator->fill_per_analysable_caches($analysable); 150 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', time(), time() + 10); 151 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 152 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', time()); 153 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 154 155 // Max value if the existing records are prior to end. 156 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', time() - 10, time()); 157 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 158 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', false, time()); 159 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 160 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', false, time()); 161 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 162 163 // Max value if no end time and existing user_lastaccess record. 164 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', time() - 10); 165 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 166 167 // Rely on logs if the last time access is after the end time. 168 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', false, time() - 10); 169 // Min value if no logs are found. 170 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 171 172 \logstore_standard\event\unittest_executed::create( 173 array('context' => \context_course::instance($course->id), 'userid' => $user1->id))->trigger(); 174 // Max value if logs are found before the end time. 175 list($values, $unused) = $indicator->calculate($sampleids, 'notrelevanthere', false, time() + 10); 176 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 177 178 // Test any write action. 179 $course1 = $this->getDataGenerator()->create_course(); 180 $coursecontext1 = \context_course::instance($course1->id); 181 $course2 = $this->getDataGenerator()->create_course(); 182 $coursecontext2 = \context_course::instance($course2->id); 183 $this->getDataGenerator()->enrol_user($user1->id, $course2->id); 184 185 $indicator = new \core\analytics\indicator\any_write_action(); 186 187 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); 188 $data = array($user1->id => array( 189 'context' => $coursecontext1, 190 'course' => $course1, 191 'user' => $user1 192 )); 193 $data[$user2->id] = $data[$user1->id]; 194 $data[$user2->id]['user'] = $user2; 195 $indicator->add_sample_data($data); 196 197 list($values, $unused) = $indicator->calculate($sampleids, 'user'); 198 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 199 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 200 201 $beforecourseeventcreate = time(); 202 sleep(1); 203 204 \logstore_standard\event\unittest_executed::create( 205 array('context' => $coursecontext1, 'userid' => $user1->id))->trigger(); 206 list($values, $unused) = $indicator->calculate($sampleids, 'user'); 207 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 208 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 209 210 // Now try with course-level samples where user is not available. 211 $sampleids = array($course1->id => $course1->id, $course2->id => $course2->id); 212 $data = array( 213 $course1->id => array( 214 'context' => $coursecontext1, 215 'course' => $course1, 216 ), 217 $course2->id => array( 218 'context' => $coursecontext2, 219 'course' => $course2, 220 ) 221 ); 222 $indicator->clear_sample_data(); 223 $indicator->add_sample_data($data); 224 225 // Limited by time to avoid previous logs interfering as other logs 226 // have been generated by the system. 227 list($values, $unused) = $indicator->calculate($sampleids, 'course', $beforecourseeventcreate); 228 $this->assertEquals($indicator::get_max_value(), $values[$course1->id][0]); 229 $this->assertEquals($indicator::get_min_value(), $values[$course2->id][0]); 230 231 // Test any write action in the course. 232 $course1 = $this->getDataGenerator()->create_course(); 233 $coursecontext1 = \context_course::instance($course1->id); 234 $activity1 = $this->getDataGenerator()->create_module('forum', array('course' => $course1->id)); 235 $activity1context = \context_module::instance($activity1->cmid); 236 $course2 = $this->getDataGenerator()->create_course(); 237 $coursecontext2 = \context_course::instance($course2->id); 238 $this->getDataGenerator()->enrol_user($user1->id, $course2->id); 239 240 $indicator = new \core\analytics\indicator\any_write_action_in_course(); 241 242 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); 243 $data = array($user1->id => array( 244 'context' => $coursecontext1, 245 'course' => $course1, 246 'user' => $user1 247 )); 248 $data[$user2->id] = $data[$user1->id]; 249 $data[$user2->id]['user'] = $user2; 250 $indicator->add_sample_data($data); 251 252 list($values, $unused) = $indicator->calculate($sampleids, 'user'); 253 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 254 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 255 256 $beforecourseeventcreate = time(); 257 sleep(1); 258 259 \logstore_standard\event\unittest_executed::create( 260 array('context' => $activity1context, 'userid' => $user1->id))->trigger(); 261 list($values, $unused) = $indicator->calculate($sampleids, 'user'); 262 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 263 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 264 265 // Now try with course-level samples where user is not available. 266 $sampleids = array($course1->id => $course1->id, $course2->id => $course2->id); 267 $data = array( 268 $course1->id => array( 269 'context' => $coursecontext1, 270 'course' => $course1, 271 ), 272 $course2->id => array( 273 'context' => $coursecontext2, 274 'course' => $course2, 275 ) 276 ); 277 $indicator->clear_sample_data(); 278 $indicator->add_sample_data($data); 279 280 // Limited by time to avoid previous logs interfering as other logs 281 // have been generated by the system. 282 list($values, $unused) = $indicator->calculate($sampleids, 'course', $beforecourseeventcreate); 283 $this->assertEquals($indicator::get_max_value(), $values[$course1->id][0]); 284 $this->assertEquals($indicator::get_min_value(), $values[$course2->id][0]); 285 286 // Test read actions. 287 $course = $this->getDataGenerator()->create_course(); 288 $coursecontext = \context_course::instance($course->id); 289 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 290 291 $indicator = new \core\analytics\indicator\read_actions(); 292 293 $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); 294 $data = array($user1->id => array( 295 'context' => $coursecontext, 296 'course' => $course, 297 'user' => $user1 298 )); 299 $data[$user2->id] = $data[$user1->id]; 300 $data[$user2->id]['user'] = $user2; 301 $indicator->add_sample_data($data); 302 303 // More or less 4 weeks duration. 304 $startdate = time() - (WEEKSECS * 2); 305 $enddate = time() + (WEEKSECS * 2); 306 307 $this->setAdminUser(); 308 list($values, $unused) = $indicator->calculate($sampleids, 'user'); 309 $this->assertNull($values[$user1->id][0]); 310 $this->assertNull($values[$user1->id][1]); 311 $this->assertNull($values[$user1->id][0]); 312 $this->assertNull($values[$user2->id][1]); 313 314 // Zero score for 0 accesses. 315 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate); 316 $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); 317 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 318 319 // 1/3 score for more than 0 accesses. 320 \core\event\course_viewed::create( 321 array('context' => $coursecontext, 'userid' => $user1->id))->trigger(); 322 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate); 323 $this->assertEquals(-0.33, $values[$user1->id][0]); 324 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 325 326 // 2/3 score for more than 1 access per week. 327 for ($i = 0; $i < 12; $i++) { 328 \core\event\course_viewed::create( 329 array('context' => $coursecontext, 'userid' => $user1->id))->trigger(); 330 } 331 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate); 332 $this->assertEquals(0.33, $values[$user1->id][0]); 333 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 334 335 // 100% score for tons of accesses during this period (3 logs per access * 4 weeks * 10 accesses). 336 for ($i = 0; $i < (3 * 10 * 4); $i++) { 337 \core\event\course_viewed::create( 338 array('context' => $coursecontext, 'userid' => $user1->id))->trigger(); 339 } 340 list($values, $unused) = $indicator->calculate($sampleids, 'user', $startdate, $enddate); 341 $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); 342 $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); 343 344 set_config('enabled_stores', '', 'tool_log'); 345 get_log_manager(true); 346 } 347 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body