Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   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\local;
  18  
  19  use GuzzleHttp\Handler\MockHandler;
  20  use GuzzleHttp\Psr7\Request;
  21  use GuzzleHttp\Psr7\Response;
  22  use ReflectionMethod;
  23  
  24  defined('MOODLE_INTERNAL') || die();
  25  require_once(dirname(__DIR__) . '/matrix_client_test_trait.php');
  26  
  27  /**
  28   * Tests for the Matrix command class.
  29   *
  30   * @package    communication_matrix
  31   * @category   test
  32   * @copyright  2023 Andrew Lyons <andrew@nicols.co.uk>
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   * @covers \communication_matrix\local\command
  35   * @coversDefaultClass \communication_matrix\local\command
  36   */
  37  class command_test extends \advanced_testcase {
  38      use \communication_matrix\matrix_client_test_trait;
  39  
  40      /**
  41       * Test instantiation of a command when no method is provided.
  42       */
  43      public function test_standard_instantiation(): void {
  44          $instance = $this->get_mocked_instance_for_version('v1.7');
  45          $command = new command(
  46              $instance,
  47              method: 'PUT',
  48              endpoint: 'example/endpoint',
  49          );
  50  
  51          // Check the standard functionality.
  52          $this->assertEquals('/example/endpoint', $command->getUri()->getPath());
  53          $this->assertEquals('PUT', $command->getMethod());
  54          $this->assertArrayHasKey('Authorization', $command->getHeaders());
  55      }
  56  
  57      /**
  58       * Test instantiation of a command when no method is provided.
  59       */
  60      public function test_instantiation_without_auth(): void {
  61          $instance = $this->get_mocked_instance_for_version('v1.7');
  62          $command = new command(
  63              $instance,
  64              method: 'PUT',
  65              endpoint: 'example/endpoint',
  66              requireauthorization: false,
  67          );
  68  
  69          // Check the standard functionality.
  70          $this->assertEquals('/example/endpoint', $command->getUri()->getPath());
  71          $this->assertEquals('PUT', $command->getMethod());
  72          $this->assertArrayNotHasKey('Authorization', $command->getHeaders());
  73      }
  74  
  75      /**
  76       * Test processing of command URL properties.
  77       *
  78       * @dataProvider url_parsing_provider
  79       * @param string $url
  80       * @param array $params
  81       * @param string $expected
  82       */
  83      public function test_url_parsing(
  84          string $url,
  85          array $params,
  86          string $expected,
  87      ): void {
  88          $instance = $this->get_mocked_instance_for_version('v1.7');
  89  
  90          $command = new command(
  91              $instance,
  92              method: 'PUT',
  93              endpoint: $url,
  94              params: $params,
  95          );
  96  
  97          $this->assertEquals($expected, $command->getUri()->getPath());
  98      }
  99  
 100      /**
 101       * Data provider for url parsing tests.
 102       *
 103       * @return array
 104       */
 105      public static function url_parsing_provider(): array {
 106          return [
 107              [
 108                  'example/:id/endpoint',
 109                  [':id' => '39492'],
 110                  '/example/39492/endpoint',
 111              ],
 112              [
 113                  'example/:id/endpoint/:id',
 114                  [':id' => '39492'],
 115                  '/example/39492/endpoint/39492',
 116              ],
 117              [
 118                  'example/:id/endpoint/:id/:name',
 119                  [
 120                      ':id' => '39492',
 121                      ':name' => 'matrix',
 122                  ],
 123                  '/example/39492/endpoint/39492/matrix',
 124              ],
 125          ];
 126      }
 127  
 128      /**
 129       * Test processing of command URL properties with an array which contains untranslated parameters.
 130       */
 131      public function test_url_parsing_extra_properties(): void {
 132          $instance = $this->get_mocked_instance_for_version('v1.7');
 133          $this->expectException(\OutOfRangeException::class);
 134          $this->expectExceptionMessage("URL contains untranslated parameters 'example/:id/endpoint'");
 135  
 136          new command(
 137              $instance,
 138              method: 'PUT',
 139              endpoint: 'example/:id/endpoint',
 140          );
 141      }
 142  
 143      /**
 144       * Test processing of command URL properties with an array which contains untranslated parameters.
 145       */
 146      public function test_url_parsing_unused_properites(): void {
 147          $instance = $this->get_mocked_instance_for_version('v1.7');
 148          $this->expectException(\OutOfRangeException::class);
 149          $this->expectExceptionMessage("Parameter not found in URL ':id'");
 150  
 151          new command(
 152              $instance,
 153              method: 'PUT',
 154              endpoint: 'example/:ids/endpoint',
 155              params: [
 156                  ':id' => 12345,
 157              ],
 158          );
 159      }
 160  
 161      /**
 162       * Test the parameter fetching, processing, and parsing.
 163       *
 164       * @dataProvider parameter_and_option_provider
 165       * @param string $endpoint
 166       * @param array $params
 167       * @param array $remainingparams
 168       * @param array $allparams
 169       * @param array $options
 170       */
 171      public function test_parameters(
 172          string $endpoint,
 173          array $params,
 174          array $remainingparams,
 175          array $allparams,
 176          array $options,
 177      ): void {
 178          $instance = $this->get_mocked_instance_for_version('v1.7');
 179  
 180          $command = new command(
 181              $instance,
 182              method: 'PUT',
 183              endpoint: $endpoint,
 184              params: $params,
 185          );
 186  
 187          $this->assertSame($remainingparams, $command->get_remaining_params());
 188          $this->assertSame($allparams, $command->get_all_params());
 189          $this->assertSame($options, $command->get_options());
 190      }
 191  
 192      /**
 193       * Data provider for parameter tests.
 194       *
 195       * @return array
 196       */
 197      public static function parameter_and_option_provider(): array {
 198          $command = [
 199              'method' => 'PUT',
 200              'endpoint' => 'example/:id/endpoint',
 201          ];
 202  
 203          return [
 204              'no parameters' => [
 205                  'endpoint' => 'example/endpoint',
 206                  'params' => [],
 207                  'remainingparams' => [],
 208                  'allparams' => [],
 209                  'options' => [
 210                      'json' => [],
 211                  ],
 212              ],
 213              'named params' => [
 214                  'endpoint' => 'example/:id/endpoint',
 215                  'params' => [
 216                      ':id' => 12345,
 217                  ],
 218                  'remainingparams' => [],
 219                  'allparams' => [
 220                      ':id' => 12345,
 221                  ],
 222                  'options' => [
 223                      'json' => [],
 224                  ],
 225              ],
 226              'mixture of params' => [
 227                  'endpoint' => 'example/:id/endpoint',
 228                  'params' => [
 229                      ':id' => 12345,
 230                      'name' => 'matrix',
 231                  ],
 232                  'remainingparams' => [
 233                      'name' => 'matrix',
 234                  ],
 235                  'allparams' => [
 236                      ':id' => 12345,
 237                      'name' => 'matrix',
 238                  ],
 239                  'options' => [
 240                      'json' => [
 241                          'name' => 'matrix',
 242                      ],
 243                  ],
 244              ],
 245          ];
 246      }
 247  
 248      /**
 249       * Test the query parameter handling.
 250       *
 251       * @dataProvider query_provider
 252       * @param array $query
 253       * @param string $expected
 254       */
 255      public function test_query_parameters(
 256          array $query,
 257          string $expected,
 258      ): void {
 259          // The query parameter is only added at the time we call send.
 260          // That's because it can only be provided to Guzzle as an Option, not as part of the URL.
 261          // Options can only be applied at time of transfer.
 262          // Unfortuantely that leads to slightly less ideal testing that we'd like here.
 263          $mock = new MockHandler();
 264          $instance = $this->get_mocked_instance_for_version(
 265              'v1.7',
 266              mock: $mock,
 267          );
 268  
 269          $mock->append(function (Request $request) use ($expected): Response {
 270              $this->assertSame(
 271                  $expected,
 272                  $request->getUri()->getQuery(),
 273              );
 274              return new Response();
 275          });
 276          $command = new command(
 277              $instance,
 278              method: 'PUT',
 279              endpoint: 'example/endpoint',
 280              query: $query,
 281          );
 282  
 283          $execute = new ReflectionMethod($instance, 'execute');
 284          $execute->setAccessible(true);
 285          $execute->invoke($instance, $command);
 286      }
 287  
 288      /**
 289       * Data provider for query parameter tests.
 290       * @return array
 291       */
 292      public static function query_provider(): array {
 293          return [
 294              'no query' => [
 295                  'query' => [],
 296                  'expected' => '',
 297              ],
 298              'single query' => [
 299                  'query' => [
 300                      'name' => 'matrix',
 301                  ],
 302                  'expected' => 'name=matrix',
 303              ],
 304              'multiple queries' => [
 305                  'query' => [
 306                      'name' => 'matrix',
 307                      'type' => 'room',
 308                  ],
 309                  'expected' => 'name=matrix&type=room',
 310              ],
 311          ];
 312      }
 313  
 314      /**
 315       * Test the sendasjson constructor parameter.
 316       *
 317       * @dataProvider sendasjson_provider
 318       * @param bool $sendasjson
 319       * @param string $endpoint
 320       * @param array $params
 321       * @param array $remainingparams
 322       * @param array $allparams
 323       * @param array $expectedoptions
 324       */
 325      public function test_send_as_json(
 326          bool $sendasjson,
 327          string $endpoint,
 328          array $params,
 329          array $remainingparams,
 330          array $allparams,
 331          array $expectedoptions,
 332      ): void {
 333          $instance = $this->get_mocked_instance_for_version('v1.7');
 334  
 335          $command = new command(
 336              $instance,
 337              method: 'PUT',
 338              endpoint: $endpoint,
 339              params: $params,
 340              sendasjson: $sendasjson,
 341          );
 342  
 343          $this->assertSame($remainingparams, $command->get_remaining_params());
 344          $this->assertSame($allparams, $command->get_all_params());
 345          $this->assertSame($expectedoptions, $command->get_options());
 346      }
 347  
 348      /**
 349       * Test the sendasjosn option to the command constructor.
 350       *
 351       * @return array
 352       */
 353      public static function sendasjson_provider(): array {
 354          return [
 355              'As JSON' => [
 356                  'sendasjon' => true,
 357                  'endpoint' => 'example/:id/endpoint',
 358                  'params' => [
 359                      ':id' => 12345,
 360                      'name' => 'matrix',
 361                  ],
 362                  'remainingparams' => [
 363                      'name' => 'matrix',
 364                  ],
 365                  'allparams' => [
 366                      ':id' => 12345,
 367                      'name' => 'matrix',
 368                  ],
 369                  'expectedoptions' => [
 370                      'json' => [
 371                          'name' => 'matrix',
 372                      ],
 373                  ],
 374              ],
 375              'Not as JSON' => [
 376                  'sendasjson' => false,
 377                  'endpoint' => 'example/:id/endpoint',
 378                  'params' => [
 379                      ':id' => 12345,
 380                      'name' => 'matrix',
 381                  ],
 382                  'remainingparams' => [
 383                      'name' => 'matrix',
 384                  ],
 385                  'allparams' => [
 386                      ':id' => 12345,
 387                      'name' => 'matrix',
 388                  ],
 389                  'expectedoptions' => [
 390                  ],
 391              ],
 392          ];
 393      }
 394  
 395      /**
 396       * Test the sendasjosn option to the command constructor.
 397       */
 398      public function test_ignorehttperrors(): void {
 399          $instance = $this->get_mocked_instance_for_version('v1.7');
 400  
 401          $command = new command(
 402              $instance,
 403              method: 'PUT',
 404              endpoint: 'example/endpoint',
 405              ignorehttperrors: true,
 406          );
 407  
 408          $options = $command->get_options();
 409          $this->assertArrayHasKey('http_errors', $options);
 410          $this->assertFalse($options['http_errors']);
 411      }
 412  }