Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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_analytics;
18
 
1441 ariadna 19
use core_analytics\tests\mlbackend_helper_trait;
20
 
1 efrain 21
defined('MOODLE_INTERNAL') || die();
22
 
23
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
24
require_once(__DIR__ . '/fixtures/test_indicator_min.php');
25
require_once(__DIR__ . '/fixtures/test_indicator_fullname.php');
26
require_once(__DIR__ . '/fixtures/test_target_course_level_shortname.php');
27
 
28
/**
29
 * Unit tests for the core_analytics manager.
30
 *
31
 * @package   core_analytics
32
 * @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
33
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 * @covers    \core_analytics\manager
35
 */
1441 ariadna 36
final class manager_test extends \advanced_testcase {
37
    use mlbackend_helper_trait;
1 efrain 38
 
39
    /**
40
     * test_deleted_context
41
     */
11 efrain 42
    public function test_deleted_context(): void {
1 efrain 43
        global $DB;
44
 
1441 ariadna 45
        if (!self::is_mlbackend_python_configured()) {
46
            $this->markTestSkipped('mlbackend_python is not configured.');
47
        }
48
 
1 efrain 49
        $this->resetAfterTest(true);
50
        $this->setAdminuser();
51
        set_config('enabled_stores', 'logstore_standard', 'tool_log');
52
 
1441 ariadna 53
        // Create some courses.
54
        $this->generate_courses(2, ['visible' => 0]);
55
        $this->generate_courses(2, ['visible' => 1]);
56
 
1 efrain 57
        $target = \core_analytics\manager::get_target('test_target_course_level_shortname');
1441 ariadna 58
        $indicators = ['test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'];
1 efrain 59
        foreach ($indicators as $key => $indicator) {
60
            $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
61
        }
62
 
63
        $model = \core_analytics\model::create($target, $indicators);
64
        $modelobj = $model->get_model_obj();
65
 
66
        $model->enable('\core\analytics\time_splitting\no_splitting');
67
 
68
        $model->train();
69
        $model->predict();
70
 
71
        // Generate a prediction action to confirm that it is deleted when there is an important update.
72
        $predictions = $DB->get_records('analytics_predictions');
73
        $prediction = reset($predictions);
1441 ariadna 74
        $prediction = new \core_analytics\prediction($prediction, ['whatever' => 'not used']);
1 efrain 75
        $prediction->action_executed(\core_analytics\prediction::ACTION_USEFUL, $model->get_target());
76
 
77
        $predictioncontextid = $prediction->get_prediction_data()->contextid;
78
 
1441 ariadna 79
        $npredictions = $DB->count_records('analytics_predictions', ['contextid' => $predictioncontextid]);
80
        $npredictionactions = $DB->count_records(
81
            'analytics_prediction_actions',
82
            ['predictionid' => $prediction->get_prediction_data()->id]
83
        );
84
        $nindicatorcalc = $DB->count_records('analytics_indicator_calc', ['contextid' => $predictioncontextid]);
1 efrain 85
 
86
        \core_analytics\manager::cleanup();
87
 
88
        // Nothing is incorrectly deleted.
1441 ariadna 89
        $this->assertEquals($npredictions, $DB->count_records(
90
            'analytics_predictions',
91
            ['contextid' => $predictioncontextid]
92
        ));
93
        $this->assertEquals($npredictionactions, $DB->count_records(
94
            'analytics_prediction_actions',
95
            ['predictionid' => $prediction->get_prediction_data()->id]
96
        ));
97
        $this->assertEquals($nindicatorcalc, $DB->count_records(
98
            'analytics_indicator_calc',
99
            ['contextid' => $predictioncontextid]
100
        ));
1 efrain 101
 
102
        // Now we delete a context, the course predictions and prediction actions should be deleted.
103
        $deletedcontext = \context::instance_by_id($predictioncontextid);
104
        delete_course($deletedcontext->instanceid, false);
105
 
106
        \core_analytics\manager::cleanup();
107
 
1441 ariadna 108
        $this->assertEmpty($DB->count_records('analytics_predictions', ['contextid' => $predictioncontextid]));
109
        $this->assertEmpty($DB->count_records(
110
            'analytics_prediction_actions',
111
            ['predictionid' => $prediction->get_prediction_data()->id]
112
        ));
113
        $this->assertEmpty($DB->count_records('analytics_indicator_calc', ['contextid' => $predictioncontextid]));
1 efrain 114
 
115
        set_config('enabled_stores', '', 'tool_log');
116
        get_log_manager(true);
117
    }
118
 
119
    /**
120
     * test_deleted_analysable
121
     */
11 efrain 122
    public function test_deleted_analysable(): void {
1 efrain 123
        global $DB;
124
 
1441 ariadna 125
        if (!self::is_mlbackend_python_configured()) {
126
            $this->markTestSkipped('mlbackend_python is not configured.');
127
        }
128
 
1 efrain 129
        $this->resetAfterTest(true);
130
        $this->setAdminuser();
131
        set_config('enabled_stores', 'logstore_standard', 'tool_log');
132
 
133
        $target = \core_analytics\manager::get_target('test_target_course_level_shortname');
1441 ariadna 134
        $indicators = ['test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'];
1 efrain 135
        foreach ($indicators as $key => $indicator) {
136
            $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
137
        }
138
 
139
        $model = \core_analytics\model::create($target, $indicators);
140
        $modelobj = $model->get_model_obj();
141
 
1441 ariadna 142
        $coursepredict1 = $this->getDataGenerator()->create_course(['visible' => 0]);
143
        $coursepredict2 = $this->getDataGenerator()->create_course(['visible' => 0]);
144
        $coursetrain1 = $this->getDataGenerator()->create_course(['visible' => 1]);
145
        $coursetrain2 = $this->getDataGenerator()->create_course(['visible' => 1]);
1 efrain 146
 
147
        $model->enable('\core\analytics\time_splitting\no_splitting');
148
 
149
        $model->train();
150
        $model->predict();
151
 
152
        $this->assertNotEmpty($DB->count_records('analytics_predict_samples'));
153
        $this->assertNotEmpty($DB->count_records('analytics_train_samples'));
154
        $this->assertNotEmpty($DB->count_records('analytics_used_analysables'));
155
 
156
        // Now we delete an analysable, stored predict and training samples should be deleted.
157
        $deletedcontext = \context_course::instance($coursepredict1->id);
158
        delete_course($coursepredict1, false);
159
 
160
        \core_analytics\manager::cleanup();
161
 
1441 ariadna 162
        $this->assertEmpty($DB->count_records('analytics_predict_samples', ['analysableid' => $coursepredict1->id]));
163
        $this->assertEmpty($DB->count_records('analytics_train_samples', ['analysableid' => $coursepredict1->id]));
164
        $this->assertEmpty($DB->count_records('analytics_used_analysables', ['analysableid' => $coursepredict1->id]));
1 efrain 165
 
166
        set_config('enabled_stores', '', 'tool_log');
167
        get_log_manager(true);
168
    }
169
 
170
    /**
171
     * Tests for the {@link \core_analytics\manager::load_default_models_for_component()} implementation.
172
     */
11 efrain 173
    public function test_load_default_models_for_component(): void {
1 efrain 174
        $this->resetAfterTest();
175
 
176
        // Attempting to load builtin models should always work without throwing exception.
177
        \core_analytics\manager::load_default_models_for_component('core');
178
 
179
        // Attempting to load from a core subsystem without its own subsystem directory.
180
        $this->assertSame([], \core_analytics\manager::load_default_models_for_component('core_access'));
181
 
182
        // Attempting to load from a non-existing subsystem.
183
        $this->assertSame([], \core_analytics\manager::load_default_models_for_component('core_nonexistingsubsystem'));
184
 
185
        // Attempting to load from a non-existing plugin of a known plugin type.
186
        $this->assertSame([], \core_analytics\manager::load_default_models_for_component('mod_foobarbazquaz12240996776'));
187
 
188
        // Attempting to load from a non-existing plugin type.
189
        $this->assertSame([], \core_analytics\manager::load_default_models_for_component('foo_bar2776327736558'));
190
    }
191
 
192
    /**
193
     * Tests for the {@link \core_analytics\manager::load_default_models_for_all_components()} implementation.
194
     */
11 efrain 195
    public function test_load_default_models_for_all_components(): void {
1 efrain 196
        $this->resetAfterTest();
197
 
198
        $models = \core_analytics\manager::load_default_models_for_all_components();
199
 
200
        $this->assertTrue(is_array($models['core']));
201
        $this->assertNotEmpty($models['core']);
202
        $this->assertNotEmpty($models['core'][0]['target']);
203
        $this->assertNotEmpty($models['core'][0]['indicators']);
204
    }
205
 
206
    /**
207
     * Tests for the successful execution of the {@link \core_analytics\manager::validate_models_declaration()}.
208
     */
11 efrain 209
    public function test_validate_models_declaration(): void {
1 efrain 210
        $this->resetAfterTest();
211
 
212
        // This is expected to run without an exception.
1441 ariadna 213
        $models = self::load_models_from_fixture_file('no_teaching');
1 efrain 214
        \core_analytics\manager::validate_models_declaration($models);
215
    }
216
 
217
    /**
218
     * Tests for the exceptions thrown by {@link \core_analytics\manager::validate_models_declaration()}.
219
     *
220
     * @dataProvider validate_models_declaration_exceptions_provider
221
     * @param array $models Models declaration.
222
     * @param string $exception Expected coding exception message.
223
     */
11 efrain 224
    public function test_validate_models_declaration_exceptions(array $models, string $exception): void {
1 efrain 225
        $this->resetAfterTest();
226
 
227
        $this->expectException(\coding_exception::class);
228
        $this->expectExceptionMessage($exception);
229
        \core_analytics\manager::validate_models_declaration($models);
230
    }
231
 
232
    /**
233
     * Data provider for the {@link self::test_validate_models_declaration_exceptions()}.
234
     *
235
     * @return array of (string)testcase => [(array)models, (string)expected exception message]
236
     */
1441 ariadna 237
    public static function validate_models_declaration_exceptions_provider(): array {
1 efrain 238
        return [
239
            'missing_target' => [
1441 ariadna 240
                self::load_models_from_fixture_file('missing_target'),
1 efrain 241
                'Missing target declaration',
242
            ],
243
            'invalid_target' => [
1441 ariadna 244
                self::load_models_from_fixture_file('invalid_target'),
1 efrain 245
                'Invalid target classname',
246
            ],
247
            'missing_indicators' => [
1441 ariadna 248
                self::load_models_from_fixture_file('missing_indicators'),
1 efrain 249
                'Missing indicators declaration',
250
            ],
251
            'invalid_indicators' => [
1441 ariadna 252
                self::load_models_from_fixture_file('invalid_indicators'),
1 efrain 253
                'Invalid indicator classname',
254
            ],
255
            'invalid_time_splitting' => [
1441 ariadna 256
                self::load_models_from_fixture_file('invalid_time_splitting'),
1 efrain 257
                'Invalid time splitting classname',
258
            ],
259
            'invalid_time_splitting_fq' => [
1441 ariadna 260
                self::load_models_from_fixture_file('invalid_time_splitting_fq'),
1 efrain 261
                'Expecting fully qualified time splitting classname',
262
            ],
263
            'invalid_enabled' => [
1441 ariadna 264
                self::load_models_from_fixture_file('invalid_enabled'),
1 efrain 265
                'Cannot enable a model without time splitting method specified',
266
            ],
267
        ];
268
    }
269
 
270
    /**
271
     * Loads models as declared in the given fixture file.
272
     *
273
     * @param string $filename
274
     * @return array
275
     */
1441 ariadna 276
    protected static function load_models_from_fixture_file(string $filename) {
1 efrain 277
        global $CFG;
278
 
279
        $models = null;
280
 
1441 ariadna 281
        require("{$CFG->dirroot}/analytics/tests/fixtures/db_analytics_php/{$filename}.php");
1 efrain 282
 
283
        return $models;
284
    }
285
 
286
    /**
287
     * Test the implementation of the {@link \core_analytics\manager::create_declared_model()}.
288
     */
11 efrain 289
    public function test_create_declared_model(): void {
1 efrain 290
        global $DB;
291
 
292
        $this->resetAfterTest();
293
        $this->setAdminuser();
294
 
295
        $declaration = [
296
            'target' => 'test_target_course_level_shortname',
297
            'indicators' => [
298
                'test_indicator_max',
299
                'test_indicator_min',
300
                'test_indicator_fullname',
301
            ],
302
        ];
303
 
304
        $declarationwithtimesplitting = array_merge($declaration, [
305
            'timesplitting' => '\core\analytics\time_splitting\no_splitting',
306
        ]);
307
 
308
        $declarationwithtimesplittingenabled = array_merge($declarationwithtimesplitting, [
309
            'enabled' => true,
310
        ]);
311
 
312
        // Check that no such model exists yet.
313
        $target = \core_analytics\manager::get_target('test_target_course_level_shortname');
314
        $this->assertEquals(0, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
315
        $this->assertFalse(\core_analytics\model::exists($target));
316
 
317
        // Check that the model is created.
318
        $created = \core_analytics\manager::create_declared_model($declaration);
319
        $this->assertTrue($created instanceof \core_analytics\model);
320
        $this->assertTrue(\core_analytics\model::exists($target));
321
        $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
322
        $modelid = $created->get_id();
323
 
324
        // Check that created models are disabled by default.
325
        $existing = new \core_analytics\model($modelid);
326
        $this->assertEquals(0, $existing->get_model_obj()->enabled);
327
        $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
328
 
329
        // Let the admin enable the model.
330
        $existing->enable('\core\analytics\time_splitting\no_splitting');
331
        $this->assertEquals(1, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
332
 
333
        // Check that further calls create a new model.
334
        $repeated = \core_analytics\manager::create_declared_model($declaration);
335
        $this->assertTrue($repeated instanceof \core_analytics\model);
336
        $this->assertEquals(2, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
337
 
338
        // Delete the models.
339
        $existing->delete();
340
        $repeated->delete();
341
        $this->assertEquals(0, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
342
        $this->assertFalse(\core_analytics\model::exists($target));
343
 
344
        // Create it again, this time with time splitting method specified.
345
        $created = \core_analytics\manager::create_declared_model($declarationwithtimesplitting);
346
        $this->assertTrue($created instanceof \core_analytics\model);
347
        $this->assertTrue(\core_analytics\model::exists($target));
348
        $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
349
        $modelid = $created->get_id();
350
 
351
        // Even if the time splitting method was specified, the model is still not enabled automatically.
352
        $existing = new \core_analytics\model($modelid);
353
        $this->assertEquals(0, $existing->get_model_obj()->enabled);
354
        $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
355
        $existing->delete();
356
 
357
        // Let's define the model so that it is enabled by default.
358
        $enabled = \core_analytics\manager::create_declared_model($declarationwithtimesplittingenabled);
359
        $this->assertTrue($enabled instanceof \core_analytics\model);
360
        $this->assertTrue(\core_analytics\model::exists($target));
361
        $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()]));
362
        $modelid = $enabled->get_id();
363
        $existing = new \core_analytics\model($modelid);
364
        $this->assertEquals(1, $existing->get_model_obj()->enabled);
365
        $this->assertEquals(1, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
366
 
367
        // Let the admin disable the model.
368
        $existing->update(0, false, false);
369
        $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
370
    }
371
 
372
    /**
373
     * Test the implementation of the {@link \core_analytics\manager::update_default_models_for_component()}.
374
     */
11 efrain 375
    public function test_update_default_models_for_component(): void {
1 efrain 376
 
377
        $this->resetAfterTest();
378
        $this->setAdminuser();
379
 
380
        $noteaching = \core_analytics\manager::get_target('\core_course\analytics\target\no_teaching');
381
        $dropout = \core_analytics\manager::get_target('\core_course\analytics\target\course_dropout');
382
        $upcomingactivities = \core_analytics\manager::get_target('\core_user\analytics\target\upcoming_activities_due');
383
        $norecentaccesses = \core_analytics\manager::get_target('\core_course\analytics\target\no_recent_accesses');
384
        $noaccesssincestart = \core_analytics\manager::get_target('\core_course\analytics\target\no_access_since_course_start');
385
 
386
        $this->assertTrue(\core_analytics\model::exists($noteaching));
387
        $this->assertTrue(\core_analytics\model::exists($dropout));
388
        $this->assertTrue(\core_analytics\model::exists($upcomingactivities));
389
        $this->assertTrue(\core_analytics\model::exists($norecentaccesses));
390
        $this->assertTrue(\core_analytics\model::exists($noaccesssincestart));
391
 
392
        foreach (\core_analytics\manager::get_all_models() as $model) {
393
            $model->delete();
394
        }
395
 
396
        $this->assertFalse(\core_analytics\model::exists($noteaching));
397
        $this->assertFalse(\core_analytics\model::exists($dropout));
398
        $this->assertFalse(\core_analytics\model::exists($upcomingactivities));
399
        $this->assertFalse(\core_analytics\model::exists($norecentaccesses));
400
        $this->assertFalse(\core_analytics\model::exists($noaccesssincestart));
401
 
402
        $updated = \core_analytics\manager::update_default_models_for_component('moodle');
403
 
404
        $this->assertEquals(5, count($updated));
405
        $this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
406
        $this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
407
        $this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
408
        $this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
409
        $this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
410
        $this->assertTrue(\core_analytics\model::exists($noteaching));
411
        $this->assertTrue(\core_analytics\model::exists($dropout));
412
        $this->assertTrue(\core_analytics\model::exists($upcomingactivities));
413
        $this->assertTrue(\core_analytics\model::exists($norecentaccesses));
414
        $this->assertTrue(\core_analytics\model::exists($noaccesssincestart));
415
 
416
        $repeated = \core_analytics\manager::update_default_models_for_component('moodle');
417
 
418
        $this->assertSame([], $repeated);
419
    }
420
 
421
    /**
422
     * test_get_time_splitting_methods description
423
     * @return null
424
     */
11 efrain 425
    public function test_get_time_splitting_methods(): void {
1 efrain 426
        $this->resetAfterTest(true);
427
 
428
        $all = \core_analytics\manager::get_all_time_splittings();
429
        $this->assertArrayHasKey('\core\analytics\time_splitting\upcoming_week', $all);
430
        $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $all);
431
 
432
        $allforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(true);
433
        $this->assertArrayNotHasKey('\core\analytics\time_splitting\upcoming_week', $allforevaluation);
434
        $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $allforevaluation);
435
 
436
        $defaultforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(false);
437
        $this->assertArrayNotHasKey('\core\analytics\time_splitting\upcoming_week', $defaultforevaluation);
438
        $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $defaultforevaluation);
439
 
440
        $sometimesplittings = '\core\analytics\time_splitting\single_range,' .
441
            '\core\analytics\time_splitting\tenths';
442
        set_config('defaulttimesplittingsevaluation', $sometimesplittings, 'analytics');
443
 
444
        $defaultforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(false);
445
        $this->assertArrayNotHasKey('\core\analytics\time_splitting\quarters', $defaultforevaluation);
446
    }
