| 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 | use test_target_course_level_shortname;
 | 
        
           |  |  | 20 | use test_target_shortname;
 | 
        
           |  |  | 21 |   | 
        
           |  |  | 22 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | require_once(__DIR__ . '/../../analytics/tests/fixtures/test_target_course_level_shortname.php');
 | 
        
           |  |  | 25 | require_once(__DIR__ . '/../../analytics/tests/fixtures/test_target_shortname.php');
 | 
        
           |  |  | 26 | require_once(__DIR__ . '/../../lib/enrollib.php');
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | /**
 | 
        
           |  |  | 29 |  * Unit tests for core analysers.
 | 
        
           |  |  | 30 |  *
 | 
        
           |  |  | 31 |  * @package   core
 | 
        
           |  |  | 32 |  * @category  test
 | 
        
           |  |  | 33 |  * @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
 | 
        
           |  |  | 34 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 35 |  */
 | 
        
           | 1441 | ariadna | 36 | final class analysers_test extends \advanced_testcase {
 | 
        
           | 1 | efrain | 37 |   | 
        
           |  |  | 38 |     /**
 | 
        
           |  |  | 39 |      * test_courses_analyser
 | 
        
           |  |  | 40 |      *
 | 
        
           |  |  | 41 |      * @return void
 | 
        
           |  |  | 42 |      */
 | 
        
           | 11 | efrain | 43 |     public function test_courses_analyser(): void {
 | 
        
           | 1 | efrain | 44 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 |         $course1 = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 47 |         $coursecontext = \context_course::instance($course1->id);
 | 
        
           |  |  | 48 |   | 
        
           |  |  | 49 |         $target = new test_target_shortname();
 | 
        
           |  |  | 50 |         $analyser = new \core\analytics\analyser\courses(1, $target, [], [], []);
 | 
        
           |  |  | 51 |         $analysable = new \core_analytics\course($course1);
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 |         $this->assertInstanceOf('\core_analytics\course', $analyser->get_sample_analysable($course1->id));
 | 
        
           |  |  | 54 |   | 
        
           |  |  | 55 |         $this->assertInstanceOf('\context_course', $analyser->sample_access_context($course1->id));
 | 
        
           |  |  | 56 |   | 
        
           |  |  | 57 |         // Just 1 sample per course.
 | 
        
           |  |  | 58 |         $class = new \ReflectionClass('\core\analytics\analyser\courses');
 | 
        
           |  |  | 59 |         $method = $class->getMethod('get_all_samples');
 | 
        
           |  |  | 60 |         list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
 | 
        
           |  |  | 61 |         $this->assertCount(1, $sampleids);
 | 
        
           |  |  | 62 |         $sampleid = reset($sampleids);
 | 
        
           |  |  | 63 |         $this->assertEquals($course1->id, $sampleid);
 | 
        
           |  |  | 64 |         $this->assertEquals($course1->fullname, $samplesdata[$sampleid]['course']->fullname);
 | 
        
           |  |  | 65 |         $this->assertEquals($coursecontext, $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 66 |   | 
        
           |  |  | 67 |         // To compare it later.
 | 
        
           |  |  | 68 |         $prevsampledata = $samplesdata[$sampleid];
 | 
        
           |  |  | 69 |         list($sampleids, $samplesdata) = $analyser->get_samples(array($sampleid));
 | 
        
           |  |  | 70 |         $this->assertEquals($prevsampledata['context'], $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 71 |         $this->assertEquals($prevsampledata['course']->shortname, $samplesdata[$sampleid]['course']->shortname);
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 |         // Context restriction.
 | 
        
           |  |  | 74 |         $category1 = $this->getDataGenerator()->create_category();
 | 
        
           |  |  | 75 |         $category1context = \context_coursecat::instance($category1->id);
 | 
        
           |  |  | 76 |         $category2 = $this->getDataGenerator()->create_category();
 | 
        
           |  |  | 77 |         $category2context = \context_coursecat::instance($category2->id);
 | 
        
           |  |  | 78 |         $course2 = $this->getDataGenerator()->create_course(['category' => $category1->id]);
 | 
        
           |  |  | 79 |         $course3 = $this->getDataGenerator()->create_course(['category' => $category2->id]);
 | 
        
           |  |  | 80 |         $this->assertCount(2, $analyser->get_analysables_iterator(false, [$category1context, $category2context]));
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |     }
 | 
        
           |  |  | 83 |   | 
        
           |  |  | 84 |     /**
 | 
        
           |  |  | 85 |      * test_site_courses_analyser
 | 
        
           |  |  | 86 |      *
 | 
        
           |  |  | 87 |      * @return void
 | 
        
           |  |  | 88 |      */
 | 
        
           | 11 | efrain | 89 |     public function test_site_courses_analyser(): void {
 | 
        
           | 1 | efrain | 90 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |         $course1 = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 93 |         $course2 = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 94 |         $course3 = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 95 |         $course1context = \context_course::instance($course1->id);
 | 
        
           |  |  | 96 |   | 
        
           |  |  | 97 |         $target = new test_target_shortname();
 | 
        
           |  |  | 98 |         $analyser = new \core\analytics\analyser\site_courses(1, $target, [], [], []);
 | 
        
           |  |  | 99 |         $analysable = new \core_analytics\site();
 | 
        
           |  |  | 100 |   | 
        
           |  |  | 101 |         $this->assertInstanceOf('\core_analytics\site', $analyser->get_sample_analysable($course1->id));
 | 
        
           |  |  | 102 |         $this->assertInstanceOf('\core_analytics\site', $analyser->get_sample_analysable($course2->id));
 | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 |         $this->assertInstanceOf('\context_system', $analyser->sample_access_context($course1->id));
 | 
        
           |  |  | 105 |         $this->assertInstanceOf('\context_system', $analyser->sample_access_context($course3->id));
 | 
        
           |  |  | 106 |   | 
        
           |  |  | 107 |         $class = new \ReflectionClass('\core\analytics\analyser\site_courses');
 | 
        
           |  |  | 108 |         $method = $class->getMethod('get_all_samples');
 | 
        
           |  |  | 109 |         list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
 | 
        
           |  |  | 110 |         $this->assertCount(3, $sampleids);
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 |         // Use course1 it does not really matter.
 | 
        
           |  |  | 113 |         $this->assertArrayHasKey($course1->id, $sampleids);
 | 
        
           |  |  | 114 |         $sampleid = $course1->id;
 | 
        
           |  |  | 115 |         $this->assertEquals($course1->id, $sampleid);
 | 
        
           |  |  | 116 |         $this->assertEquals($course1->fullname, $samplesdata[$sampleid]['course']->fullname);
 | 
        
           |  |  | 117 |         $this->assertEquals($course1context, $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |         // To compare it later.
 | 
        
           |  |  | 120 |         $prevsampledata = $samplesdata[$sampleid];
 | 
        
           |  |  | 121 |         list($sampleids, $samplesdata) = $analyser->get_samples(array($sampleid));
 | 
        
           |  |  | 122 |         $this->assertEquals($prevsampledata['context'], $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 123 |         $this->assertEquals($prevsampledata['course']->shortname, $samplesdata[$sampleid]['course']->shortname);
 | 
        
           |  |  | 124 |     }
 | 
        
           |  |  | 125 |   | 
        
           |  |  | 126 |     /**
 | 
        
           |  |  | 127 |      * test_student_enrolments_analyser
 | 
        
           |  |  | 128 |      *
 | 
        
           |  |  | 129 |      * @return void
 | 
        
           |  |  | 130 |      */
 | 
        
           | 11 | efrain | 131 |     public function test_student_enrolments_analyser(): void {
 | 
        
           | 1 | efrain | 132 |         global $DB;
 | 
        
           |  |  | 133 |   | 
        
           |  |  | 134 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 135 |   | 
        
           |  |  | 136 |         $course1 = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 137 |         $course1context = \context_course::instance($course1->id);
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         $user1 = $this->getDataGenerator()->create_user();
 | 
        
           |  |  | 140 |         $user2 = $this->getDataGenerator()->create_user();
 | 
        
           |  |  | 141 |         $user3 = $this->getDataGenerator()->create_user();
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |         // Checking that suspended users are also included.
 | 
        
           |  |  | 144 |         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
 | 
        
           |  |  | 145 |         $this->getDataGenerator()->enrol_user($user2->id, $course1->id, 'student', 'manual', 0, 0, ENROL_USER_SUSPENDED);
 | 
        
           |  |  | 146 |         $this->getDataGenerator()->enrol_user($user3->id, $course1->id, 'editingteacher');
 | 
        
           |  |  | 147 |         $enrol = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'));
 | 
        
           |  |  | 148 |         $ue1 = $DB->get_record('user_enrolments', array('userid' => $user1->id, 'enrolid' => $enrol->id));
 | 
        
           |  |  | 149 |         $ue2 = $DB->get_record('user_enrolments', array('userid' => $user2->id, 'enrolid' => $enrol->id));
 | 
        
           |  |  | 150 |   | 
        
           |  |  | 151 |         $target = new test_target_shortname();
 | 
        
           |  |  | 152 |         $analyser = new \core\analytics\analyser\student_enrolments(1, $target, [], [], []);
 | 
        
           |  |  | 153 |         $analysable = new \core_analytics\course($course1);
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |         $this->assertInstanceOf('\core_analytics\course', $analyser->get_sample_analysable($ue1->id));
 | 
        
           |  |  | 156 |         $this->assertInstanceOf('\context_course', $analyser->sample_access_context($ue1->id));
 | 
        
           |  |  | 157 |   | 
        
           |  |  | 158 |         $class = new \ReflectionClass('\core\analytics\analyser\student_enrolments');
 | 
        
           |  |  | 159 |         $method = $class->getMethod('get_all_samples');
 | 
        
           |  |  | 160 |         list($sampleids, $samplesdata) = $method->invoke($analyser, $analysable);
 | 
        
           |  |  | 161 |         // Only students.
 | 
        
           |  |  | 162 |         $this->assertCount(2, $sampleids);
 | 
        
           |  |  | 163 |   | 
        
           |  |  | 164 |         $this->assertArrayHasKey($ue1->id, $sampleids);
 | 
        
           |  |  | 165 |         $this->assertArrayHasKey($ue2->id, $sampleids);
 | 
        
           |  |  | 166 |   | 
        
           |  |  | 167 |         // Shouldn't matter which one we select.
 | 
        
           |  |  | 168 |         $sampleid = $ue1->id;
 | 
        
           |  |  | 169 |         $this->assertEquals($ue1, $samplesdata[$sampleid]['user_enrolments']);
 | 
        
           |  |  | 170 |         $this->assertEquals($course1->fullname, $samplesdata[$sampleid]['course']->fullname);
 | 
        
           |  |  | 171 |         $this->assertEquals($course1context, $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 172 |         $this->assertEquals($user1->firstname, $samplesdata[$sampleid]['user']->firstname);
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |         // To compare it later.
 | 
        
           |  |  | 175 |         $prevsampledata = $samplesdata[$sampleid];
 | 
        
           |  |  | 176 |         list($sampleids, $samplesdata) = $analyser->get_samples(array($sampleid));
 | 
        
           |  |  | 177 |         $this->assertEquals($prevsampledata['user_enrolments'], $samplesdata[$sampleid]['user_enrolments']);
 | 
        
           |  |  | 178 |         $this->assertEquals($prevsampledata['context'], $samplesdata[$sampleid]['context']);
 | 
        
           |  |  | 179 |         $this->assertEquals($prevsampledata['course']->shortname, $samplesdata[$sampleid]['course']->shortname);
 | 
        
           |  |  | 180 |         $this->assertEquals($prevsampledata['user']->firstname, $samplesdata[$sampleid]['user']->firstname);
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 |         // Context restriction.
 | 
        
           |  |  | 183 |         $category1 = $this->getDataGenerator()->create_category();
 | 
        
           |  |  | 184 |         $category1context = \context_coursecat::instance($category1->id);
 | 
        
           |  |  | 185 |         $category2 = $this->getDataGenerator()->create_category();
 | 
        
           |  |  | 186 |         $category2context = \context_coursecat::instance($category2->id);
 | 
        
           |  |  | 187 |         $course2 = $this->getDataGenerator()->create_course(['category' => $category1->id]);
 | 
        
           |  |  | 188 |         $course3 = $this->getDataGenerator()->create_course(['category' => $category2->id]);
 | 
        
           |  |  | 189 |         $this->assertCount(2, $analyser->get_analysables_iterator(false, [$category1context, $category2context]));
 | 
        
           |  |  | 190 |     }
 | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 |     /**
 | 
        
           |  |  | 193 |      * test_get_analysables_iterator description
 | 
        
           |  |  | 194 |      *
 | 
        
           |  |  | 195 |      * @return null
 | 
        
           |  |  | 196 |      */
 | 
        
           | 11 | efrain | 197 |     public function test_get_analysables_iterator(): void {
 | 
        
           | 1 | efrain | 198 |         global $DB;
 | 
        
           |  |  | 199 |   | 
        
           |  |  | 200 |         $this->resetAfterTest(true);
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 |         $courses = array();
 | 
        
           |  |  | 203 |         for ($i = 0; $i < 2; $i++) {
 | 
        
           |  |  | 204 |             $course = $this->getDataGenerator()->create_course();
 | 
        
           |  |  | 205 |             $analysable = new \core_analytics\course($course);
 | 
        
           |  |  | 206 |             $courses[$analysable->get_id()] = $course;
 | 
        
           |  |  | 207 |         }
 | 
        
           |  |  | 208 |   | 
        
           |  |  | 209 |         // Check that the analysis performs as expected.
 | 
        
           |  |  | 210 |         $modelid = 1;
 | 
        
           |  |  | 211 |         $includetarget = false;
 | 
        
           |  |  | 212 |   | 
        
           |  |  | 213 |         $target = new test_target_course_level_shortname();
 | 
        
           |  |  | 214 |         $analyser = new \core\analytics\analyser\courses($modelid, $target, [], [], []);
 | 
        
           |  |  | 215 |   | 
        
           |  |  | 216 |         $result = new \core_analytics\local\analysis\result_array($modelid, $includetarget, []);
 | 
        
           |  |  | 217 |         $analysis = new \core_analytics\analysis($analyser, $includetarget, $result);
 | 
        
           |  |  | 218 |         $analysis->run();
 | 
        
           |  |  | 219 |         $params = array('modelid' => $modelid, 'action' => 'prediction');
 | 
        
           |  |  | 220 |         $this->assertEquals(2, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 221 |   | 
        
           |  |  | 222 |         // Check that the previous records do not conflict with the includetarget == false ones.
 | 
        
           |  |  | 223 |         $includetarget = true;
 | 
        
           |  |  | 224 |   | 
        
           |  |  | 225 |         $target = new test_target_course_level_shortname();
 | 
        
           |  |  | 226 |         $analyser = new \core\analytics\analyser\courses($modelid, $target, [], [], []);
 | 
        
           |  |  | 227 |   | 
        
           |  |  | 228 |         $result = new \core_analytics\local\analysis\result_array($modelid, $includetarget, []);
 | 
        
           |  |  | 229 |         $analysis = new \core_analytics\analysis($analyser, $includetarget, $result);
 | 
        
           |  |  | 230 |         $analysis->run();
 | 
        
           |  |  | 231 |         $params = array('modelid' => $modelid, 'action' => 'prediction');
 | 
        
           |  |  | 232 |         $this->assertEquals(2, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 233 |         $params = array('modelid' => $modelid, 'action' => 'training');
 | 
        
           |  |  | 234 |         $this->assertEquals(2, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 235 |         $params = array('modelid' => $modelid);
 | 
        
           |  |  | 236 |         $this->assertEquals(4, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 |         // Check that other models' records do not conflict with previous records.
 | 
        
           |  |  | 239 |         $prevmodelid = 1;
 | 
        
           |  |  | 240 |         $modelid = 2;
 | 
        
           |  |  | 241 |         $includetarget = false;
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 |         $target = new test_target_course_level_shortname();
 | 
        
           |  |  | 244 |         $analyser = new \core\analytics\analyser\courses($modelid, $target, [], [], []);
 | 
        
           |  |  | 245 |   | 
        
           |  |  | 246 |         $result = new \core_analytics\local\analysis\result_array($modelid, $includetarget, []);
 | 
        
           |  |  | 247 |         $analysis = new \core_analytics\analysis($analyser, $includetarget, $result);
 | 
        
           |  |  | 248 |         $analysis->run();
 | 
        
           |  |  | 249 |         $params = array('modelid' => $prevmodelid);
 | 
        
           |  |  | 250 |         $this->assertEquals(4, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 251 |         $params = array('modelid' => $modelid, 'action' => 'prediction');
 | 
        
           |  |  | 252 |         $this->assertEquals(2, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 253 |         $this->assertEquals(6, $DB->count_records('analytics_used_analysables'));
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 |         $includetarget = true;
 | 
        
           |  |  | 256 |   | 
        
           |  |  | 257 |         $target = new test_target_course_level_shortname();
 | 
        
           |  |  | 258 |         $analyser = new \core\analytics\analyser\courses($modelid, $target, [], [], []);
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 |         $result = new \core_analytics\local\analysis\result_array($modelid, $includetarget, []);
 | 
        
           |  |  | 261 |         $analysis = new \core_analytics\analysis($analyser, $includetarget, $result);
 | 
        
           |  |  | 262 |         $analysis->run();
 | 
        
           |  |  | 263 |         $params = array('modelid' => $prevmodelid);
 | 
        
           |  |  | 264 |         $this->assertEquals(4, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 265 |         $params = array('modelid' => $modelid, 'action' => 'training');
 | 
        
           |  |  | 266 |         $this->assertEquals(2, $DB->count_records('analytics_used_analysables', $params));
 | 
        
           |  |  | 267 |         $this->assertEquals(8, $DB->count_records('analytics_used_analysables'));
 | 
        
           |  |  | 268 |     }
 | 
        
           |  |  | 269 | }
 |