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 ltiservice_gradebookservices;
18
 
19
use ltiservice_gradebookservices\local\service\gradebookservices;
20
 
21
/**
22
 * Unit tests for lti gradebookservices.
23
 *
24
 * @package    ltiservice_gradebookservices
25
 * @category   test
26
 * @copyright  2020 Claude Vervoort <claude.vervoort@cengage.com>
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 * @coversDefaultClass \mod_lti\service\gradebookservices\local\gradebookservices
29
 */
1441 ariadna 30
final class gradebookservices_test extends \advanced_testcase {
1 efrain 31
    /**
32
     * Load the necessary libs for the tests.
33
     */
34
    public static function setUpBeforeClass(): void {
35
        global $CFG;
36
        require_once($CFG->dirroot . '/mod/lti/locallib.php');
1441 ariadna 37
        parent::setUpBeforeClass();
1 efrain 38
    }
39
 
40
    /**
41
     * @covers ::instance_added
42
     *
43
     * Test saving a graded LTI with resource and tag info (as a result of
44
     * content item selection) creates a gradebookservices record
45
     * that can be retrieved using the gradebook service API.
46
     */
11 efrain 47
    public function test_lti_add_coupled_lineitem(): void {
1 efrain 48
        $this->resetAfterTest();
49
        $this->setAdminUser();
50
 
51
        // Create a tool type, associated with that proxy.
52
 
53
        $typeid = $this->create_type();
54
        $course = $this->getDataGenerator()->create_course();
55
        $resourceid = 'test-resource-id';
56
        $tag = 'tag';
57
        $subreviewurl = 'https://subreview.example.com';
58
        $subreviewparams = 'a=2';
59
 
60
        $ltiinstance = $this->create_graded_lti($typeid, $course, $resourceid, $tag, $subreviewurl, $subreviewparams);
61
 
62
        $this->assertNotNull($ltiinstance);
63
 
64
        $gbs = gradebookservices::find_ltiservice_gradebookservice_for_lti($ltiinstance->id);
65
 
66
        $this->assertNotNull($gbs);
67
        $this->assertEquals($resourceid, $gbs->resourceid);
68
        $this->assertEquals($tag, $gbs->tag);
69
        $this->assertEquals($subreviewurl, $gbs->subreviewurl);
70
        $this->assertEquals($subreviewparams, $gbs->subreviewparams);
71
        $this->assert_lineitems($course, $typeid, $ltiinstance->name,
72
            $ltiinstance, $resourceid, $tag, $subreviewurl, $subreviewparams);
73
    }
74
 
75
    /**
76
     * @covers ::instance_added
77
     *
78
     * Test saving a graded LTI with resource and tag info (as a result of
79
     * content item selection) creates a gradebookservices record
80
     * that can be retrieved using the gradebook service API.
81
     */
11 efrain 82
    public function test_lti_add_coupled_lineitem_default_subreview(): void {
1 efrain 83
        $this->resetAfterTest();
84
        $this->setAdminUser();
85
 
86
        // Create a tool type, associated with that proxy.
87
 
88
        $typeid = $this->create_type();
89
        $course = $this->getDataGenerator()->create_course();
90
        $resourceid = 'test-resource-id';
91
        $tag = 'tag';
92
 
93
        $ltiinstance = $this->create_graded_lti($typeid, $course, $resourceid, $tag, 'DEFAULT');
94
 
95
        $this->assertNotNull($ltiinstance);
96
 
97
        $gbs = gradebookservices::find_ltiservice_gradebookservice_for_lti($ltiinstance->id);
98
 
99
        $this->assertNotNull($gbs);
100
        $this->assertEquals('DEFAULT', $gbs->subreviewurl);
101
        $this->assert_lineitems($course, $typeid, $ltiinstance->name, $ltiinstance, $resourceid, $tag, 'DEFAULT');
102
    }
103
 
104
    /**
105
     * @covers ::add_standalone_lineitem
106
     *
107
     * Test saving a standalone LTI lineitem with resource and tag info
108
     * that can be retrieved using the gradebook service API.
109
     */
11 efrain 110
    public function test_lti_add_standalone_lineitem(): void {
1 efrain 111
        $this->resetAfterTest();
112
        $this->setAdminUser();
113
 
114
        $course = $this->getDataGenerator()->create_course();
115
        $resourceid = "test-resource-standalone";
116
        $tag = "test-tag-standalone";
117
        $typeid = $this->create_type();
118
 
119
        $this->create_standalone_lineitem($course->id, $typeid, $resourceid, $tag);
120
 
121
        $this->assert_lineitems($course, $typeid, "manualtest", null, $resourceid, $tag);
122
    }
123
 
124
    /**
125
     * @covers ::find_ltiservice_gradebookservice_for_lti
126
     *
127
     * Test line item URL is populated for coupled line item only
128
     * if there is not another line item bound to the lti instance,
129
     * since in that case there would be no rule to define which of
130
     * the line items should be actually passed.
131
     */
11 efrain 132
    public function test_get_launch_parameters_coupled(): void {
1 efrain 133
        $this->resetAfterTest();
134
        $this->setAdminUser();
135
 
136
        // Create a tool type, associated with that proxy.
137
 
138
        $typeid = $this->create_type();
139
        $course = $this->getDataGenerator()->create_course();
140
 
141
        $ltiinstance = $this->create_graded_lti($typeid, $course, 'resource-id', 'tag', 'https://subreview.url', 'sub=review');
142
 
143
        $this->assertNotNull($ltiinstance);
144
 
145
        $gbservice = new gradebookservices();
146
        $params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
147
        $this->assertEquals('$LineItem.url', $params['lineitem_url']);
148
        $this->assertEquals('$LineItem.url', $params['lineitem_url']);
149
 
150
        $this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag', $ltiinstance->id);
151
        $params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
152
        $this->assertEquals('$LineItems.url', $params['lineitems_url']);
153
        // 2 line items for a single link, we cannot return a single line item url.
154
        $this->assertFalse(array_key_exists('$LineItem.url', $params));
155
    }
156
 
157
    /**
158
     * @covers ::override_endpoint
159
     *
160
     * Test Submission Review URL and custom parameter is applied when the
161
     * launch is submission review.
162
     */
11 efrain 163
    public function test_get_launch_parameters_coupled_subreview_override(): void {
1 efrain 164
        $this->resetAfterTest();
165
        $this->setAdminUser();
166
 
167
        // Create a tool type, associated with that proxy.
168
 
169
        $typeid = $this->create_type();
170
        $course = $this->getDataGenerator()->create_course();
171
 
172
        $ltiinstance = $this->create_graded_lti($typeid, $course, 'resource-id', 'tag',
173
            'https://example.com/subreview', 'action=review');
174
 
175
        $this->assertNotNull($ltiinstance);
176
 
177
        $gbservice = new gradebookservices();
178
        $overrides = $gbservice->override_endpoint('LtiSubmissionReviewRequest', 'https://example.com/lti',
179
            "color=blue", $course->id, $ltiinstance);
180
 
181
        $this->assertEquals('https://example.com/subreview', $overrides[0]);
182
        $this->assertEquals("color=blue\naction=review", $overrides[1]);
183
    }
184
 
185
    /**
186
     * @covers ::override_endpoint
187
     *
188
     * Test Submission Review URL and custom parameter is applied when the
189
     * launch is submission review.
190
     */
11 efrain 191
    public function test_get_launch_parameters_coupled_subreview_override_default(): void {
1 efrain 192
        $this->resetAfterTest();
193
        $this->setAdminUser();
194
 
195
        // Create a tool type, associated with that proxy.
196
 
197
        $typeid = $this->create_type();
198
        $course = $this->getDataGenerator()->create_course();
199
 
200
        $ltiinstance = $this->create_graded_lti($typeid, $course, 'resource-id', 'tag',
201
            'DEFAULT', '');
202
 
203
        $this->assertNotNull($ltiinstance);
204
 
205
        $gbservice = new gradebookservices();
206
        $overrides = $gbservice->override_endpoint('LtiSubmissionReviewRequest', 'https://example.com/lti',
207
            "color=blue", $course->id, $ltiinstance);
208
 
209
        $this->assertEquals('https://example.com/lti', $overrides[0]);
210
        $this->assertEquals("color=blue", $overrides[1]);
211
    }
212
 
213
    /**
214
     * @covers ::get_launch_parameters
215
     *
216
     * Test line item URL is populated for not coupled line item only
217
     * if there is a single line item attached to that lti instance.
218
     */
11 efrain 219
    public function test_get_launch_parameters_decoupled(): void {
1 efrain 220
        $this->resetAfterTest();
221
        $this->setAdminUser();
222
 
223
        // Create a tool type, associated with that proxy.
224
 
225
        $typeid = $this->create_type();
226
 
227
        $course = $this->getDataGenerator()->create_course();
228
 
229
        $ltiinstance = $this->create_notgraded_lti($typeid, $course);
230
 
231
        $this->assertNotNull($ltiinstance);
232
 
233
        $gbservice = new gradebookservices();
234
        $params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
235
        $this->assertEquals('$LineItems.url', $params['lineitems_url']);
236
        $this->assertFalse(array_key_exists('$LineItem.url', $params));
237
 
238
        $this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag', $ltiinstance->id);
239
        $params = $gbservice->get_launch_parameters('basic-lti-launch-request', $course->id, 111, $typeid, $ltiinstance->id);
240
        $this->assertEquals('$LineItems.url', $params['lineitems_url']);
241
        $this->assertEquals('$LineItem.url', $params['lineitem_url']);
242
 
243
        // 2 line items for a single link, we cannot return a single line item url.
244
        $this->create_standalone_lineitem($course->id, $typeid, 'resource-id', 'tag-2', $ltiinstance->id);
245
        $this->assertFalse(array_key_exists('$LineItem.url', $params));
246
    }
247
 
248
    /**
249
     * @covers ::is_user_gradable_in_course
250
     *
251
     * Test if a user can be graded in a course.
252
     */
11 efrain 253
    public function test_is_user_gradable_in_course(): void {
1 efrain 254
        $this->resetAfterTest();
255
 
256
        $generator = $this->getDataGenerator();
257
        $course = $generator->create_course();
258
        $user1 = $generator->create_user();
259
        $user2 = $generator->create_user();
260
        $generator->enrol_user($user1->id, $course->id, 'student');
261
        $generator->enrol_user($user2->id, $course->id, 'editingteacher');
262
 
263
        $this->assertTrue(gradebookservices::is_user_gradable_in_course($course->id, $user1->id));
264
        $this->assertFalse(gradebookservices::is_user_gradable_in_course($course->id, $user2->id));
265
    }
266
 
267
    /**
268
     * Asserts a matching gradebookservices record exist with the matching tag and resourceid.
269
     *
270
     * @param object $course current course
271
     * @param int $typeid Type id of the tool
272
     * @param string $label Label of the line item
273
     * @param object|null $ltiinstance lti instance related to that line item
274
     * @param string|null $resourceid resourceid the line item should have
275
     * @param string|null $tag tag the line item should have
276
     * @param string|null $subreviewurl submission review url
277
     * @param string|null $subreviewparams submission review custom params
278
     */
279
    private function assert_lineitems(object $course, int $typeid,
280
            string $label, ?object $ltiinstance, ?string $resourceid, ?string $tag,
281
            ?string $subreviewurl = null, ?string $subreviewparams = null): void {
282
        $gbservice = new gradebookservices();
283
        $gradeitems = $gbservice->get_lineitems($course->id, null, null, null, null, null, $typeid);
284
 
285
        // The 1st item in the array is the items count.
286
        $this->assertEquals(1, $gradeitems[0]);
287
        $lineitem = gradebookservices::item_for_json($gradeitems[1][0], '', $typeid);
288
        $this->assertEquals(10, $lineitem->scoreMaximum);
289
        $this->assertEquals($resourceid, $lineitem->resourceId);
290
        $this->assertEquals($tag, $lineitem->tag);
291
        $this->assertEquals($label, $lineitem->label);
292
        $this->assertEquals(!empty($subreviewurl), isset($lineitem->submissionReview));
293
        if ($subreviewurl) {
294
            if ($subreviewurl == 'DEFAULT') {
295
                $this->assertFalse(isset($lineitem->submissionReview->url));
296
            } else {
297
                $this->assertEquals($subreviewurl, $lineitem->submissionReview->url);
298
            }
299
            if ($subreviewparams) {
300
                $custom = $lineitem->submissionReview->custom;
301
                $this->assertEquals($subreviewparams, join("\n", array_map(fn($k) => $k.'='.$custom[$k], array_keys($custom))));
302
            } else {
303
                $this->assertFalse(isset($lineitem->submissionReview->custom));
304
            }
305
        }
306
 
307
        $gradeitems = $gbservice->get_lineitems($course->id, $resourceid, null, null, null, null, $typeid);
308
        $this->assertEquals(1, $gradeitems[0]);
309
 
310
        if (isset($ltiinstance)) {
311
            $gradeitems = $gbservice->get_lineitems($course->id, null, $ltiinstance->id, null, null, null, $typeid);
312
            $this->assertEquals(1, $gradeitems[0]);
313
            $gradeitems = $gbservice->get_lineitems($course->id, null, $ltiinstance->id + 1, null, null, null, $typeid);
314
            $this->assertEquals(0, $gradeitems[0]);
315
        }
316
 
317
        $gradeitems = $gbservice->get_lineitems($course->id, null, null, $tag, null, null, $typeid);
318
        $this->assertEquals(1, $gradeitems[0]);
319
 
320
        $gradeitems = $gbservice->get_lineitems($course->id, 'an unknown resource id', null, null, null, null, $typeid);
321
        $this->assertEquals(0, $gradeitems[0]);
322
 
323
        $gradeitems = $gbservice->get_lineitems($course->id, null, null, 'an unknown tag', null, null, $typeid);
324
        $this->assertEquals(0, $gradeitems[0]);
325
    }
326
 
327
    /**
328
     * Inserts a graded lti instance, which should create a grade_item and gradebookservices record.
329
     *
330
     * @param int $typeid Type ID of the LTI Tool.
331
     * @param object $course course where to add the lti instance.
332
     * @param string|null $resourceid resource id
333
     * @param string|null $tag tag
334
     * @param string|null $subreviewurl submission review url
335
     * @param string|null $subreviewparams submission review custom params
336
     *
337
     * @return object lti instance created
338
     */
339
    private function create_graded_lti(int $typeid, object $course, ?string $resourceid, ?string $tag,
340
            ?string $subreviewurl = null, ?string $subreviewparams = null): object {
341
 
342
        $lti = ['course' => $course->id,
343
            'typeid' => $typeid,
344
            'instructorchoiceacceptgrades' => LTI_SETTING_ALWAYS,
345
            'grade' => 10,
346
            'lineitemresourceid' => $resourceid,
347
            'lineitemtag' => $tag,
348
            'lineitemsubreviewurl' => $subreviewurl,
349
            'lineitemsubreviewparams' => $subreviewparams];
350
 
351
        return $this->getDataGenerator()->create_module('lti', $lti, array());
352
    }
353
 
354
     /**
355
      * Inserts an lti instance that is not graded.
356
      *
357
      * @param int $typeid Type Id of the LTI Tool.
358
      * @param object $course course where to add the lti instance.
359
      *
360
      * @return object lti instance created
361
      */
362
    private function create_notgraded_lti(int $typeid, object $course): object {
363
 
364
        $lti = ['course' => $course->id,
365
            'typeid' => $typeid,
366
            'instructorchoiceacceptgrades' => LTI_SETTING_NEVER];
367
 
368
        return $this->getDataGenerator()->create_module('lti', $lti, array());
369
    }
370
 
371
    /**
372
     * Inserts a standalone lineitem (gradeitem, gradebookservices entries).
373
     *
374
     * @param int $courseid Id of the course where the standalone line item will be added.
375
     * @param int $typeid of the LTI Tool
376
     * @param string|null $resourceid resource id
377
     * @param string|null $tag tag
378
     * @param int|null $ltiinstanceid Id of the LTI instance the standalone line item will be related to.
379
     *
380
     */
381
    private function create_standalone_lineitem(int $courseid, int $typeid, ?string $resourceid,
1441 ariadna 382
            ?string $tag, ?int $ltiinstanceid = null): void {
1 efrain 383
        $gbservice = new gradebookservices();
384
        $gbservice->add_standalone_lineitem($courseid,
385
            "manualtest",
386
            10,
387
            "https://test.phpunit",
388
            $ltiinstanceid,
389
            $resourceid,
390
            $tag,
391
            $typeid,
392
            null /*toolproxyid*/);
393
    }
394
 
395
    /**
396
     * Creates a new LTI Tool Type.
397
     */
398
    private function create_type() {
399
        $type = new \stdClass();
400
        $type->state = LTI_TOOL_STATE_CONFIGURED;
401
        $type->name = "Test tool";
402
        $type->description = "Example description";
403
        $type->clientid = "Test client ID";
404
        $type->baseurl = $this->getExternalTestFileUrl('/test.html');
405
 
406
        $config = new \stdClass();
407
        $config->ltiservice_gradesynchronization = 2;
408
        return lti_add_type($type, $config);
409
    }
410
}