447
 
448
    /**
449
     * Test the implementation of the {@link \core_analytics\manager::model_declaration_identifier()}.
450
     */
11 efrain 451
    public function test_model_declaration_identifier(): void {
1 efrain 452
 
1441 ariadna 453
        $noteaching1 = self::load_models_from_fixture_file('no_teaching');
454
        $noteaching2 = self::load_models_from_fixture_file('no_teaching');
455
        $noteaching3 = self::load_models_from_fixture_file('no_teaching');
1 efrain 456
 
457
        // Same model declaration should always lead to same identifier.
458
        $this->assertEquals(
459
            \core_analytics\manager::model_declaration_identifier(reset($noteaching1)),
460
            \core_analytics\manager::model_declaration_identifier(reset($noteaching2))
461
        );
462
 
463
        // If something is changed, the identifier should change, too.
464
        $noteaching2[0]['target'] .= '_';
465
        $this->assertNotEquals(
466
            \core_analytics\manager::model_declaration_identifier(reset($noteaching1)),
467
            \core_analytics\manager::model_declaration_identifier(reset($noteaching2))
468
        );
469
 
470
        $noteaching3[0]['indicators'][] = '\core_analytics\local\indicator\binary';
471
        $this->assertNotEquals(
472
            \core_analytics\manager::model_declaration_identifier(reset($noteaching1)),
473
            \core_analytics\manager::model_declaration_identifier(reset($noteaching3))
474
        );
475
 
476
        // The identifier is supposed to contain PARAM_ALPHANUM only.
477
        $this->assertEquals(
478
            \core_analytics\manager::model_declaration_identifier(reset($noteaching1)),
479
            clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching1)), PARAM_ALPHANUM)
