See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 /** 18 * Unit tests for those parts of adminlib.php that implement the admin tree 19 * functionality. 20 * 21 * @package core 22 * @category phpunit 23 * @copyright 2013 David Mudrak <david@moodle.com> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 require_once($CFG->libdir.'/adminlib.php'); 31 32 /** 33 * Provides the unit tests for admin tree functionality. 34 */ 35 class core_admintree_testcase extends advanced_testcase { 36 37 /** 38 * Adding nodes into the admin tree. 39 */ 40 public function test_add_nodes() { 41 42 $tree = new admin_root(true); 43 $tree->add('root', $one = new admin_category('one', 'One')); 44 $tree->add('root', new admin_category('three', 'Three')); 45 $tree->add('one', new admin_category('one-one', 'One-one')); 46 $tree->add('one', new admin_category('one-three', 'One-three')); 47 48 // Check the order of nodes in the root. 49 $map = array(); 50 foreach ($tree->children as $child) { 51 $map[] = $child->name; 52 } 53 $this->assertEquals(array('one', 'three'), $map); 54 55 // Insert a node into the middle. 56 $tree->add('root', new admin_category('two', 'Two'), 'three'); 57 $map = array(); 58 foreach ($tree->children as $child) { 59 $map[] = $child->name; 60 } 61 $this->assertEquals(array('one', 'two', 'three'), $map); 62 63 // Non-existing sibling. 64 $tree->add('root', new admin_category('four', 'Four'), 'five'); 65 $this->assertDebuggingCalled('Sibling five not found', DEBUG_DEVELOPER); 66 67 $tree->add('root', new admin_category('five', 'Five')); 68 $map = array(); 69 foreach ($tree->children as $child) { 70 $map[] = $child->name; 71 } 72 $this->assertEquals(array('one', 'two', 'three', 'four', 'five'), $map); 73 74 // Insert a node into the middle of the subcategory. 75 $tree->add('one', new admin_category('one-two', 'One-two'), 'one-three'); 76 $map = array(); 77 foreach ($one->children as $child) { 78 $map[] = $child->name; 79 } 80 $this->assertEquals(array('one-one', 'one-two', 'one-three'), $map); 81 82 // Check just siblings, not parents or children. 83 $tree->add('one', new admin_category('one-four', 'One-four'), 'one'); 84 $this->assertDebuggingCalled('Sibling one not found', DEBUG_DEVELOPER); 85 86 $tree->add('root', new admin_category('six', 'Six'), 'one-two'); 87 $this->assertDebuggingCalled('Sibling one-two not found', DEBUG_DEVELOPER); 88 89 // Me! Me! I wanna be first! 90 $tree->add('root', new admin_externalpage('zero', 'Zero', 'http://foo.bar'), 'one'); 91 $map = array(); 92 foreach ($tree->children as $child) { 93 $map[] = $child->name; 94 } 95 $this->assertEquals(array('zero', 'one', 'two', 'three', 'four', 'five', 'six'), $map); 96 } 97 98 /** 99 * @expectedException coding_exception 100 */ 101 public function test_add_nodes_before_invalid1() { 102 $tree = new admin_root(true); 103 $tree->add('root', new admin_externalpage('foo', 'Foo', 'http://foo.bar'), array('moodle:site/config')); 104 } 105 106 /** 107 * @expectedException coding_exception 108 */ 109 public function test_add_nodes_before_invalid2() { 110 $tree = new admin_root(true); 111 $tree->add('root', new admin_category('bar', 'Bar'), ''); 112 } 113 114 /** 115 * Test that changes to config trigger events. 116 */ 117 public function test_config_log_created_event() { 118 global $DB; 119 $this->resetAfterTest(); 120 $this->setAdminUser(); 121 122 $adminroot = new admin_root(true); 123 $adminroot->add('root', $one = new admin_category('one', 'One')); 124 $page = new admin_settingpage('page', 'Page'); 125 $page->add(new admin_setting_configtext('text1', 'Text 1', '', '')); 126 $page->add(new admin_setting_configpasswordunmask('pass1', 'Password 1', '', '')); 127 $adminroot->add('one', $page); 128 129 $sink = $this->redirectEvents(); 130 $data = array('s__text1' => 'sometext', 's__pass1' => ''); 131 $this->save_config_data($adminroot, $data); 132 133 $events = $sink->get_events(); 134 $sink->close(); 135 $event = array_pop($events); 136 $this->assertInstanceOf('\core\event\config_log_created', $event); 137 138 $sink = $this->redirectEvents(); 139 $data = array('s__text1'=>'other', 's__pass1'=>'nice password'); 140 $count = $this->save_config_data($adminroot, $data); 141 142 $events = $sink->get_events(); 143 $sink->close(); 144 $event = array_pop($events); 145 $this->assertInstanceOf('\core\event\config_log_created', $event); 146 // Verify password was nuked. 147 $this->assertNotEquals($event->other['value'], 'nice password'); 148 149 } 150 151 /** 152 * Testing whether a configexecutable setting is executable. 153 */ 154 public function test_admin_setting_configexecutable() { 155 global $CFG; 156 $this->resetAfterTest(); 157 158 $CFG->theme = 'classic'; 159 $executable = new admin_setting_configexecutable('test1', 'Text 1', 'Help Path', ''); 160 161 // Check for an invalid path. 162 $result = $executable->output_html($CFG->dirroot . '/lib/tests/other/file_does_not_exist'); 163 $this->assertRegexp('/class="text-danger"/', $result); 164 165 // Check for a directory. 166 $result = $executable->output_html($CFG->dirroot); 167 $this->assertRegexp('/class="text-danger"/', $result); 168 169 // Check for a file which is not executable. 170 $result = $executable->output_html($CFG->dirroot . '/filter/tex/readme_moodle.txt'); 171 $this->assertRegexp('/class="text-danger"/', $result); 172 173 // Check for an executable file. 174 if ($CFG->ostype == 'WINDOWS') { 175 $filetocheck = 'mimetex.exe'; 176 } else { 177 $filetocheck = 'mimetex.darwin'; 178 } 179 $result = $executable->output_html($CFG->dirroot . '/filter/tex/' . $filetocheck); 180 $this->assertRegexp('/class="text-success"/', $result); 181 182 // Check for no file specified. 183 $result = $executable->output_html(''); 184 $this->assertRegexp('/name="s__test1"/', $result); 185 $this->assertRegexp('/value=""/', $result); 186 } 187 188 /** 189 * Saving of values. 190 */ 191 public function test_config_logging() { 192 global $DB; 193 $this->resetAfterTest(); 194 $this->setAdminUser(); 195 196 $DB->delete_records('config_log', array()); 197 198 $adminroot = new admin_root(true); 199 $adminroot->add('root', $one = new admin_category('one', 'One')); 200 $page = new admin_settingpage('page', 'Page'); 201 $page->add(new admin_setting_configtext('text1', 'Text 1', '', '')); 202 $page->add(new admin_setting_configpasswordunmask('pass1', 'Password 1', '', '')); 203 $adminroot->add('one', $page); 204 205 $this->assertEmpty($DB->get_records('config_log')); 206 $data = array('s__text1'=>'sometext', 's__pass1'=>''); 207 $count = $this->save_config_data($adminroot, $data); 208 209 $this->assertEquals(2, $count); 210 $records = $DB->get_records('config_log', array(), 'id asc'); 211 $this->assertCount(2, $records); 212 reset($records); 213 $record = array_shift($records); 214 $this->assertNull($record->plugin); 215 $this->assertSame('text1', $record->name); 216 $this->assertNull($record->oldvalue); 217 $this->assertSame('sometext', $record->value); 218 $record = array_shift($records); 219 $this->assertNull($record->plugin); 220 $this->assertSame('pass1', $record->name); 221 $this->assertNull($record->oldvalue); 222 $this->assertSame('', $record->value); 223 224 $DB->delete_records('config_log', array()); 225 $data = array('s__text1'=>'other', 's__pass1'=>'nice password'); 226 $count = $this->save_config_data($adminroot, $data); 227 228 $this->assertEquals(2, $count); 229 $records = $DB->get_records('config_log', array(), 'id asc'); 230 $this->assertCount(2, $records); 231 reset($records); 232 $record = array_shift($records); 233 $this->assertNull($record->plugin); 234 $this->assertSame('text1', $record->name); 235 $this->assertSame('sometext', $record->oldvalue); 236 $this->assertSame('other', $record->value); 237 $record = array_shift($records); 238 $this->assertNull($record->plugin); 239 $this->assertSame('pass1', $record->name); 240 $this->assertSame('', $record->oldvalue); 241 $this->assertSame('********', $record->value); 242 243 $DB->delete_records('config_log', array()); 244 $data = array('s__text1'=>'', 's__pass1'=>''); 245 $count = $this->save_config_data($adminroot, $data); 246 247 $this->assertEquals(2, $count); 248 $records = $DB->get_records('config_log', array(), 'id asc'); 249 $this->assertCount(2, $records); 250 reset($records); 251 $record = array_shift($records); 252 $this->assertNull($record->plugin); 253 $this->assertSame('text1', $record->name); 254 $this->assertSame('other', $record->oldvalue); 255 $this->assertSame('', $record->value); 256 $record = array_shift($records); 257 $this->assertNull($record->plugin); 258 $this->assertSame('pass1', $record->name); 259 $this->assertSame('********', $record->oldvalue); 260 $this->assertSame('', $record->value); 261 } 262 263 protected function save_config_data(admin_root $adminroot, array $data) { 264 $adminroot->errors = array(); 265 266 $settings = admin_find_write_settings($adminroot, $data); 267 268 $count = 0; 269 foreach ($settings as $fullname=>$setting) { 270 /** @var $setting admin_setting */ 271 $original = $setting->get_setting(); 272 $error = $setting->write_setting($data[$fullname]); 273 if ($error !== '') { 274 $adminroot->errors[$fullname] = new stdClass(); 275 $adminroot->errors[$fullname]->data = $data[$fullname]; 276 $adminroot->errors[$fullname]->id = $setting->get_id(); 277 $adminroot->errors[$fullname]->error = $error; 278 } else { 279 $setting->write_setting_flags($data); 280 } 281 if ($setting->post_write_settings($original)) { 282 $count++; 283 } 284 } 285 286 return $count; 287 } 288 289 public function test_preventexecpath() { 290 $this->resetAfterTest(); 291 292 set_config('preventexecpath', 0); 293 set_config('execpath', null, 'abc_cde'); 294 $this->assertFalse(get_config('abc_cde', 'execpath')); 295 $setting = new admin_setting_configexecutable('abc_cde/execpath', 'some desc', '', '/xx/yy'); 296 $setting->write_setting('/oo/pp'); 297 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 298 299 // Prevent changes. 300 set_config('preventexecpath', 1); 301 $setting->write_setting('/mm/nn'); 302 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 303 304 // Use default in install. 305 set_config('execpath', null, 'abc_cde'); 306 $setting->write_setting('/mm/nn'); 307 $this->assertSame('/xx/yy', get_config('abc_cde', 'execpath')); 308 309 // Use empty value if no default. 310 $setting = new admin_setting_configexecutable('abc_cde/execpath', 'some desc', '', null); 311 set_config('execpath', null, 'abc_cde'); 312 $setting->write_setting('/mm/nn'); 313 $this->assertSame('', get_config('abc_cde', 'execpath')); 314 315 // This also affects admin_setting_configfile and admin_setting_configdirectory. 316 317 set_config('preventexecpath', 0); 318 set_config('execpath', null, 'abc_cde'); 319 $this->assertFalse(get_config('abc_cde', 'execpath')); 320 $setting = new admin_setting_configfile('abc_cde/execpath', 'some desc', '', '/xx/yy'); 321 $setting->write_setting('/oo/pp'); 322 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 323 324 // Prevent changes. 325 set_config('preventexecpath', 1); 326 $setting->write_setting('/mm/nn'); 327 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 328 329 // Use default in install. 330 set_config('execpath', null, 'abc_cde'); 331 $setting->write_setting('/mm/nn'); 332 $this->assertSame('/xx/yy', get_config('abc_cde', 'execpath')); 333 334 // Use empty value if no default. 335 $setting = new admin_setting_configfile('abc_cde/execpath', 'some desc', '', null); 336 set_config('execpath', null, 'abc_cde'); 337 $setting->write_setting('/mm/nn'); 338 $this->assertSame('', get_config('abc_cde', 'execpath')); 339 340 set_config('preventexecpath', 0); 341 set_config('execpath', null, 'abc_cde'); 342 $this->assertFalse(get_config('abc_cde', 'execpath')); 343 $setting = new admin_setting_configdirectory('abc_cde/execpath', 'some desc', '', '/xx/yy'); 344 $setting->write_setting('/oo/pp'); 345 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 346 347 // Prevent changes. 348 set_config('preventexecpath', 1); 349 $setting->write_setting('/mm/nn'); 350 $this->assertSame('/oo/pp', get_config('abc_cde', 'execpath')); 351 352 // Use default in install. 353 set_config('execpath', null, 'abc_cde'); 354 $setting->write_setting('/mm/nn'); 355 $this->assertSame('/xx/yy', get_config('abc_cde', 'execpath')); 356 357 // Use empty value if no default. 358 $setting = new admin_setting_configdirectory('abc_cde/execpath', 'some desc', '', null); 359 set_config('execpath', null, 'abc_cde'); 360 $setting->write_setting('/mm/nn'); 361 $this->assertSame('', get_config('abc_cde', 'execpath')); 362 } 363 364 /** 365 * Test setting for blocked hosts 366 * 367 * For testing the admin settings element only. Test for blocked hosts functionality can be found 368 * in lib/tests/curl_security_helper_test.php 369 */ 370 public function test_mixedhostiplist() { 371 $this->resetAfterTest(); 372 373 $adminsetting = new admin_setting_configmixedhostiplist('abc_cde/hostiplist', 'some desc', '', ''); 374 375 // Test valid settings. 376 $validsimplesettings = [ 377 'localhost', 378 "localhost\n127.0.0.1", 379 '192.168.10.1', 380 '0:0:0:0:0:0:0:1', 381 '::1', 382 'fe80::', 383 '231.54.211.0/20', 384 'fe80::/64', 385 '231.3.56.10-20', 386 'fe80::1111-bbbb', 387 '*.example.com', 388 '*.sub.example.com', 389 ]; 390 391 foreach ($validsimplesettings as $setting) { 392 $errormessage = $adminsetting->write_setting($setting); 393 $this->assertEmpty($errormessage, $errormessage); 394 $this->assertSame($setting, get_config('abc_cde', 'hostiplist')); 395 $this->assertSame($setting, $adminsetting->get_setting()); 396 } 397 398 // Test valid international site names. 399 $valididnsettings = [ 400 'правительство.рф' => 'xn--80aealotwbjpid2k.xn--p1ai', 401 'faß.de' => 'xn--fa-hia.de', 402 'ß.ß' => 'xn--zca.xn--zca', 403 '*.tharkûn.com' => '*.xn--tharkn-0ya.com', 404 ]; 405 406 foreach ($valididnsettings as $setting => $encodedsetting) { 407 $errormessage = $adminsetting->write_setting($setting); 408 $this->assertEmpty($errormessage, $errormessage); 409 $this->assertSame($encodedsetting, get_config('abc_cde', 'hostiplist')); 410 $this->assertSame($setting, $adminsetting->get_setting()); 411 } 412 413 // Invalid settings. 414 $this->assertEquals('These entries are invalid: nonvalid site name', $adminsetting->write_setting('nonvalid site name')); 415 $this->assertEquals('Empty lines are not valid', $adminsetting->write_setting("localhost\n")); 416 } 417 418 /** 419 * Verifies the $ADMIN global (adminroot cache) is properly reset when changing users, which might occur naturally during cron. 420 */ 421 public function test_adminroot_cache_reset() { 422 $this->resetAfterTest(); 423 global $DB; 424 // Current user is a manager at site context, which won't have access to the 'debugging' section of the admin tree. 425 $manageruser = $this->getDataGenerator()->create_user(); 426 $context = context_system::instance(); 427 $managerrole = $DB->get_record('role', array('shortname' => 'manager')); 428 role_assign($managerrole->id, $manageruser->id, $context->id); 429 $this->setUser($manageruser); 430 $adminroot = admin_get_root(); 431 $section = $adminroot->locate('debugging'); 432 $this->assertEmpty($section); 433 434 // Now, change the user to an admin user and confirm we get a new copy of the admin tree when next we ask for it. 435 $adminuser = get_admin(); 436 $this->setUser($adminuser); 437 $adminroot = admin_get_root(); 438 $section = $adminroot->locate('debugging'); 439 $this->assertInstanceOf('\admin_settingpage', $section); 440 } 441 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body