diff --git a/.github/workflows/config-template.php b/.github/workflows/config-template.php index 2227832ee3b..ae49d583954 100644 --- a/.github/workflows/config-template.php +++ b/.github/workflows/config-template.php @@ -58,6 +58,8 @@ $CFG->pathtophp = getenv('pathtophp'); $CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata'; $CFG->phpunit_prefix = 't_'; +$CFG->routerconfigured = true; + define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080'); define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080'); diff --git a/.upgradenotes/MDL-87648-2026011405492190.yml b/.upgradenotes/MDL-87648-2026011405492190.yml new file mode 100644 index 00000000000..5e6b109aa42 --- /dev/null +++ b/.upgradenotes/MDL-87648-2026011405492190.yml @@ -0,0 +1,11 @@ +issueNumber: MDL-87648 +notes: + core: + - message: > + The Checks API now supports multiple results being returned for a single + instance of `\core\check\check`. + + + To support this a new `get_results(): array;` method has been created + which returns an array of `\core\check\result` objects. + type: improved diff --git a/admin/cli/checks.php b/admin/cli/checks.php index 40deb4d5535..fc434c6de48 100644 --- a/admin/cli/checks.php +++ b/admin/cli/checks.php @@ -110,46 +110,49 @@ $exitcode = $exitcodes[result::OK]; foreach ($checks as $check) { $ref = $check->get_ref(); - $result = $check->get_result(); - $status = $result->get_status(); - $checkexitcode = $exitcodes[$status]; + foreach ($check->get_results() as $result) { + $status = $result->get_status(); + $checkexitcode = $exitcodes[$status]; - // Summary is treated as html. - $summary = $result->get_summary(); - $summary = html_to_text($summary, 60, false); + // Summary is treated as html. + $summary = $result->get_summary(); + $summary = html_to_text($summary, 60, false); - if ($checkexitcode > $exitcode) { - $exitcode = $checkexitcode; - $header = $exitlabel[$status] . ': ' . $check->get_name() . " (" . $check->get_ref() . ")\n"; - } + if ($checkexitcode > $exitcode) { + $exitcode = $checkexitcode; + $header = $exitlabel[$status] . ': ' . $check->get_name() . " (" . $check->get_ref() . ")\n"; + } - if (empty($messages[$status])) { - $messages[$status] = $result; - } + if (empty($messages[$status])) { + $messages[$status] = $result; + } - $len = strlen(get_string('status' . $status)); + $len = strlen(get_string('status' . $status)); - if ($options['verbose'] || - $status == result::WARNING || - $status == result::CRITICAL || - $status == result::ERROR) { + if ( + $options['verbose'] + || $status == result::WARNING + || $status == result::CRITICAL + || $status == result::ERROR + ) { + $output .= sprintf( + $format, + $OUTPUT->check_result($result), + sprintf('%s (%s)', $check->get_name(), $ref), + ); - $output .= sprintf( - $format, - $OUTPUT->check_result($result), - sprintf('%s (%s)', $check->get_name(), $ref) - ); + $summary = str_replace("\n", "\n" . $prefix . ' ', $summary); + $output .= sprintf($format, '', ' ' . $summary); + $output .= sprintf($format, '', ' ' . html_to_text($result->get_details(), width: 0, dolinks: false)); - $summary = str_replace("\n", "\n" . $prefix . ' ', $summary); - $output .= sprintf( $format, '', ' ' . $summary); - - if ($options['verbose']) { - $actionlink = $check->get_action_link(); - if ($actionlink) { - $output .= sprintf( $format, '', ' ' . $actionlink->url); + if ($options['verbose']) { + $actionlink = $check->get_action_link(); + if ($actionlink) { + $output .= sprintf($format, '', ' ' . $actionlink->url); + } + $output .= sprintf($format, '', ''); } - $output .= sprintf( $format, '', ''); } } } @@ -168,4 +171,3 @@ if ($output) { // NRPE shell exit code. exit($exitcode); - diff --git a/public/admin/environment.xml b/public/admin/environment.xml index 30a56c7abe5..4593b6e3a20 100644 --- a/public/admin/environment.xml +++ b/public/admin/environment.xml @@ -5233,6 +5233,7 @@ + diff --git a/public/lang/en/admin.php b/public/lang/en/admin.php index 88b7969d33e..c3f4aab139d 100644 --- a/public/lang/en/admin.php +++ b/public/lang/en/admin.php @@ -126,6 +126,7 @@ $string['cannotuninstall'] = '{$a} can not be uninstalled.'; $string['categoryemail'] = 'Email'; $string['cfgwwwrootslashwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It includes a \'/\' character at the end which must be removed.'; $string['cfgwwwrootwarning'] = '$CFG->wwwroot is defined incorrectly in the config.php file. It should match the URL you are using to access this page.'; +$string['check_router'] = 'Router configuration'; $string['checkupgradepending'] = 'Upgrade'; $string['cleanup'] = 'Cleanup'; $string['clianswerno'] = 'n'; @@ -1171,6 +1172,21 @@ $string['requiremodintro'] = 'Require activity description'; $string['requiremodintro_desc'] = 'If enabled, users will be forced to enter a description for each activity.'; $string['required'] = 'Required'; $string['requires'] = 'Requires'; +$string['routerconfigurationset'] = 'Moodle has been informed that the web server is correctly configured.'; +$string['routerconfigureddetails'] = 'The router correctly serves {$a->url} with a {$a->expectedstatuscode} ("{$a->expectedstatuscodetitle}") response.'; +$string['routerconfiguredok'] = 'The router appears to be configured correctly.'; +$string['routerconfiguredwithissues'] = 'The router is not correctly configured.'; +$string['routerconfiguredwithissuesdetail'] = 'The router is not correctly configured - Issues were detected in {$a->count} checks.'; +$string['routerdocs'] = 'Router documentation'; +$string['routerexpectedgot'] = 'Expected {$a->expectedstatuscode} ("{$a->expectedstatuscodetitle}") and received {$a->statuscode} ("{$a->statuscodetitle}").'; +$string['routerfailapipage'] = 'An API route did not respond with the expected response.'; +$string['routerfailmissingpage'] = 'The missing page handler did not respond to the test URL correctly.'; +$string['routerfailpage'] = 'A standard page controller could not be loaded correctly. The router may not be configured properly.'; +$string['routerfailroutershim'] = 'A routed page whose path ends in ".php" did not response correctly.'; +$string['routerfailshim'] = 'A shimmed page did not response correctly.'; +$string['routernotconfigured'] = 'The router is not configured.'; +$string['routernotconfigureddetail'] = 'The router has not been configured correctly. Please see the documentation for more information on how to configure it correctly.'; +$string['routernotconfigureddetailwithurl'] = 'The following URL did not return the expected status code: {$a->url}.'; $string['purgecaches'] = 'Purge all caches'; $string['purgecachesconfirm'] = 'Moodle can cache themes, JavaScript, language strings, filtered text, RSS feeds and other pieces of calculated data. Purging caches will delete data from the server and force browsers to re-fetch data, so you can be sure you are seeing the most up-to-date values produced by the current code. There is no danger in purging caches, but your site may appear slower for a while until the server and clients calculate new information and cache it.'; $string['purgecachesfinished'] = 'All caches were purged.'; diff --git a/public/lib/classes/check/check.php b/public/lib/classes/check/check.php index 6fdb79f4f92..129626c36a6 100644 --- a/public/lib/classes/check/check.php +++ b/public/lib/classes/check/check.php @@ -128,5 +128,12 @@ abstract class check { */ abstract public function get_result(): result; + /** + * Return all results for this check + * + * @return result[] + */ + public function get_results(): array { + return [$this->get_result()]; + } } - diff --git a/public/lib/classes/check/environment/router.php b/public/lib/classes/check/environment/router.php new file mode 100644 index 00000000000..75f87f8b8f6 --- /dev/null +++ b/public/lib/classes/check/environment/router.php @@ -0,0 +1,183 @@ +. + +namespace core\check\environment; + +use core\check\check; +use core\check\result; +use core\output\action_link; +use GuzzleHttp\HandlerStack; + +/** + * Checks status of router by making test requests to shimmed and API pages. + * + * @package core + * @category check + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class router extends check { + #[\Override] + public function get_name(): string { + return get_string('check_router', 'admin'); + } + + /** + * Get the list of tests + * + * @return \Generator + */ + protected function get_tests(): \Generator { + yield [ + 'url' => '/core/check/controller/test', + 'expectedcode' => 200, + 'expectedcodetitle' => "OK", + 'failfeedbackstr' => 'routerfailpage', + 'bookmarkanchor' => 'routerfailpage', + ]; + yield [ + 'url' => '/api/rest/v2/openapi.json', + 'expectedcode' => 200, + 'expectedcodetitle' => "OK", + 'failfeedbackstr' => 'routerfailapipage', + 'bookmarkanchor' => 'routerfailapipage', + ]; + yield [ + 'url' => '/not/a/valid/request', + 'expectedcode' => 404, + 'expectedcodetitle' => "Not Found", + 'failfeedbackstr' => 'routerfailmissingpage', + 'bookmarkanchor' => 'routerfailmissingpage', + ]; + yield [ + 'url' => \core\router\util::get_path_for_callable([\core\route\shim\test_controller::class, 'real_file_shim']), + 'expectedcode' => 302, + 'expectedcodetitle' => "Found", + 'failfeedbackstr' => 'routerfailshim', + 'bookmarkanchor' => 'routerfailshim', + ]; + yield [ + 'url' => \core\router\util::get_path_for_callable([\core\route\shim\test_controller::class, 'nofile_shim']), + 'expectedcode' => 302, + 'expectedcodetitle' => "Found", + 'failfeedbackstr' => 'routerfailroutershim', + 'bookmarkanchor' => 'routerfailroutershim', + ]; + } + + #[\Override] + public function get_results(): array { + global $CFG; + + $results = []; + + if (empty($CFG->routerconfigured)) { + $result = new result( + result::ERROR, + get_string('routernotconfigured', 'admin'), + get_string('routernotconfigureddetail', 'admin', [ + 'docs' => get_docs_url("Configuring_the_Router#routernotconfigured"), + ]), + ); + + return [$result]; + } else { + $results[] = new result( + result::OK, + get_string('routerconfigurationset', 'admin'), + ); + } + + // The router is marked as configured. Check if it actually works though. + $client = \core\di::get(\core\http_client::class); + + $clientoptions = [ + 'http_errors' => false, + 'allow_redirects' => false, + // Override the Handler Stack to ensure that no caching is used, an that the security helper is not applied. + 'handler' => HandlerStack::create(), + ]; + + foreach ($this->get_tests() as $test) { + if ($test['url'] instanceof \core\url) { + $fullurl = $test['url']->out(false); + } else { + $fullurl = $CFG->wwwroot . $test['url']; + } + + try { + $response = $client->get($fullurl, $clientoptions); + $code = $response->getStatusCode(); + $codetitle = $response->getReasonPhrase(); + } catch (\GuzzleHttp\Exception\GuzzleException $e) { + $code = $e->getCode(); + $codetitle = $e->getMessage(); + } + + $resultprops = [ + 'url' => $fullurl, + 'docs' => get_docs_url("Configuring_the_Router#{$test['bookmarkanchor']}"), + 'expectedstatuscode' => $test['expectedcode'], + 'expectedstatuscodetitle' => $test['expectedcodetitle'], + 'statuscode' => $code, + 'statuscodetitle' => $codetitle, + ]; + if ($code === $test['expectedcode']) { + $results[] = new result( + result::OK, + get_string('routerconfigureddetails', 'admin', $resultprops), + ); + } else { + $expectedgot = get_string('routerexpectedgot', 'admin', $resultprops); + $results[] = new result( + result::ERROR, + get_string($test['failfeedbackstr'], 'admin', $resultprops), + get_string('routernotconfigureddetailwithurl', 'admin', $resultprops) . " {$expectedgot}", + new action_link( + new \core\url(get_docs_url("Configuring_the_Router#{$test['bookmarkanchor']}")), + get_string('routerdocs', 'admin'), + ), + ); + } + } + + return $results; + } + + #[\Override] + public function get_result(): result { + // Aggregate the results. + $failed = array_filter( + $this->get_results(), + fn ($result) => $result->get_status() !== result::OK, + ); + + if (empty($failed)) { + // Nothing failed. Return the OK result. + return new result( + result::OK, + get_string('routerconfiguredok', 'admin'), + ); + } + + // Some form of failure. Return the generic failure result. + return new result( + result::ERROR, + get_string('routerconfiguredwithissues', 'admin'), + get_string('routerconfiguredwithissuesdetail', 'admin', ['count' => count($failed)]), + ); + } +} diff --git a/public/lib/classes/check/manager.php b/public/lib/classes/check/manager.php index fceea2ff6f9..4b04fc0e03b 100644 --- a/public/lib/classes/check/manager.php +++ b/public/lib/classes/check/manager.php @@ -97,6 +97,7 @@ class manager { new environment\environment(), new environment\upgradecheck(), new environment\antivirus(), + new environment\router(), ]; // Any plugin can add status checks to this report by implementing a callback diff --git a/public/lib/classes/check/result.php b/public/lib/classes/check/result.php index 41b3596500d..2da3b57a2f4 100644 --- a/public/lib/classes/check/result.php +++ b/public/lib/classes/check/result.php @@ -16,6 +16,8 @@ namespace core\check; +use core\output\action_link; + /** * A check object returns a result object * @@ -29,7 +31,6 @@ namespace core\check; * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class result implements \renderable { - /** * This is used to notify if a check does not apply. * @@ -99,7 +100,14 @@ class result implements \renderable { * This may be a large amount of preformatted html text, possibly describing all the * different states and actions to address them. */ - protected $details = ''; + protected string $details = ''; + + /** + * @var null|action_link An action link which is more specific than the general check link, if relvant + * + * If no specific check link is specified, then the check link will be used. + */ + protected ?action_link $actionlink = null; /** * Constructor @@ -107,11 +115,18 @@ class result implements \renderable { * @param string $status code * @param string $summary a 1 liner summary * @param string $details as a html chunk + * @param ?action_link $details An action link which is more specific than the general check link, if relevant */ - public function __construct($status, $summary, $details = '') { + public function __construct( + string $status, + string $summary, + string $details = '', + ?action_link $actionlink = null, + ) { $this->status = $status; $this->summary = $summary; $this->details = $details; + $this->actionlink = $actionlink; } /** @@ -166,5 +181,13 @@ class result implements \renderable { public function get_template_name(): string { return 'core/check/result'; } -} + /** + * Get an action link if a more specific one was specified. + * + * @return null|action_link + */ + public function get_action_link(): ?action_link { + return $this->actionlink; + } +} diff --git a/public/lib/classes/check/table.php b/public/lib/classes/check/table.php index afe79c60282..669f7d06029 100644 --- a/public/lib/classes/check/table.php +++ b/public/lib/classes/check/table.php @@ -14,26 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +namespace core\check; + +use core\output\html_writer; + /** - * A table of check results + * A table of check results. * * @package core * @category check * @copyright 2020 Brendan Heywood * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -namespace core\check; - -defined('MOODLE_INTERNAL') || die(); - -/** - * A table of check results - * - * @copyright 2020 Brendan Heywood - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class table implements \renderable { - +class table implements \core\output\renderable { /** * @var \moodle_url $url */ @@ -49,6 +42,13 @@ class table implements \renderable { */ public $detail = ''; + /** + * The name of the check that was requested. + * + * @var string + */ + protected string $checkname = ''; + /** * @var array $checks shown in this table */ @@ -62,7 +62,6 @@ class table implements \renderable { * @param string $detail check to focus on */ public function __construct($type, $url, $detail = '') { - // We may need a bit more memory and this may take a long time to process. \raise_memory_limit(MEMORY_EXTRA); \core_php_time_limit::raise(); @@ -70,6 +69,7 @@ class table implements \renderable { $this->type = $type; $this->url = $url; $this->checks = \core\check\manager::get_checks($type); + $this->checkname = $detail; if ($detail) { $this->checks = array_filter($this->checks, function($check) use ($detail) { @@ -84,63 +84,91 @@ class table implements \renderable { /** * Render a table of checks * - * @param renderer $output to use + * @param \core\output\renderer $output to use * @return string html output */ public function render($output) { + $html = ''; - $table = new \html_table(); + $table = new \core_table\output\html_table(); $table->data = []; - $table->head = [ - get_string('status'), - get_string('check'), - get_string('summary'), - get_string('action'), - ]; - $table->colclasses = [ - 'rightalign status', - 'leftalign check', - 'leftalign summary', - 'leftalign action', - ]; + $table->head = [get_string('status')]; + $table->colclasses = ['rightalign status']; + + if (empty($this->checkname)) { + $table->head[] = get_string('check'); + $table->colclasses[] = 'leftalign check'; + } else { + $html .= html_writer::tag('h3', $this->detail->get_name()); + } + + $table->head[] = get_string('summary'); + $table->colclasses[] = 'leftalign summary'; + $table->head[] = get_string('action'); + $table->colclasses[] = 'leftalign action'; + $table->id = $this->type . 'reporttable'; $table->attributes = ['class' => 'admintable ' . $this->type . 'report table generaltable']; + $fails = []; foreach ($this->checks as $check) { $ref = $check->get_ref(); - $result = $check->get_result(); - $component = $check->get_component(); - $actionlink = $check->get_action_link(); $link = new \moodle_url($this->url, ['detail' => $ref]); - $row = []; - $row[] = $output->check_result($result); - $row[] = $output->action_link($link, $check->get_name()); + $results = empty($this->checkname) + ? [$check->get_result()] + : $check->get_results(); - $row[] = $result->get_summary() - . '
' - . \html_writer::start_tag('small') - . $output->action_link($link, get_string('moreinfo')) - . \html_writer::end_tag('small'); - if ($actionlink) { - $row[] = $output->render($actionlink); - } else { - $row[] = ''; + foreach ($results as $result) { + $row = []; + if ($result->get_status() !== result::OK) { + $fails[] = $result; + } + $row[] = $output->check_result($result); + + if (empty($this->checkname)) { + $row[] = $output->action_link($link, $check->get_name()); + } + + $row[] = $result->get_summary() + . '
' + . \html_writer::start_tag('small') + . $output->action_link($link, get_string('moreinfo')) + . \html_writer::end_tag('small'); + + $actionlink = $result->get_action_link() ?? $check->get_action_link(); + if ($actionlink) { + $row[] = $output->render($actionlink); + } else { + $row[] = ''; + } + + $table->data[] = $row; } - - $table->data[] = $row; } - $html = \html_writer::table($table); + $html .= \html_writer::table($table); - if ($this->detail && $result) { - $details = $result->get_details(); + $details = array_filter(array_map( + fn ($result) => $result->get_details(), + $fails, + )); + if (count($details) > 0) { + $html .= $output->heading(get_string('details'), 3); - if (!empty($details)) { - $html .= $output->heading(get_string('details'), 3); - $html .= $output->box($details, 'generalbox boxwidthnormal boxaligncenter'); + if (count($details) === 1) { + $result = reset($fails); + $html .= $output->box($result->get_details(), 'generalbox boxwidthnormal boxaligncenter'); + } else { + $html .= html_writer::start_tag('ul'); + foreach ($details as $detail) { + $html .= html_writer::tag('li', $detail); + } + $html .= html_writer::end_tag('ul'); } + } + if ($this->detail) { $html .= $output->continue_button($this->url); } diff --git a/public/lib/classes/environment.php b/public/lib/classes/environment.php index c05e756ef4c..403dc7357f4 100644 --- a/public/lib/classes/environment.php +++ b/public/lib/classes/environment.php @@ -160,4 +160,23 @@ class environment { return !empty($CFG->debugdeveloper); } + + /** + * Ensure that the Router is correctly configured. + * + * @param \environment_results $result + * @return \environment_results|null + */ + public static function check_router_configuration(\environment_results $result): ?\environment_results { + global $CFG; + + if (empty($CFG->routerconfigured)) { + // The router has not been marked as configured. + $result->setInfo('Router not configured'); + $result->setFeedbackStr('routernotconfigured'); + return $result; + } + + return null; + } } diff --git a/public/lib/classes/route/controller/test_controller.php b/public/lib/classes/route/controller/test_controller.php new file mode 100644 index 00000000000..f0b972c7d1b --- /dev/null +++ b/public/lib/classes/route/controller/test_controller.php @@ -0,0 +1,45 @@ +. + +namespace core\route\controller; + +use Psr\Http\Message\ResponseInterface; + +/** + * Test controller to provide a route for testing purposes. + * + * This set of routes is primarily intended for use with the Environment Checks + * to help administrators ensure that the Routing system is correctly configured. + * + * @package core + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class test_controller { + /** + * Test controller route. + * + * @param ResponseInterface $response + * @return ResponseInterface + */ + #[\core\router\route( + path: '/check/controller/test', + )] + public function test_action(ResponseInterface $response): ResponseInterface { + $response->getBody()->write('Test controller response'); + return $response; + } +} diff --git a/public/lib/classes/route/shim/test_controller.php b/public/lib/classes/route/shim/test_controller.php new file mode 100644 index 00000000000..c820ae60e89 --- /dev/null +++ b/public/lib/classes/route/shim/test_controller.php @@ -0,0 +1,75 @@ +. + +namespace core\route\shim; + +use core\router\route_controller; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * An example shim route to use for testing. + * + * This set of routes is primarily intended for use with the Environment Checks + * to help administrators ensure that the Routing system is correctly configured. + * + * @package core + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class test_controller { + use route_controller; + + /** + * An example shim route action for a file which manually shims the request. + * + * @param ResponseInterface $response + * @return ResponseInterface + */ + #[\core\router\route( + path: '/lib/exampleshimroute.php', + )] + public function real_file_shim( + RequestInterface $request, + ResponseInterface $response, + ): ResponseInterface { + return self::redirect_to_callable( + $request, + $response, + [\core\route\controller\test_controller::class, 'test_action'], + ); + } + + /** + * An example shim route action for a file which no longer exists. + * + * @param ResponseInterface $response + * @return ResponseInterface + */ + #[\core\router\route( + path: '/lib/exampleshimroute2.php', + )] + public function nofile_shim( + RequestInterface $request, + ResponseInterface $response, + ): ResponseInterface { + return self::redirect_to_callable( + $request, + $response, + [\core\route\controller\test_controller::class, 'test_action'], + ); + } +} diff --git a/public/lib/exampleshimroute.php b/public/lib/exampleshimroute.php new file mode 100644 index 00000000000..bc48c9353ba --- /dev/null +++ b/public/lib/exampleshimroute.php @@ -0,0 +1,30 @@ +. + +/** + * An example shim route to use for testing. + * + * This page is primarily intended for use with the Environment Checks + * to help administrators ensure that the Routing system is correctly configured. + * + * This file simulates a legacy file which has not yet been removed, but which exists in the Routing configuration. + * + * @package core + * @copyright Andrew Lyons + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once("../r.php"); diff --git a/public/lib/phpunit/bootstrap.php b/public/lib/phpunit/bootstrap.php index 8916ad69765..48dfd049174 100644 --- a/public/lib/phpunit/bootstrap.php +++ b/public/lib/phpunit/bootstrap.php @@ -201,6 +201,7 @@ $allowed = ['wwwroot', 'dataroot', 'dirroot', 'admin', 'directorypermissions', ' 'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword', 'proxybypass', 'altcacheconfigpath', 'pathtogs', 'pathtophp', 'pathtodu', 'aspellpath', 'pathtodot', 'pathtounoconv', 'alternative_file_system_class', 'pathtopython', + 'routerconfigured', ]; $productioncfg = (array) $CFG; $CFG = new stdClass(); diff --git a/public/lib/tests/router_test.php b/public/lib/tests/router_test.php index d7e8f089c0f..ea3be2793c6 100644 --- a/public/lib/tests/router_test.php +++ b/public/lib/tests/router_test.php @@ -93,12 +93,14 @@ final class router_test extends route_testcase { */ public function test_basepath( string $wwwroot, + bool $configured, string $expected, ): void { global $CFG; $this->resetAfterTest(); $CFG->wwwroot = $wwwroot; + $CFG->routerconfigured = $configured; $router = di::get(router::class); @@ -106,8 +108,10 @@ final class router_test extends route_testcase { } public static function basepath_provider(): \Iterator { - yield 'Domain' => ['http://example.com', '/r.php']; - yield 'Subdirectory' => ['http://example.com/moodle', '/moodle/r.php']; + yield 'Domain Router not configured' => ['http://example.com', false, '/r.php']; + yield 'Domain Router configured' => ['http://example.com', true, '']; + yield 'Subdirectory Router not configured' => ['http://example.com/moodle', false, '/moodle/r.php']; + yield 'Subdirectory Router configured' => ['http://example.com/moodle', true, '/moodle']; } public function test_basepath_guessed_rphp(): void {