480
        );
481
        $this->assertEquals(
482
            \core_analytics\manager::model_declaration_identifier(reset($noteaching2)),
483
            clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching2)), PARAM_ALPHANUM)
484
        );
485
        $this->assertEquals(
486
            \core_analytics\manager::model_declaration_identifier(reset($noteaching3)),
487
            clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching3)), PARAM_ALPHANUM)
488
        );
489
    }
490
 
491
    /**
492
     * Tests for the {@link \core_analytics\manager::get_declared_target_and_indicators_instances()}.
493
     */
11 efrain 494
    public function test_get_declared_target_and_indicators_instances(): void {
1 efrain 495
        $this->resetAfterTest();
496
 
1441 ariadna 497
        $definition = self::load_models_from_fixture_file('no_teaching');
1 efrain 498
 
1441 ariadna 499
        [$target, $indicators] = \core_analytics\manager::get_declared_target_and_indicators_instances($definition[0]);
1 efrain 500
 
501
        $this->assertTrue($target instanceof \core_analytics\local\target\base);
502
        $this->assertNotEmpty($indicators);
503
        $this->assertContainsOnlyInstancesOf(\core_analytics\local\indicator\base::class, $indicators);
504
    }
505
 
506
    /**
507
     * test_get_potential_context_restrictions description
508
     */
