See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 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 * 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 namespace repository_nextcloud; 25 26 use repository; 27 use repository_nextcloud; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once($CFG->dirroot . '/repository/lib.php'); 33 require_once($CFG->libdir . '/webdavlib.php'); 34 35 /** 36 * Class repository_nextcloud_lib_testcase 37 * @group repository_nextcloud 38 * @copyright 2017 Project seminar (Learnweb, University of Münster) 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class lib_test extends \advanced_testcase { 42 43 /** @var null|\repository_nextcloud the repository_nextcloud object, which the tests are run on. */ 44 private $repo = null; 45 46 /** @var null|\core\oauth2\issuer which belongs to the repository_nextcloud object.*/ 47 private $issuer = null; 48 49 /** 50 * SetUp to create an repository instance. 51 */ 52 protected function setUp(): void { 53 $this->resetAfterTest(true); 54 55 // Admin is neccessary to create api and issuer objects. 56 $this->setAdminUser(); 57 58 /** @var repository_nextcloud_generator $generator */ 59 $generator = $this->getDataGenerator()->get_plugin_generator('repository_nextcloud'); 60 $this->issuer = $generator->test_create_issuer(); 61 62 // Create Endpoints for issuer. 63 $generator->test_create_endpoints($this->issuer->get('id')); 64 65 // Params for the config form. 66 $reptype = $generator->create_type([ 67 'visible' => 1, 68 'enableuserinstances' => 0, 69 'enablecourseinstances' => 0, 70 ]); 71 72 $instance = $generator->create_instance([ 73 'issuerid' => $this->issuer->get('id'), 74 'pluginname' => 'Nextcloud', 75 'controlledlinkfoldername' => 'Moodlefiles', 76 'supportedreturntypes' => 'both', 77 'defaultreturntype' => FILE_INTERNAL, 78 ]); 79 80 // At last, create a repository_nextcloud object from the instance id. 81 $this->repo = new repository_nextcloud($instance->id); 82 $this->repo->options['typeid'] = $reptype->id; 83 $this->repo->options['sortorder'] = 1; 84 $this->resetAfterTest(true); 85 } 86 87 /** 88 * Checks the is_visible method in case the repository is set to hidden in the database. 89 */ 90 public function test_is_visible_parent_false() { 91 global $DB; 92 $id = $this->repo->options['typeid']; 93 94 // Check, if the method returns false, when the repository is set to visible in the database 95 // and the client configuration data is complete. 96 $DB->update_record('repository', (object) array('id' => $id, 'visible' => 0)); 97 98 $this->assertFalse($this->repo->is_visible()); 99 } 100 101 /** 102 * Test whether the repo is disabled. 103 */ 104 public function test_repo_creation() { 105 $issuerid = $this->repo->get_option('issuerid'); 106 107 // Config saves the right id. 108 $this->assertEquals($this->issuer->get('id'), $issuerid); 109 110 // Function that is used in construct method returns the right id. 111 $constructissuer = \core\oauth2\api::get_issuer($issuerid); 112 $this->assertEquals($this->issuer->get('id'), $constructissuer->get('id')); 113 114 $this->assertEquals(true, $constructissuer->get('enabled')); 115 $this->assertFalse($this->repo->disabled); 116 } 117 118 /** 119 * Returns an array of endpoints or null. 120 * @param string $endpointname 121 * @return array|null 122 */ 123 private function get_endpoint_id($endpointname) { 124 $endpoints = \core\oauth2\api::get_endpoints($this->issuer); 125 $id = array(); 126 foreach ($endpoints as $endpoint) { 127 $name = $endpoint->get('name'); 128 if ($name === $endpointname) { 129 $id[$endpoint->get('id')] = $endpoint->get('id'); 130 } 131 } 132 if (empty($id)) { 133 return null; 134 } 135 return $id; 136 } 137 /** 138 * Test if repository is disabled when webdav_endpoint is deleted. 139 */ 140 public function test_issuer_webdav() { 141 $idwebdav = $this->get_endpoint_id('webdav_endpoint'); 142 if (!empty($idwebdav)) { 143 foreach ($idwebdav as $id) { 144 \core\oauth2\api::delete_endpoint($id); 145 } 146 } 147 $this->assertFalse(\repository_nextcloud\issuer_management::is_valid_issuer($this->issuer)); 148 } 149 /** 150 * Test if repository is disabled when ocs_endpoint is deleted. 151 */ 152 public function test_issuer_ocs() { 153 $idocs = $this->get_endpoint_id('ocs_endpoint'); 154 if (!empty($idocs)) { 155 foreach ($idocs as $id) { 156 \core\oauth2\api::delete_endpoint($id); 157 } 158 } 159 $this->assertFalse(\repository_nextcloud\issuer_management::is_valid_issuer($this->issuer)); 160 } 161 162 /** 163 * Test if repository is disabled when userinfo_endpoint is deleted. 164 */ 165 public function test_issuer_userinfo() { 166 $idtoken = $this->get_endpoint_id('userinfo_endpoint'); 167 if (!empty($idtoken)) { 168 foreach ($idtoken as $id) { 169 \core\oauth2\api::delete_endpoint($id); 170 } 171 } 172 $this->assertFalse(\repository_nextcloud\issuer_management::is_valid_issuer($this->issuer)); 173 } 174 175 /** 176 * Test if repository is disabled when token_endpoint is deleted. 177 */ 178 public function test_issuer_token() { 179 $idtoken = $this->get_endpoint_id('token_endpoint'); 180 if (!empty($idtoken)) { 181 foreach ($idtoken as $id) { 182 \core\oauth2\api::delete_endpoint($id); 183 } 184 } 185 $this->assertFalse(\repository_nextcloud\issuer_management::is_valid_issuer($this->issuer)); 186 } 187 188 /** 189 * Test if repository is disabled when auth_endpoint is deleted. 190 */ 191 public function test_issuer_authorization() { 192 $idauth = $this->get_endpoint_id('authorization_endpoint'); 193 if (!empty($idauth)) { 194 foreach ($idauth as $id) { 195 \core\oauth2\api::delete_endpoint($id); 196 } 197 } 198 $this->assertFalse(\repository_nextcloud\issuer_management::is_valid_issuer($this->issuer)); 199 } 200 /** 201 * Test if repository throws an error when endpoint does not exist. 202 */ 203 public function test_parse_endpoint_url_error() { 204 $this->expectException(\repository_nextcloud\configuration_exception::class); 205 \repository_nextcloud\issuer_management::parse_endpoint_url('notexisting', $this->issuer); 206 } 207 /** 208 * Test get_listing method with an example directory. Tests error cases. 209 */ 210 public function test_get_listing_error() { 211 $ret = $this->get_initialised_return_array(); 212 $this->setUser(); 213 // WebDAV socket is not opened. 214 $mock = $this->createMock(\webdav_client::class); 215 $mock->expects($this->once())->method('open')->will($this->returnValue(false)); 216 $private = $this->set_private_property($mock, 'dav'); 217 218 $this->assertEquals($ret, $this->repo->get_listing('/')); 219 220 // Response is not an array. 221 $mock = $this->createMock(\webdav_client::class); 222 $mock->expects($this->once())->method('open')->will($this->returnValue(true)); 223 $mock->expects($this->once())->method('ls')->will($this->returnValue('notanarray')); 224 $private->setValue($this->repo, $mock); 225 226 $this->assertEquals($ret, $this->repo->get_listing('/')); 227 } 228 /** 229 * Test get_listing method with an example directory. Tests the root directory. 230 */ 231 public function test_get_listing_root() { 232 $this->setUser(); 233 $ret = $this->get_initialised_return_array(); 234 235 // This is the expected response from the ls method. 236 $response = array( 237 array( 238 'href' => 'remote.php/webdav/', 239 'lastmodified' => 'Thu, 08 Dec 2016 16:06:26 GMT', 240 'resourcetype' => 'collection', 241 'status' => 'HTTP/1.1 200 OK', 242 'getcontentlength' => '' 243 ), 244 array( 245 'href' => 'remote.php/webdav/Documents/', 246 'lastmodified' => 'Thu, 08 Dec 2016 16:06:26 GMT', 247 'resourcetype' => 'collection', 248 'status' => 'HTTP/1.1 200 OK', 249 'getcontentlength' => '' 250 ), 251 array( 252 'href' => 'remote.php/webdav/welcome.txt', 253 'lastmodified' => 'Thu, 08 Dec 2016 16:06:26 GMT', 254 'status' => 'HTTP/1.1 200 OK', 255 'getcontentlength' => '163' 256 ) 257 ); 258 259 // The expected result from the get_listing method in the repository_nextcloud class. 260 $ret['list'] = array( 261 'DOCUMENTS/' => array( 262 'title' => 'Documents', 263 'thumbnail' => null, 264 'children' => array(), 265 'datemodified' => 1481213186, 266 'path' => '/Documents/' 267 ), 268 'WELCOME.TXT' => array( 269 'title' => 'welcome.txt', 270 'thumbnail' => null, 271 'size' => '163', 272 'datemodified' => 1481213186, 273 'source' => '/welcome.txt' 274 ) 275 ); 276 277 // Valid response from the client. 278 $mock = $this->createMock(\webdav_client::class); 279 $mock->expects($this->once())->method('open')->will($this->returnValue(true)); 280 $mock->expects($this->once())->method('ls')->will($this->returnValue($response)); 281 $this->set_private_property($mock, 'dav'); 282 283 $ls = $this->repo->get_listing('/'); 284 285 // Those attributes can not be tested properly. 286 $ls['list']['DOCUMENTS/']['thumbnail'] = null; 287 $ls['list']['WELCOME.TXT']['thumbnail'] = null; 288 289 $this->assertEquals($ret, $ls); 290 } 291 /** 292 * Test get_listing method with an example directory. Tests a different directory than the root 293 * directory. 294 */ 295 public function test_get_listing_directory() { 296 $ret = $this->get_initialised_return_array(); 297 $this->setUser(); 298 299 // An additional directory path has to be added to the 'path' field within the returned array. 300 $ret['path'][1] = array( 301 'name' => 'dir', 302 'path' => '/dir/' 303 ); 304 305 // This is the expected response from the get_listing method in the Nextcloud client. 306 $response = array( 307 array( 308 'href' => 'remote.php/webdav/dir/', 309 'lastmodified' => 'Thu, 08 Dec 2016 16:06:26 GMT', 310 'resourcetype' => 'collection', 311 'status' => 'HTTP/1.1 200 OK', 312 'getcontentlength' => '' 313 ), 314 array( 315 'href' => 'remote.php/webdav/dir/Documents/', 316 'lastmodified' => null, 317 'resourcetype' => 'collection', 318 'status' => 'HTTP/1.1 200 OK', 319 'getcontentlength' => '' 320 ), 321 array( 322 'href' => 'remote.php/webdav/dir/welcome.txt', 323 'lastmodified' => 'Thu, 08 Dec 2016 16:06:26 GMT', 324 'status' => 'HTTP/1.1 200 OK', 325 'getcontentlength' => '163' 326 ) 327 ); 328 329 // The expected result from the get_listing method in the repository_nextcloud class. 330 $ret['list'] = array( 331 'DOCUMENTS/' => array( 332 'title' => 'Documents', 333 'thumbnail' => null, 334 'children' => array(), 335 'datemodified' => null, 336 'path' => '/dir/Documents/' 337 ), 338 'WELCOME.TXT' => array( 339 'title' => 'welcome.txt', 340 'thumbnail' => null, 341 'size' => '163', 342 'datemodified' => 1481213186, 343 'source' => '/dir/welcome.txt' 344 ) 345 ); 346 347 // Valid response from the client. 348 $mock = $this->createMock(\webdav_client::class); 349 $mock->expects($this->once())->method('open')->will($this->returnValue(true)); 350 $mock->expects($this->once())->method('ls')->will($this->returnValue($response)); 351 $this->set_private_property($mock, 'dav'); 352 353 $ls = $this->repo->get_listing('/dir/'); 354 355 // Can not be tested properly. 356 $ls['list']['DOCUMENTS/']['thumbnail'] = null; 357 $ls['list']['WELCOME.TXT']['thumbnail'] = null; 358 359 $this->assertEquals($ret, $ls); 360 } 361 /** 362 * Test the get_link method. 363 */ 364 public function test_get_link_success() { 365 $mock = $this->getMockBuilder(\repository_nextcloud\ocs_client::class)->disableOriginalConstructor()->disableOriginalClone( 366 )->getMock(); 367 $file = '/datei'; 368 $expectedresponse = <<<XML 369 <?xml version="1.0"?> 370 <ocs> 371 <meta> 372 <status>ok</status> 373 <statuscode>100</statuscode> 374 <message/> 375 </meta> 376 <data> 377 <id>2</id> 378 <share_type>3</share_type> 379 <uid_owner>admin</uid_owner> 380 <displayname_owner>admin</displayname_owner> 381 <permissions>1</permissions> 382 <stime>1502883721</stime> 383 <parent/> 384 <expiration/> 385 <token>QXbqrJj8DcMaXen</token> 386 <uid_file_owner>admin</uid_file_owner> 387 <displayname_file_owner>admin</displayname_file_owner> 388 <path>/somefile</path> 389 <item_type>file</item_type> 390 <mimetype>application/pdf</mimetype> 391 <storage_id>home::admin</storage_id> 392 <storage>1</storage> 393 <item_source>6</item_source> 394 <file_source>6</file_source> 395 <file_parent>4</file_parent> 396 <file_target>/somefile</file_target> 397 <share_with/> 398 <share_with_displayname/> 399 <name/> 400 <url>https://www.default.test/somefile</url> 401 <mail_send>0</mail_send> 402 </data> 403 </ocs> 404 XML; 405 // Expected Parameters. 406 $ocsquery = [ 407 'path' => $file, 408 'shareType' => \repository_nextcloud\ocs_client::SHARE_TYPE_PUBLIC, 409 'publicUpload' => false, 410 'permissions' => \repository_nextcloud\ocs_client::SHARE_PERMISSION_READ 411 ]; 412 413 // With test whether mock is called with right parameters. 414 $mock->expects($this->once())->method('call')->with('create_share', $ocsquery)->will($this->returnValue($expectedresponse)); 415 $this->set_private_property($mock, 'ocsclient'); 416 417 // Method does extract the link from the xml format. 418 $this->assertEquals('https://www.default.test/somefile/download', $this->repo->get_link($file)); 419 } 420 421 /** 422 * get_link can get OCS failure responses. Test that this is handled appropriately. 423 */ 424 public function test_get_link_failure() { 425 $mock = $this->getMockBuilder(\repository_nextcloud\ocs_client::class)->disableOriginalConstructor()->disableOriginalClone( 426 )->getMock(); 427 $file = '/datei'; 428 $expectedresponse = <<<XML 429 <?xml version="1.0"?> 430 <ocs> 431 <meta> 432 <status>failure</status> 433 <statuscode>404</statuscode> 434 <message>Msg</message> 435 </meta> 436 <data/> 437 </ocs> 438 XML; 439 // Expected Parameters. 440 $ocsquery = [ 441 'path' => $file, 442 'shareType' => \repository_nextcloud\ocs_client::SHARE_TYPE_PUBLIC, 443 'publicUpload' => false, 444 'permissions' => \repository_nextcloud\ocs_client::SHARE_PERMISSION_READ 445 ]; 446 447 // With test whether mock is called with right parameters. 448 $mock->expects($this->once())->method('call')->with('create_share', $ocsquery)->will($this->returnValue($expectedresponse)); 449 $this->set_private_property($mock, 'ocsclient'); 450 451 // Suppress (expected) XML parse error... Nextcloud sometimes returns JSON on extremely bad errors. 452 libxml_use_internal_errors(true); 453 454 // Method get_link correctly raises an exception that contains error code and message. 455 $this->expectException(\repository_nextcloud\request_exception::class); 456 $params = array('instance' => $this->repo->get_name(), 'errormessage' => sprintf('(%s) %s', '404', 'Msg')); 457 $this->expectExceptionMessage(get_string('request_exception', 'repository_nextcloud', $params)); 458 $this->repo->get_link($file); 459 } 460 461 /** 462 * get_link can get OCS responses that are not actually XML. Test that this is handled appropriately. 463 */ 464 public function test_get_link_problem() { 465 $mock = $this->getMockBuilder(\repository_nextcloud\ocs_client::class)->disableOriginalConstructor()->disableOriginalClone( 466 )->getMock(); 467 $file = '/datei'; 468 $expectedresponse = <<<JSON 469 {"message":"CSRF check failed"} 470 JSON; 471 // Expected Parameters. 472 $ocsquery = [ 473 'path' => $file, 474 'shareType' => \repository_nextcloud\ocs_client::SHARE_TYPE_PUBLIC, 475 'publicUpload' => false, 476 'permissions' => \repository_nextcloud\ocs_client::SHARE_PERMISSION_READ 477 ]; 478 479 // With test whether mock is called with right parameters. 480 $mock->expects($this->once())->method('call')->with('create_share', $ocsquery)->will($this->returnValue($expectedresponse)); 481 $this->set_private_property($mock, 'ocsclient'); 482 483 // Suppress (expected) XML parse error... Nextcloud sometimes returns JSON on extremely bad errors. 484 libxml_use_internal_errors(true); 485 486 // Method get_link correctly raises an exception. 487 $this->expectException(\repository_nextcloud\request_exception::class); 488 $this->repo->get_link($file); 489 } 490 491 /** 492 * Test get_file reference, merely returns the input if no optional_param is set. 493 */ 494 public function test_get_file_reference_withoutoptionalparam() { 495 $this->assertEquals('/somefile', $this->repo->get_file_reference('/somefile')); 496 } 497 498 /** 499 * Test logout. 500 */ 501 public function test_logout() { 502 $mock = $this->createMock(\core\oauth2\client::class); 503 504 $mock->expects($this->exactly(2))->method('log_out'); 505 $this->set_private_property($mock, 'client'); 506 $this->repo->options['ajax'] = false; 507 $this->expectOutputString('<a target="_blank" rel="noopener noreferrer">Log in to your account</a>' . 508 '<a target="_blank" rel="noopener noreferrer">Log in to your account</a>'); 509 510 $this->assertEquals($this->repo->print_login(), $this->repo->logout()); 511 512 $mock->expects($this->exactly(2))->method('get_login_url')->will($this->returnValue(new \moodle_url('url'))); 513 514 $this->repo->options['ajax'] = true; 515 $this->assertEquals($this->repo->print_login(), $this->repo->logout()); 516 517 } 518 /** 519 * Test for the get_file method from the repository_nextcloud class. 520 */ 521 public function test_get_file() { 522 // WebDAV socket is not open. 523 $mock = $this->createMock(\webdav_client::class); 524 $mock->expects($this->once())->method('open')->will($this->returnValue(false)); 525 $private = $this->set_private_property($mock, 'dav'); 526 527 $this->assertFalse($this->repo->get_file('path')); 528 529 // WebDAV socket is open and the request successful. 530 $mock = $this->createMock(\webdav_client::class); 531 $mock->expects($this->once())->method('open')->will($this->returnValue(true)); 532 $mock->expects($this->once())->method('get_file')->will($this->returnValue(true)); 533 $private->setValue($this->repo, $mock); 534 535 $result = $this->repo->get_file('path', 'file'); 536 537 $this->assertNotNull($result['path']); 538 } 539 540 /** 541 * Test callback. 542 */ 543 public function test_callback() { 544 $mock = $this->createMock(\core\oauth2\client::class); 545 // Should call check_login exactly once. 546 $mock->expects($this->once())->method('log_out'); 547 $mock->expects($this->once())->method('is_logged_in'); 548 549 $this->set_private_property($mock, 'client'); 550 551 $this->repo->callback(); 552 } 553 /** 554 * Test check_login. 555 */ 556 public function test_check_login() { 557 $mock = $this->createMock(\core\oauth2\client::class); 558 $mock->expects($this->once())->method('is_logged_in')->will($this->returnValue(true)); 559 $this->set_private_property($mock, 'client'); 560 561 $this->assertTrue($this->repo->check_login()); 562 } 563 /** 564 * Test print_login. 565 */ 566 public function test_print_login() { 567 $mock = $this->createMock(\core\oauth2\client::class); 568 $mock->expects($this->exactly(2))->method('get_login_url')->will($this->returnValue(new \moodle_url('url'))); 569 $this->set_private_property($mock, 'client'); 570 571 // Test with ajax activated. 572 $this->repo->options['ajax'] = true; 573 574 $url = new \moodle_url('url'); 575 $ret = array(); 576 $btn = new \stdClass(); 577 $btn->type = 'popup'; 578 $btn->url = $url->out(false); 579 $ret['login'] = array($btn); 580 581 $this->assertEquals($ret, $this->repo->print_login()); 582 583 // Test without ajax. 584 $this->repo->options['ajax'] = false; 585 586 $output = \html_writer::link($url, get_string('login', 'repository'), 587 array('target' => '_blank', 'rel' => 'noopener noreferrer')); 588 $this->expectOutputString($output); 589 $this->repo->print_login(); 590 } 591 592 /** 593 * Test the initiate_webdavclient function. 594 */ 595 public function test_initiate_webdavclient() { 596 global $CFG; 597 598 $idwebdav = $this->get_endpoint_id('webdav_endpoint'); 599 if (!empty($idwebdav)) { 600 foreach ($idwebdav as $id) { 601 \core\oauth2\api::delete_endpoint($id); 602 } 603 } 604 605 $generator = $this->getDataGenerator()->get_plugin_generator('repository_nextcloud'); 606 $generator->test_create_single_endpoint($this->issuer->get('id'), "webdav_endpoint", 607 "https://www.default.test:8080/webdav/index.php"); 608 609 $fakeaccesstoken = new \stdClass(); 610 $fakeaccesstoken->token = "fake access token"; 611 $oauthmock = $this->createMock(\core\oauth2\client::class); 612 $oauthmock->expects($this->once())->method('get_accesstoken')->will($this->returnValue($fakeaccesstoken)); 613 $this->set_private_property($oauthmock, 'client'); 614 615 $dav = \phpunit_util::call_internal_method($this->repo, "initiate_webdavclient", [], 'repository_nextcloud'); 616 617 // Verify that port is set correctly (private property). 618 $refclient = new \ReflectionClass($dav); 619 620 $property = $refclient->getProperty('_port'); 621 $property->setAccessible(true); 622 623 $port = $property->getValue($dav); 624 625 $this->assertEquals('8080', $port); 626 } 627 628 /** 629 * Test supported_returntypes. 630 * FILE_INTERNAL | FILE_REFERENCE when no system account is connected. 631 * FILE_INTERNAL | FILE_CONTROLLED_LINK | FILE_REFERENCE when a system account is connected. 632 */ 633 public function test_supported_returntypes() { 634 global $DB; 635 $this->assertEquals(FILE_INTERNAL | FILE_REFERENCE, $this->repo->supported_returntypes()); 636 $dataobject = new \stdClass(); 637 $dataobject->timecreated = time(); 638 $dataobject->timemodified = time(); 639 $dataobject->usermodified = 2; 640 $dataobject->issuerid = $this->issuer->get('id'); 641 $dataobject->refreshtoken = 'sometokenthatwillnotbeused'; 642 $dataobject->grantedscopes = 'openid profile email'; 643 $dataobject->email = 'some.email@some.de'; 644 $dataobject->username = 'someusername'; 645 646 $DB->insert_record('oauth2_system_account', $dataobject); 647 // When a system account is registered the file_type FILE_CONTROLLED_LINK is supported. 648 $this->assertEquals(FILE_INTERNAL | FILE_CONTROLLED_LINK | FILE_REFERENCE, 649 $this->repo->supported_returntypes()); 650 } 651 652 /** 653 * The reference_file_selected() method is called every time a FILE_CONTROLLED_LINK is chosen for upload. 654 * Since the function is very long the private function are tested separately, and merely the abortion of the 655 * function are tested. 656 * 657 */ 658 public function test_reference_file_selected_error() { 659 $this->repo->disabled = true; 660 $this->expectException(\repository_exception::class); 661 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 662 663 $this->repo->disabled = false; 664 $this->expectException(\repository_exception::class); 665 $this->expectExceptionMessage('Cannot connect as system user'); 666 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 667 668 $mock = $this->createMock(\core\oauth2\client::class); 669 $mock->expects($this->once())->method('get_system_oauth_client')->with($this->issuer)->willReturn(true); 670 671 $this->expectException(\repository_exception::class); 672 $this->expectExceptionMessage('Cannot connect as current user'); 673 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 674 675 $this->repo->expects($this->once())->method('get_user_oauth_client')->willReturn(true); 676 $this->expectException(\repository_exception::class); 677 $this->expectExceptionMessage('cannotdownload'); 678 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 679 680 $this->repo->expects($this->once())->method('get_user_oauth_client')->willReturn(true); 681 $this->expectException(\repository_exception::class); 682 $this->expectExceptionMessage('cannotdownload'); 683 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 684 685 $this->repo->expects($this->once())->method('get_user_oauth_client')->willReturn(true); 686 $this->repo->expects($this->once())->method('copy_file_to_path')->willReturn(array('statuscode' => 687 array('success' => 400))); 688 $this->expectException(\repository_exception::class); 689 $this->expectExceptionMessage('Could not copy file'); 690 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 691 692 $this->repo->expects($this->once())->method('get_user_oauth_client')->willReturn(true); 693 $this->repo->expects($this->once())->method('copy_file_to_path')->willReturn(array('statuscode' => 694 array('success' => 201))); 695 $this->repo->expects($this->once())->method('delete_share_dataowner_sysaccount')->willReturn( 696 array('statuscode' => array('success' => 400))); 697 $this->expectException(\repository_exception::class); 698 $this->expectExceptionMessage('Share is still present'); 699 $this->repo->reference_file_selected('', \context_system::instance(), '', '', ''); 700 701 $this->repo->expects($this->once())->method('get_user_oauth_client')->willReturn(true); 702 $this->repo->expects($this->once())->method('copy_file_to_path')->willReturn(array('statuscode' => 703 array('success' => 201))); 704 $this->repo->expects($this->once())->method('delete_share_dataowner_sysaccount')->willReturn( 705 array('statuscode' => array('success' => 100))); 706 $filereturn = array(); 707 $filereturn->link = 'some/fullpath' . 'some/target/path'; 708 $filereturn->name = 'mysource'; 709 $filereturn->usesystem = true; 710 $filereturn = json_encode($filereturn); 711 $return = $this->repo->reference_file_selected('mysource', \context_system::instance(), '', '', ''); 712 $this->assertEquals($filereturn, $return); 713 } 714 715 /** 716 * Test the send_file function for access controlled links. 717 */ 718 public function test_send_file_errors() { 719 $fs = get_file_storage(); 720 $storedfile = $fs->create_file_from_reference([ 721 'contextid' => \context_system::instance()->id, 722 'component' => 'core', 723 'filearea' => 'unittest', 724 'itemid' => 0, 725 'filepath' => '/', 726 'filename' => 'testfile.txt', 727 ], $this->repo->id, json_encode([ 728 'type' => 'FILE_CONTROLLED_LINK', 729 'link' => 'https://test.local/fakelink/', 730 'usesystem' => true, 731 ])); 732 $this->set_private_property('', 'client'); 733 $this->expectException(repository_nextcloud\request_exception::class); 734 $this->expectExceptionMessage(get_string('contactadminwith', 'repository_nextcloud', 735 'The OAuth clients could not be connected.')); 736 737 $this->repo->send_file($storedfile, '', '', ''); 738 739 // Testing whether the mock up appears is topic to behat. 740 $mock = $this->createMock(\core\oauth2\client::class); 741 $mock->expects($this->once())->method('is_logged_in')->willReturn(true); 742 $this->repo->send_file($storedfile, '', '', ''); 743 744 // Checks that setting for foldername are used. 745 $mock->expects($this->once())->method('is_dir')->with('Moodlefiles')->willReturn(false); 746 // In case of false as return value mkcol is called to create the folder. 747 $parsedwebdavurl = parse_url($this->issuer->get_endpoint_url('webdav')); 748 $webdavprefix = $parsedwebdavurl['path']; 749 $mock->expects($this->once())->method('mkcol')->with( 750 $webdavprefix . 'Moodlefiles')->willReturn(400); 751 $this->expectException(\repository_nextcloud\request_exception::class); 752 $this->expectExceptionMessage(get_string('requestnotexecuted', 'repository_nextcloud')); 753 $this->repo->send_file($storedfile, '', '', ''); 754 755 $expectedresponse = <<<XML 756 <?xml version="1.0"?> 757 <ocs> 758 <meta> 759 <status>ok</status> 760 <statuscode>100</statuscode> 761 <message/> 762 </meta> 763 <data> 764 <element> 765 <id>6</id> 766 <share_type>0</share_type> 767 <uid_owner>tech</uid_owner> 768 <displayname_owner>tech</displayname_owner> 769 <permissions>19</permissions> 770 <stime>1511877999</stime> 771 <parent/> 772 <expiration/> 773 <token/> 774 <uid_file_owner>tech</uid_file_owner> 775 <displayname_file_owner>tech</displayname_file_owner> 776 <path>/System/Category Category 1/Course Example Course/File morefiles/mod_resource/content/0/merge.txt</path> 777 <item_type>file</item_type> 778 <mimetype>text/plain</mimetype> 779 <storage_id>home::tech</storage_id> 780 <storage>4</storage> 781 <item_source>824</item_source> 782 <file_source>824</file_source> 783 <file_parent>823</file_parent> 784 <file_target>/merge (3).txt</file_target> 785 <share_with>user2</share_with> 786 <share_with_displayname>user1</share_with_displayname> 787 <mail_send>0</mail_send> 788 </element> 789 <element> 790 <id>5</id> 791 <share_type>0</share_type> 792 <uid_owner>tech</uid_owner> 793 <displayname_owner>tech</displayname_owner> 794 <permissions>19</permissions> 795 <stime>1511877999</stime> 796 <parent/> 797 <expiration/> 798 <token/> 799 <uid_file_owner>tech</uid_file_owner> 800 <displayname_file_owner>tech</displayname_file_owner> 801 <path>/System/Category Category 1/Course Example Course/File morefiles/mod_resource/content/0/merge.txt</path> 802 <item_type>file</item_type> 803 <mimetype>text/plain</mimetype> 804 <storage_id>home::tech</storage_id> 805 <storage>4</storage> 806 <item_source>824</item_source> 807 <file_source>824</file_source> 808 <file_parent>823</file_parent> 809 <file_target>/merged (3).txt</file_target> 810 <share_with>user1</share_with> 811 <share_with_displayname>user1</share_with_displayname> 812 <mail_send>0</mail_send> 813 </element> 814 </data> 815 </ocs> 816 XML; 817 818 // Checks that setting for foldername are used. 819 $mock->expects($this->once())->method('is_dir')->with('Moodlefiles')->willReturn(true); 820 // In case of true as return value mkcol is not called to create the folder. 821 $shareid = 5; 822 823 $mockocsclient = $this->getMockBuilder( 824 \repository_nextcloud\ocs_client::class)->disableOriginalConstructor()->disableOriginalClone()->getMock(); 825 $mockocsclient->expects($this->exactly(2))->method('call')->with('get_information_of_share', 826 array('share_id' => $shareid))->will($this->returnValue($expectedresponse)); 827 $this->set_private_property($mock, 'ocsclient'); 828 $this->repo->expects($this->once())->method('move_file_to_folder')->with('/merged (3).txt', 'Moodlefiles', 829 $mock)->willReturn(array('success' => 201)); 830 831 $this->repo->send_file('', '', '', ''); 832 833 // Create test for statuscode 403. 834 835 // Checks that setting for foldername are used. 836 $mock->expects($this->once())->method('is_dir')->with('Moodlefiles')->willReturn(true); 837 // In case of true as return value mkcol is not called to create the folder. 838 $shareid = 5; 839 $mockocsclient = $this->getMockBuilder(\repository_nextcloud\ocs_client::class 840 )->disableOriginalConstructor()->disableOriginalClone()->getMock(); 841 $mockocsclient->expects($this->exactly(1))->method('call')->with('get_shares', 842 array('path' => '/merged (3).txt', 'reshares' => true))->will($this->returnValue($expectedresponse)); 843 $mockocsclient->expects($this->exactly(1))->method('call')->with('get_information_of_share', 844 array('share_id' => $shareid))->will($this->returnValue($expectedresponse)); 845 $this->set_private_property($mock, 'ocsclient'); 846 $this->repo->expects($this->once())->method('move_file_to_folder')->with('/merged (3).txt', 'Moodlefiles', 847 $mock)->willReturn(array('success' => 201)); 848 $this->repo->send_file('', '', '', ''); 849 } 850 851 /** 852 * This function provides the data for test_sync_reference 853 * 854 * @return array[] 855 */ 856 public function sync_reference_provider():array { 857 return [ 858 'referecncelastsync done recently' => [ 859 [ 860 'storedfile_record' => [ 861 'contextid' => \context_system::instance()->id, 862 'component' => 'core', 863 'filearea' => 'unittest', 864 'itemid' => 0, 865 'filepath' => '/', 866 'filename' => 'testfile.txt', 867 ], 868 'storedfile_reference' => json_encode( 869 [ 870 'type' => 'FILE_REFERENCE', 871 'link' => 'https://test.local/fakelink/', 872 'usesystem' => true, 873 'referencelastsync' => DAYSECS + time() 874 ] 875 ), 876 ], 877 'mockfunctions' => ['get_referencelastsync'], 878 'expectedresult' => false 879 ], 880 'file without link' => [ 881 [ 882 'storedfile_record' => [ 883 'contextid' => \context_system::instance()->id, 884 'component' => 'core', 885 'filearea' => 'unittest', 886 'itemid' => 0, 887 'filepath' => '/', 888 'filename' => 'testfile.txt', 889 ], 890 'storedfile_reference' => json_encode( 891 [ 892 'type' => 'FILE_REFERENCE', 893 'usesystem' => true, 894 ] 895 ), 896 ], 897 'mockfunctions' => [], 898 'expectedresult' => false 899 ], 900 'file extenstion to exclude' => [ 901 [ 902 'storedfile_record' => [ 903 'contextid' => \context_system::instance()->id, 904 'component' => 'core', 905 'filearea' => 'unittest', 906 'itemid' => 0, 907 'filepath' => '/', 908 'filename' => 'testfile.txt', 909 ], 910 'storedfile_reference' => json_encode( 911 [ 912 'link' => 'https://test.local/fakelink/', 913 'type' => 'FILE_REFERENCE', 914 'usesystem' => true, 915 ] 916 ), 917 ], 918 'mockfunctions' => [], 919 'expectedresult' => false 920 ], 921 'file extenstion for image' => [ 922 [ 923 'storedfile_record' => [ 924 'contextid' => \context_system::instance()->id, 925 'component' => 'core', 926 'filearea' => 'unittest', 927 'itemid' => 0, 928 'filepath' => '/', 929 'filename' => 'testfile.png', 930 ], 931 'storedfile_reference' => json_encode( 932 [ 933 'link' => 'https://test.local/fakelink/', 934 'type' => 'FILE_REFERENCE', 935 'usesystem' => true, 936 ] 937 ), 938 'mock_curl' => true, 939 ], 940 'mockfunctions' => [''], 941 'expectedresult' => true 942 ], 943 ]; 944 } 945 946 /** 947 * Testing sync_reference 948 * 949 * @dataProvider sync_reference_provider 950 * @param array $storedfileargs 951 * @param array $storedfilemethodsmock 952 * @param bool $expectedresult 953 * @return void 954 */ 955 public function test_sync_reference(array $storedfileargs, $storedfilemethodsmock, bool $expectedresult):void { 956 $this->resetAfterTest(true); 957 958 if (isset($storedfilemethodsmock[0])) { 959 $storedfile = $this->createMock(\stored_file::class); 960 961 if ($storedfilemethodsmock[0] === 'get_referencelastsync') { 962 if (!$expectedresult) { 963 $storedfile->method('get_referencelastsync')->willReturn(DAYSECS + time()); 964 } 965 } else { 966 $storedfile->method('get_referencelastsync')->willReturn(null); 967 } 968 969 $storedfile->method('get_reference')->willReturn($storedfileargs['storedfile_reference']); 970 $storedfile->method('get_filepath')->willReturn($storedfileargs['storedfile_record']['filepath']); 971 $storedfile->method('get_filename')->willReturn($storedfileargs['storedfile_record']['filename']); 972 973 if ((isset($storedfileargs['mock_curl']) && $storedfileargs)) { 974 // Lets mock curl, else it would not serve the purpose here. 975 $curl = $this->createMock(\curl::class); 976 $curl->method('download_one')->willReturn(true); 977 $curl->method('get_info')->willReturn(['http_code' => 200]); 978 979 $reflectionproperty = new \ReflectionProperty($this->repo, 'curl'); 980 $reflectionproperty->setAccessible(true); 981 $reflectionproperty->setValue($this->repo, $curl); 982 } 983 } else { 984 $fs = get_file_storage(); 985 $storedfile = $fs->create_file_from_reference( 986 $storedfileargs['storedfile_record'], 987 $this->repo->id, 988 $storedfileargs['storedfile_reference']); 989 } 990 991 $actualresult = $this->repo->sync_reference($storedfile); 992 $this->assertEquals($expectedresult, $actualresult); 993 } 994 995 /** 996 * Helper method, which inserts a given mock value into the repository_nextcloud object. 997 * 998 * @param mixed $value mock value that will be inserted. 999 * @param string $propertyname name of the private property. 1000 * @return ReflectionProperty the resulting reflection property. 1001 */ 1002 protected function set_private_property($value, $propertyname) { 1003 $refclient = new \ReflectionClass($this->repo); 1004 $private = $refclient->getProperty($propertyname); 1005 $private->setAccessible(true); 1006 $private->setValue($this->repo, $value); 1007 1008 return $private; 1009 } 1010 /** 1011 * Helper method to set required return parameters for get_listing. 1012 * 1013 * @return array array, which contains the parameters. 1014 */ 1015 protected function get_initialised_return_array() { 1016 $ret = array(); 1017 $ret['dynload'] = true; 1018 $ret['nosearch'] = true; 1019 $ret['nologin'] = false; 1020 $ret['path'] = [ 1021 [ 1022 'name' => $this->repo->get_meta()->name, 1023 'path' => '', 1024 ] 1025 ]; 1026 $ret['manage'] = ''; 1027 $ret['defaultreturntype'] = FILE_INTERNAL; 1028 $ret['list'] = array(); 1029 1030 $ret['filereferencewarning'] = get_string('externalpubliclinkwarning', 'repository_nextcloud'); 1031 1032 return $ret; 1033 } 1034 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body