Moodle release 4.4rc1
[moodle.git] / reportbuilder / tests / helpers.php
blob056e4f5acf449f824cf1e2876a12ec9cefac4f97
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.
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/>.
17 declare(strict_types=1);
19 use core_reportbuilder\manager;
20 use core_reportbuilder\local\helpers\aggregation;
21 use core_reportbuilder\local\helpers\report;
22 use core_reportbuilder\local\helpers\user_filter_manager;
23 use core_reportbuilder\table\custom_report_table_view;
25 /**
26 * Helper base class for reportbuilder unit tests
28 * @package core_reportbuilder
29 * @copyright 2021 Paul Holden <paulh@moodle.com>
30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32 abstract class core_reportbuilder_testcase extends advanced_testcase {
34 /**
35 * Retrieve content for given report as array of report data
37 * @param int $reportid
38 * @param int $pagesize
39 * @param array $filtervalues
40 * @return array[]
42 protected function get_custom_report_content(int $reportid, int $pagesize = 30, array $filtervalues = []): array {
43 $records = [];
45 // Apply filter values.
46 user_filter_manager::set($reportid, $filtervalues);
48 // Create table instance.
49 $table = custom_report_table_view::create($reportid);
50 $table->setup();
51 $table->query_db($pagesize, false);
53 // Extract raw data.
54 foreach ($table->rawdata as $record) {
55 $records[] = $table->format_row($record);
58 $table->close_recordset();
60 return $records;
63 /**
64 * Stress test a report source by iterating over all it's columns, enabling sorting where possible and asserting we can
65 * create a report for each
67 * @param string $source
69 protected function datasource_stress_test_columns(string $source): void {
71 /** @var core_reportbuilder_generator $generator */
72 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
74 $report = $generator->create_report(['name' => 'Stress columns', 'source' => $source, 'default' => 0]);
75 $instance = manager::get_report_from_persistent($report);
77 // Iterate over each available column, ensure each works correctly independent of any others.
78 foreach ($instance->get_columns() as $columnidentifier => $columninstance) {
79 $column = report::add_report_column($report->get('id'), $columnidentifier);
81 // Enable sorting of the column where possible.
82 if ($columninstance->get_is_sortable()) {
83 report::toggle_report_column_sorting($report->get('id'), $column->get('id'), true, SORT_DESC);
86 // We are only asserting the report returns content without errors, not the content itself.
87 try {
88 $content = $this->get_custom_report_content($report->get('id'));
89 $this->assertNotEmpty($content);
91 // Ensure appropriate debugging was triggered for deprecated column.
92 if ($columninstance->get_is_deprecated()) {
93 $this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
95 } catch (Throwable $exception) {
96 $this->fail("Error for column '{$columnidentifier}': " . $exception->getMessage());
99 report::delete_report_column($report->get('id'), $column->get('id'));
104 * Stress test a report source by iterating over all columns and asserting we can create a report while aggregating each
106 * @param string $source
108 protected function datasource_stress_test_columns_aggregation(string $source): void {
110 /** @var core_reportbuilder_generator $generator */
111 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
113 $report = $generator->create_report(['name' => 'Stress aggregation', 'source' => $source, 'default' => 0]);
114 $instance = manager::get_report_from_persistent($report);
116 // Add every column.
117 $columndeprecatedcount = 0;
118 foreach ($instance->get_columns() as $columnidentifier => $column) {
119 $columndeprecatedcount += (int) $column->get_is_deprecated();
120 report::add_report_column($report->get('id'), $columnidentifier);
123 // Now iterate over each column, and apply all suitable aggregation types.
124 $columns = $instance->get_active_columns();
125 $this->assertDebuggingCalledCount($columndeprecatedcount, null,
126 array_fill(0, $columndeprecatedcount, DEBUG_DEVELOPER));
127 foreach ($columns as $column) {
128 $aggregations = aggregation::get_column_aggregations($column->get_type(), $column->get_disabled_aggregation());
129 foreach (array_keys($aggregations) as $aggregation) {
130 $column->get_persistent()->set('aggregation', $aggregation)->update();
132 // We are only asserting the report returns content without errors, not the content itself.
133 try {
134 $content = $this->get_custom_report_content($report->get('id'));
135 $this->assertNotEmpty($content);
137 // Ensure appropriate debugging was triggered for deprecated columns.
138 $this->assertDebuggingCalledCount($columndeprecatedcount, null,
139 array_fill(0, $columndeprecatedcount, DEBUG_DEVELOPER));
140 } catch (Throwable $exception) {
141 $this->fail("Error for column '{$column->get_unique_identifier()}' with aggregation '{$aggregation}': " .
142 $exception->getMessage());
146 // Reset the column aggregation.
147 $column->get_persistent()->set('aggregation', null)->update();
152 * Stress test a report source by iterating over all it's conditions and asserting we can create a report using each
154 * @param string $source
155 * @param string $columnidentifier Should be a simple column, with as few fields and joins as possible, ideally selected
156 * from the base table itself
158 protected function datasource_stress_test_conditions(string $source, string $columnidentifier): void {
160 /** @var core_reportbuilder_generator $generator */
161 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
163 $report = $generator->create_report(['name' => 'Stress conditions', 'source' => $source, 'default' => 0]);
164 $instance = manager::get_report_from_persistent($report);
166 // Add single column only (to ensure no conditions have reliance on any columns).
167 report::add_report_column($report->get('id'), $columnidentifier);
169 // Iterate over each available condition, ensure each works correctly independent of any others.
170 $conditionidentifiers = array_keys($instance->get_conditions());
171 foreach ($conditionidentifiers as $conditionidentifier) {
172 $condition = report::add_report_condition($report->get('id'), $conditionidentifier);
173 $conditioninstance = $instance->get_condition($condition->get('uniqueidentifier'));
175 /** @var \core_reportbuilder\local\filters\base $conditionclass */
176 $conditionclass = $conditioninstance->get_filter_class();
178 // Set report condition values in order to activate it.
179 $conditionvalues = $conditionclass::create($conditioninstance)->get_sample_values();
180 if (empty($conditionvalues)) {
181 debugging("Missing sample values from filter '{$conditionclass}'", DEBUG_DEVELOPER);
183 $instance->set_condition_values($conditionvalues);
185 // We are only asserting the report returns content without errors, not the content itself.
186 try {
187 $content = $this->get_custom_report_content($report->get('id'));
188 $this->assertIsArray($content);
190 // Ensure appropriate debugging was triggered for deprecated condition.
191 if ($conditioninstance->get_is_deprecated()) {
192 $this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
194 } catch (Throwable $exception) {
195 $this->fail("Error for condition '{$conditionidentifier}': " . $exception->getMessage());
198 report::delete_report_condition($report->get('id'), $condition->get('id'));