11 efrain 509
    public function test_get_potential_context_restrictions(): void {
1 efrain 510
        $this->resetAfterTest();
511
 
512
        // No potential context restrictions.
513
        $this->assertFalse(\core_analytics\manager::get_potential_context_restrictions([]));
514
 
515
        $defaultcategory = \core_course_category::get_default();
516
        $defaultcategorycontext = $defaultcategory->get_context();
517
 
518
        // Include the all context levels so the misc. category get included.
519
        $this->assertEquals([
520
            $defaultcategorycontext->id => "Category: {$defaultcategory->name}",
521
        ], manager::get_potential_context_restrictions());
522
 
523
        $category = $this->getDataGenerator()->create_category(['name' => 'My category']);
524
        $categorycontext = $category->get_context();
525
 
526
        $courseone = $this->getDataGenerator()->create_course(['fullname' => 'Course one', 'shortname' => 'CS1']);
527
        $courseonecontext = \context_course::instance($courseone->id);
528
 
529
        $coursetwo = $this->getDataGenerator()->create_course(['fullname' => 'Course two', 'shortname' => 'CS2']);
530
        $coursetwocontext = \context_course::instance($coursetwo->id);
531
 
532
        // All context levels.
533
        $this->assertEqualsCanonicalizing([
534
            $defaultcategorycontext->id => "Category: {$defaultcategory->name}",
535
            $categorycontext->id => "Category: {$category->name}",
536
            $courseonecontext->id => "Course: {$courseone->shortname}",
537
            $coursetwocontext->id => "Course: {$coursetwo->shortname}",
538
        ], manager::get_potential_context_restrictions());
539
 
540
        // All category/course context levels.
541
        $this->assertEqualsCanonicalizing([
542
            $defaultcategorycontext->id => "Category: {$defaultcategory->name}",
543
            $categorycontext->id => "Category: {$category->name}",
544
            $courseonecontext->id => "Course: {$courseone->shortname}",
545
            $coursetwocontext->id => "Course: {$coursetwo->shortname}",
546
        ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT, CONTEXT_COURSE]));
547
 
548
        // All category context levels.
549
        $this->assertEqualsCanonicalizing([
550
            $defaultcategorycontext->id => "Category: {$defaultcategory->name}",
551
            $categorycontext->id => "Category: {$category->name}",
552
        ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT]));
553
 
554
        // Filtered category context levels.
555
        $this->assertEquals([
556
            $categorycontext->id => "Category: {$category->name}",
557
        ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'My cat'));
558
 
559
        $this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'nothing'));
560
 
561
        // All course context levels.
562
        $this->assertEqualsCanonicalizing([
563
            $courseonecontext->id => "Course: {$courseone->shortname}",
564
            $coursetwocontext->id => "Course: {$coursetwo->shortname}",
565
        ], manager::get_potential_context_restrictions([CONTEXT_COURSE]));
566
 
567
        // Filtered course context levels.
568
        $this->assertEquals([
569
            $courseonecontext->id => "Course: {$courseone->shortname}",
570
        ], manager::get_potential_context_restrictions([CONTEXT_COURSE], 'one'));
571
 
572
        $this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSE], 'nothing'));
573
    }
574
}