See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [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 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; 24 25 /** 26 * Helper base class for reportbuilder unit tests 27 * 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 31 */ 32 abstract class core_reportbuilder_testcase extends advanced_testcase { 33 34 /** 35 * Retrieve content for given report as array of report data 36 * 37 * @param int $reportid 38 * @param int $pagesize 39 * @param array $filtervalues 40 * @return array[] 41 */ 42 protected function get_custom_report_content(int $reportid, int $pagesize = 30, array $filtervalues = []): array { 43 $records = []; 44 45 // Apply filter values. 46 user_filter_manager::set($reportid, $filtervalues); 47 48 // Create table instance. 49 $table = custom_report_table_view::create($reportid); 50 $table->setup(); 51 $table->query_db($pagesize, false); 52 53 // Extract raw data. 54 foreach ($table->rawdata as $record) { 55 $records[] = $table->format_row($record); 56 } 57 58 $table->close_recordset(); 59 60 return $records; 61 } 62 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 66 * 67 * @param string $source 68 */ 69 protected function datasource_stress_test_columns(string $source): void { 70 71 /** @var core_reportbuilder_generator $generator */ 72 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 73 74 $report = $generator->create_report(['name' => 'Stress columns', 'source' => $source, 'default' => 0]); 75 $instance = manager::get_report_from_persistent($report); 76 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); 80 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); 84 } 85 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); 90 } catch (Throwable $exception) { 91 $this->fail("Error for column '{$columnidentifier}': " . $exception->getMessage()); 92 } 93 94 report::delete_report_column($report->get('id'), $column->get('id')); 95 } 96 } 97 98 /** 99 * Stress test a report source by iterating over all columns and asserting we can create a report while aggregating each 100 * 101 * @param string $source 102 */ 103 protected function datasource_stress_test_columns_aggregation(string $source): void { 104 105 /** @var core_reportbuilder_generator $generator */ 106 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 107 108 $report = $generator->create_report(['name' => 'Stress aggregation', 'source' => $source, 'default' => 0]); 109 $instance = manager::get_report_from_persistent($report); 110 111 // Add every column. 112 $columnidentifiers = array_keys($instance->get_columns()); 113 foreach ($columnidentifiers as $columnidentifier) { 114 report::add_report_column($report->get('id'), $columnidentifier); 115 } 116 117 // Now iterate over each column, and apply all suitable aggregation types. 118 foreach ($instance->get_active_columns() as $column) { 119 $aggregations = aggregation::get_column_aggregations($column->get_type(), $column->get_disabled_aggregation()); 120 foreach (array_keys($aggregations) as $aggregation) { 121 $column->get_persistent()->set('aggregation', $aggregation)->update(); 122 123 // We are only asserting the report returns content without errors, not the content itself. 124 try { 125 $content = $this->get_custom_report_content($report->get('id')); 126 $this->assertNotEmpty($content); 127 } catch (Throwable $exception) { 128 $this->fail("Error for column '{$column->get_unique_identifier()}' with aggregation '{$aggregation}': " . 129 $exception->getMessage()); 130 } 131 } 132 133 // Reset the column aggregation. 134 $column->get_persistent()->set('aggregation', null)->update(); 135 } 136 } 137 138 /** 139 * Stress test a report source by iterating over all it's conditions and asserting we can create a report using each 140 * 141 * @param string $source 142 * @param string $columnidentifier Should be a simple column, with as few fields and joins as possible, ideally selected 143 * from the base table itself 144 */ 145 protected function datasource_stress_test_conditions(string $source, string $columnidentifier): void { 146 147 /** @var core_reportbuilder_generator $generator */ 148 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 149 150 $report = $generator->create_report(['name' => 'Stress conditions', 'source' => $source, 'default' => 0]); 151 $instance = manager::get_report_from_persistent($report); 152 153 // Add single column only (to ensure no conditions have reliance on any columns). 154 report::add_report_column($report->get('id'), $columnidentifier); 155 156 // Iterate over each available condition, ensure each works correctly independent of any others. 157 $conditionidentifiers = array_keys($instance->get_conditions()); 158 foreach ($conditionidentifiers as $conditionidentifier) { 159 $condition = report::add_report_condition($report->get('id'), $conditionidentifier); 160 $conditioninstance = $instance->get_condition($condition->get('uniqueidentifier')); 161 162 /** @var \core_reportbuilder\local\filters\base $conditionclass */ 163 $conditionclass = $conditioninstance->get_filter_class(); 164 165 // Set report condition values in order to activate it. 166 $conditionvalues = $conditionclass::create($conditioninstance)->get_sample_values(); 167 if (empty($conditionvalues)) { 168 debugging("Missing sample values from filter '{$conditionclass}'", DEBUG_DEVELOPER); 169 } 170 $instance->set_condition_values($conditionvalues); 171 172 // We are only asserting the report returns content without errors, not the content itself. 173 try { 174 $content = $this->get_custom_report_content($report->get('id')); 175 $this->assertIsArray($content); 176 } catch (Throwable $exception) { 177 $this->fail("Error for condition '{$conditionidentifier}': " . $exception->getMessage()); 178 } 179 180 report::delete_report_condition($report->get('id'), $condition->get('id')); 181 } 182 } 183 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body