Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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   * IMS Enterprise enrolment tests.
  19   *
  20   * @package    enrol_imsenterprise
  21   * @category   test
  22   * @copyright  2012 David MonllaĆ³
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  require_once($CFG->dirroot . '/enrol/imsenterprise/locallib.php');
  30  require_once($CFG->dirroot . '/enrol/imsenterprise/lib.php');
  31  
  32  /**
  33   * IMS Enterprise test case
  34   *
  35   * @package    enrol_imsenterprise
  36   * @category   test
  37   * @copyright  2012 David MonllaĆ³
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class enrol_imsenterprise_testcase extends advanced_testcase {
  41  
  42      /**
  43       * @var $imsplugin enrol_imsenterprise_plugin IMS plugin instance.
  44       */
  45      public $imsplugin;
  46  
  47      /**
  48       * Setup required for all tests.
  49       */
  50      protected function setUp() {
  51          $this->resetAfterTest(true);
  52          $this->imsplugin = enrol_get_plugin('imsenterprise');
  53          $this->set_test_config();
  54      }
  55  
  56      /**
  57       * With an empty IMS enterprise file
  58       */
  59      public function test_emptyfile() {
  60          global $DB;
  61  
  62          $prevncourses = $DB->count_records('course');
  63          $prevnusers = $DB->count_records('user');
  64  
  65          $this->set_xml_file(false, false);
  66          $this->imsplugin->cron();
  67  
  68          $this->assertEquals($prevncourses, $DB->count_records('course'));
  69          $this->assertEquals($prevnusers, $DB->count_records('user'));
  70      }
  71  
  72      /**
  73       * Existing users are not created again
  74       */
  75      public function test_users_existing() {
  76          global $DB;
  77  
  78          $user1 = $this->getDataGenerator()->create_user();
  79          $user2 = $this->getDataGenerator()->create_user();
  80  
  81          $prevnusers = $DB->count_records('user');
  82  
  83          $users = array($user1, $user2);
  84          $this->set_xml_file($users);
  85          $this->imsplugin->cron();
  86  
  87          $this->assertEquals($prevnusers, $DB->count_records('user'));
  88      }
  89  
  90      /**
  91       * Add new users
  92       */
  93      public function test_users_add() {
  94          global $DB;
  95  
  96          $prevnusers = $DB->count_records('user');
  97  
  98          $user1 = new StdClass();
  99          $user1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 100          $user1->username = 'u1';
 101          $user1->email = 'u1@example.com';
 102          $user1->firstname = 'U';
 103          $user1->lastname = '1';
 104  
 105          $users = array($user1);
 106          $this->set_xml_file($users);
 107          $this->imsplugin->cron();
 108  
 109          $this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
 110      }
 111  
 112      /**
 113       * Add new users and set an auth type
 114       */
 115      public function test_users_add_with_auth() {
 116          global $DB;
 117  
 118          $prevnusers = $DB->count_records('user');
 119  
 120          $user2 = new StdClass();
 121          $user2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 122          $user2->username = 'u2';
 123          $user2->auth = 'cas';
 124          $user2->email = 'u2@u2.org';
 125          $user2->firstname = 'U';
 126          $user2->lastname = '2';
 127  
 128          $users = array($user2);
 129          $this->set_xml_file($users);
 130          $this->imsplugin->cron();
 131  
 132          $dbuser = $DB->get_record('user', array('username' => $user2->username));
 133          // TODO: MDL-15863 this needs more work due to multiauth changes, use first auth for now.
 134          $dbauth = explode(',', $dbuser->auth);
 135          $dbauth = reset($dbauth);
 136  
 137          $this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
 138          $this->assertEquals($dbauth, $user2->auth);
 139      }
 140  
 141  
 142      /**
 143       * Update user
 144       */
 145      public function test_user_update() {
 146          global $DB;
 147  
 148          $user = $this->getDataGenerator()->create_user(array('idnumber' => 'test-update-user'));
 149          $imsuser = new stdClass();
 150          $imsuser->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_UPDATE;
 151          // THIS SHOULD WORK, surely?: $imsuser->username = $user->username;
 152          // But this is required...
 153          $imsuser->username = $user->idnumber;
 154          $imsuser->email = 'u3@u3.org';
 155          $imsuser->firstname = 'U';
 156          $imsuser->lastname = '3';
 157  
 158          $this->set_xml_file(array($imsuser));
 159          $this->imsplugin->cron();
 160          $dbuser = $DB->get_record('user', array('id' => $user->id), '*', MUST_EXIST);
 161          $this->assertEquals($imsuser->email, $dbuser->email);
 162          $this->assertEquals($imsuser->firstname, $dbuser->firstname);
 163          $this->assertEquals($imsuser->lastname, $dbuser->lastname);
 164      }
 165  
 166      public function test_user_update_disabled() {
 167          global $DB;
 168  
 169          $this->imsplugin->set_config('imsupdateusers', false);
 170  
 171          $user = $this->getDataGenerator()->create_user(array('idnumber' => 'test-update-user'));
 172          $imsuser = new stdClass();
 173          $imsuser->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_UPDATE;
 174          // THIS SHOULD WORK, surely?: $imsuser->username = $user->username;
 175          // But this is required...
 176          $imsuser->username = $user->idnumber;
 177          $imsuser->email = 'u3@u3.org';
 178          $imsuser->firstname = 'U';
 179          $imsuser->lastname = '3';
 180  
 181          $this->set_xml_file(array($imsuser));
 182          $this->imsplugin->cron();
 183  
 184          // Verify no changes have been made.
 185          $dbuser = $DB->get_record('user', array('id' => $user->id), '*', MUST_EXIST);
 186          $this->assertEquals($user->email, $dbuser->email);
 187          $this->assertEquals($user->firstname, $dbuser->firstname);
 188          $this->assertEquals($user->lastname, $dbuser->lastname);
 189      }
 190  
 191      /**
 192       * Delete user
 193       */
 194      public function test_user_delete() {
 195          global $DB;
 196  
 197          $this->imsplugin->set_config('imsdeleteusers', true);
 198          $user = $this->getDataGenerator()->create_user(array('idnumber' => 'test-update-user'));
 199  
 200          $imsuser = new stdClass();
 201          $imsuser->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_DELETE;
 202          $imsuser->username = $user->username;
 203          $imsuser->firstname = $user->firstname;
 204          $imsuser->lastname = $user->lastname;
 205          $imsuser->email = $user->email;
 206          $this->set_xml_file(array($imsuser));
 207  
 208          $this->imsplugin->cron();
 209          $this->assertEquals(1, $DB->get_field('user', 'deleted', array('id' => $user->id), MUST_EXIST));
 210      }
 211  
 212      /**
 213       * Delete user disabled
 214       */
 215      public function test_user_delete_disabled() {
 216          global $DB;
 217  
 218          $this->imsplugin->set_config('imsdeleteusers', false);
 219          $user = $this->getDataGenerator()->create_user(array('idnumber' => 'test-update-user'));
 220  
 221          $imsuser = new stdClass();
 222          $imsuser->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_DELETE;
 223          $imsuser->username = $user->username;
 224          $imsuser->firstname = $user->firstname;
 225          $imsuser->lastname = $user->lastname;
 226          $imsuser->email = $user->email;
 227          $this->set_xml_file(array($imsuser));
 228  
 229          $this->imsplugin->cron();
 230          $this->assertEquals(0, $DB->get_field('user', 'deleted', array('id' => $user->id), MUST_EXIST));
 231      }
 232  
 233      /**
 234       * Existing courses are not created again
 235       */
 236      public function test_courses_existing() {
 237          global $DB;
 238  
 239          $course1 = $this->getDataGenerator()->create_course(array('idnumber' => 'id1'));
 240          $course2 = $this->getDataGenerator()->create_course(array('idnumber' => 'id2'));
 241  
 242          // Default mapping according to default course attributes - IMS description tags mapping.
 243          $course1->imsshort = $course1->fullname;
 244          $course2->imsshort = $course2->fullname;
 245          unset($course1->category);
 246          unset($course2->category);
 247  
 248          $prevncourses = $DB->count_records('course');
 249  
 250          $courses = array($course1, $course2);
 251          $this->set_xml_file(false, $courses);
 252          $this->imsplugin->cron();
 253  
 254          $this->assertEquals($prevncourses, $DB->count_records('course'));
 255      }
 256  
 257      /**
 258       * Add new courses
 259       */
 260      public function test_courses_add() {
 261          global $DB;
 262  
 263          $prevncourses = $DB->count_records('course');
 264  
 265          $course1 = new StdClass();
 266          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 267          $course1->idnumber = 'id1';
 268          $course1->imsshort = 'id1';
 269          $course1->category[] = 'DEFAULT CATNAME';
 270  
 271          $course2 = new StdClass();
 272          $course2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 273          $course2->idnumber = 'id2';
 274          $course2->imsshort = 'id2';
 275          $course2->category[] = 'DEFAULT CATNAME';
 276  
 277          $courses = array($course1, $course2);
 278          $this->set_xml_file(false, $courses);
 279          $this->imsplugin->cron();
 280  
 281          $this->assertEquals(($prevncourses + 2), $DB->count_records('course'));
 282          $this->assertTrue($DB->record_exists('course', array('idnumber' => $course1->idnumber)));
 283          $this->assertTrue($DB->record_exists('course', array('idnumber' => $course2->idnumber)));
 284      }
 285  
 286      /**
 287       * Verify that courses are not created when createnewcourses
 288       * option is diabled.
 289       */
 290      public function test_courses_add_createnewcourses_disabled() {
 291          global $DB;
 292  
 293          $this->imsplugin->set_config('createnewcourses', false);
 294          $prevncourses = $DB->count_records('course');
 295  
 296          $course1 = new StdClass();
 297          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 298          $course1->idnumber = 'id1';
 299          $course1->imsshort = 'id1';
 300          $course1->category[] = 'DEFAULT CATNAME';
 301  
 302          $course2 = new StdClass();
 303          $course2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 304          $course2->idnumber = 'id2';
 305          $course2->imsshort = 'id2';
 306          $course2->category[] = 'DEFAULT CATNAME';
 307  
 308          $courses = array($course1, $course2);
 309          $this->set_xml_file(false, $courses);
 310          $this->imsplugin->cron();
 311  
 312          $courses = array($course1, $course2);
 313          $this->set_xml_file(false, $courses);
 314          $this->imsplugin->cron();
 315  
 316          // Verify the courses have not ben creased.
 317          $this->assertEquals($prevncourses , $DB->count_records('course'));
 318          $this->assertFalse($DB->record_exists('course', array('idnumber' => $course1->idnumber)));
 319          $this->assertFalse($DB->record_exists('course', array('idnumber' => $course2->idnumber)));
 320      }
 321  
 322      /**
 323       * Test adding a course with no idnumber.
 324       */
 325      public function test_courses_no_idnumber() {
 326          global $DB;
 327  
 328          $prevncourses = $DB->count_records('course');
 329  
 330          $course1 = new StdClass();
 331          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 332          $course1->idnumber = '';
 333          $course1->imsshort = 'id1';
 334          $course1->category[] = 'DEFAULT CATNAME';
 335  
 336          $this->set_xml_file(false, array($course1));
 337          $this->imsplugin->cron();
 338  
 339          // Verify no action.
 340          $this->assertEquals($prevncourses, $DB->count_records('course'));
 341      }
 342  
 343      /**
 344       * Add new course with the truncateidnumber setting.
 345       */
 346      public function test_courses_add_truncate_idnumber() {
 347          global $DB;
 348  
 349          $truncatelength = 4;
 350  
 351          $this->imsplugin->set_config('truncatecoursecodes', $truncatelength);
 352          $prevncourses = $DB->count_records('course');
 353  
 354          $course1 = new StdClass();
 355          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 356          $course1->idnumber = '123456789';
 357          $course1->imsshort = 'id1';
 358          $course1->category[] = 'DEFAULT CATNAME';
 359  
 360          $this->set_xml_file(false, array($course1));
 361          $this->imsplugin->cron();
 362  
 363          // Verify the new course has been added.
 364          $this->assertEquals(($prevncourses + 1), $DB->count_records('course'));
 365  
 366          $truncatedidnumber = substr($course1->idnumber, 0, $truncatelength);
 367  
 368          $this->assertTrue($DB->record_exists('course', array('idnumber' => $truncatedidnumber)));
 369      }
 370  
 371      /**
 372       * Add new course without a category.
 373       */
 374      public function test_course_add_default_category() {
 375          global $DB;
 376  
 377          $this->imsplugin->set_config('createnewcategories', false);
 378  
 379          // Delete the default category, to ensure the plugin handles this gracefully.
 380          $defaultcat = core_course_category::get_default();
 381          $defaultcat->delete_full(false);
 382  
 383          // Create an course with the IMS plugin without a category.
 384          $course1 = new stdClass();
 385          $course1->idnumber = 'id1';
 386          $course1->imsshort = 'id1';
 387          $course1->category[] = '';
 388          $this->set_xml_file(false, array($course1));
 389          $this->imsplugin->cron();
 390  
 391          // Check the course has been created.
 392          $dbcourse = $DB->get_record('course', array('idnumber' => $course1->idnumber), '*', MUST_EXIST);
 393          // Check that it belongs to a category which exists.
 394          $this->assertTrue($DB->record_exists('course_categories', array('id' => $dbcourse->category)));
 395      }
 396  
 397      /**
 398       * Course attributes mapping to IMS enterprise group description tags
 399       */
 400      public function test_courses_attrmapping() {
 401          global $DB;
 402  
 403          // Setting a all = coursecode (idnumber) mapping.
 404          $this->imsplugin->set_config('imscoursemapshortname', 'coursecode');
 405          $this->imsplugin->set_config('imscoursemapfullname', 'coursecode');
 406          $this->imsplugin->set_config('imscoursemapsummary', 'coursecode');
 407  
 408          $course1 = new StdClass();
 409          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 410          $course1->idnumber = 'id1';
 411          $course1->imsshort = 'description_short1';
 412          $course1->imslong = 'description_long';
 413          $course1->imsfull = 'description_full';
 414          $course1->category[] = 'DEFAULT CATNAME';
 415  
 416          $this->set_xml_file(false, array($course1));
 417          $this->imsplugin->cron();
 418  
 419          $dbcourse = $DB->get_record('course', array('idnumber' => $course1->idnumber));
 420          $this->assertFalse(!$dbcourse);
 421          $this->assertEquals($dbcourse->shortname, $course1->idnumber);
 422          $this->assertEquals($dbcourse->fullname, $course1->idnumber);
 423          $this->assertEquals($dbcourse->summary, $course1->idnumber);
 424  
 425          // Setting a mapping using all the description tags.
 426          $this->imsplugin->set_config('imscoursemapshortname', 'short');
 427          $this->imsplugin->set_config('imscoursemapfullname', 'long');
 428          $this->imsplugin->set_config('imscoursemapsummary', 'full');
 429  
 430          $course2 = new StdClass();
 431          $course2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 432          $course2->idnumber = 'id2';
 433          $course2->imsshort = 'description_short2';
 434          $course2->imslong = 'description_long';
 435          $course2->imsfull = 'description_full';
 436          $course2->category[] = 'DEFAULT CATNAME';
 437  
 438          $this->set_xml_file(false, array($course2));
 439          $this->imsplugin->cron();
 440  
 441          $dbcourse = $DB->get_record('course', array('idnumber' => $course2->idnumber));
 442          $this->assertFalse(!$dbcourse);
 443          $this->assertEquals($dbcourse->shortname, $course2->imsshort);
 444          $this->assertEquals($dbcourse->fullname, $course2->imslong);
 445          $this->assertEquals($dbcourse->summary, $course2->imsfull);
 446  
 447          // Setting a mapping where the specified description tags doesn't exist in the XML file (must delegate into idnumber).
 448          $this->imsplugin->set_config('imscoursemapshortname', 'short');
 449          $this->imsplugin->set_config('imscoursemapfullname', 'long');
 450          $this->imsplugin->set_config('imscoursemapsummary', 'full');
 451  
 452          $course3 = new StdClass();
 453          $course3->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 454          $course3->idnumber = 'id3';
 455          $course3->imsshort = 'description_short3';
 456          $course3->category[] = 'DEFAULT CATNAME';
 457  
 458          $this->set_xml_file(false, array($course3));
 459          $this->imsplugin->cron();
 460  
 461          $dbcourse = $DB->get_record('course', array('idnumber' => $course3->idnumber));
 462          $this->assertFalse(!$dbcourse);
 463          $this->assertEquals($dbcourse->shortname, $course3->imsshort);
 464          $this->assertEquals($dbcourse->fullname, $course3->idnumber);
 465          $this->assertEquals($dbcourse->summary, $course3->idnumber);
 466  
 467      }
 468  
 469      /**
 470       * Course updates
 471       */
 472      public function test_course_update() {
 473          global $DB;
 474  
 475          $course4 = new StdClass();
 476          $course4->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 477          $course4->idnumber = 'id4';
 478          $course4->imsshort = 'id4';
 479          $course4->imsfull = 'id4';
 480          $course4->category[] = 'DEFAULT CATNAME';
 481  
 482          $this->set_xml_file(false, array($course4));
 483          $this->imsplugin->cron();
 484  
 485          $course4u = $DB->get_record('course', array('idnumber' => $course4->idnumber));
 486  
 487          $course4u->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_UPDATE;
 488          $course4u->imsshort = 'description_short_updated';
 489          $course4u->imsfull = 'description_full_updated';
 490          unset($course4u->category);
 491  
 492          $this->set_xml_file(false, array($course4u));
 493          $this->imsplugin->cron();
 494  
 495          $dbcourse = $DB->get_record('course', array('idnumber' => $course4->idnumber));
 496          $this->assertFalse(!$dbcourse);
 497          $this->assertEquals($dbcourse->shortname, $course4u->imsshort);
 498          $this->assertEquals($dbcourse->fullname, $course4u->imsfull);
 499      }
 500  
 501      /**
 502       * Course delete. Make it hidden.
 503       */
 504      public function test_course_delete() {
 505          global $DB;
 506  
 507          $course8 = new StdClass();
 508          $course8->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 509          $course8->idnumber = 'id8';
 510          $course8->imsshort = 'id8';
 511          $course8->imsfull = 'id8';
 512          $course8->category[] = 'DEFAULT CATNAME';
 513  
 514          $this->set_xml_file(false, array($course8));
 515          $this->imsplugin->cron();
 516  
 517          $course8d = $DB->get_record('course', array('idnumber' => $course8->idnumber));
 518          $this->assertEquals($course8d->visible, 1);
 519  
 520          $course8d->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_DELETE;
 521          unset($course8d->category);
 522  
 523          $this->set_xml_file(false, array($course8d));
 524          $this->imsplugin->cron();
 525  
 526          $dbcourse = $DB->get_record('course', array('idnumber' => $course8d->idnumber));
 527          $this->assertFalse(!$dbcourse);
 528          $this->assertEquals($dbcourse->visible, 0);
 529      }
 530  
 531  
 532      /**
 533       * Nested categories with name during course creation
 534       */
 535      public function test_nested_categories() {
 536          global $DB;
 537  
 538          $this->imsplugin->set_config('nestedcategories', true);
 539  
 540          $topcat = 'DEFAULT CATNAME';
 541          $subcat = 'DEFAULT SUB CATNAME';
 542  
 543          $course5 = new StdClass();
 544          $course5->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 545          $course5->idnumber = 'id5';
 546          $course5->imsshort = 'description_short';
 547          $course5->imslong = 'description_long';
 548          $course5->imsfull = 'description_full';
 549          $course5->category = array();
 550          $course5->category[] = $topcat;
 551          $course5->category[] = $subcat;
 552  
 553          $this->set_xml_file(false, array($course5));
 554          $this->imsplugin->cron();
 555  
 556          $parentcatid = $DB->get_field('course_categories', 'id', array('name' => $topcat));
 557          $subcatid = $DB->get_field('course_categories', 'id', array('name' => $subcat, 'parent' => $parentcatid));
 558  
 559          $this->assertTrue(isset($subcatid));
 560          $this->assertTrue($subcatid > 0);
 561  
 562          $topcat = 'DEFAULT CATNAME';
 563          $subcat = 'DEFAULT SUB CATNAME TEST2';
 564  
 565          $course6 = new StdClass();
 566          $course6->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 567          $course6->idnumber = 'id6';
 568          $course6->imsshort = 'description_short';
 569          $course6->imslong = 'description_long';
 570          $course6->imsfull = 'description_full';
 571          $course6->category = array();
 572          $course6->category[] = $topcat;
 573          $course6->category[] = $subcat;
 574  
 575          $this->set_xml_file(false, array($course6));
 576          $this->imsplugin->cron();
 577  
 578          $parentcatid = $DB->get_field('course_categories', 'id', array('name' => $topcat));
 579          $subcatid = $DB->get_field('course_categories', 'id', array('name' => $subcat, 'parent' => $parentcatid));
 580  
 581          $this->assertTrue(isset($subcatid));
 582          $this->assertTrue($subcatid > 0);
 583      }
 584  
 585  
 586      /**
 587       * Test that duplicate nested categories with name are not created
 588       */
 589      public function test_nested_categories_for_dups() {
 590          global $DB;
 591  
 592          $this->imsplugin->set_config('nestedcategories', true);
 593  
 594          $topcat = 'DEFAULT CATNAME';
 595          $subcat = 'DEFAULT SUB CATNAME DUPTEST';
 596  
 597          $course7 = new StdClass();
 598          $course7->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 599          $course7->idnumber = 'id7';
 600          $course7->imsshort = 'description_short';
 601          $course7->imslong = 'description_long';
 602          $course7->imsfull = 'description_full';
 603          $course7->category[] = $topcat;
 604          $course7->category[] = $subcat;
 605  
 606          $this->set_xml_file(false, array($course7));
 607          $this->imsplugin->cron();
 608  
 609          $prevncategories = $DB->count_records('course_categories');
 610  
 611          $course8 = new StdClass();
 612          $course8->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 613          $course8->idnumber = 'id8';
 614          $course8->imsshort = 'description_short';
 615          $course8->imslong = 'description_long';
 616          $course8->imsfull = 'description_full';
 617          $course8->category[] = $topcat;
 618          $course8->category[] = $subcat;
 619  
 620          $this->set_xml_file(false, array($course8));
 621          $this->imsplugin->cron();
 622  
 623          $this->assertEquals($prevncategories, $DB->count_records('course_categories'));
 624      }
 625  
 626      /**
 627       * Nested categories with idnumber during course creation
 628       */
 629      public function test_nested_categories_idnumber() {
 630          global $DB;
 631  
 632          $this->imsplugin->set_config('nestedcategories', true);
 633          $this->imsplugin->set_config('categoryidnumber', true);
 634          $this->imsplugin->set_config('categoryseparator', '|');
 635  
 636          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 637  
 638          $topcatname = 'DEFAULT CATNAME';
 639          $subcatname = 'DEFAULT SUB CATNAME';
 640          $topcatidnumber = '01';
 641          $subcatidnumber = '0101';
 642  
 643          $topcat = $topcatname.$catsep.$topcatidnumber;
 644          $subcat = $subcatname.$catsep.$subcatidnumber;
 645  
 646          $course1 = new StdClass();
 647          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 648          $course1->idnumber = 'id5';
 649          $course1->imsshort = 'description_short';
 650          $course1->imslong = 'description_long';
 651          $course1->imsfull = 'description_full';
 652          $course1->category[] = $topcat;
 653          $course1->category[] = $subcat;
 654  
 655          $this->set_xml_file(false, array($course1));
 656          $this->imsplugin->cron();
 657  
 658          $parentcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $topcatidnumber));
 659          $subcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $subcatidnumber, 'parent' => $parentcatid));
 660  
 661          $this->assertTrue(isset($subcatid));
 662          $this->assertTrue($subcatid > 0);
 663  
 664          // Change the category separator character.
 665          $this->imsplugin->set_config('categoryseparator', ':');
 666  
 667          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 668  
 669          $topcatname = 'DEFAULT CATNAME';
 670          $subcatname = 'DEFAULT SUB CATNAME TEST2';
 671          $topcatidnumber = '01';
 672          $subcatidnumber = '0102';
 673  
 674          $topcat = $topcatname.$catsep.$topcatidnumber;
 675          $subcat = $subcatname.$catsep.$subcatidnumber;
 676  
 677          $course2 = new StdClass();
 678          $course2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 679          $course2->idnumber = 'id6';
 680          $course2->imsshort = 'description_short';
 681          $course2->imslong = 'description_long';
 682          $course2->imsfull = 'description_full';
 683          $course2->category[] = $topcat;
 684          $course2->category[] = $subcat;
 685  
 686          $this->set_xml_file(false, array($course2));
 687          $this->imsplugin->cron();
 688  
 689          $parentcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $topcatidnumber));
 690          $subcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $subcatidnumber, 'parent' => $parentcatid));
 691  
 692          $this->assertTrue(isset($subcatid));
 693          $this->assertTrue($subcatid > 0);
 694      }
 695  
 696      /**
 697       * Test that duplicate nested categories with idnumber are not created
 698       */
 699      public function test_nested_categories_idnumber_for_dups() {
 700          global $DB;
 701  
 702          $this->imsplugin->set_config('nestedcategories', true);
 703          $this->imsplugin->set_config('categoryidnumber', true);
 704          $this->imsplugin->set_config('categoryseparator', '|');
 705  
 706          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 707  
 708          $topcatname = 'DEFAULT CATNAME';
 709          $subcatname = 'DEFAULT SUB CATNAME';
 710          $topcatidnumber = '01';
 711          $subcatidnumber = '0101';
 712  
 713          $topcat = $topcatname.$catsep.$topcatidnumber;
 714          $subcat = $subcatname.$catsep.$subcatidnumber;
 715  
 716          $course1 = new StdClass();
 717          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 718          $course1->idnumber = 'id1';
 719          $course1->imsshort = 'description_short';
 720          $course1->imslong = 'description_long';
 721          $course1->imsfull = 'description_full';
 722          $course1->category[] = $topcat;
 723          $course1->category[] = $subcat;
 724  
 725          $this->set_xml_file(false, array($course1));
 726          $this->imsplugin->cron();
 727  
 728          $prevncategories = $DB->count_records('course_categories');
 729  
 730          $course2 = new StdClass();
 731          $course2->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 732          $course2->idnumber = 'id2';
 733          $course2->imsshort = 'description_short';
 734          $course2->imslong = 'description_long';
 735          $course2->imsfull = 'description_full';
 736          $course2->category[] = $topcat;
 737          $course2->category[] = $subcat;
 738  
 739          $this->set_xml_file(false, array($course2));
 740          $this->imsplugin->cron();
 741  
 742          $this->assertEquals($prevncategories, $DB->count_records('course_categories'));
 743      }
 744  
 745      /**
 746       * Test that nested categories with idnumber is not created if name is missing
 747       */
 748      public function test_categories_idnumber_missing_name() {
 749          global $DB, $CFG;
 750  
 751          $this->imsplugin->set_config('nestedcategories', true);
 752          $this->imsplugin->set_config('categoryidnumber', true);
 753          $this->imsplugin->set_config('categoryseparator', '|');
 754          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 755  
 756          $topcatname = 'DEFAULT CATNAME';
 757          $subcatname = '';
 758          $topcatidnumber = '01';
 759          $subcatidnumber = '0101';
 760  
 761          $topcat = $topcatname.$catsep.$topcatidnumber;
 762          $subcat = $subcatname.$catsep.$subcatidnumber;
 763  
 764          $course1 = new StdClass();
 765          $course1->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 766          $course1->idnumber = 'id1';
 767          $course1->imsshort = 'description_short';
 768          $course1->imslong = 'description_long';
 769          $course1->imsfull = 'description_full';
 770          $course1->category[] = $topcat;
 771          $course1->category[] = $subcat;
 772  
 773          $this->set_xml_file(false, array($course1));
 774          $this->imsplugin->cron();
 775  
 776          // Check all categories except the last subcategory was created.
 777          $parentcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $topcatidnumber));
 778          $this->assertTrue((boolean)$parentcatid);
 779          $subcatid = $DB->get_field('course_categories', 'id', array('idnumber' => $subcatidnumber, 'parent' => $parentcatid));
 780          $this->assertFalse((boolean)$subcatid);
 781  
 782          // Check course was put in default category.
 783          $defaultcat = core_course_category::get_default();
 784          $dbcourse = $DB->get_record('course', array('idnumber' => $course1->idnumber), '*', MUST_EXIST);
 785          $this->assertEquals($dbcourse->category, $defaultcat->id);
 786  
 787      }
 788  
 789      /**
 790       * Create category with name (nested categories not activated).
 791       */
 792      public function test_create_category_name_no_nested() {
 793          global $DB;
 794  
 795          $course = new StdClass();
 796          $course->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 797          $course->idnumber = 'id';
 798          $course->imsshort = 'description_short';
 799          $course->imslong = 'description_long';
 800          $course->imsfull = 'description_full';
 801          $course->category[] = 'CATNAME';
 802  
 803          $this->set_xml_file(false, array($course));
 804          $this->imsplugin->cron();
 805  
 806          $dbcat = $DB->get_record('course_categories', array('name' => $course->category[0]));
 807          $this->assertFalse(!$dbcat);
 808          $this->assertEquals($dbcat->parent, 0);
 809  
 810          $dbcourse = $DB->get_record('course', array('idnumber' => $course->idnumber));
 811          $this->assertFalse(!$dbcourse);
 812          $this->assertEquals($dbcourse->category, $dbcat->id);
 813  
 814      }
 815  
 816      /**
 817       * Find a category with name (nested categories not activated).
 818       */
 819      public function test_find_category_name_no_nested() {
 820          global $DB;
 821  
 822          $cattop = $this->getDataGenerator()->create_category(array('name' => 'CAT-TOP'));
 823          $catsub = $this->getDataGenerator()->create_category(array('name' => 'CAT-SUB', 'parent' => $cattop->id));
 824          $prevcats = $DB->count_records('course_categories');
 825  
 826          $course = new StdClass();
 827          $course->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 828          $course->idnumber = 'id';
 829          $course->imsshort = 'description_short';
 830          $course->imslong = 'description_long';
 831          $course->imsfull = 'description_full';
 832          $course->category[] = 'CAT-SUB';
 833  
 834          $this->set_xml_file(false, array($course));
 835          $this->imsplugin->cron();
 836  
 837          $newcats = $DB->count_records('course_categories');
 838  
 839          // Check that no new category was not created.
 840          $this->assertEquals($prevcats, $newcats);
 841  
 842          // Check course is associated to CAT-SUB.
 843          $dbcourse = $DB->get_record('course', array('idnumber' => $course->idnumber));
 844          $this->assertFalse(!$dbcourse);
 845          $this->assertEquals($dbcourse->category, $catsub->id);
 846  
 847      }
 848  
 849      /**
 850       * Create category with idnumber (nested categories not activated).
 851       */
 852      public function test_create_category_idnumber_no_nested() {
 853          global $DB;
 854  
 855          $this->imsplugin->set_config('categoryidnumber', true);
 856          $this->imsplugin->set_config('categoryseparator', '|');
 857          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 858  
 859          $course = new StdClass();
 860          $course->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 861          $course->idnumber = 'id';
 862          $course->imsshort = 'description_short';
 863          $course->imslong = 'description_long';
 864          $course->imsfull = 'description_full';
 865          $course->category[] = 'CATNAME'. $catsep .  'CATIDNUMBER';
 866  
 867          $this->set_xml_file(false, array($course));
 868          $this->imsplugin->cron();
 869  
 870          $dbcat = $DB->get_record('course_categories', array('idnumber' => 'CATIDNUMBER'));
 871          $this->assertFalse(!$dbcat);
 872          $this->assertEquals($dbcat->parent, 0);
 873          $this->assertEquals($dbcat->name, 'CATNAME');
 874  
 875          $dbcourse = $DB->get_record('course', array('idnumber' => $course->idnumber));
 876          $this->assertFalse(!$dbcourse);
 877          $this->assertEquals($dbcourse->category, $dbcat->id);
 878  
 879      }
 880  
 881      /**
 882       * Find a category with idnumber (nested categories not activated).
 883       */
 884      public function test_find_category_idnumber_no_nested() {
 885          global $DB;
 886  
 887          $this->imsplugin->set_config('categoryidnumber', true);
 888          $this->imsplugin->set_config('categoryseparator', '|');
 889          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 890  
 891          $topcatname = 'CAT-TOP';
 892          $subcatname = 'CAT-SUB';
 893          $topcatidnumber = 'ID-TOP';
 894          $subcatidnumber = 'ID-SUB';
 895  
 896          $cattop = $this->getDataGenerator()->create_category(array('name' => $topcatname, 'idnumber' => $topcatidnumber));
 897          $catsub = $this->getDataGenerator()->create_category(array('name' => $subcatname, 'idnumber' => $subcatidnumber,
 898                  'parent' => $cattop->id));
 899          $prevcats = $DB->count_records('course_categories');
 900  
 901          $course = new StdClass();
 902          $course->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 903          $course->idnumber = 'id';
 904          $course->imsshort = 'description_short';
 905          $course->imslong = 'description_long';
 906          $course->imsfull = 'description_full';
 907          $course->category[] = $subcatname . $catsep . $subcatidnumber;
 908  
 909          $this->set_xml_file(false, array($course));
 910          $this->imsplugin->cron();
 911  
 912          $newcats = $DB->count_records('course_categories');
 913  
 914          // Check that no new category was not created.
 915          $this->assertEquals($prevcats, $newcats);
 916  
 917          $dbcourse = $DB->get_record('course', array('idnumber' => $course->idnumber));
 918          $this->assertFalse(!$dbcourse);
 919          $this->assertEquals($dbcourse->category, $catsub->id);
 920  
 921      }
 922  
 923      /**
 924       * Test that category with idnumber is not created if name is missing (nested categories not activated).
 925       */
 926      public function test_category_idnumber_missing_name_no_nested() {
 927          global $DB;
 928  
 929          $this->imsplugin->set_config('categoryidnumber', true);
 930          $this->imsplugin->set_config('categoryseparator', '|');
 931          $catsep = trim($this->imsplugin->get_config('categoryseparator'));
 932  
 933          $catidnumber = '01';
 934  
 935          $course = new StdClass();
 936          $course->recstatus = enrol_imsenterprise_plugin::IMSENTERPRISE_ADD;
 937          $course->idnumber = 'id1';
 938          $course->imsshort = 'description_short';
 939          $course->imslong = 'description_long';
 940          $course->imsfull = 'description_full';
 941          $course->category[] = '' . $catsep . $catidnumber;
 942  
 943          $this->set_xml_file(false, array($course));
 944          $this->imsplugin->cron();
 945  
 946          // Check category was not created.
 947          $catid = $DB->get_record('course_categories', array('idnumber' => $catidnumber));
 948          $this->assertFalse($catid);
 949  
 950          // Check course was put in default category.
 951          $defaultcat = core_course_category::get_default();
 952          $dbcourse = $DB->get_record('course', array('idnumber' => $course->idnumber), '*', MUST_EXIST);
 953          $this->assertEquals($dbcourse->category, $defaultcat->id);
 954  
 955      }
 956  
 957      /**
 958       * Sets the plugin configuration for testing
 959       */
 960      public function set_test_config() {
 961          $this->imsplugin->set_config('mailadmins', false);
 962          $this->imsplugin->set_config('prev_path', '');
 963          $this->imsplugin->set_config('createnewusers', true);
 964          $this->imsplugin->set_config('imsupdateusers', true);
 965          $this->imsplugin->set_config('createnewcourses', true);
 966          $this->imsplugin->set_config('updatecourses', true);
 967          $this->imsplugin->set_config('createnewcategories', true);
 968          $this->imsplugin->set_config('categoryseparator', '');
 969          $this->imsplugin->set_config('categoryidnumber', false);
 970          $this->imsplugin->set_config('nestedcategories', false);
 971      }
 972  
 973      /**
 974       * Creates an IMS enterprise XML file and adds it's path to config settings.
 975       *
 976       * @param bool|array $users false or array of users StdClass
 977       * @param bool|array $courses false or of courses StdClass
 978       */
 979      public function set_xml_file($users = false, $courses = false) {
 980  
 981          $xmlcontent = '<enterprise>';
 982  
 983          // Users.
 984          if (!empty($users)) {
 985              foreach ($users as $user) {
 986                  $xmlcontent .= '
 987    <person';
 988  
 989                  // Optional recstatus (1=add, 2=update, 3=delete).
 990                  if (!empty($user->recstatus)) {
 991                      $xmlcontent .= ' recstatus="'.$user->recstatus.'"';
 992                  }
 993  
 994                  $xmlcontent .= '>
 995      <sourcedid>
 996        <source>TestSource</source>
 997        <id>'.$user->username.'</id>
 998      </sourcedid>
 999      <userid';
1000  
1001                  // Optional authentication type.
1002                  if (!empty($user->auth)) {
1003                      $xmlcontent .= ' authenticationtype="'.$user->auth.'"';
1004                  }
1005  
1006                  $xmlcontent .= '>'.$user->username.'</userid>
1007      <name>
1008        <fn>'.$user->firstname.' '.$user->lastname.'</fn>
1009        <n>
1010          <family>'.$user->lastname.'</family>
1011          <given>'.$user->firstname.'</given>
1012        </n>
1013      </name>
1014      <email>'.$user->email.'</email>
1015    </person>';
1016              }
1017          }
1018  
1019          // Courses.
1020          // Mapping based on default course attributes - IMS group tags mapping.
1021          if (!empty($courses)) {
1022              foreach ($courses as $course) {
1023  
1024                  $xmlcontent .= '
1025    <group';
1026  
1027                  // Optional recstatus (1=add, 2=update, 3=delete).
1028                  if (!empty($course->recstatus)) {
1029                      $xmlcontent .= ' recstatus="'.$course->recstatus.'"';
1030                  }
1031  
1032                  $xmlcontent .= '>
1033      <sourcedid>
1034        <source>TestSource</source>
1035        <id>'.$course->idnumber.'</id>
1036      </sourcedid>
1037      <description>';
1038  
1039                  // Optional to test course attributes mappings.
1040                  if (!empty($course->imsshort)) {
1041                      $xmlcontent .= '
1042        <short>'.$course->imsshort.'</short>';
1043                  }
1044  
1045                  // Optional to test course attributes mappings.
1046                  if (!empty($course->imslong)) {
1047                      $xmlcontent .= '
1048        <long>'.$course->imslong.'</long>';
1049                  }
1050  
1051                  // Optional to test course attributes mappings.
1052                  if (!empty($course->imsfull)) {
1053                      $xmlcontent .= '
1054        <full>'.$course->imsfull.'</full>';
1055                  }
1056  
1057                  // The orgunit tag value is used by moodle as category name.
1058                  $xmlcontent .= '
1059      </description>
1060      <org>';
1061                  // Optional category name.
1062                  if (isset($course->category) && !empty($course->category)) {
1063                      foreach ($course->category as $category) {
1064                          $xmlcontent .= '
1065        <orgunit>'.$category.'</orgunit>';
1066                      }
1067                  }
1068  
1069                  $xmlcontent .= '
1070      </org>
1071    </group>';
1072              }
1073          }
1074  
1075          $xmlcontent .= '
1076  </enterprise>';
1077  
1078          // Creating the XML file.
1079          $filename = 'ims_' . rand(1000, 9999) . '.xml';
1080          $tmpdir = make_temp_directory('enrol_imsenterprise');
1081          $xmlfilepath = $tmpdir . '/' . $filename;
1082          file_put_contents($xmlfilepath, $xmlcontent);
1083  
1084          // Setting the file path in CFG.
1085          $this->imsplugin->set_config('imsfilelocation', $xmlfilepath);
1086      }
1087  
1088      /**
1089       * IMS Enterprise enrolment task test.
1090       */
1091      public function test_imsenterprise_cron_task() {
1092          global $DB;
1093          $prevnusers = $DB->count_records('user');
1094  
1095          $user1 = new StdClass();
1096          $user1->username = 'u1';
1097          $user1->email = 'u1@example.com';
1098          $user1->firstname = 'U';
1099          $user1->lastname = '1';
1100  
1101          $users = array($user1);
1102          $this->set_xml_file($users);
1103  
1104          $task = new enrol_imsenterprise\task\cron_task();
1105          $task->execute();
1106  
1107          $this->assertEquals(($prevnusers + 1), $DB->count_records('user'));
1108      }
1109  }