See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 403]
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 declare(strict_types=1); 18 19 namespace core_files\reportbuilder\datasource; 20 21 use context_course; 22 use context_user; 23 use core_collator; 24 use core_reportbuilder_generator; 25 use core_reportbuilder_testcase; 26 use core_reportbuilder\local\filters\{boolean_select, date, number, select, text}; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 global $CFG; 31 require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php"); 32 33 /** 34 * Unit tests for files datasource 35 * 36 * @package core_files 37 * @covers \core_files\reportbuilder\datasource\files 38 * @copyright 2022 Paul Holden <paulh@moodle.com> 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class files_test extends core_reportbuilder_testcase { 42 43 /** 44 * Test default datasource 45 */ 46 public function test_datasource_default(): void { 47 $this->resetAfterTest(); 48 49 $user = $this->getDataGenerator()->create_user(); 50 $usercontext = context_user::instance($user->id); 51 52 $this->setUser($user); 53 54 $course = $this->getDataGenerator()->create_course(); 55 $coursecontext = context_course::instance($course->id); 56 57 $this->generate_test_files($coursecontext); 58 59 /** @var core_reportbuilder_generator $generator */ 60 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 61 $report = $generator->create_report(['name' => 'Files', 'source' => files::class, 'default' => 1]); 62 63 $content = $this->get_custom_report_content($report->get('id')); 64 $content = $this->filter_custom_report_content($content, static function(array $row): bool { 65 return $row['c0_contextid'] !== 'System'; 66 }, 'c0_contextid'); 67 68 $this->assertCount(2, $content); 69 70 // First row (course summary file). 71 [$contextname, $userfullname, $filename, $mimetype, $filesize, $timecreated] = array_values($content[0]); 72 73 $this->assertEquals($coursecontext->get_context_name(), $contextname); 74 $this->assertEquals(fullname($user), $userfullname); 75 $this->assertEquals('Hello.txt', $filename); 76 $this->assertEquals('Text file', $mimetype); 77 $this->assertEquals("5\xc2\xa0bytes", $filesize); 78 $this->assertNotEmpty($timecreated); 79 80 // Second row (user draft file). 81 [$contextname, $userfullname, $filename, $mimetype, $filesize, $timecreated] = array_values($content[1]); 82 83 $this->assertEquals($usercontext->get_context_name(), $contextname); 84 $this->assertEquals(fullname($user), $userfullname); 85 $this->assertEquals('Hello.txt', $filename); 86 $this->assertEquals('Text file', $mimetype); 87 $this->assertEquals("5\xc2\xa0bytes", $filesize); 88 $this->assertNotEmpty($timecreated); 89 } 90 91 /** 92 * Test datasource columns that aren't added by default 93 */ 94 public function test_datasource_non_default_columns(): void { 95 $this->resetAfterTest(); 96 $this->setAdminUser(); 97 98 $user = $this->getDataGenerator()->create_user(); 99 $usercontext = context_user::instance($user->id); 100 101 $this->setUser($user); 102 103 $course = $this->getDataGenerator()->create_course(); 104 $coursecontext = context_course::instance($course->id); 105 106 $draftitemid = $this->generate_test_files($coursecontext); 107 108 /** @var core_reportbuilder_generator $generator */ 109 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 110 $report = $generator->create_report(['name' => 'Files', 'source' => files::class, 'default' => 0]); 111 112 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:contexturl']); 113 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:path']); 114 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:author']); 115 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:license']); 116 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:component']); 117 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:area']); 118 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:itemid']); 119 120 $content = $this->get_custom_report_content($report->get('id')); 121 $content = $this->filter_custom_report_content($content, static function(array $row): bool { 122 return stripos($row['c0_contextid'], 'System') === false; 123 }, 'c0_contextid'); 124 125 // There should be two entries (directory & file) for each context. 126 $this->assertEquals([ 127 [ 128 "<a href=\"{$coursecontext->get_url()}\">{$coursecontext->get_context_name()}</a>", 129 '/', 130 null, 131 '', 132 'course', 133 'summary', 134 0, 135 ], 136 [ 137 "<a href=\"{$coursecontext->get_url()}\">{$coursecontext->get_context_name()}</a>", 138 '/', 139 null, 140 '', 141 'course', 142 'summary', 143 0, 144 ], 145 [ 146 "<a href=\"{$usercontext->get_url()}\">{$usercontext->get_context_name()}</a>", 147 '/', 148 null, 149 '', 150 'user', 151 'draft', 152 $draftitemid, 153 ], 154 [ 155 "<a href=\"{$usercontext->get_url()}\">{$usercontext->get_context_name()}</a>", 156 '/', 157 null, 158 '', 159 'user', 160 'draft', 161 $draftitemid, 162 ], 163 ], array_map('array_values', $content)); 164 } 165 166 /** 167 * Data provider for {@see test_datasource_filters} 168 * 169 * @return array[] 170 */ 171 public function datasource_filters_provider(): array { 172 return [ 173 // File. 174 'Filter directory' => ['file:directory', [ 175 'file:directory_operator' => boolean_select::CHECKED, 176 ], 2], 177 'Filter draft' => ['file:draft', [ 178 'file:draft_operator' => boolean_select::CHECKED, 179 ], 2], 180 'Filter name' => ['file:name', [ 181 'file:name_operator' => text::IS_EQUAL_TO, 182 'file:name_value' => 'Hello.txt', 183 ], 2], 184 'Filter size' => ['file:size', [ 185 'file:size_operator' => number::GREATER_THAN, 186 'file:size_value1' => 2, 187 ], 2], 188 'Filter license' => ['file:license', [ 189 'file:license_operator' => select::EQUAL_TO, 190 'file:license_value' => 'unknown', 191 ], 4], 192 'Filter license (non match)' => ['file:license', [ 193 'file:license_operator' => select::EQUAL_TO, 194 'file:license_value' => 'public', 195 ], 0], 196 'Filter time created' => ['file:timecreated', [ 197 'file:timecreated_operator' => date::DATE_RANGE, 198 'file:timecreated_from' => 1622502000, 199 ], 4], 200 'Filter time created (non match)' => ['file:timecreated', [ 201 'file:timecreated_operator' => date::DATE_RANGE, 202 'file:timecreated_to' => 1622502000, 203 ], 0], 204 205 // User (just to check the join). 206 'Filter user' => ['user:username', [ 207 'user:username_operator' => text::IS_EQUAL_TO, 208 'user:username_value' => 'alfie', 209 ], 4], 210 'Filter user (no match)' => ['user:username', [ 211 'user:username_operator' => text::IS_EQUAL_TO, 212 'user:username_value' => 'lionel', 213 ], 0], 214 ]; 215 } 216 217 /** 218 * Test datasource filters 219 * 220 * @param string $filtername 221 * @param array $filtervalues 222 * @param int $expectmatchcount 223 * 224 * @dataProvider datasource_filters_provider 225 */ 226 public function test_datasource_filters( 227 string $filtername, 228 array $filtervalues, 229 int $expectmatchcount 230 ): void { 231 $this->resetAfterTest(); 232 $this->setAdminUser(); 233 234 $user = $this->getDataGenerator()->create_user(['username' => 'alfie']); 235 $this->setUser($user); 236 237 $course = $this->getDataGenerator()->create_course(); 238 $coursecontext = context_course::instance($course->id); 239 240 $this->generate_test_files($coursecontext); 241 242 /** @var core_reportbuilder_generator $generator */ 243 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 244 245 // Create report containing single column, and given filter. 246 $report = $generator->create_report(['name' => 'Files', 'source' => files::class, 'default' => 0]); 247 $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'file:context']); 248 249 // Add filter, set it's values. 250 $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]); 251 $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues); 252 $content = $this->filter_custom_report_content($content, static function(array $row): bool { 253 return stripos($row['c0_contextid'], 'System') === false; 254 }, 'c0_contextid'); 255 256 $this->assertCount($expectmatchcount, $content); 257 } 258 259 /** 260 * Stress test datasource 261 * 262 * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php 263 */ 264 public function test_stress_datasource(): void { 265 if (!PHPUNIT_LONGTEST) { 266 $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); 267 } 268 269 $this->resetAfterTest(); 270 $this->setAdminUser(); 271 272 $course = $this->getDataGenerator()->create_course(); 273 $coursecontext = context_course::instance($course->id); 274 275 $this->generate_test_files($coursecontext); 276 277 $this->datasource_stress_test_columns(files::class); 278 $this->datasource_stress_test_columns_aggregation(files::class); 279 $this->datasource_stress_test_conditions(files::class, 'file:path'); 280 } 281 282 /** 283 * Ensuring report content only includes files we have explicitly created within the test, and ordering them 284 * 285 * @param array $content 286 * @param callable $callback 287 * @param string $sortfield 288 * @return array 289 */ 290 protected function filter_custom_report_content(array $content, callable $callback, string $sortfield): array { 291 $content = array_filter($content, $callback); 292 core_collator::asort_array_of_arrays_by_key($content, $sortfield); 293 return array_values($content); 294 } 295 296 /** 297 * Helper method to generate some test files for reporting on 298 * 299 * @param context_course $context 300 * @return int Draft item ID 301 */ 302 protected function generate_test_files(context_course $context): int { 303 global $USER; 304 305 $draftitemid = file_get_unused_draft_itemid(); 306 307 // Populate user draft. 308 get_file_storage()->create_file_from_string([ 309 'contextid' => context_user::instance($USER->id)->id, 310 'userid' => $USER->id, 311 'component' => 'user', 312 'filearea' => 'draft', 313 'itemid' => $draftitemid, 314 'filepath' => '/', 315 'filename' => 'Hello.txt', 316 ], 'Hello'); 317 318 // Save draft to course summary file area. 319 file_save_draft_area_files($draftitemid, $context->id, 'course', 'summary', 0); 320 321 return $draftitemid; 322 } 323 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body