Proyectos de Subversion Moodle

Rev

| 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\moodlenet;
18
 
19
use context_course;
20
use core\http_client;
21
use core\oauth2\issuer;
22
use GuzzleHttp\Exception\ClientException;
23
use GuzzleHttp\Handler\MockHandler;
24
use GuzzleHttp\HandlerStack;
25
use GuzzleHttp\Psr7\Response;
26
use moodle_exception;
27
use PHPUnit\Framework\MockObject\MockObject;
28
use Psr\Http\Message\ResponseInterface;
29
use ReflectionMethod;
30
use stdClass;
31
use testing_data_generator;
32
 
33
defined('MOODLE_INTERNAL') || die();
34
 
35
global $CFG;
36
 
37
require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php');
38
 
39
/**
40
 * Unit tests for {@see \core\moodlenet\course_partial_sender}.
41
 *
42
 * @coversDefaultClass \core\moodlenet\course_partial_sender
43
 * @package    core
44
 * @copyright  2023 Huong Nguyen <huongnv13@gmail.com>
45
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46
 */
47
class course_partial_sender_test extends \advanced_testcase {
48
 
49
    /** @var testing_data_generator Data generator. */
50
    private testing_data_generator $generator;
51
    /** @var stdClass Course object. */
52
    private stdClass $course;
53
    /** @var context_course Course context instance. */
54
    private context_course $coursecontext;
55
    /** @var array List of activities. */
56
    private array $activities;
57
    /** @var issuer $issuer Dummy issuer. */
58
    private issuer $issuer;
59
    /** @var MockObject $mockoauthclient Mock OAuth client. */
60
    private MockObject $mockoauthclient;
61
 
62
    /**
63
     * Set up function for tests.
64
     */
65
    protected function setUp(): void {
66
        parent::setUp();
67
 
68
        $this->resetAfterTest();
69
        // Get data generator.
70
        $this->generator = $this->getDataGenerator();
71
        // Create course.
72
        $this->course = $this->generator->create_course(['shortname' => 'testcourse']);
73
        $this->coursecontext = context_course::instance($this->course->id);
74
        // Create activities.
75
        $this->activities[1] = $this->generator->create_module('page', ['course' => $this->course->id]);
76
        $this->activities[2] = $this->generator->create_module('page', ['course' => $this->course->id]);
77
        // Create mock issuer.
78
        $this->issuer = helpers::get_mock_issuer(1);
79
        // Create mock builder for OAuth2 client.
80
        $mockbuilder = $this->getMockBuilder('core\oauth2\client');
81
        $mockbuilder->onlyMethods(['get_issuer', 'is_logged_in', 'get_accesstoken']);
82
        $mockbuilder->setConstructorArgs([$this->issuer, '', '']);
83
        // Get the OAuth2 client mock.
84
        $this->mockoauthclient = $mockbuilder->getMock();
85
    }
86
 
87
    /**
88
     * Test prepare_share_contents method.
89
     *
90
     * @covers ::prepare_share_contents
91
     */
92
    public function test_prepare_share_contents(): void {
93
        global $USER;
94
        $this->setAdminUser();
95
 
96
        // Set get_file method accessibility.
97
        $method = new ReflectionMethod(course_partial_sender::class, 'prepare_share_contents');
98
 
99
        $httpclient = new http_client();
100
        $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient);
101
 
102
        $this->expectException(moodle_exception::class);
103
        $this->expectExceptionMessage(get_string('invalidcoursemodule', 'error'));
104
 
105
        // Test with valid share format and invalid course module id.
106
        $package = $method->invoke(new course_partial_sender(
107
            $this->course->id,
108
            $USER->id,
109
            $moodlenetclient,
110
            $this->mockoauthclient,
111
            [random_int(5, 30)],
112
            resource_sender::SHARE_FORMAT_BACKUP
113
        ));
114
        $this->assertEmpty($package);
115
 
116
        // Test with valid share format and valid course module ids.
117
        $package = $method->invoke(new course_partial_sender(
118
            $this->course->id,
119
            $USER->id,
120
            $moodlenetclient,
121
            $this->mockoauthclient,
122
            [$this->activities[1]->cmid, $this->activities[2]->cmid],
123
            resource_sender::SHARE_FORMAT_BACKUP
124
        ));
125
        $this->assertNotEmpty($package);
126
 
127
        // Confirm the expected stored_file object is returned.
128
        $this->assertInstanceOf(\stored_file::class, $package);
129
    }
130
 
131
    /**
132
     * Test get_resource_description method.
133
     *
134
     * @covers ::get_resource_description
135
     */
136
    public function test_get_resource_description(): void {
137
        global $USER;
138
        $this->setAdminUser();
139
 
140
        $course = $this->generator->create_course([
141
            'summary' => '<p>This is an example Moodle course description.</p>
142
<p>&nbsp;</p>
143
<p>This is a formatted intro</p>
144
<p>&nbsp;</p>
145
<p>This thing has many lines.</p>
146
<p>&nbsp;</p>
147
<p>The last word of this sentence is in <strong>bold</strong></p>'
148
        ]);
149
        $page = $this->generator->create_module('page', ['course' => $course->id]);
150
 
151
        // Set get_resource_description method accessibility.
152
        $method = new ReflectionMethod(course_partial_sender::class, 'get_resource_description');
153
 
154
        // Test the processed description.
155
        $httpclient = new http_client();
156
        $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient);
