Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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  namespace core;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  global $CFG;
  22  require_once($CFG->libdir . '/adminlib.php');
  23  require_once($CFG->libdir . '/statslib.php');
  24  require_once($CFG->libdir . '/cronlib.php');
  25  require_once (__DIR__ . '/fixtures/stats_events.php');
  26  
  27  /**
  28   * Test functions that affect daily stats.
  29   *
  30   * @package    core
  31   * @category   test
  32   * @copyright  2012 Tyler Bannister
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class statslib_test extends \advanced_testcase {
  36      /** The day to use for testing **/
  37      const DAY = 1272672000;
  38  
  39      /** The timezone to use for testing **/
  40      const TIMEZONE = 0;
  41  
  42      /** @var array The list of temporary tables created for the statistic calculations **/
  43      protected $tables = array('temp_log1', 'temp_log2', 'temp_stats_daily', 'temp_stats_user_daily');
  44  
  45      /** @var array The replacements to be used when loading XML files **/
  46      protected $replacements = null;
  47  
  48  
  49      /**
  50       * Setup function
  51       *   - Allow changes to CFG->debug for testing purposes.
  52       */
  53      protected function setUp(): void {
  54          global $CFG, $DB;
  55          parent::setUp();
  56  
  57          // Settings to force statistic to run during testing.
  58          $this->setTimezone(self::TIMEZONE);
  59          \core_date::set_default_server_timezone();
  60          $CFG->statsfirstrun           = 'all';
  61          $CFG->statslastdaily          = 0;
  62  
  63          // Figure out the broken day start so I can figure out when to the start time should be.
  64          $time   = time();
  65          // This nonsense needs to be rewritten.
  66          $date = new \DateTime('now', \core_date::get_server_timezone_object());
  67          $offset = $date->getOffset();
  68          $stime  = $time + $offset;
  69          $stime  = intval($stime / (60*60*24)) * 60*60*24;
  70          $stime -= $offset;
  71  
  72          $shour  = intval(($time - $stime) / (60*60));
  73  
  74          if ($DB->record_exists('user', array('username' => 'user1'))) {
  75              return;
  76          }
  77  
  78          // Set up the database.
  79          $datagen = self::getDataGenerator();
  80  
  81          $user1   = $datagen->create_user(array('username'=>'user1'));
  82          $user2   = $datagen->create_user(array('username'=>'user2'));
  83  
  84          $course1 = $datagen->create_course(array('shortname'=>'course1'));
  85          $datagen->enrol_user($user1->id, $course1->id);
  86  
  87          $this->generate_replacement_list();
  88  
  89          // Reset between tests.
  90          $this->resetAfterTest();
  91      }
  92  
  93      /**
  94       * Function to setup database.
  95       *
  96       * @param phpunit_dataset $dataset Containing all the information loaded from fixtures.
  97       * @param array $filter Tables to be sent to database.
  98       */
  99      protected function prepare_db($dataset, $tables) {
 100          global $DB;
 101  
 102          foreach ($tables as $tablename) {
 103              $DB->delete_records($tablename);
 104              $dataset->to_database([$tablename]);
 105          }
 106      }
 107  
 108      /**
 109       * Load dataset from XML file.
 110       */
 111      protected function generate_replacement_list() {
 112          global $CFG, $DB;
 113  
 114          if ($this->replacements !== null) {
 115              return;
 116          }
 117  
 118          $this->setTimezone(self::TIMEZONE);
 119  
 120          $guest = $DB->get_record('user', array('id' => $CFG->siteguest));
 121          $user1 = $DB->get_record('user', array('username' => 'user1'));
 122          $user2 = $DB->get_record('user', array('username' => 'user2'));
 123  
 124          if (($guest === false) || ($user1 === false) || ($user2 === false)) {
 125              trigger_error('User setup incomplete', E_USER_ERROR);
 126          }
 127  
 128          $site    = $DB->get_record('course', array('id' => SITEID));
 129          $course1 = $DB->get_record('course', array('shortname' => 'course1'));
 130  
 131          if (($site === false) || ($course1 === false)) {
 132              trigger_error('Course setup incomplete', E_USER_ERROR);
 133          }
 134  
 135          $start      = stats_get_base_daily(self::DAY + 3600);
 136          $startnolog = stats_get_base_daily(stats_get_start_from('daily'));
 137          $gr         = get_guest_role();
 138          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 139  
 140          $this->replacements = array(
 141              // Start and end times.
 142              '[start_0]'          => $start -  14410,  // 4 hours before.
 143              '[start_1]'          => $start +  14410,  // 4 hours after.
 144              '[start_2]'          => $start +  14420,
 145              '[start_3]'          => $start +  14430,
 146              '[start_4]'          => $start + 100800, // 28 hours after.
 147              '[end]'              => stats_get_next_day_start($start),
 148              '[end_no_logs]'      => stats_get_next_day_start($startnolog),
 149  
 150              // User ids.
 151              '[guest_id]'         => $guest->id,
 152              '[user1_id]'         => $user1->id,
 153              '[user2_id]'         => $user2->id,
 154  
 155              // Course ids.
 156              '[course1_id]'       => $course1->id,
 157              '[site_id]'          => SITEID,
 158  
 159              // Role ids.
 160              '[frontpage_roleid]' => (int) $CFG->defaultfrontpageroleid,
 161              '[guest_roleid]'     => $gr->id,
 162              '[student_roleid]'   => $studentrole->id,
 163          );
 164      }
 165  
 166      /**
 167       * Load dataset from XML file.
 168       *
 169       * @param string $file The name of the file to load
 170       * @return phpunit_dataset
 171       */
 172      protected function load_xml_data_file($file) {
 173  
 174          $xml = file_get_contents($file);
 175  
 176          // Apply all the replacements straight in xml.
 177          foreach ($this->replacements as $placeholder => $value) {
 178              $placeholder = preg_quote($placeholder, '/');
 179              $xml = preg_replace('/' . $placeholder . '/', $value, $xml);
 180          }
 181  
 182          return $this->dataset_from_string($xml, 'xml');
 183      }
 184  
 185      /**
 186       * Provides the log data for test_statslib_cron_daily.
 187       *
 188       * @return array of fixture XML log file names.
 189       */
 190      public function daily_log_provider() {
 191          $logfiles = array();
 192          $fileno = array('00', '01', '02', '03', '04', '05', '06', '07', '08');
 193  
 194          foreach ($fileno as $no) {
 195              $logfiles[] = array("statslib-test{$no}.xml");
 196          }
 197  
 198          return $logfiles;
 199      }
 200  
 201      /**
 202       * Set of data for test_statlibs_get_base_weekly
 203       *
 204       * @return array Dates and timezones for which the first day of the week will be calculated
 205       */
 206      public function get_base_weekly_provider() {
 207          return [
 208              [
 209                  "startwday" => 0,
 210                  "timezone" => 'America/Chicago',
 211                  "timestart" => '18-03-2017 22:00',
 212                  "expected" => '12-03-2017 00:00:00'
 213              ],
 214              [
 215                  "startwday" => 0,
 216                  "timezone" => 'America/Chicago',
 217                  "date" => '25-03-2017 22:00',
 218                  "expected" => '19-03-2017 00:00:00'
 219              ],
 220              [
 221                  "startwday" => 1,
 222                  "timezone" => 'Atlantic/Canary',
 223                  "date" => '06-08-2018 22:00',
 224                  "expected" => '06-08-2018 00:00:00'
 225              ],
 226          ];
 227      }
 228  
 229      /**
 230       * Compare the expected stats to those in the database.
 231       *
 232       * @param array $expected
 233       * @param string $output
 234       */
 235      protected function verify_stats($expected, $output = '') {
 236          global $DB;
 237  
 238          // Note: We can not use $this->assertDataSetEqual($expected, $actual) because there's no
 239          //       $this->getConnection() in advanced_testcase.
 240  
 241          foreach ($expected as $type => $table) {
 242              $records = $DB->get_records($type);
 243  
 244              $rows = count($table);
 245  
 246              $message = 'Incorrect number of results returned for '. $type;
 247  
 248              if ($output != '') {
 249                  $message .= "\nCron output:\n$output";
 250              }
 251  
 252              $this->assertCount($rows, $records, $message);
 253  
 254              for ($i = 0; $i < $rows; $i++) {
 255                  $row   = $table[$i];
 256                  $found = 0;
 257  
 258                  foreach ($records as $key => $record) {
 259                      $record = (array) $record;
 260                      unset($record['id']);
 261                      $diff = array_merge(array_diff_assoc($row, $record),
 262                              array_diff_assoc($record, $row));
 263  
 264                      if (empty($diff)) {
 265                          $found = $key;
 266                          break;
 267                      }
 268                  }
 269  
 270                  $this->assertGreaterThan(0, $found, 'Expected log '. var_export($row, true)
 271                                          ." was not found in $type ". var_export($records, true));
 272                  unset($records[$found]);
 273              }
 274          }
 275      }
 276  
 277      /**
 278       * Test progress output when debug is on.
 279       */
 280      public function test_statslib_progress_debug() {
 281          set_debugging(DEBUG_ALL);
 282          $this->expectOutputString('1:0 ');
 283          stats_progress('init');
 284          stats_progress('1');
 285          $this->resetDebugging();
 286      }
 287  
 288      /**
 289       * Test progress output when debug is off.
 290       */
 291      public function test_statslib_progress_no_debug() {
 292          set_debugging(DEBUG_NONE);
 293          $this->expectOutputString('.');
 294          stats_progress('init');
 295          stats_progress('1');
 296          $this->resetDebugging();
 297      }
 298  
 299      /**
 300       * Test the function that gets the start date from the config.
 301       */
 302      public function test_statslib_get_start_from() {
 303          global $CFG, $DB;
 304  
 305          $dataset = $this->load_xml_data_file(__DIR__."/fixtures/statslib-test01.xml");
 306          $DB->delete_records('log');
 307  
 308          $date = new \DateTime('now', \core_date::get_server_timezone_object());
 309          $day = self::DAY - $date->getOffset();
 310  
 311          $CFG->statsfirstrun = 'all';
 312          // Allow 1 second difference in case we cross a second boundary.
 313          // Note: within 3 days of a DST change - -3 days != 3 * 24 hours (it may be more or less).
 314          $this->assertLessThanOrEqual(1, stats_get_start_from('daily') - strtotime('-3 days', time()), 'All start time');
 315  
 316          $this->prepare_db($dataset, array('log'));
 317          $records = $DB->get_records('log');
 318  
 319          $this->assertEquals($day + 14410, stats_get_start_from('daily'), 'Log entry start');
 320  
 321          $CFG->statsfirstrun = 'none';
 322          $this->assertLessThanOrEqual(1, stats_get_start_from('daily') - strtotime('-3 days', time()), 'None start time');
 323  
 324          $CFG->statsfirstrun = 14515200;
 325          $this->assertLessThanOrEqual(1, stats_get_start_from('daily') - (time() - (14515200)), 'Specified start time');
 326  
 327          $this->prepare_db($dataset, array('stats_daily'));
 328          $this->assertEquals($day + DAYSECS, stats_get_start_from('daily'), 'Daily stats start time');
 329  
 330          // New log stores.
 331          $this->preventResetByRollback();
 332  
 333          $this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
 334          set_config('enabled_stores', 'logstore_standard', 'tool_log');
 335          set_config('buffersize', 0, 'logstore_standard');
 336          set_config('logguests', 1, 'logstore_standard');
 337          get_log_manager(true);
 338  
 339          $this->assertEquals(0, $DB->count_records('logstore_standard_log'));
 340  
 341          $DB->delete_records('stats_daily');
 342          $CFG->statsfirstrun = 'all';
 343          $firstoldtime = $DB->get_field_sql('SELECT MIN(time) FROM {log}');
 344  
 345          $this->assertEquals($firstoldtime, stats_get_start_from('daily'));
 346  
 347          $time = time() - 5;
 348          \core_tests\event\create_executed::create(array('context' => \context_system::instance()))->trigger();
 349          $DB->set_field('logstore_standard_log', 'timecreated', $time++, [
 350                  'eventname' => '\\core_tests\\event\\create_executed',
 351              ]);
 352  
 353          \core_tests\event\read_executed::create(array('context' => \context_system::instance()))->trigger();
 354          $DB->set_field('logstore_standard_log', 'timecreated', $time++, [
 355                  'eventname' => '\\core_tests\\event\\read_executed',
 356              ]);
 357  
 358          \core_tests\event\update_executed::create(array('context' => \context_system::instance()))->trigger();
 359          $DB->set_field('logstore_standard_log', 'timecreated', $time++, [
 360                  'eventname' => '\\core_tests\\event\\update_executed',
 361              ]);
 362  
 363          \core_tests\event\delete_executed::create(array('context' => \context_system::instance()))->trigger();
 364          $DB->set_field('logstore_standard_log', 'timecreated', $time++, [
 365                  'eventname' => '\\core_tests\\event\\delete_executed',
 366              ]);
 367  
 368          $DB->set_field('logstore_standard_log', 'origin', 'web', array());
 369          $logs = $DB->get_records('logstore_standard_log', null, 'timecreated ASC');
 370          $this->assertCount(4, $logs);
 371  
 372          $firstnew = reset($logs);
 373          $this->assertGreaterThan($firstoldtime, $firstnew->timecreated);
 374          $DB->set_field('logstore_standard_log', 'timecreated', 10, array('id' => $firstnew->id));
 375          $this->assertEquals(10, stats_get_start_from('daily'));
 376  
 377          $DB->set_field('logstore_standard_log', 'timecreated', $firstnew->timecreated, array('id' => $firstnew->id));
 378          $DB->delete_records('log');
 379          $this->assertEquals($firstnew->timecreated, stats_get_start_from('daily'));
 380  
 381          set_config('enabled_stores', '', 'tool_log');
 382          get_log_manager(true);
 383      }
 384  
 385      /**
 386       * Test the function that calculates the start of the day.
 387       *
 388       * NOTE: I don't think this is the way this function should work.
 389       *       This test documents the current functionality.
 390       */
 391      public function test_statslib_get_base_daily() {
 392          global $CFG;
 393  
 394          for ($x = 0; $x < 13; $x += 1) {
 395              $this->setTimezone($x);
 396  
 397              $start = 1272672000 - ($x * 3600);
 398              if ($x >= 20) {
 399                  $start += (24 * 3600);
 400              }
 401  
 402              $this->assertEquals($start, stats_get_base_daily(1272686410), "Timezone $x check");
 403          }
 404      }
 405  
 406      /**
 407       * Test the function that gets the start of the next day.
 408       */
 409      public function test_statslib_get_next_day_start() {
 410          $this->setTimezone(0);
 411          $this->assertEquals(1272758400, stats_get_next_day_start(1272686410));
 412  
 413          // Try setting timezone to some place in the US.
 414          $this->setTimezone('America/New_York', 'America/New_York');
 415          // Then set the time for midnight before daylight savings.
 416          // 1425790800 is midnight in New York (2015-03-08) Daylight saving will occur in 2 hours time.
 417          // 1425873600 is midnight the next day.
 418          $this->assertEquals(1425873600, stats_get_next_day_start(1425790800));
 419          $this->assertEquals(23, ((1425873600 - 1425790800) / 60 ) / 60);
 420          // Then set the time for midnight before daylight savings ends.
 421          // 1446350400 is midnight in New York (2015-11-01) Daylight saving will finish in 2 hours time.
 422          // 1446440400 is midnight the next day.
 423          $this->assertEquals(1446440400, stats_get_next_day_start(1446350400));
 424          $this->assertEquals(25, ((1446440400 - 1446350400) / 60 ) / 60);
 425          // The next day should be normal.
 426          $this->assertEquals(1446526800, stats_get_next_day_start(1446440400));
 427          $this->assertEquals(24, ((1446526800 - 1446440400) / 60 ) / 60);
 428      }
 429  
 430      /**
 431       * Test the function that calculates the start of the week.
 432       *
 433       * @dataProvider get_base_weekly_provider
 434       * @param int $startwday Day in which the week starts (Sunday = 0)
 435       * @param string $timezone Default timezone
 436       * @param string $timestart Date and time for which the first day of the week will be obtained
 437       * @param string $expected Expected date of the first day of the week
 438       */
 439      public function test_statslib_get_base_weekly($startwday, $timezone, $timestart, $expected) {
 440          $this->setTimezone($timezone);
 441          $time = strtotime($timestart);
 442          $expected = strtotime($expected);
 443          set_config('calendar_startwday', $startwday);
 444          set_config('statslastweekly', $time);
 445  
 446          $weekstarttime = stats_get_base_weekly($time);
 447  
 448          $this->assertEquals($expected, $weekstarttime);
 449      }
 450  
 451      /**
 452       * Test the function that gets the action names.
 453       *
 454       * Note: The function results depend on installed modules.  The hard coded lists are the
 455       *       defaults for a new Moodle 2.3 install.
 456       */
 457      public function test_statslib_get_action_names() {
 458          $basepostactions = array (
 459              0 => 'add',
 460              1 => 'delete',
 461              2 => 'edit',
 462              3 => 'add mod',
 463              4 => 'delete mod',
 464              5 => 'edit sectionenrol',
 465              6 => 'loginas',
 466              7 => 'new',
 467              8 => 'unenrol',
 468              9 => 'update',
 469              10 => 'update mod',
 470              11 => 'upload',
 471              12 => 'submit',
 472              13 => 'submit for grading',
 473              14 => 'talk',
 474              15 => 'choose',
 475              16 => 'choose again',
 476              17 => 'record delete',
 477              18 => 'add discussion',
 478              19 => 'add post',
 479              20 => 'delete discussion',
 480              21 => 'delete post',
 481              22 => 'move discussion',
 482              23 => 'prune post',
 483              24 => 'update post',
 484              25 => 'add category',
 485              26 => 'add entry',
 486              27 => 'approve entry',
 487              28 => 'delete category',
 488              29 => 'delete entry',
 489              30 => 'edit category',
 490              31 => 'update entry',
 491              32 => 'end',
 492              33 => 'start',
 493              34 => 'attempt',
 494              35 => 'close attempt',
 495              36 => 'preview',
 496              37 => 'editquestions',
 497              38 => 'delete attempt',
 498              39 => 'manualgrade',
 499          );
 500  
 501           $baseviewactions = array (
 502              0 => 'view',
 503              1 => 'view all',
 504              2 => 'history',
 505              3 => 'view submission',
 506              4 => 'view feedback',
 507              5 => 'print',
 508              6 => 'report',
 509              7 => 'view discussion',
 510              8 => 'search',
 511              9 => 'forum',
 512              10 => 'forums',
 513              11 => 'subscribers',
 514              12 => 'view forum',
 515              13 => 'view entry',
 516              14 => 'review',
 517              15 => 'pre-view',
 518              16 => 'download',
 519              17 => 'view form',
 520              18 => 'view graph',
 521              19 => 'view report',
 522          );
 523  
 524          $postactions = stats_get_action_names('post');
 525  
 526          foreach ($basepostactions as $action) {
 527              $this->assertContains($action, $postactions);
 528          }
 529  
 530          $viewactions = stats_get_action_names('view');
 531  
 532          foreach ($baseviewactions as $action) {
 533              $this->assertContains($action, $viewactions);
 534          }
 535      }
 536  
 537      /**
 538       * Test the temporary table creation and deletion.
 539       */
 540      public function test_statslib_temp_table_create_and_drop() {
 541          global $DB;
 542  
 543          foreach ($this->tables as $table) {
 544              $this->assertFalse($DB->get_manager()->table_exists($table));
 545          }
 546  
 547          stats_temp_table_create();
 548  
 549          foreach ($this->tables as $table) {
 550              $this->assertTrue($DB->get_manager()->table_exists($table));
 551          }
 552  
 553          stats_temp_table_drop();
 554  
 555          foreach ($this->tables as $table) {
 556              $this->assertFalse($DB->get_manager()->table_exists($table));
 557          }
 558      }
 559  
 560      /**
 561       * Test the temporary table creation and deletion.
 562       *
 563       * @depends test_statslib_temp_table_create_and_drop
 564       */
 565      public function test_statslib_temp_table_fill() {
 566          global $CFG, $DB, $USER;
 567  
 568          $dataset = $this->load_xml_data_file(__DIR__."/fixtures/statslib-test09.xml");
 569          $this->prepare_db($dataset, array('log'));
 570  
 571          // This nonsense needs to be rewritten.
 572          $date = new \DateTime('now', \core_date::get_server_timezone_object());
 573          $start = self::DAY - $date->getOffset();
 574          $end   = $start + (24 * 3600);
 575  
 576          stats_temp_table_create();
 577          stats_temp_table_fill($start, $end);
 578  
 579          $this->assertEquals(1, $DB->count_records('temp_log1'));
 580          $this->assertEquals(1, $DB->count_records('temp_log2'));
 581  
 582          stats_temp_table_drop();
 583  
 584          // New log stores.
 585          $this->preventResetByRollback();
 586          stats_temp_table_create();
 587  
 588          $course = $this->getDataGenerator()->create_course();
 589          $context = \context_course::instance($course->id);
 590          $fcontext = \context_course::instance(SITEID);
 591          $user = $this->getDataGenerator()->create_user();
 592          $this->setUser($user);
 593  
 594          $this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
 595          set_config('enabled_stores', 'logstore_standard', 'tool_log');
 596          set_config('buffersize', 0, 'logstore_standard');
 597          set_config('logguests', 1, 'logstore_standard');
 598          get_log_manager(true);
 599  
 600          $DB->delete_records('logstore_standard_log');
 601  
 602          \core_tests\event\create_executed::create(array('context' => $fcontext, 'courseid' => SITEID))->trigger();
 603          \core_tests\event\read_executed::create(array('context' => $context, 'courseid' => $course->id))->trigger();
 604          \core_tests\event\update_executed::create(array('context' => \context_system::instance()))->trigger();
 605          \core_tests\event\delete_executed::create(array('context' => \context_system::instance()))->trigger();
 606  
 607          \core\event\user_loggedin::create(
 608              array(
 609                  'userid' => $USER->id,
 610                  'objectid' => $USER->id,
 611                  'other' => array('username' => $USER->username),
 612              )
 613          )->trigger();
 614  
 615          $DB->set_field('logstore_standard_log', 'timecreated', 10);
 616  
 617          $this->assertEquals(5, $DB->count_records('logstore_standard_log'));
 618  
 619          \core_tests\event\delete_executed::create(array('context' => \context_system::instance()))->trigger();
 620          \core_tests\event\delete_executed::create(array('context' => \context_system::instance()))->trigger();
 621  
 622          // Fake the origin of events.
 623          $DB->set_field('logstore_standard_log', 'origin', 'web', array());
 624  
 625          $this->assertEquals(7, $DB->count_records('logstore_standard_log'));
 626  
 627          stats_temp_table_fill(9, 11);
 628  
 629          $logs1 = $DB->get_records('temp_log1');
 630          $logs2 = $DB->get_records('temp_log2');
 631          $this->assertCount(5, $logs1);
 632          $this->assertCount(5, $logs2);
 633          // The order of records in the temp tables is not guaranteed...
 634  
 635          $viewcount = 0;
 636          $updatecount = 0;
 637          $logincount = 0;
 638          foreach ($logs1 as $log) {
 639              if ($log->course == $course->id) {
 640                  $this->assertEquals('view', $log->action);
 641                  $viewcount++;
 642              } else {
 643                  $this->assertTrue(in_array($log->action, array('update', 'login')));
 644                  if ($log->action === 'update') {
 645                      $updatecount++;
 646                  } else {
 647                      $logincount++;
 648                  }
 649                  $this->assertEquals(SITEID, $log->course);
 650              }
 651              $this->assertEquals($user->id, $log->userid);
 652          }
 653          $this->assertEquals(1, $viewcount);
 654          $this->assertEquals(3, $updatecount);
 655          $this->assertEquals(1, $logincount);
 656  
 657          set_config('enabled_stores', '', 'tool_log');
 658          get_log_manager(true);
 659          stats_temp_table_drop();
 660      }
 661  
 662      /**
 663       * Test the temporary table creation and deletion.
 664       *
 665       * @depends test_statslib_temp_table_create_and_drop
 666       */
 667      public function test_statslib_temp_table_setup() {
 668          global $DB;
 669  
 670          $DB->delete_records('log');
 671  
 672          stats_temp_table_create();
 673          stats_temp_table_setup();
 674  
 675          $this->assertEquals(1, $DB->count_records('temp_enroled'));
 676  
 677          stats_temp_table_drop();
 678      }
 679  
 680      /**
 681       * Test the function that clean out the temporary tables.
 682       *
 683       * @depends test_statslib_temp_table_create_and_drop
 684       */
 685      public function test_statslib_temp_table_clean() {
 686          global $DB;
 687  
 688          $rows = array(
 689              'temp_log1'             => array('id' => 1, 'course' => 1),
 690              'temp_log2'             => array('id' => 1, 'course' => 1),
 691              'temp_stats_daily'      => array('id' => 1, 'courseid' => 1),
 692              'temp_stats_user_daily' => array('id' => 1, 'courseid' => 1),
 693          );
 694  
 695          stats_temp_table_create();
 696  
 697          foreach ($rows as $table => $row) {
 698              $DB->insert_record_raw($table, $row);
 699              $this->assertEquals(1, $DB->count_records($table));
 700          }
 701  
 702          stats_temp_table_clean();
 703  
 704          foreach ($rows as $table => $row) {
 705              $this->assertEquals(0, $DB->count_records($table));
 706          }
 707  
 708          $this->assertEquals(1, $DB->count_records('stats_daily'));
 709          $this->assertEquals(1, $DB->count_records('stats_user_daily'));
 710  
 711          stats_temp_table_drop();
 712      }
 713  
 714      /**
 715       * Test the daily stats function.
 716       *
 717       * @depends test_statslib_get_base_daily
 718       * @depends test_statslib_get_next_day_start
 719       * @depends test_statslib_get_start_from
 720       * @depends test_statslib_temp_table_create_and_drop
 721       * @depends test_statslib_temp_table_setup
 722       * @depends test_statslib_temp_table_fill
 723       * @dataProvider daily_log_provider
 724       */
 725      public function test_statslib_cron_daily($xmlfile) {
 726          global $CFG, $DB;
 727  
 728          $dataset = $this->load_xml_data_file(__DIR__."/fixtures/{$xmlfile}");
 729          $stats = $this->prepare_db($dataset, array('log'));
 730          $stats = $dataset->get_rows(['stats_daily', 'stats_user_daily']);
 731  
 732          // Stats cron daily uses mtrace, turn on buffering to silence output.
 733          ob_start();
 734          stats_cron_daily(1);
 735          $output = ob_get_contents();
 736          ob_end_clean();
 737  
 738          $this->verify_stats($stats, $output);
 739      }
 740  
 741      /**
 742       * Test the daily stats function.
 743       *
 744       * @depends test_statslib_get_base_daily
 745       * @depends test_statslib_get_next_day_start
 746       */
 747      public function test_statslib_cron_daily_no_default_profile_id() {
 748          global $CFG, $DB;
 749          $CFG->defaultfrontpageroleid = 0;
 750  
 751          $course1  = $DB->get_record('course', array('shortname' => 'course1'));
 752          $guestid  = $CFG->siteguest;
 753          $start    = stats_get_base_daily(1272758400);
 754          $end      = stats_get_next_day_start($start);
 755          $fpid     = (int) $CFG->defaultfrontpageroleid;
 756          $gr       = get_guest_role();
 757  
 758          $dataset = $this->load_xml_data_file(__DIR__."/fixtures/statslib-test10.xml");
 759          $this->prepare_db($dataset, array('log'));
 760          $stats = $dataset->get_rows(['stats_user_daily']);
 761  
 762          // Stats cron daily uses mtrace, turn on buffering to silence output.
 763          ob_start();
 764          stats_cron_daily($maxdays=1);
 765          $output = ob_get_contents();
 766          ob_end_clean();
 767  
 768          $this->verify_stats($dataset, $output);
 769      }
 770  }