Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [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_group\reportbuilder\datasource;
  20  
  21  use core_reportbuilder_generator;
  22  use core_reportbuilder_testcase;
  23  use core_reportbuilder\local\filters\{date, text};
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
  29  
  30  /**
  31   * Unit tests for groups datasource
  32   *
  33   * @package     core_group
  34   * @covers      \core_group\reportbuilder\datasource\groups
  35   * @copyright   2022 Paul Holden <paulh@moodle.com>
  36   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class groups_test extends core_reportbuilder_testcase {
  39  
  40      /**
  41       * Test default datasource
  42       */
  43      public function test_datasource_default(): void {
  44          $this->resetAfterTest();
  45  
  46          $course = $this->getDataGenerator()->create_course();
  47          $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
  48  
  49          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
  50          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
  51  
  52          /** @var core_reportbuilder_generator $generator */
  53          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  54          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 1]);
  55  
  56          $content = $this->get_custom_report_content($report->get('id'));
  57          $this->assertCount(1, $content);
  58  
  59          $contentrow = array_values(reset($content));
  60          $this->assertEquals([
  61              "<a href=\"https://www.example.com/moodle/course/view.php?id={$course->id}\">{$course->fullname}</a>", // Course.
  62              $group->name, // Group.
  63              fullname($user), // User.
  64          ], $contentrow);
  65      }
  66  
  67      /**
  68       * Test datasource groupings reports
  69       */
  70      public function test_datasource_groupings(): void {
  71          $this->resetAfterTest();
  72  
  73          $course = $this->getDataGenerator()->create_course();
  74  
  75          // Create group, add to grouping.
  76          $groupone = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Group A']);
  77          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id]);
  78          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $groupone->id]);
  79  
  80          // Create second group, no grouping.
  81          $grouptwo = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'Group B']);
  82  
  83          /** @var core_reportbuilder_generator $generator */
  84          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  85          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 0]);
  86  
  87          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
  88          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:name']);
  89          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:name', 'sortenabled' => 1]);
  90  
  91          $content = $this->get_custom_report_content($report->get('id'));
  92          $this->assertCount(2, $content);
  93  
  94          $this->assertEquals([
  95              [
  96                  $course->fullname,
  97                  $grouping->name,
  98                  $groupone->name,
  99              ],
 100              [
 101                  $course->fullname,
 102                  null,
 103                  $grouptwo->name,
 104              ],
 105          ], array_map('array_values', $content));
 106      }
 107  
 108      /**
 109       * Test datasource columns that aren't added by default
 110       */
 111      public function test_datasource_non_default_columns(): void {
 112          $this->resetAfterTest();
 113  
 114          $course = $this->getDataGenerator()->create_course();
 115          $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
 116  
 117          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'enrolmentkey' => 'S',
 118              'description' => 'My group']);
 119          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 120  
 121          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 122              'description' => 'My grouping']);
 123          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 124  
 125          /** @var core_reportbuilder_generator $generator */
 126          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 127          $report = $generator->create_report(['name' => 'Groups', 'source' => groups::class, 'default' => 0]);
 128  
 129          // Course (just to test join).
 130          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:shortname']);
 131  
 132          // Group.
 133          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:idnumber']);
 134          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:description']);
 135          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:enrolmentkey']);
 136          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:picture']);
 137          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:timecreated']);
 138          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:timemodified']);
 139  
 140          // Grouping.
 141          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:name']);
 142          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:idnumber']);
 143          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:description']);
 144          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:timecreated']);
 145          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'grouping:timemodified']);
 146  
 147          // Group member.
 148          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group_member:timeadded']);
 149          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group_member:component']);
 150  
 151          // User (just to test join).
 152          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:username']);
 153  
 154          $content = $this->get_custom_report_content($report->get('id'));
 155          $this->assertCount(1, $content);
 156  
 157          [
 158              $courseshortname,
 159              $groupidnumber,
 160              $groupdescription,
 161              $groupenrolmentkey,
 162              $grouppicture,
 163              $grouptimecreated,
 164              $grouptimemodified,
 165              $groupingname,
 166              $groupingidnumber,
 167              $groupingdescription,
 168              $groupingtimecreated,
 169              $groupingtimemodified,
 170              $groupmembertimeadded,
 171              $groupmemebercomponent,
 172              $userusername,
 173          ] = array_values($content[0]);
 174  
 175          $this->assertEquals($course->shortname, $courseshortname);
 176          $this->assertEquals('G101', $groupidnumber);
 177          $this->assertEquals(format_text($group->description), $groupdescription);
 178          $this->assertEquals('S', $groupenrolmentkey);
 179          $this->assertEmpty($grouppicture);
 180          $this->assertNotEmpty($grouptimecreated);
 181          $this->assertNotEmpty($grouptimemodified);
 182          $this->assertEquals($grouping->name, $groupingname);
 183          $this->assertEquals('GR101', $groupingidnumber);
 184          $this->assertEquals(format_text($grouping->description), $groupingdescription);
 185          $this->assertNotEmpty($groupingtimecreated);
 186          $this->assertNotEmpty($groupingtimemodified);
 187          $this->assertNotEmpty($groupmembertimeadded);
 188          $this->assertEmpty($groupmemebercomponent);
 189          $this->assertEquals($user->username, $userusername);
 190      }
 191  
 192      /**
 193       * Data provider for {@see test_datasource_filters}
 194       *
 195       * @return array[]
 196       */
 197      public function datasource_filters_provider(): array {
 198          return [
 199              // Course (just to test join).
 200              'Filter course name' => ['course:fullname', [
 201                  'course:fullname_operator' => text::IS_EQUAL_TO,
 202                  'course:fullname_value' => 'Test course',
 203              ], true],
 204              'Filter course name (no match)' => ['course:fullname', [
 205                  'course:fullname_operator' => text::IS_NOT_EQUAL_TO,
 206                  'course:fullname_value' => 'Test course',
 207              ], false],
 208  
 209              // Group.
 210              'Filter group name' => ['group:name', [
 211                  'group:name_operator' => text::IS_EQUAL_TO,
 212                  'group:name_value' => 'Test group',
 213              ], true],
 214              'Filter group name (no match)' => ['group:name', [
 215                  'group:name_operator' => text::IS_NOT_EQUAL_TO,
 216                  'group:name_value' => 'Test group',
 217              ], false],
 218              'Filter group idnumber' => ['group:idnumber', [
 219                  'group:idnumber_operator' => text::IS_EQUAL_TO,
 220                  'group:idnumber_value' => 'G101',
 221              ], true],
 222              'Filter group idnumber (no match)' => ['group:idnumber', [
 223                  'group:idnumber_operator' => text::IS_NOT_EQUAL_TO,
 224                  'group:idnumber_value' => 'G101',
 225              ], false],
 226              'Filter group time created' => ['group:timecreated', [
 227                  'group:timecreated_operator' => date::DATE_RANGE,
 228                  'group:timecreated_from' => 1622502000,
 229              ], true],
 230              'Filter group time created (no match)' => ['group:timecreated', [
 231                  'group:timecreated_operator' => date::DATE_RANGE,
 232                  'group:timecreated_to' => 1622502000,
 233              ], false],
 234  
 235              // Grouping.
 236              'Filter grouping name' => ['grouping:name', [
 237                  'grouping:name_operator' => text::IS_EQUAL_TO,
 238                  'grouping:name_value' => 'Test grouping',
 239              ], true],
 240              'Filter grouping name (no match)' => ['grouping:name', [
 241                  'grouping:name_operator' => text::IS_NOT_EQUAL_TO,
 242                  'grouping:name_value' => 'Test grouping',
 243              ], false],
 244              'Filter grouping idnumber' => ['grouping:idnumber', [
 245                  'grouping:idnumber_operator' => text::IS_EQUAL_TO,
 246                  'grouping:idnumber_value' => 'GR101',
 247              ], true],
 248              'Filter grouping idnumber (no match)' => ['grouping:idnumber', [
 249                  'grouping:idnumber_operator' => text::IS_NOT_EQUAL_TO,
 250                  'grouping:idnumber_value' => 'GR101',
 251              ], false],
 252              'Filter grouping time created' => ['grouping:timecreated', [
 253                  'grouping:timecreated_operator' => date::DATE_RANGE,
 254                  'grouping:timecreated_from' => 1622502000,
 255              ], true],
 256              'Filter grouping time created (no match)' => ['grouping:timecreated', [
 257                  'grouping:timecreated_operator' => date::DATE_RANGE,
 258                  'grouping:timecreated_to' => 1622502000,
 259              ], false],
 260  
 261              // Group member.
 262              'Filter group member time added' => ['group_member:timeadded', [
 263                  'group_member:timeadded_operator' => date::DATE_RANGE,
 264                  'group_member:timeadded_from' => 1622502000,
 265              ], true],
 266              'Filter group member time added (no match)' => ['group_member:timeadded', [
 267                  'group_member:timeadded_operator' => date::DATE_RANGE,
 268                  'group_member:timeadded_to' => 1622502000,
 269              ], false],
 270  
 271              // User (just to test join).
 272              'Filter user username' => ['user:username', [
 273                  'user:username_operator' => text::IS_EQUAL_TO,
 274                  'user:username_value' => 'testuser',
 275              ], true],
 276              'Filter user username (no match)' => ['user:username', [
 277                  'user:username_operator' => text::IS_NOT_EQUAL_TO,
 278                  'user:username_value' => 'testuser',
 279              ], false],
 280          ];
 281      }
 282  
 283      /**
 284       * Test datasource filters
 285       *
 286       * @param string $filtername
 287       * @param array $filtervalues
 288       * @param bool $expectmatch
 289       *
 290       * @dataProvider datasource_filters_provider
 291       */
 292      public function test_datasource_filters(
 293          string $filtername,
 294          array $filtervalues,
 295          bool $expectmatch
 296      ): void {
 297          $this->resetAfterTest();
 298  
 299          $course = $this->getDataGenerator()->create_course(['fullname' => 'Test course']);
 300          $user = $this->getDataGenerator()->create_and_enrol($course, 'student', ['username' => 'testuser']);
 301  
 302          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'name' => 'Test group']);
 303          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 304  
 305          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 306              'name' => 'Test grouping']);
 307          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 308  
 309          /** @var core_reportbuilder_generator $generator */
 310          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 311  
 312          // Create report containing single column, and given filter.
 313          $report = $generator->create_report(['name' => 'Tasks', 'source' => groups::class, 'default' => 0]);
 314          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'group:idnumber']);
 315  
 316          // Add filter, set it's values.
 317          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
 318          $content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
 319  
 320          if ($expectmatch) {
 321              $this->assertCount(1, $content);
 322              $this->assertEquals('G101', reset($content[0]));
 323          } else {
 324              $this->assertEmpty($content);
 325          }
 326      }
 327  
 328      /**
 329       * Stress test datasource
 330       *
 331       * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
 332       */
 333      public function test_stress_datasource(): void {
 334          if (!PHPUNIT_LONGTEST) {
 335              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
 336          }
 337  
 338          $this->resetAfterTest();
 339  
 340          $course = $this->getDataGenerator()->create_course(['fullname' => 'Test course']);
 341          $user = $this->getDataGenerator()->create_and_enrol($course, 'student', ['username' => 'testuser']);
 342  
 343          $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'idnumber' => 'G101', 'name' => 'Test group']);
 344          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 345  
 346          $grouping = $this->getDataGenerator()->create_grouping(['courseid' => $course->id, 'idnumber' => 'GR101',
 347              'name' => 'Test grouping']);
 348          $this->getDataGenerator()->create_grouping_group(['groupingid' => $grouping->id, 'groupid' => $group->id]);
 349  
 350          $this->datasource_stress_test_columns(groups::class);
 351          $this->datasource_stress_test_columns_aggregation(groups::class);
 352          $this->datasource_stress_test_conditions(groups::class, 'group:idnumber');
 353      }
 354  }