Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

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