MDL-65588 analytics: New models for student accesses

This commit is contained in:
David Monllaó 2019-05-17 12:24:13 +02:00
parent 7d8ed90757
commit 2d9280e0df
21 changed files with 1079 additions and 89 deletions

View file

@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_seconds.php');
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_upcoming_seconds.php');
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_weekly.php');
require_once(__DIR__ . '/../../lib/enrollib.php');
/**
@ -197,23 +196,38 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
// Using a finished course.
$weekly = new test_timesplitting_weekly();
$weekly->set_analysable($this->analysable);
$this->assertCount(1, $weekly->get_distinct_ranges());
$pastweek = new \core\analytics\time_splitting\past_week();
$pastweek->set_analysable($this->analysable);
$this->assertCount(1, $pastweek->get_distinct_ranges());
$ranges = $weekly->get_all_ranges();
$ranges = $pastweek->get_all_ranges();
$this->assertEquals(52, count($ranges));
$this->assertEquals($this->course->startdate, $ranges[0]['start']);
$this->assertNotEquals($this->course->startdate, $ranges[0]['time']);
// The analysable is finished so all ranges are available for training.
$this->assertCount(count($ranges), $weekly->get_training_ranges());
$this->assertCount(count($ranges), $pastweek->get_training_ranges());
$ranges = $weekly->get_most_recent_prediction_range();
$ranges = $pastweek->get_most_recent_prediction_range();
$range = reset($ranges);
$this->assertEquals(51, key($ranges));
// We now use an ongoing course.
// We now use an ongoing course not yet ready to generate predictions.
$threedaysago = new DateTime('-3 days');
$params = array(
'startdate' => $threedaysago->getTimestamp(),
);
$ongoingcourse = $this->getDataGenerator()->create_course($params);
$ongoinganalysable = new \core_analytics\course($ongoingcourse);
$pastweek = new \core\analytics\time_splitting\past_week();
$pastweek->set_analysable($ongoinganalysable);
$ranges = $pastweek->get_all_ranges();
$this->assertEquals(0, count($ranges));
$this->assertCount(0, $pastweek->get_training_ranges());
// We now use a ready-to-predict ongoing course.
$onemonthago = new DateTime('-30 days');
$params = array(
@ -222,20 +236,24 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
$ongoingcourse = $this->getDataGenerator()->create_course($params);
$ongoinganalysable = new \core_analytics\course($ongoingcourse);
$weekly = new test_timesplitting_weekly();
$weekly->set_analysable($ongoinganalysable);
$this->assertCount(1, $weekly->get_distinct_ranges());
$pastweek = new \core\analytics\time_splitting\past_week();
$pastweek->set_analysable($ongoinganalysable);
$this->assertCount(1, $pastweek->get_distinct_ranges());
$ranges = $weekly->get_all_ranges();
$ranges = $pastweek->get_all_ranges();
$this->assertEquals(4, count($ranges));
$this->assertCount(4, $weekly->get_training_ranges());
$this->assertCount(4, $pastweek->get_training_ranges());
$ranges = $weekly->get_most_recent_prediction_range();
$ranges = $pastweek->get_most_recent_prediction_range();
$range = reset($ranges);
$this->assertEquals(3, key($ranges));
$this->assertLessThan(time(), $range['time']);
$this->assertLessThan(time(), $range['start']);
$this->assertLessThan(time(), $range['end']);
$this->assertEquals(time(), $range['time'], '', 1);
// 1 second delta for the start just in case a second passes between the set_analysable call
// and this checking below.
$time = new \DateTime();
$time->sub($pastweek->periodicity());
$this->assertEquals($time->getTimestamp(), $range['start'], '', 1.0);
$this->assertEquals(time(), $range['end'], '', 1);
$starttime = time();
@ -246,8 +264,8 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
$ranges = $upcomingweek->get_all_ranges();
$this->assertEquals(1, count($ranges));
$range = reset($ranges);
$this->assertLessThan(time(), $range['time']);
$this->assertLessThan(time(), $range['start']);
$this->assertEquals(time(), $range['time'], '', 1);
$this->assertEquals(time(), $range['start'], '', 1);
$this->assertGreaterThan(time(), $range['end']);
$this->assertCount(0, $upcomingweek->get_training_ranges());
@ -255,12 +273,10 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
$ranges = $upcomingweek->get_most_recent_prediction_range();
$range = reset($ranges);
$this->assertEquals(0, key($ranges));
$this->assertLessThan(time(), $range['time']);
$this->assertLessThan(time(), $range['start']);
// We substract 1 because upcoming_periodic also has that -1 so that predictions
// get executed once the first time range is set.
$this->assertGreaterThanOrEqual($starttime - 1, $range['time']);
$this->assertGreaterThanOrEqual($starttime - 1, $range['start']);
$this->assertEquals(time(), $range['time'], '', 1);
$this->assertEquals(time(), $range['start'], '', 1);
$this->assertGreaterThanOrEqual($starttime, $range['time']);
$this->assertGreaterThanOrEqual($starttime, $range['start']);
$this->assertGreaterThan(time(), $range['end']);
$this->assertNotEmpty($upcomingweek->get_range_by_index(0));
@ -280,7 +296,8 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
$seconds->set_analysable($analysable);
// Store the ranges we just obtained.
$nranges = count($seconds->get_all_ranges());
$ranges = $seconds->get_all_ranges();
$nranges = count($ranges);
$ntrainingranges = count($seconds->get_training_ranges());
$mostrecentrange = $seconds->get_most_recent_prediction_range();
$mostrecentrange = reset($mostrecentrange);
@ -291,7 +308,8 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
// We set the analysable again so the time ranges are recalculated.
$seconds->set_analysable($analysable);
$nnewranges = $seconds->get_all_ranges();
$newranges = $seconds->get_all_ranges();
$nnewranges = count($newranges);
$nnewtrainingranges = $seconds->get_training_ranges();
$newmostrecentrange = $seconds->get_most_recent_prediction_range();
$newmostrecentrange = reset($newmostrecentrange);
@ -299,25 +317,67 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
$this->assertGreaterThan($ntrainingranges, $nnewtrainingranges);
$this->assertGreaterThan($mostrecentrange['time'], $newmostrecentrange['time']);
$seconds = new test_timesplitting_upcoming_seconds();
$seconds->set_analysable($analysable);
// All the ranges but the last one should return the same values.
array_pop($ranges);
array_pop($newranges);
foreach ($ranges as $key => $range) {
$this->assertEquals($newranges[$key]['start'], $range['start']);
$this->assertEquals($newranges[$key]['end'], $range['end']);
$this->assertEquals($newranges[$key]['time'], $range['time']);
}
// Fake model id, we can use any int, we will need to reference it later.
$modelid = 1505347200;
$upcomingseconds = new test_timesplitting_upcoming_seconds();
$upcomingseconds->set_modelid($modelid);
$upcomingseconds->set_analysable($analysable);
// Store the ranges we just obtained.
$nranges = count($seconds->get_all_ranges());
$ntrainingranges = count($seconds->get_training_ranges());
$mostrecentrange = $seconds->get_most_recent_prediction_range();
$ranges = $upcomingseconds->get_all_ranges();
$nranges = count($ranges);
$ntrainingranges = count($upcomingseconds->get_training_ranges());
$mostrecentrange = $upcomingseconds->get_most_recent_prediction_range();
$mostrecentrange = reset($mostrecentrange);
// Mimic the modelfirstanalyses caching in \core_analytics\analysis.
$this->mock_cache_first_analysis_caching($modelid, $analysable->get_id(), end($ranges));
// We wait for the next range to be added.
usleep(1000000);
$seconds->set_analysable($analysable);
$nnewranges = $seconds->get_all_ranges();
$nnewtrainingranges = $seconds->get_training_ranges();
$newmostrecentrange = $seconds->get_most_recent_prediction_range();
// We set the analysable again so the time ranges are recalculated.
$upcomingseconds->set_analysable($analysable);
$newranges = $upcomingseconds->get_all_ranges();
$nnewranges = count($newranges);
$nnewtrainingranges = $upcomingseconds->get_training_ranges();
$newmostrecentrange = $upcomingseconds->get_most_recent_prediction_range();
$newmostrecentrange = reset($newmostrecentrange);
$this->assertGreaterThan($nranges, $nnewranges);
$this->assertGreaterThan($ntrainingranges, $nnewtrainingranges);
$this->assertGreaterThan($mostrecentrange['time'], $newmostrecentrange['time']);
// All the ranges but the last one should return the same values.
array_pop($ranges);
array_pop($newranges);
foreach ($ranges as $key => $range) {
$this->assertEquals($newranges[$key]['start'], $range['start']);
$this->assertEquals($newranges[$key]['end'], $range['end']);
$this->assertEquals($newranges[$key]['time'], $range['time']);
}
}
/**
* Mocks core_analytics\analysis caching of the first time analysables were analysed.
*
* @param int $modelid
* @param int $analysableid
* @param array $range
* @return null
*/
private function mock_cache_first_analysis_caching($modelid, $analysableid, $range) {
$cache = \cache::make('core', 'modelfirstanalyses');
$cache->set($modelid . '_' . $analysableid, $range['time']);
}
}