Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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   * This file contains tests for the repository_nextcloud class.
  19   *
  20   * @package     repository_nextcloud
  21   * @copyright  2017 Project seminar (Learnweb, University of Münster)
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  use core\oauth2\system_account;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->libdir . '/webdavlib.php');
  31  require_once($CFG->dirroot . '/repository/nextcloud/tests/fixtures/testable_access_controlled_link_manager.php');
  32  
  33  /**
  34   * Class repository_nextcloud_testcase
  35   * @group repository_nextcloud
  36   * @copyright  2017 Project seminar (Learnweb, University of Münster)
  37   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class repository_nextcloud_access_controlled_link_manager_testcase extends advanced_testcase {
  40  
  41      /** @var null|testable_access_controlled_link_manager a malleable variant of the access_controlled_link_manager. */
  42      public $linkmanager = null;
  43  
  44      /** @var null|\repository_nextcloud\ocs_client The ocs_client used to send requests. */
  45      public $ocsmockclient = null;
  46  
  47      /** @var null|\core\oauth2\client Mock oauth client for the system account. */
  48      private $oauthsystemmock = null;
  49  
  50      /** @var null|\core\oauth2\issuer which belongs to the repository_nextcloud object. */
  51      public $issuer = null;
  52  
  53      /**
  54       * SetUp to create an repository instance.
  55       */
  56      protected function setUp(): void {
  57          $this->resetAfterTest(true);
  58  
  59          // Admin is necessary to create issuer object.
  60          $this->setAdminUser();
  61  
  62          $generator = $this->getDataGenerator()->get_plugin_generator('repository_nextcloud');
  63          $this->issuer = $generator->test_create_issuer();
  64          $generator->test_create_endpoints($this->issuer->get('id'));
  65  
  66          // Mock clients.
  67          $this->ocsmockclient = $this->getMockBuilder(repository_nextcloud\ocs_client::class
  68          )->disableOriginalConstructor()->disableOriginalClone()->getMock();
  69          $this->oauthsystemmock = $this->getMockBuilder(\core\oauth2\client::class
  70          )->disableOriginalConstructor()->disableOriginalClone()->getMock();
  71          $systemwebdavclient = $this->getMockBuilder(\webdav_client::class
  72          )->disableOriginalConstructor()->disableOriginalClone()->getMock();
  73          $systemocsclient = $systemocsclient = $this->getMockBuilder(repository_nextcloud\ocs_client::class
  74          )->disableOriginalConstructor()->disableOriginalClone()->getMock();
  75  
  76          // Pseudo system account user.
  77          $this->systemaccountusername = 'pseudouser';
  78          $record = new stdClass();
  79          $record->issuerid = $this->issuer->get('id');
  80          $record->refreshtoken = 'pseudotoken';
  81          $record->grantedscopes = 'scopes';
  82          $record->email = '';
  83          $record->username = $this->systemaccountusername;
  84          $systemaccount = new system_account(0, $record);
  85          $systemaccount->create();
  86  
  87          $this->linkmanager = new testable_access_controlled_link_manager($this->ocsmockclient,
  88              $this->oauthsystemmock, $systemocsclient,
  89              $this->issuer, 'Nextcloud', $systemwebdavclient);
  90  
  91      }
  92  
  93      /**
  94       * Function to test the private function create_share_user_sysaccount.
  95       */
  96      public function test_create_share_user_sysaccount_user_shares() {
  97          $params = [
  98              'path' => "/ambient.txt",
  99              'shareType' => \repository_nextcloud\ocs_client::SHARE_TYPE_USER,
 100              'publicUpload' => false,
 101              'shareWith' => $this->systemaccountusername,
 102              'permissions' => \repository_nextcloud\ocs_client::SHARE_PERMISSION_READ,
 103          ];
 104          $expectedresponse = <<<XML
 105  <?xml version="1.0"?>
 106  <ocs>
 107   <meta>
 108    <status>ok</status>
 109    <statuscode>100</statuscode>
 110    <message/>
 111   </meta>
 112   <data>
 113    <id>207</id>
 114    <share_type>0</share_type>
 115    <uid_owner>user1</uid_owner>
 116    <displayname_owner>user1</displayname_owner>
 117    <permissions>19</permissions>
 118    <stime>1511532198</stime>
 119    <parent/>
 120    <expiration/>
 121    <token/>
 122    <uid_file_owner>user1</uid_file_owner>
 123    <displayname_file_owner>user1</displayname_file_owner>
 124    <path>/ambient.txt</path>
 125    <item_type>file</item_type>
 126    <mimetype>text/plain</mimetype>
 127    <storage_id>home::user1</storage_id>
 128    <storage>3</storage>
 129    <item_source>545</item_source>
 130    <file_source>545</file_source>
 131    <file_parent>20</file_parent>
 132    <file_target>/ambient.txt</file_target>
 133    <share_with>tech</share_with>
 134    <share_with_displayname>tech</share_with_displayname>
 135    <mail_send>0</mail_send>
 136   </data>
 137  </ocs>
 138  XML;
 139          $this->ocsmockclient->expects($this->once())->method('call')->with('create_share', $params)->will(
 140              $this->returnValue($expectedresponse));
 141  
 142          $result = $this->linkmanager->create_share_user_sysaccount("/ambient.txt");
 143          $xml = simplexml_load_string($expectedresponse);
 144          $expected = array();
 145          $expected['statuscode'] = (int)$xml->meta->statuscode;
 146          $expected['shareid'] = (int)$xml->data->id;
 147          $expected['filetarget'] = (string)$xml->data[0]->file_target;
 148          $this->assertEquals($expected, $result);
 149      }
 150      /**
 151       * Test the delete_share_function. In case the request fails, the function throws an exception, however this
 152       * can not be tested in phpUnit since it is javascript.
 153       */
 154      public function test_delete_share_dataowner_sysaccount() {
 155          $shareid = 5;
 156          $deleteshareparams = [
 157              'share_id' => $shareid
 158          ];
 159          $returnxml = <<<XML
 160  <?xml version="1.0"?>
 161  <ocs>
 162      <meta>
 163      <status>ok</status>
 164      <statuscode>100</statuscode>
 165      <message/>
 166      </meta>
 167      <data/>
 168  </ocs>
 169  XML;
 170          $this->ocsmockclient->expects($this->once())->method('call')->with('delete_share', $deleteshareparams)->will(
 171              $this->returnValue($returnxml));
 172          $this->linkmanager->delete_share_dataowner_sysaccount($shareid, 'repository_nextcloud');
 173  
 174      }
 175  
 176      /**
 177       * Function which test that create folder path does return the adequate results (path and success).
 178       * Additionally mock checks whether the right params are passed to the corresponding functions.
 179       */
 180      public function test_create_folder_path_folders_are_not_created() {
 181  
 182          $mocks = $this->set_up_mocks_for_create_folder_path(true, 'somename');
 183          $this->set_private_property($mocks['mockclient'], 'systemwebdavclient', $this->linkmanager);
 184          $result = $this->linkmanager->create_folder_path_access_controlled_links($mocks['mockcontext'], "mod_resource",
 185              'content', 0);
 186          $this->assertEquals('/somename (ctx )/mod_resource/content/0', $result);
 187      }
 188      /**
 189       * Function which test that create folder path does return the adequate results (path and success).
 190       * Additionally mock checks whether the right params are passed to the corresponding functions.
 191       */
 192      public function test_create_folder_path_folders_are_created() {
 193  
 194          // In Context is okay, number of context counts for number of iterations.
 195          $mocks = $this->set_up_mocks_for_create_folder_path(false, 'somename/withslash', true, 201);
 196          $this->set_private_property($mocks['mockclient'], 'systemwebdavclient', $this->linkmanager);
 197          $result = $this->linkmanager->create_folder_path_access_controlled_links($mocks['mockcontext'], "mod_resource",
 198              'content', 0);
 199          $this->assertEquals('/somenamewithslash (ctx )/mod_resource/content/0', $result);
 200      }
 201      /**
 202       * Test whether the create_folder_path methode throws exception.
 203       */
 204      public function test_create_folder_path_folder_creation_fails() {
 205  
 206          $mocks = $this->set_up_mocks_for_create_folder_path(false, 'somename', true, 400);
 207          $this->set_private_property($mocks['mockclient'], 'systemwebdavclient', $this->linkmanager);
 208          $this->expectException(\repository_nextcloud\request_exception::class);
 209          $this->linkmanager->create_folder_path_access_controlled_links($mocks['mockcontext'], "mod_resource",
 210              'content', 0);
 211      }
 212  
 213      /**
 214       * Helper function to generate mocks for testing create folder path.
 215       * @param bool $returnisdir Return value mocking the result of invoking is_dir
 216       * @param bool $returnestedcontext Name of the folder that is simulated to be checked/created
 217       * @param bool $callmkcol Also mock creation of the folder
 218       * @param int $returnmkcol Return value mocking the result of invoking mkcol
 219       * @return array ['mockcontext' context_module mock, 'mockclient' => webdav client mock]
 220       */
 221      protected function set_up_mocks_for_create_folder_path($returnisdir, $returnestedcontext, $callmkcol = false,
 222                                                             $returnmkcol = 201) {
 223          $mockcontext = $this->createMock(context_module::class);
 224          $mockclient = $this->getMockBuilder(\webdav_client::class
 225          )->disableOriginalConstructor()->disableOriginalClone()->getMock();
 226          $parsedwebdavurl = parse_url($this->issuer->get_endpoint_url('webdav'));
 227          $webdavprefix = $parsedwebdavurl['path'];
 228          // Empty ctx 'id' expected because using code will not be able to access $ctx->id.
 229          $cleanedcontextname = clean_param($returnestedcontext, PARAM_FILE);
 230          $dirstring = $webdavprefix . '/' . $cleanedcontextname . ' (ctx )';
 231          $mockclient->expects($this->atMost(4))->method('is_dir')->with($this->logicalOr(
 232              $dirstring, $dirstring . '/mod_resource', $dirstring . '/mod_resource/content',
 233              $dirstring . '/mod_resource/content/0'))->willReturn($returnisdir);
 234          if ($callmkcol == true) {
 235              $mockclient->expects($this->atMost(4))->method('mkcol')->willReturn($returnmkcol);
 236          }
 237          $mockcontext->method('get_parent_contexts')->willReturn(array('1' => $mockcontext));
 238          $mockcontext->method('get_context_name')->willReturn($returnestedcontext);
 239  
 240          return array('mockcontext' => $mockcontext, 'mockclient' => $mockclient);
 241      }
 242  
 243      /**
 244       * Test whether the right methods from the webdavclient are called when the storage_folder is created.
 245       * 1. Directory already exist -> no further action needed.
 246       */
 247      public function test_create_storage_folder_success() {
 248          $mockwebdavclient = $this->createMock(\webdav_client::class);
 249          $url = $this->issuer->get_endpoint_url('webdav');
 250          $parsedwebdavurl = parse_url($url);
 251          $webdavprefix = $parsedwebdavurl['path'];
 252          $mockwebdavclient->expects($this->once())->method('open')->willReturn(true);
 253          $mockwebdavclient->expects($this->once())->method('is_dir')->with($webdavprefix . 'myname')->willReturn(true);
 254          $mockwebdavclient->expects($this->once())->method('close');
 255          $this->linkmanager->create_storage_folder('myname', $mockwebdavclient);
 256  
 257      }
 258      /**
 259       * Test whether the right methods from the webdavclient are called when the storage_folder is created.
 260       * 2. Directory does not exist. It is created with mkcol and returns a success.
 261       *
 262       */
 263      public function test_create_storage_folder_success_mkcol() {
 264          $mockwebdavclient = $this->createMock(\webdav_client::class);
 265          $url = $this->issuer->get_endpoint_url('webdav');
 266          $parsedwebdavurl = parse_url($url);
 267          $webdavprefix = $parsedwebdavurl['path'];
 268          $mockwebdavclient->expects($this->once())->method('open')->willReturn(true);
 269          $mockwebdavclient->expects($this->once())->method('is_dir')->with($webdavprefix . 'myname')->willReturn(false);
 270          $mockwebdavclient->expects($this->once())->method('mkcol')->with($webdavprefix . 'myname')->willReturn(201);
 271          $mockwebdavclient->expects($this->once())->method('close');
 272  
 273          $this->linkmanager->create_storage_folder('myname', $mockwebdavclient);
 274      }
 275      /**
 276       * Test whether the right methods from the webdavclient are called when the storage_folder is created.
 277       * 3. Request to create Folder fails.
 278       */
 279      public function test_create_storage_folder_failure() {
 280          $mockwebdavclient = $this->createMock(\webdav_client::class);
 281          $url = $this->issuer->get_endpoint_url('webdav');
 282          $parsedwebdavurl = parse_url($url);
 283          $webdavprefix = $parsedwebdavurl['path'];
 284          $mockwebdavclient->expects($this->once())->method('open')->willReturn(true);
 285          $mockwebdavclient->expects($this->once())->method('is_dir')->with($webdavprefix . 'myname')->willReturn(false);
 286          $mockwebdavclient->expects($this->once())->method('mkcol')->with($webdavprefix . 'myname')->willReturn(400);
 287  
 288          $this->expectException(\repository_nextcloud\request_exception::class);
 289          $this->linkmanager->create_storage_folder('myname', $mockwebdavclient);
 290      }
 291      /**
 292       * Test whether the webdav client gets the right params and whether function differentiates between move and copy.
 293       */
 294      public function test_transfer_file_to_path_copyfile() {
 295          // Initialize params.
 296          $parsedwebdavurl = parse_url($this->issuer->get_endpoint_url('webdav'));
 297          $webdavprefix = $parsedwebdavurl['path'];
 298          $srcpath = 'sourcepath';
 299          $dstpath = "destinationpath/another/path";
 300  
 301          // Mock the Webdavclient and set expected methods.
 302          $systemwebdavclientmock = $this->createMock(\webdav_client::class);
 303          $systemwebdavclientmock->expects($this->once())->method('open')->willReturn(true);
 304          $systemwebdavclientmock->expects($this->once())->method('copy_file')->with($webdavprefix . $srcpath,
 305              $webdavprefix . $dstpath . '/' . $srcpath, true)->willReturn(201);
 306          $this->set_private_property($systemwebdavclientmock, 'systemwebdavclient', $this->linkmanager);
 307  
 308          // Call of function.
 309          $result = $this->linkmanager->transfer_file_to_path($srcpath, $dstpath, 'copy');
 310  
 311          $this->assertEquals(201, $result);
 312      }
 313      /**
 314       * This function tests whether the function transfer_file_to_path() moves or copies a given file to a given path
 315       * It tests whether the webdav_client gets the right parameter and whether function distinguishes between move and copy.
 316       *
 317       */
 318      public function test_transfer_file_to_path_copyfile_movefile() {
 319          // Initialize params.
 320          $parsedwebdavurl = parse_url($this->issuer->get_endpoint_url('webdav'));
 321          $webdavprefix = $parsedwebdavurl['path'];
 322          $srcpath = 'sourcepath';
 323          $dstpath = "destinationpath/another/path";
 324  
 325          $systemwebdavclientmock = $this->createMock(\webdav_client::class);
 326  
 327          $systemwebdavclientmock->expects($this->once())->method('open')->willReturn(true);
 328          $this->set_private_property($systemwebdavclientmock, 'systemwebdavclient', $this->linkmanager);
 329          $webdavclientmock = $this->createMock(\webdav_client::class);
 330  
 331          $webdavclientmock->expects($this->once())->method('move')->with($webdavprefix . $srcpath,
 332              $webdavprefix . $dstpath . '/' . $srcpath, false)->willReturn(201);
 333          $result = $this->linkmanager->transfer_file_to_path($srcpath, $dstpath, 'move', $webdavclientmock);
 334          $this->assertEquals(201, $result);
 335      }
 336  
 337      /**
 338       * Test the get_shares_from path() function. This function extracts from an list of shares the share of a given user
 339       * (the username is a parameter in the function call) and returns the id. The test firstly test whether the right fileid
 340       * for user1 is extracted then for user2 and last but least whether an error is thrown if the user does not have a share.
 341       * @throws moodle_exception
 342       */
 343      public function test_get_shares_from_path() {
 344          $params = [
 345              'path' => '/Kernsystem/Kursbereich Miscellaneous/Kurs Example Course/Datei zet/mod_resource/content/0/picture.png',
 346              'reshares' => true
 347          ];
 348          $reference = new stdClass();
 349          $reference->link = "/Kernsystem/Kursbereich Miscellaneous/Kurs Example Course/Datei zet/mod_resource/content/0/picture.png";
 350          $reference->name = "f\u00fcrdennis.png";
 351          $reference->usesystem = true;
 352          $expectedresponse = <<<XML
 353  <?xml version="1.0"?>
 354  <ocs>
 355   <meta>
 356    <status>ok</status>
 357    <statuscode>100</statuscode>
 358    <message/>
 359   </meta>
 360   <data>
 361    <element>
 362     <id>292</id>
 363     <share_type>0</share_type>
 364     <uid_owner>tech</uid_owner>
 365     <displayname_owner>tech</displayname_owner>
 366     <permissions>19</permissions>
 367     <stime>1515752494</stime>
 368     <parent/>
 369     <expiration/>
 370     <token/>
 371     <uid_file_owner>tech</uid_file_owner>
 372     <displayname_file_owner>tech</displayname_file_owner>
 373     <path>some/path/of/some/file.pdf</path>
 374     <item_type>file</item_type>
 375     <mimetype>image/png</mimetype>
 376     <storage_id>home::tech</storage_id>
 377     <storage>4</storage>
 378     <item_source>1085</item_source>
 379     <file_source>1085</file_source>
 380     <file_parent>1084</file_parent>
 381     <file_target>/fehler (3).png</file_target>
 382     <share_with>user1</share_with>
 383     <share_with_displayname>user1</share_with_displayname>
 384     <mail_send>0</mail_send>
 385    </element>
 386    <element>
 387     <id>293</id>
 388     <share_type>0</share_type>
 389     <uid_owner>tech</uid_owner>
 390     <displayname_owner>tech</displayname_owner>
 391     <permissions>19</permissions>
 392     <stime>1515752494</stime>
 393     <parent/>
 394     <expiration/>
 395     <token/>
 396     <uid_file_owner>tech</uid_file_owner>
 397     <displayname_file_owner>tech</displayname_file_owner>
 398     <path>some/path/of/some/file.pdf</path>
 399     <item_type>file</item_type>
 400     <mimetype>image/png</mimetype>
 401     <storage_id>home::tech</storage_id>
 402     <storage>4</storage>
 403     <item_source>1085</item_source>
 404     <file_source>1085</file_source>
 405     <file_parent>1084</file_parent>
 406     <file_target>/fehler (3).png</file_target>
 407     <share_with>user2</share_with>
 408     <share_with_displayname>user2</share_with_displayname>
 409     <mail_send>0</mail_send>
 410    </element>
 411   </data>
 412  </ocs>
 413  XML;
 414          $this->set_private_property($this->ocsmockclient, 'systemocsclient', $this->linkmanager);
 415  
 416          $this->ocsmockclient->expects($this->exactly(3))->method('call')->with('get_shares', $params)->will(
 417              $this->returnValue($expectedresponse));
 418          $xmlobjuser1 = (int) $this->linkmanager->get_shares_from_path($reference->link, 'user2');
 419          $xmlobjuser2 = (int) $this->linkmanager->get_shares_from_path($reference->link, 'user1');
 420  
 421          $this->assertEquals(293, $xmlobjuser1);
 422          $this->assertEquals(292, $xmlobjuser2);
 423  
 424          $this->expectException(\repository_nextcloud\request_exception::class);
 425  
 426          $this->expectExceptionMessage('A request to Nextcloud has failed. The requested file could not be accessed. Please ' .
 427              'check whether you have chosen a valid file and you are authenticated with the right account.');
 428          $this->linkmanager->get_shares_from_path($reference->link, 'user3');
 429  
 430      }
 431      /** Test whether the systemwebdav client is constructed correctly. Port is set to 443 in case of https, to 80 in
 432       * case of http and exception is thrown when endpoint does not exist.
 433       * @throws \repository_nextcloud\configuration_exception
 434       * @throws coding_exception
 435       */
 436      public function test_create_system_dav() {
 437          // Initialize mock and params.
 438          $fakeaccesstoken = new stdClass();
 439          $fakeaccesstoken->token = "fake access token";
 440          // Use `atLeastOnce` instead of `exactly(2)` because it is only called a second time on dev systems that allow http://.
 441          $this->oauthsystemmock->expects($this->atLeastOnce())->method('get_accesstoken')->willReturn($fakeaccesstoken);
 442          $parsedwebdavurl = parse_url($this->issuer->get_endpoint_url('webdav'));
 443  
 444          // Call function and create own client.
 445          $dav = $this->linkmanager->create_system_dav();
 446          $mydav = new \webdav_client($parsedwebdavurl['host'], '', '', 'bearer', 'ssl://',
 447              "fake access token", $parsedwebdavurl['path']);
 448          $mydav->port = 443;
 449          $mydav->debug = false;
 450          $this->assertEquals($mydav, $dav);
 451  
 452          // Deletes the old webdav endpoint and ...
 453          $this->delete_endpoints('webdav_endpoint');
 454          // Creates a new one which requires different ports.
 455          try {
 456              $endpoint = new stdClass();
 457              $endpoint->name = "webdav_endpoint";
 458              $endpoint->url = 'http://www.default.test/webdav/index.php';
 459              $endpoint->issuerid = $this->issuer->get('id');
 460              \core\oauth2\api::create_endpoint($endpoint);
 461  
 462              // Call function and create own client.
 463              $dav = $this->linkmanager->create_system_dav();
 464              $mydav = new \webdav_client($parsedwebdavurl['host'], '', '', 'bearer', '',
 465                  "fake access token");
 466              $mydav->port = 80;
 467              $mydav->debug = false;
 468              $this->assertEquals($mydav, $dav);
 469          } catch (core\invalid_persistent_exception $e) {
 470              // In some cases Moodle does not allow to create http connections. In those cases the exception
 471              // is catched here and the test are executed.
 472              $this->expectException(\core\invalid_persistent_exception::class);
 473              $this->linkmanager->create_system_dav();
 474          } finally {
 475  
 476              // Delte endpoints and ...
 477              $this->delete_endpoints('webdav_endpoint');
 478  
 479              // Do not insert new ones, therefore exception is thrown.
 480              $this->expectException(\repository_nextcloud\configuration_exception::class);
 481              $this->linkmanager->create_system_dav();
 482          }
 483      }
 484  
 485      /**
 486       * Tests the function get_share_information_from_shareid(). From a response with two element it is tested
 487       * whether the right file_target is extracted and lastly it is checked whether an error is thrown in case no suitable
 488       * element exists.
 489       * @throws \repository_nextcloud\request_exception
 490       * @throws coding_exception
 491       */
 492      public function test_get_share_information_from_shareid() {
 493          $params303 = [
 494              'share_id' => 303,
 495          ];
 496          $params302 = [
 497              'share_id' => 302,
 498          ];
 499          $expectedresponse = <<<XML
 500  <?xml version="1.0"?>
 501  <ocs>
 502   <meta>
 503    <status>ok</status>
 504    <statuscode>100</statuscode>
 505    <message/>
 506   </meta>
 507   <data>
 508    <element>
 509     <id>302</id>
 510     <share_type>0</share_type>
 511     <uid_owner>tech</uid_owner>
 512     <displayname_owner>tech</displayname_owner>
 513     <permissions>19</permissions>
 514     <stime>1516096325</stime>
 515     <parent/>
 516     <expiration/>
 517     <token/>
 518     <uid_file_owner>tech</uid_file_owner>
 519     <displayname_file_owner>tech</displayname_file_owner>
 520       <path>/some/target (2).png</path>
 521     <item_type>file</item_type>
 522     <mimetype>image/png</mimetype>
 523     <storage_id>shared::/some/target.png</storage_id>
 524     <storage>4</storage>
 525     <item_source>1125</item_source>
 526     <file_source>1125</file_source>
 527     <file_parent>20</file_parent>
 528     <file_target>/some/target.png</file_target>
 529     <share_with>user1</share_with>
 530     <share_with_displayname>user1</share_with_displayname>
 531     <mail_send>0</mail_send>
 532    </element>
 533    <element>
 534     <id>303</id>
 535     <share_type>0</share_type>
 536     <uid_owner>tech</uid_owner>
 537     <displayname_owner>tech</displayname_owner>
 538     <permissions>19</permissions>
 539     <stime>1516096325</stime>
 540     <parent/>
 541     <expiration/>
 542     <token/>
 543     <uid_file_owner>tech</uid_file_owner>
 544     <displayname_file_owner>tech</displayname_file_owner>
 545     <path>/some/target (2).pdf</path>
 546     <item_type>file</item_type>
 547     <mimetype>image/png</mimetype>
 548     <storage_id>shared::/some/target.pdf</storage_id>
 549     <storage>4</storage>
 550     <item_source>1125</item_source>
 551     <file_source>1125</file_source>
 552     <file_parent>20</file_parent>
 553     <file_target>/some/target.pdf</file_target>
 554     <share_with>user2</share_with>
 555     <share_with_displayname>user1</share_with_displayname>
 556     <mail_send>0</mail_send>
 557    </element>
 558   </data>
 559  </ocs>
 560  XML;
 561          $this->set_private_property($this->ocsmockclient, 'systemocsclient', $this->linkmanager);
 562  
 563          $this->ocsmockclient->expects($this->exactly(3))->method('call')->with('get_information_of_share',
 564              $this->logicalOr($params303, $params302))->will($this->returnValue($expectedresponse));
 565  
 566          // Test function for two different users. Setting the id is just a dummy value since always $expectedresponse ...
 567          // ... is returned.
 568          $filetarget = $this->linkmanager->get_share_information_from_shareid(303, 'user2');
 569          $this->assertEquals('/some/target.pdf', $filetarget);
 570  
 571          $filetarget = $this->linkmanager->get_share_information_from_shareid(302, 'user1');
 572          $this->assertEquals('/some/target.png', $filetarget);
 573  
 574          // Expect exception in case no suitable elemtn exist in the response.
 575          $this->expectException(\repository_nextcloud\request_exception::class);
 576          $this->expectExceptionMessage('A request to Nextcloud has failed. The requested file could not be accessed. Please ' .
 577              'check whether you have chosen a valid file and you are authenticated with the right account.');
 578          $this->linkmanager->get_share_information_from_shareid(302, 'user3');
 579      }
 580  
 581      /**
 582       * Helper method which inserts a value into a non-public field of an object.
 583       *
 584       * @param mixed $value mock value that will be inserted.
 585       * @param string $propertyname name of the private property.
 586       * @param object $class Instance that is being modified.
 587       * @return ReflectionProperty the resulting reflection property.
 588       */
 589      protected function set_private_property($value, $propertyname, $class) {
 590          $refclient = new ReflectionClass($class);
 591          $private = $refclient->getProperty($propertyname);
 592          $private->setAccessible(true);
 593          $private->setValue($class, $value);
 594          return $private;
 595      }
 596      /**
 597       * Helper method which gets a value from a non-public field of an object.
 598       *
 599       * @param string $propertyname name of the private property.
 600       * @param object $class Instance that is being modified.
 601       * @return mixed the resulting value.
 602       */
 603      protected function get_private_property($propertyname, $class) {
 604          $refclient = new ReflectionClass($class);
 605          $private = $refclient->getProperty($propertyname);
 606          $private->setAccessible(true);
 607          $property = $private->getValue($private);
 608          return $property;
 609      }
 610      /**
 611       * Deletes all endpoint with the given name.
 612       * @param string $endpointname
 613       * @return array|null
 614       * @throws moodle_exception
 615       */
 616      protected function delete_endpoints($endpointname) {
 617          $endpoints = \core\oauth2\api::get_endpoints($this->issuer);
 618          $arrayofids = array();
 619          foreach ($endpoints as $endpoint) {
 620              $name = $endpoint->get('name');
 621              if ($name === $endpointname) {
 622                  $arrayofids[$endpoint->get('id')] = $endpoint->get('id');
 623              }
 624          }
 625          if (empty($arrayofids)) {
 626              return;
 627          }
 628          foreach ($arrayofids as $id) {
 629              core\oauth2\api::delete_endpoint($id);
 630          }
 631      }
 632  
 633  }