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 communication_matrix;
18
 
19
use communication_matrix\local\command;
20
use communication_matrix\local\spec\v1p7;
21
use communication_matrix\local\spec\features;
22
use communication_matrix\tests\fixtures\mocked_matrix_client;
23
use core\http_client;
24
use GuzzleHttp\Handler\MockHandler;
25
use GuzzleHttp\HandlerStack;
26
use GuzzleHttp\Middleware;
27
use GuzzleHttp\Psr7\Response;
28
use moodle_exception;
29
 
30
defined('MOODLE_INTERNAL') || die();
31
require_once(__DIR__ . '/matrix_client_test_trait.php');
32
 
33
/**
34
 * Tests for the matrix_client class.
35
 *
36
 * @package    communication_matrix
37
 * @category   test
38
 * @copyright  2023 Andrew Lyons <andrew@nicols.co.uk>
39
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40
 * @covers \communication_matrix\matrix_client
41
 * @coversDefaultClass \communication_matrix\matrix_client
42
 */
43
class matrix_client_test extends \advanced_testcase {
44
    use matrix_client_test_trait;
45
 
46
    /**
47
     * Data provider for valid calls to ::instance.
48
     * @return array
49
     */
50
    public static function instance_provider(): array {
51
        $testcases = [
52
            'Standard versions' => [
53
                null,
54
                v1p7::class,
55
            ],
56
        ];
57
 
58
        // Remove a couple of versions.
59
        $versions = self::get_current_versions();
60
        array_pop($versions);
61
        array_pop($versions);
62
 
63
        $testcases['Older server'] = [
64
            $versions,
65
            array_key_last($versions),
66
        ];
67
 
68
        // Limited version compatibility, including newer than we support now.
69
        $testcases['Newer versions with crossover'] = [
70
            [
71
                'v1.6',
72
                'v1.7',
73
                'v7.9',
74
            ],
75
            \communication_matrix\local\spec\v1p7::class,
76
        ];
77
 
78
        return $testcases;
79
    }
80
 
81
    /**
82
     * Test that the instance method returns a valid instance for the given versions.
83
     *
84
     * @dataProvider instance_provider
85
     * @param array|null $versions
86
     * @param string $expectedversion
87
     */
88
    public function test_instance(
89
        ?array $versions,
90
        string $expectedversion,
91
    ): void {
92
        // Create a mock and queue two responses.
93
 
94
        $mock = new MockHandler([
95
            $this->get_mocked_version_response($versions),
96
        ]);
97
        $handlerstack = HandlerStack::create($mock);
98
        $container = [];
99
        $history = Middleware::history($container);
100
        $handlerstack->push($history);
101
        $client = new http_client(['handler' => $handlerstack]);
102
        mocked_matrix_client::set_client($client);
103
 
104
        $instance = mocked_matrix_client::instance(
105
            'https://example.com',
106
            'testtoken',
107
        );
108
 
109
        $this->assertInstanceOf(matrix_client::class, $instance);
110
 
111
        // Only the version API has been called.
112
        $this->assertCount(1, $container);
113
        $request = reset($container);
114
        $this->assertEquals('/_matrix/client/versions', $request['request']->getUri()->getPath());
115
 
116
        // The client should be a v1p7 client as that is the highest compatible version.
117
        $this->assertInstanceOf($expectedversion, $instance);
118
    }
119
 
120
    /**
121
     * Test that the instance method returns a valid instance for the given versions.
122
     */
123
    public function test_instance_cached(): void {
124
        $mock = new MockHandler([
125
            $this->get_mocked_version_response(),
126
            $this->get_mocked_version_response(),
127
        ]);
128
        $handlerstack = HandlerStack::create($mock);
129
        $container = [];
130
        $history = Middleware::history($container);
131
        $handlerstack->push($history);
132
        $client = new http_client(['handler' => $handlerstack]);
133
        mocked_matrix_client::set_client($client);
134
 
135
        $instance = mocked_matrix_client::instance('https://example.com', 'testtoken');
136
 
137
        $this->assertInstanceOf(matrix_client::class, $instance);
138
 
139
        // Only the version API has been called.
140
        $this->assertCount(1, $container);
141
 
142
        // Call the API again. It should not lead to additional fetches.
143
        $instance = mocked_matrix_client::instance('https://example.com', 'testtoken');
144
        $instance = mocked_matrix_client::instance('https://example.com', 'testtoken');
145
        $this->assertCount(1, $container);
146
 
147
        // But a different endpoint will.
148
        $instance = mocked_matrix_client::instance('https://example.org', 'testtoken');
149
        $this->assertCount(2, $container);
150
    }
151
 
152
    /**
153
     * Test that the instance method throws an appropriate exception if no support is found.
154
     */
155
    public function test_instance_no_support(): void {
156
        // Create a mock and queue two responses.
157
 
158
        $mock = new MockHandler([
159
            $this->get_mocked_version_response(['v99.9']),
160
        ]);
161
        $handlerstack = HandlerStack::create($mock);
162
        $container = [];
163
        $history = Middleware::history($container);
164
        $handlerstack->push($history);
165
        $client = new http_client(['handler' => $handlerstack]);
166
        mocked_matrix_client::set_client($client);
167
 
168
        $this->expectException(moodle_exception::class);
169
        $this->expectExceptionMessage('No supported Matrix API versions found.');
170
 
171
        mocked_matrix_client::instance(
172
            'https://example.com',
173
            'testtoken',
174
        );
175
    }
176
 
177
    /**
178
     * Test the feature implementation check methods.
179
     *
180
     * @covers ::implements_feature
181
     * @covers ::get_supported_versions
182
     * @dataProvider implements_feature_provider
183
     * @param string $version
184
     * @param array|string $features
185
     * @param bool $expected
186
     */
187
    public function test_implements_feature(
188
        string $version,
189
        array|string $features,
190
        bool $expected,
191
    ): void {
192
        $instance = $this->get_mocked_instance_for_version($version);
193
        $this->assertEquals($expected, $instance->implements_feature($features));
194
    }
195
 
196
    /**
197
     * Test the feature implementation requirement methods.
198
     *
199
     * @covers ::implements_feature
200
     * @covers ::get_supported_versions
201
     * @covers ::require_feature
202
     * @dataProvider implements_feature_provider
203
     * @param string $version
204
     * @param array|string $features
205
     * @param bool $expected
206
     */
207
    public function test_require_feature(
208
        string $version,
209
        array|string $features,
210
        bool $expected,
211
    ): void {
212
        $instance = $this->get_mocked_instance_for_version($version);
213
 
214
        if ($expected) {
215
            $this->assertEmpty($instance->require_feature($features));
216
        } else {
217
            $this->expectException('moodle_exception');
218
            $instance->require_feature($features);
219
        }
220
    }
221
 
222
    /**
223
     * Test the feature implementation requirement methods for a require all.
224
     *
225
     * @covers ::implements_feature
226
     * @covers ::get_supported_versions
227
     * @covers ::require_feature
228
     * @covers ::require_features
229
     * @dataProvider require_features_provider
230
     * @param string $version
231
     * @param array|string $features
232
     * @param bool $expected
233
     */
234
    public function test_require_features(
235
        string $version,
236
        array|string $features,
237
        bool $expected,
238
    ): void {
239
        $instance = $this->get_mocked_instance_for_version($version);
240
 
241
        if ($expected) {
242
            $this->assertEmpty($instance->require_features($features));
243
        } else {
244
            $this->expectException('moodle_exception');
245
            $instance->require_features($features);
246
        }
247
    }
248
 
249
    /**
250
     * Data provider for feature implementation check tests.
251
     *
252
     * @return array
253
     */
254
    public static function implements_feature_provider(): array {
255
        return [
256
            'Basic supported feature' => [
257
                'v1.7',
258
                features\matrix\media_create_v1::class,
259
                true,
260
            ],
261
            'Basic unsupported feature' => [
262
                'v1.6',
263
                features\matrix\media_create_v1::class,
264
                false,
265
            ],
266
            '[supported] as array' => [
267
                'v1.6',
268
                [features\matrix\create_room_v3::class],
269
                true,
270
            ],
271
            '[supported, supported] as array' => [
272
                'v1.6',
273
                [
274
                    features\matrix\create_room_v3::class,
275
                    features\matrix\update_room_avatar_v3::class,
276
                ],
277
                true,
278
            ],
279
            '[unsupported] as array' => [
280
                'v1.6',
281
                [
282
                    features\matrix\media_create_v1::class,
283
                ],
284
                false,
285
            ],
286
            '[unsupported, supported] as array' => [
287
                'v1.6',
288
                [
289
                    features\matrix\media_create_v1::class,
290
                    features\matrix\update_room_avatar_v3::class,
291
                ],
292
                true,
293
            ],
294
        ];
295
    }
296
 
297
    /**
298
     * Data provider for feature implementation check tests.
299
     *
300
     * @return array
301
     */
302
    public static function require_features_provider(): array {
303
        // We'll just add to the standard testcases.
304
        $testcases = array_map(static function (array $testcase): array {
305
            $testcase[1] = [$testcase[1]];
306
            return $testcase;
307
        }, self::implements_feature_provider());
308
 
309
        $testcases['Require many supported features'] = [
310
            'v1.6',
311
            [
312
                features\matrix\create_room_v3::class,
313
                features\matrix\update_room_avatar_v3::class,
314
            ],
315
            true,
316
        ];
317
 
318
        $testcases['Require many including an unsupported feature'] = [
319
            'v1.6',
320
            [
321
                features\matrix\create_room_v3::class,
322
                features\matrix\media_create_v1::class,
323
            ],
324
            false,
325
        ];
326
 
327
        $testcases['Require many including an unsupported feature which has an alternate'] = [
328
            'v1.6',
329
            [
330
                features\matrix\create_room_v3::class,
331
                [
332
                    features\matrix\media_create_v1::class,
333
                    features\matrix\update_room_avatar_v3::class,
334
                ],
335
            ],
336
            true,
337
        ];
338
 
339
        return $testcases;
340
    }
341
 
342
    /**
343
     * Test the get_version method.
344
     *
345
     * @param string $version
346
     * @param string $expectedversion
347
     * @dataProvider get_version_provider
348
     * @covers ::get_version
349
     * @covers ::get_version_from_classname
350
     */
351
    public function test_get_version(
352
        string $version,
353
        string $expectedversion,
354
    ): void {
355
        $instance = $this->get_mocked_instance_for_version($version);
356
        $this->assertEquals($expectedversion, $instance->get_version());
357
    }
358
 
359
    /**
360
     * Data provider for get_version tests.
361
     *
362
     * @return array
363
     */
364
    public static function get_version_provider(): array {
365
        return [
366
            ['v1.1', '1.1'],
367
            ['v1.7', '1.7'],
368
        ];
369
    }
370
 
371
    /**
372
     * Tests the meets_version method.
373
     *
374
     * @param string $version The version of the API to test against
375
     * @param string $testversion The version to test
376
     * @param bool $expected Whether the version meets the requirement
377
     * @dataProvider meets_version_provider
378
     * @covers ::meets_version
379
     */
380
    public function test_meets_version(
381
        string $version,
382
        string $testversion,
383
        bool $expected,
384
    ): void {
385
        $instance = $this->get_mocked_instance_for_version($version);
386
        $this->assertEquals($expected, $instance->meets_version($testversion));
387
    }
388
 
389
    /**
390
     * Tests the requires_version method.
391
     *
392
     * @param string $version The version of the API to test against
393
     * @param string $testversion The version to test
394
     * @param bool $expected Whether the version meets the requirement
395
     * @dataProvider meets_version_provider
396
     * @covers ::requires_version
397
     */
398
    public function test_requires_version(
399
        string $version,
400
        string $testversion,
401
        bool $expected,
402
    ): void {
403
        $instance = $this->get_mocked_instance_for_version($version);
404
 
405
        if ($expected) {
406
            $this->assertEmpty($instance->requires_version($testversion));
407
        } else {
408
            $this->expectException('moodle_exception');
409
            $instance->requires_version($testversion);
410
        }
411
    }
412
 
413
    /**
414
     * Data provider for meets_version tests.
415
     *
416
     * @return array
417
     */
418
    public static function meets_version_provider(): array {
419
        return [
420
            'Same version' => ['v1.1', '1.1', true],
421
            'Same version latest' => ['v1.7', '1.7', true],
422
            'Newer version rejected' => ['v1.1', '1.7', false],
423
            'Older version accepted' => ['v1.7', '1.1', true],
424
        ];
425
    }
426
 
427
    /**
428
     * Test the execute method with a command.
429
     *
430
     * @covers ::execute
431
     */
432
    public function test_command_is_executed(): void {
433
        $historycontainer = [];
434
        $mock = new MockHandler();
435
 
436
        $instance = $this->get_mocked_instance_for_version('v1.6', $historycontainer, $mock);
437
        $command = new command(
438
            $instance,
439
            method: 'GET',
440
            endpoint: 'test/endpoint',
441
            params: [
442
                'test' => 'test',
443
            ],
444
        );
445
 
446
        $mock->append(new Response(200));
447
 
448
        $rc = new \ReflectionClass($instance);
449
        $rcm = $rc->getMethod('execute');
450
        $result = $rcm->invoke($instance, $command);
451
 
452
        $this->assertEquals(200, $result->getStatusCode());
453
        $this->assertCount(1, $historycontainer);
454
        $request = array_shift($historycontainer);
455
        $this->assertEquals('GET', $request['request']->getMethod());
456
        $this->assertEquals('/test/endpoint', $request['request']->getUri()->getPath());
457
    }
458
}