Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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  /**
  18   * Tests for the tool_provider class.
  19   *
  20   * @package enrol_lti
  21   * @copyright 2016 Jun Pataleta <jun@moodle.com>
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  use core\session\manager;
  26  use enrol_lti\data_connector;
  27  use enrol_lti\helper;
  28  use enrol_lti\tool_provider;
  29  use IMSGlobal\LTI\HTTPMessage;
  30  use IMSGlobal\LTI\ToolProvider\ResourceLink;
  31  use IMSGlobal\LTI\ToolProvider\ToolConsumer;
  32  use IMSGlobal\LTI\ToolProvider\ToolProvider;
  33  use IMSGlobal\LTI\ToolProvider\User;
  34  
  35  defined('MOODLE_INTERNAL') || die();
  36  
  37  /**
  38   * Tests for the tool_provider class.
  39   *
  40   * @package enrol_lti
  41   * @copyright 2016 Jun Pataleta <jun@moodle.com>
  42   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  43   */
  44  class tool_provider_testcase extends advanced_testcase {
  45  
  46      /**
  47       * @var stdClass $tool The LTI tool.
  48       */
  49      protected $tool;
  50  
  51      /**
  52       * Test set up.
  53       *
  54       * This is executed before running any tests in this file.
  55       */
  56      public function setUp() {
  57          global $SESSION;
  58          $this->resetAfterTest();
  59  
  60          manager::init_empty_session();
  61  
  62          // Set this user as the admin.
  63          $this->setAdminUser();
  64  
  65          $data = new stdClass();
  66          $data->enrolstartdate = time();
  67          $data->secret = 'secret';
  68          $toolrecord = $this->getDataGenerator()->create_lti_tool($data);
  69          $this->tool = helper::get_lti_tool($toolrecord->id);
  70          $SESSION->notifications = [];
  71      }
  72  
  73      /**
  74       * Passing non-existent tool ID.
  75       */
  76      public function test_constructor_with_non_existent_tool() {
  77          $this->expectException('dml_exception');
  78          new tool_provider(-1);
  79      }
  80  
  81      /**
  82       * Constructor test.
  83       */
  84      public function test_constructor() {
  85          global $CFG, $SITE;
  86  
  87          $tool = $this->tool;
  88          $tp = new tool_provider($tool->id);
  89  
  90          $this->assertNull($tp->consumer);
  91          $this->assertNull($tp->returnUrl);
  92          $this->assertNull($tp->resourceLink);
  93          $this->assertNull($tp->context);
  94          $this->assertNotNull($tp->dataConnector);
  95          $this->assertEquals('', $tp->defaultEmail);
  96          $this->assertEquals(ToolProvider::ID_SCOPE_ID_ONLY, $tp->idScope);
  97          $this->assertFalse($tp->allowSharing);
  98          $this->assertEquals(ToolProvider::CONNECTION_ERROR_MESSAGE, $tp->message);
  99          $this->assertNull($tp->reason);
 100          $this->assertEmpty($tp->details);
 101          $this->assertEquals($CFG->wwwroot, $tp->baseUrl);
 102  
 103          $this->assertNotNull($tp->vendor);
 104          $this->assertEquals($SITE->shortname, $tp->vendor->id);
 105          $this->assertEquals($SITE->fullname, $tp->vendor->name);
 106          $this->assertEquals($SITE->summary, $tp->vendor->description);
 107  
 108          $token = helper::generate_proxy_token($tool->id);
 109          $name = helper::get_name($tool);
 110          $description = helper::get_description($tool);
 111  
 112          $this->assertNotNull($tp->product);
 113          $this->assertEquals($token, $tp->product->id);
 114          $this->assertEquals($name, $tp->product->name);
 115          $this->assertEquals($description, $tp->product->description);
 116  
 117          $this->assertNotNull($tp->requiredServices);
 118          $this->assertEmpty($tp->optionalServices);
 119          $this->assertNotNull($tp->resourceHandlers);
 120      }
 121  
 122      /**
 123       * Test for handle request.
 124       */
 125      public function test_handle_request_no_request_data() {
 126          $tool = $this->tool;
 127          $tp = new tool_provider($tool->id);
 128  
 129          // Tool provider object should have been created fine. OK flag should be fine for now.
 130          $this->assertTrue($tp->ok);
 131  
 132          // Call handleRequest but suppress output.
 133          ob_start();
 134          $tp->handleRequest();
 135          ob_end_clean();
 136  
 137          // There's basically no request data submitted so OK flag should turn out false.
 138          $this->assertFalse($tp->ok);
 139      }
 140  
 141      /**
 142       * Test for tool_provider::onError().
 143       */
 144      public function test_on_error() {
 145          $tool = $this->tool;
 146          $tp = new dummy_tool_provider($tool->id);
 147          $message = "THIS IS AN ERROR!";
 148          $tp->message = $message;
 149          $tp->onError();
 150          $errormessage = get_string('failedrequest', 'enrol_lti', ['reason' => $message]);
 151          $this->assertContains($errormessage, $tp->get_error_output());
 152      }
 153  
 154      /**
 155       * Test for tool_provider::onRegister() with no tool consumer set.
 156       */
 157      public function test_on_register_no_consumer() {
 158          $tool = $this->tool;
 159  
 160          $tp = new dummy_tool_provider($tool->id);
 161          $tp->onRegister();
 162  
 163          $this->assertFalse($tp->ok);
 164          $this->assertEquals(get_string('invalidtoolconsumer', 'enrol_lti'), $tp->message);
 165      }
 166  
 167      /**
 168       * Test for tool_provider::onRegister() without return URL.
 169       */
 170      public function test_on_register_no_return_url() {
 171          $tool = $this->tool;
 172  
 173          $dataconnector = new data_connector();
 174          $consumer = new ToolConsumer('testkey', $dataconnector);
 175          $consumer->ltiVersion = ToolProvider::LTI_VERSION2;
 176          $consumer->secret = $tool->secret;
 177          $consumer->name = 'TEST CONSUMER NAME';
 178          $consumer->consumerName = 'TEST CONSUMER INSTANCE NAME';
 179          $consumer->consumerGuid = 'TEST CONSUMER INSTANCE GUID';
 180          $consumer->consumerVersion = 'TEST CONSUMER INFO VERSION';
 181          $consumer->enabled = true;
 182          $consumer->protected = true;
 183          $consumer->save();
 184  
 185          $tp = new dummy_tool_provider($tool->id);
 186          $tp->consumer = $consumer;
 187  
 188          $tp->onRegister();
 189          $this->assertFalse($tp->ok);
 190          $this->assertEquals(get_string('returnurlnotset', 'enrol_lti'), $tp->message);
 191      }
 192  
 193      /**
 194       * Test for tool_provider::onRegister() when registration fails.
 195       */
 196      public function test_on_register_failed() {
 197          global $CFG;
 198          $tool = $this->tool;
 199  
 200          $dataconnector = new data_connector();
 201          $consumer = new dummy_tool_consumer('testkey', $dataconnector);
 202          $consumer->ltiVersion = ToolProvider::LTI_VERSION2;
 203          $consumer->secret = $tool->secret;
 204          $consumer->name = 'TEST CONSUMER NAME';
 205          $consumer->consumerName = 'TEST CONSUMER INSTANCE NAME';
 206          $consumer->consumerGuid = 'TEST CONSUMER INSTANCE GUID';
 207          $consumer->consumerVersion = 'TEST CONSUMER INFO VERSION';
 208          $consumer->enabled = true;
 209          $consumer->protected = true;
 210          $profilejson = file_get_contents(__DIR__ . '/fixtures/tool_consumer_profile.json');
 211          $consumer->profile = json_decode($profilejson);
 212          $consumer->save();
 213  
 214          $tp = new dummy_tool_provider($tool->id);
 215          $tp->consumer = $consumer;
 216          $tp->returnUrl = $CFG->wwwroot;
 217  
 218          $tp->onRegister();
 219  
 220          // The OK flag will be false.
 221          $this->assertFalse($tp->ok);
 222          // Check message.
 223          $this->assertEquals(get_string('couldnotestablishproxy', 'enrol_lti'), $tp->message);
 224      }
 225  
 226      /**
 227       * Test for tool_provider::onRegister() when registration succeeds.
 228       */
 229      public function test_on_register() {
 230          global $CFG, $DB;
 231          $tool = $this->tool;
 232  
 233          $dataconnector = new data_connector();
 234          $consumer = new dummy_tool_consumer('testkey', $dataconnector, false, true);
 235          $consumer->ltiVersion = ToolProvider::LTI_VERSION2;
 236          $consumer->secret = $tool->secret;
 237          $consumer->name = 'TEST CONSUMER NAME';
 238          $consumer->consumerName = 'TEST CONSUMER INSTANCE NAME';
 239          $consumer->consumerGuid = 'TEST CONSUMER INSTANCE GUID';
 240          $consumer->consumerVersion = 'TEST CONSUMER INFO VERSION';
 241          $consumer->enabled = true;
 242          $consumer->protected = true;
 243          $profilejson = file_get_contents(__DIR__ . '/fixtures/tool_consumer_profile.json');
 244          $consumer->profile = json_decode($profilejson);
 245          $consumer->save();
 246  
 247          $tp = new dummy_tool_provider($tool->id);
 248          $tp->consumer = $consumer;
 249          $tp->returnUrl = $CFG->wwwroot;
 250  
 251          // Capture output of onLaunch() method and save it as a string.
 252          ob_start();
 253          $tp->onRegister();
 254          $output = ob_get_clean();
 255  
 256          $successmessage = get_string('successfulregistration', 'enrol_lti');
 257  
 258          // Check output contents. Confirm that it has the success message and return URL.
 259          $this->assertContains($successmessage, $output);
 260          $this->assertContains($tp->returnUrl, $output);
 261  
 262          // The OK flag will be true on successful registration.
 263          $this->assertTrue($tp->ok);
 264  
 265          // Check tool provider message.
 266          $this->assertEquals($successmessage, $tp->message);
 267  
 268          // Check published tool and tool consumer mapping.
 269          $mappingparams = [
 270              'toolid' => $tool->id,
 271              'consumerid' => $tp->consumer->getRecordId()
 272          ];
 273          $this->assertTrue($DB->record_exists('enrol_lti_tool_consumer_map', $mappingparams));
 274      }
 275  
 276      /**
 277       * Test for tool_provider::onLaunch().
 278       */
 279      public function test_on_launch_no_frame_embedding() {
 280          $tp = $this->build_dummy_tp();
 281  
 282          // Capture output of onLaunch() method and save it as a string.
 283          ob_start();
 284          // Suppress session header errors.
 285          @$tp->onLaunch();
 286          $output = ob_get_clean();
 287  
 288          $this->assertContains(get_string('frameembeddingnotenabled', 'enrol_lti'), $output);
 289      }
 290  
 291      /**
 292       * Test for tool_provider::onLaunch().
 293       */
 294      public function test_on_launch_with_frame_embedding() {
 295          global $CFG;
 296          $CFG->allowframembedding = true;
 297  
 298          $tp = $this->build_dummy_tp();
 299  
 300          // If redirect was called here, we will encounter an 'unsupported redirect error'.
 301          // We just want to verify that redirect() was called if frame embedding is allowed.
 302          $this->expectException('moodle_exception');
 303  
 304          // Suppress session header errors.
 305          @$tp->onLaunch();
 306      }
 307  
 308      /**
 309       * Test for tool_provider::onLaunch() with invalid secret and no tool proxy (for LTI 1 launches).
 310       */
 311      public function test_on_launch_with_invalid_secret_and_no_proxy() {
 312          $tp = $this->build_dummy_tp('badsecret');
 313  
 314          // Suppress session header errors.
 315          @$tp->onLaunch();
 316          $this->assertFalse($tp->ok);
 317          $this->assertEquals(get_string('invalidrequest', 'enrol_lti'), $tp->message);
 318      }
 319  
 320      /**
 321       * Test for tool_provider::onLaunch() with invalid launch URL.
 322       */
 323      public function test_on_launch_proxy_with_invalid_launch_url() {
 324          $proxy = [
 325              'tool_profile' => [
 326                  'resource_handler' => [
 327                      [
 328                          'message' => [
 329                              [
 330                                  'message_type' => 'basic-lti-launch-request',
 331                                  'path' => '/enrol/lti/tool.php'
 332                              ]
 333                          ]
 334                      ]
 335                  ]
 336              ]
 337          ];
 338          $tp = $this->build_dummy_tp($this->tool->secret, $proxy);
 339          // Suppress session header errors.
 340          @$tp->onLaunch();
 341  
 342          $this->assertFalse($tp->ok);
 343          $this->assertEquals(get_string('invalidrequest', 'enrol_lti'), $tp->message);
 344      }
 345  
 346      /**
 347       * Test for tool_provider::onLaunch() with invalid launch URL.
 348       */
 349      public function test_on_launch_proxy_with_valid_launch_url() {
 350          $tool = $this->tool;
 351  
 352          $proxy = [
 353              'tool_profile' => [
 354                  'resource_handler' => [
 355                      [
 356                          'message' => [
 357                              [
 358                                  'message_type' => 'basic-lti-launch-request',
 359                                  'path' => '/enrol/lti/tool.php?id=' . $tool->id
 360                              ]
 361                          ]
 362                      ]
 363                  ]
 364              ]
 365          ];
 366          $tp = $this->build_dummy_tp($this->tool->secret, $proxy);
 367  
 368          // Capture output of onLaunch() method and save it as a string.
 369          ob_start();
 370          // Suppress session header errors.
 371          @$tp->onLaunch();
 372          $output = ob_get_clean();
 373  
 374          $this->assertTrue($tp->ok);
 375          $this->assertEquals(get_string('success'), $tp->message);
 376          $this->assertContains(get_string('frameembeddingnotenabled', 'enrol_lti'), $output);
 377      }
 378  
 379      /**
 380       * Test for tool_provider::onLaunch() for a request with message type other than basic-lti-launch-request.
 381       */
 382      public function test_on_launch_proxy_with_invalid_message_type() {
 383          $tool = $this->tool;
 384  
 385          $proxy = [
 386              'tool_profile' => [
 387                  'resource_handler' => [
 388                      [
 389                          'message' => [
 390                              [
 391                                  'message_type' => 'ContentItemSelectionRequest',
 392                                  'path' => '/enrol/lti/tool.php?id=' . $tool->id
 393                              ]
 394                          ]
 395                      ]
 396                  ]
 397              ]
 398          ];
 399          $tp = $this->build_dummy_tp($this->tool->secret, $proxy);
 400  
 401          // Suppress session header errors.
 402          @$tp->onLaunch();
 403  
 404          $this->assertFalse($tp->ok);
 405          $this->assertEquals(get_string('invalidrequest', 'enrol_lti'), $tp->message);
 406      }
 407  
 408      /**
 409       * Test for tool_provider::onLaunch() to verify that a user image can be set from the resource link's custom_user_image setting.
 410       */
 411      public function test_on_launch_with_user_image_from_resource_link() {
 412          global $DB;
 413  
 414          $userimageurl = $this->getExternalTestFileUrl('test.jpg');
 415          $resourcelinksettings = [
 416              'custom_user_image' => $userimageurl
 417          ];
 418          $tp = $this->build_dummy_tp($this->tool->secret, null, $resourcelinksettings);
 419  
 420          // Suppress output and session header errors.
 421          ob_start();
 422          @$tp->onLaunch();
 423          ob_end_clean();
 424  
 425          $this->assertEquals($userimageurl, $tp->resourceLink->getSetting('custom_user_image'));
 426  
 427          $username = helper::create_username($tp->consumer->getKey(), $tp->user->ltiUserId);
 428          $user = $DB->get_record('user', ['username' => $username]);
 429          // User was found.
 430          $this->assertNotFalse($user);
 431          // User picture was set.
 432          $this->assertNotEmpty($user->picture);
 433      }
 434  
 435      /**
 436       * Test for tool_provider::onLaunch() to verify that a LTI user has been enrolled.
 437       */
 438      public function test_on_launch_user_enrolment() {
 439          global $DB;
 440  
 441          $tp = $this->build_dummy_tp($this->tool->secret);
 442  
 443          // Suppress output and session header errors.
 444          ob_start();
 445          @$tp->onLaunch();
 446          ob_end_clean();
 447  
 448          $username = helper::create_username($tp->consumer->getKey(), $tp->user->ltiUserId);
 449          $user = $DB->get_record('user', ['username' => $username]);
 450          // User was found.
 451          $this->assertNotFalse($user);
 452          // User picture was not set.
 453          $this->assertEmpty($user->picture);
 454  
 455          // Check user enrolment.
 456          $enrolled = $DB->record_exists('user_enrolments', ['enrolid' => $this->tool->enrolid, 'userid' => $user->id]);
 457          $this->assertTrue($enrolled);
 458      }
 459  
 460      /**
 461       * Test for tool_provider::onLaunch() when the consumer object has not been set.
 462       */
 463      public function test_on_launch_no_consumer() {
 464          global $DB;
 465  
 466          $tool = $this->tool;
 467  
 468          $tp = new dummy_tool_provider($tool->id);
 469          $tp->onLaunch();
 470          $this->assertFalse($tp->ok);
 471          $this->assertEquals(get_string('invalidtoolconsumer', 'enrol_lti'), $tp->message);
 472  
 473          // Check published tool and tool consumer has not yet been mapped due to failure.
 474          $mappingparams = [
 475              'toolid' => $tool->id
 476          ];
 477          $this->assertFalse($DB->record_exists('enrol_lti_tool_consumer_map', $mappingparams));
 478      }
 479  
 480      /**
 481       * Test for tool_provider::onLaunch() when we have a non-existent consumer data.
 482       */
 483      public function test_on_launch_invalid_consumer() {
 484          $tool = $this->tool;
 485  
 486          $dataconnector = new data_connector();
 487          // Build consumer object but don't save it.
 488          $consumer = new dummy_tool_consumer('testkey', $dataconnector);
 489  
 490          $tp = new dummy_tool_provider($tool->id);
 491          $tp->consumer = $consumer;
 492          $tp->onLaunch();
 493          $this->assertFalse($tp->ok);
 494          $this->assertEquals(get_string('invalidtoolconsumer', 'enrol_lti'), $tp->message);
 495      }
 496  
 497      /**
 498       * Test for tool_provider::map_tool_to_consumer().
 499       */
 500      public function test_map_tool_to_consumer() {
 501          global $DB;
 502  
 503          $tp = $this->build_dummy_tp();
 504          $tp->map_tool_to_consumer();
 505  
 506          // Check published tool and tool consumer mapping.
 507          $mappingparams = [
 508              'toolid' => $this->tool->id,
 509              'consumerid' => $tp->consumer->getRecordId()
 510          ];
 511          $this->assertTrue($DB->record_exists('enrol_lti_tool_consumer_map', $mappingparams));
 512      }
 513  
 514      /**
 515       * Test for tool_provider::map_tool_to_consumer().
 516       */
 517      public function test_map_tool_to_consumer_no_consumer() {
 518          $tp = new dummy_tool_provider($this->tool->id);
 519          $this->expectException('moodle_exception');
 520          $tp->map_tool_to_consumer();
 521      }
 522  
 523      /**
 524       * Builds a dummy tool provider object.
 525       *
 526       * @param string $secret Consumer secret.
 527       * @param array|stdClass $proxy Tool proxy data.
 528       * @param null $resourcelinksettings Key-value array for resource link settings.
 529       * @return dummy_tool_provider
 530       */
 531      protected function build_dummy_tp($secret = null, $proxy = null, $resourcelinksettings = null) {
 532          $tool = $this->tool;
 533  
 534          $dataconnector = new data_connector();
 535          $consumer = new ToolConsumer('testkey', $dataconnector);
 536  
 537          $ltiversion = ToolProvider::LTI_VERSION2;
 538          if ($secret === null && $proxy === null) {
 539              $consumer->secret = $tool->secret;
 540              $ltiversion = ToolProvider::LTI_VERSION1;
 541          } else {
 542              $consumer->secret = $secret;
 543          }
 544          $consumer->ltiVersion = $ltiversion;
 545  
 546          $consumer->name = 'TEST CONSUMER NAME';
 547          $consumer->consumerName = 'TEST CONSUMER INSTANCE NAME';
 548          $consumer->consumerGuid = 'TEST CONSUMER INSTANCE GUID';
 549          $consumer->consumerVersion = 'TEST CONSUMER INFO VERSION';
 550          $consumer->enabled = true;
 551          $consumer->protected = true;
 552          if ($proxy !== null) {
 553              $consumer->toolProxy = json_encode($proxy);
 554          }
 555          $consumer->save();
 556  
 557          $resourcelink = ResourceLink::fromConsumer($consumer, 'testresourcelinkid');
 558          if (!empty($resourcelinksettings)) {
 559              foreach ($resourcelinksettings as $setting => $value) {
 560                  $resourcelink->setSetting($setting, $value);
 561              }
 562          }
 563          $resourcelink->save();
 564  
 565          $ltiuser = User::fromResourceLink($resourcelink, '');
 566          $ltiuser->ltiResultSourcedId = 'testLtiResultSourcedId';
 567          $ltiuser->ltiUserId = 'testuserid';
 568          $ltiuser->email = 'user1@example.com';
 569          $ltiuser->save();
 570  
 571          $tp = new dummy_tool_provider($tool->id);
 572          $tp->user = $ltiuser;
 573          $tp->resourceLink = $resourcelink;
 574          $tp->consumer = $consumer;
 575  
 576          return $tp;
 577      }
 578  }
 579  
 580  /**
 581   * Class dummy_tool_provider.
 582   *
 583   * A class that extends tool_provider so that we can expose the protected methods that we have overridden.
 584   *
 585   * @copyright 2016 Jun Pataleta <jun@moodle.com>
 586   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 587   */
 588  class dummy_tool_provider extends tool_provider {
 589  
 590      /**
 591       * Exposes tool_provider::onError().
 592       */
 593      public function onError() {
 594          parent::onError();
 595      }
 596  
 597      /**
 598       * Exposes tool_provider::onLaunch().
 599       */
 600      public function onLaunch() {
 601          parent::onLaunch();
 602      }
 603  
 604      /**
 605       * Exposes tool_provider::onRegister().
 606       */
 607      public function onRegister() {
 608          parent::onRegister();
 609      }
 610  
 611      /**
 612       * Expose protected variable errorOutput.
 613       *
 614       * @return string
 615       */
 616      public function get_error_output() {
 617          return $this->errorOutput;
 618      }
 619  }
 620  
 621  /**
 622   * Class dummy_tool_consumer
 623   *
 624   * A class that extends ToolConsumer in order to override and simulate sending and receiving data to tool consumer endpoint.
 625   *
 626   * @copyright 2016 Jun Pataleta <jun@moodle.com>
 627   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 628   */
 629  class dummy_tool_consumer extends ToolConsumer {
 630  
 631      /**
 632       * @var bool Flag to indicate whether to send an OK response or a failed response.
 633       */
 634      protected $success = false;
 635  
 636      /**
 637       * dummy_tool_consumer constructor.
 638       *
 639       * @param null|string $key
 640       * @param mixed|null $dataconnector
 641       * @param bool $autoenable
 642       * @param bool $success
 643       */
 644      public function __construct($key = null, $dataconnector = null, $autoenable = false, $success = false) {
 645          parent::__construct($key, $dataconnector, $autoenable);
 646          $this->success = $success;
 647      }
 648  
 649      /**
 650       * Override ToolConsumer::doServiceRequest() to simulate sending/receiving data to and from the tool consumer.
 651       *
 652       * @param object $service
 653       * @param string $method
 654       * @param string $format
 655       * @param mixed $data
 656       * @return HTTPMessage
 657       */
 658      public function doServiceRequest($service, $method, $format, $data) {
 659          $response = (object)['tool_proxy_guid' => 1];
 660          $header = ToolConsumer::addSignature($service->endpoint, $this->getKey(), $this->secret, $data, $method, $format);
 661          $http = new HTTPMessage($service->endpoint, $method, $data, $header);
 662  
 663          if ($this->success) {
 664              $http->responseJson = $response;
 665              $http->ok = true;
 666              $http->status = 201;
 667          }
 668  
 669          return $http;
 670      }
 671  }