Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

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