157
        $processeddescription = $method->invoke(new course_partial_sender(
158
            $course->id,
159
            $USER->id,
160
            $moodlenetclient,
161
            $this->mockoauthclient,
162
            [$page->cmid],
163
            resource_sender::SHARE_FORMAT_BACKUP
164
        ), $this->coursecontext);
165
 
166
        $this->assertEquals('This is an example Moodle course description.
167
 
168
This is a formatted intro
169
 
170
This thing has many lines.
171
 
172
The last word of this sentence is in bold', $processeddescription);
173
    }
174
 
175
    /**
176
     * Test share_resource() method.
177
     *
178
     * @dataProvider share_resource_provider
179
     * @covers ::share_resource
180
     * @covers ::log_event
181
     * @covers \core\moodlenet\moodlenet_client::create_resource_from_stored_file
182
     * @covers \core\moodlenet\moodlenet_client::prepare_file_share_request_data
183
     * @param ResponseInterface $httpresponse
184
     * @param array $expected
185
     */
186
    public function test_share_resource(ResponseInterface $httpresponse, array $expected): void {
187
        global $CFG, $USER;
188
        $this->setAdminUser();
189
 
190
        // Enable the experimental flag.
191
        $CFG->enablesharingtomoodlenet = true;
192
 
193
        // Set OAuth 2 service in the outbound setting to the dummy issuer.
194
        set_config('oauthservice', $this->issuer->get('id'), 'moodlenet');
195
 
196
        // Generate access token for the mock.
197
        $accesstoken = new stdClass();
198
        $accesstoken->token = random_string(64);
199
 
200
        // Get the OAuth2 client mock and set the return value for necessary methods.
201
        $this->mockoauthclient->method('get_issuer')->will($this->returnValue($this->issuer));
202
        $this->mockoauthclient->method('is_logged_in')->will($this->returnValue(true));
203
        $this->mockoauthclient->method('get_accesstoken')->will($this->returnValue($accesstoken));
204
 
205
        // Create Guzzle mock.
206
        $mockguzzlehandler = new MockHandler([$httpresponse]);
207
        $handlerstack = HandlerStack::create($mockguzzlehandler);
208
        $httpclient = new http_client(['handler' => $handlerstack]);
209
 
210
        // Create events sink.
211
        $sink = $this->redirectEvents();
212
 
213
        // Create sender.
214
        $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient);
215
        $coursepartialsender = new course_partial_sender(
216
            $this->course->id,
217
            $USER->id,
218
            $moodlenetclient,
219
            $this->mockoauthclient,
220
            [$this->activities[1]->cmid, $this->activities[2]->cmid],
221
            resource_sender::SHARE_FORMAT_BACKUP
222
        );
223
 
224
        if (isset($expected['exception'])) {
225
            $this->expectException(ClientException::class);
226
            $this->expectExceptionMessage($expected['exception']);
227
        }
228
        // Call the API.
229
        $result = $coursepartialsender->share_resource();
230
 
231
        // Verify the result.
232
        $this->assertEquals($expected['response_code'], $result['responsecode']);
233
        $this->assertEquals($expected['resource_url'], $result['drafturl']);
234
 
235
        // Verify the events.
236
        $events = $sink->get_events();
237
 
238
        $event = end($events);
239
        $this->assertInstanceOf('\core\event\moodlenet_resource_exported', $event);
240
        $this->assertEquals($USER->id, $event->userid);
241
 
242
        $cmidslist = implode("', '", [$this->activities[1]->cmid, $this->activities[2]->cmid]);
243
        if ($result['responsecode'] == 201) {
244
            $description = "The user with id '{$USER->id}' successfully shared activities to MoodleNet with the " .
245
                "following course module ids, from context with id '{$this->coursecontext->id}': '{$cmidslist}'.";
246
        } else {
247
            $description = "The user with id '{$USER->id}' failed to share activities to MoodleNet with the " .
248
                "following course module ids, from context with id '{$this->coursecontext->id}': '{$cmidslist}'.";
249
        }
250
        $this->assertEquals($description, $event->get_description());
251
    }
252
 
253
    /**
254
     * Provider for test share_resource().
255
     *
256
     * @return array Test data.
257
     */
258
    public function share_resource_provider(): array {
259
        return [
260
            'Success' => [
261
                'http_response' => new Response(
262
                    201,
263
                    ['Content-Type' => 'application/json'],
264
                    json_encode([
265
                        'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz',
266
                    ]),
267
                ),
268
                'expected' => [
269
                    'response_code' => 201,
270
                    'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz',
271
                ],
272
            ],
273
            'Fail with 200 status code' => [
274
                'http_response' => new Response(
275
                    200,
276
                    ['Content-Type' => 'application/json'],
277
                    json_encode([
278
                        'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz',
279
                    ]),
280
                ),
281
                'expected' => [
282
                    'response_code' => 200,
283
                    'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz',
284
                ],
285
            ],
286
            'Fail with 401 status code' => [
287
                'http_response' => new Response(
288
                    401,
289
                ),
290
                'expected' => [
291
                    'response_code' => 401,
292
                    'resource_url' => '',
293
                    'exception' => 'Client error: ' .
294
                        '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' .
295
                        'resulted in a `401 Unauthorized` response',
296
                ],
297
            ],
298
            'Fail with 404 status code' => [
299
                'http_response' => new Response(
300
                    404,
301
                ),
302
                'expected' => [
303
                    'response_code' => 404,
304
                    'resource_url' => '',
305
                    'exception' => 'Client error: '.
306
                        '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' .
307
                        'resulted in a `404 Not Found` response',
308
                ],
309
            ],
310
        ];
311
    }
312
 
313
}