MDL-80447 repository_googledocs: Update Google Drive OAuth2 scope tests

This commit is contained in:
raortegar
2025-09-24 11:17:11 +02:00
parent d8a1187d11
commit 7fbfa812b4
3 changed files with 143 additions and 94 deletions
@@ -34,16 +34,21 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
/**
* Test get_content_nodes().
*
* @covers \repository_googledocs\googledocs_content_search
* @dataProvider get_content_nodes_provider
* @param string $query The query string
* @param bool $sortcontent Whether the contents should be sorted in alphabetical order
* @param array $filterextensions The array containing file extensions that should be disallowed (filtered)
* @param array $shareddrives The array containing the existing shared drives
* @param array $searccontents The array containing the fetched google drive contents that match the search criteria
* @param array $expected The expected array which contains the generated repository content nodes
*/
public function test_get_content_nodes(string $query, bool $sortcontent, array $filterextensions,
array $shareddrives, array $searccontents, array $expected): void {
public function test_get_content_nodes(
string $query,
bool $sortcontent,
array $filterextensions,
array $searccontents,
array $expected
): void {
// Mock the service object.
$servicemock = $this->createMock(rest::class);
@@ -52,45 +57,27 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
'q' => "fullText contains '" . str_replace("'", "\'", $query) . "' AND trashed = false",
'fields' => 'files(id,name,mimeType,webContentLink,webViewLink,fileExtension,modifiedTime,size,iconLink)',
'spaces' => 'drive',
'supportsAllDrives' => 'true',
'includeItemsFromAllDrives' => 'true',
'corpora' => 'allDrives',
];
if (!empty($shareddrives)) {
$searchparams['supportsAllDrives'] = 'true';
$searchparams['includeItemsFromAllDrives'] = 'true';
$searchparams['corpora'] = 'allDrives';
}
// Assert that the call() method is being called twice with the given arguments consecutively. In the first
// instance it is being called to fetch the shared drives (shared_drives_list), while in the second instance
// to fetch the relevant drive contents (list) that match the search criteria. Also, define the returned
// data objects by these calls.
$callinvocations = $this->exactly(2);
// Assert that the call() method is being called to fetch the relevant drive contents (list),
// that match the search criteria. Also, define the returned data objects by these calls.
// This simulates the more restricted drive.file scope behavior.
$callinvocations = $this->exactly(1);
$servicemock->expects($callinvocations)
->method('call')
->willReturnCallback(function(string $method, array $params) use (
$callinvocations,
$shareddrives,
$searccontents,
$searchparams,
) {
switch (self::getInvocationCount($callinvocations)) {
case 1:
$this->assertEquals('shared_drives_list', $method);
$this->assertEquals('list', $method);
$this->assertEquals($searchparams, $params);
$this->assertEmpty($params);
return (object) [
'kind' => 'drive#driveList',
'nextPageToken' => 'd838181f30b0f5',
'drives' => $shareddrives,
];
case 2:
$this->assertEquals('list', $method);
$this->assertEquals($searchparams, $params);
return (object) [
'files' => $searccontents,
];
}
return (object) [
'files' => $searccontents,
];
});
// Construct the node path.
@@ -118,14 +105,11 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
$searchforstring = get_string('searchfor', 'repository_googledocs');
return [
'Folders and files match the search criteria; shared drives exist; ordering applied.' =>
'Folders and files match the search criteria; ordering applied.' =>
[
'test',
true,
[],
[
self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
],
[
self::create_google_drive_file_object('d85b21c0f86cb0', 'Test file 3.pdf',
'application/pdf', 'pdf', '1000', '',
@@ -148,12 +132,11 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download', 'download'),
],
],
'Only folders match the search criteria; shared drives do not exist; ordering not applied.' =>
'Only folders match the search criteria; ordering not applied.' =>
[
'testing',
false,
[],
[],
[
self::create_google_drive_folder_object('0c4ad262c65333', 'Testing folder 3'),
self::create_google_drive_folder_object('d85b21c0f86cb0', 'Testing folder 1'),
@@ -168,14 +151,11 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'testing'")),
],
],
'Only files match the search criteria; shared drives exist; ordering not applied; filter .doc and .txt.' =>
'Only files match the search criteria; ordering not applied; filter .doc and .txt.' =>
[
'root',
false,
['doc', 'txt'],
[
self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
],
[
self::create_google_drive_file_object('d85b21c0f86cb0', 'Testing file 3.pdf',
'application/pdf', 'pdf', '1000'),
@@ -190,14 +170,13 @@ final class googledocs_search_content_test extends \googledocs_content_testcase
'https://googleusercontent.com/type/application/pdf', '', 'download'),
],
],
'No content that matches the search criteria; shared drives do not exist.' =>
'No content that matches the search criteria.' =>
[
'root',
false,
[],
[],
[],
[],
],
];
}
@@ -16,6 +16,8 @@
namespace repository_googledocs\local\browser;
use Google_Service_Drive;
defined('MOODLE_INTERNAL') || die();
global $CFG;
@@ -53,46 +55,67 @@ final class googledocs_drive_content_test extends \googledocs_content_testcase {
'q' => "'" . str_replace("'", "\'", $query) . "' in parents AND trashed = false",
'fields' => 'files(id,name,mimeType,webContentLink,webViewLink,fileExtension,modifiedTime,size,iconLink)',
'spaces' => 'drive',
'supportsAllDrives' => 'true',
'includeItemsFromAllDrives' => 'true',
'corpora' => 'allDrives',
];
if (!empty($shareddrives)) {
$listparams['supportsAllDrives'] = 'true';
$listparams['includeItemsFromAllDrives'] = 'true';
if (!$this->shared_drives_supported()) {
$callinvocations = $this->exactly(1);
$servicemock->expects($callinvocations)
->method('call')
->willReturnCallback(function (
string $method,
array $params
) use (
$listparams,
$drivecontents,
) {
$this->assertEquals('list', $method);
$this->assertEquals($listparams, $params);
return (object) [
'files' => $drivecontents,
];
});
} else {
// Assert that the call() method is being called twice with the given arguments consecutively. In the first
// instance it is being called to fetch the shared drives (shared_drives_list), while in the second instance
// to fetch the relevant drive contents (list). Also, define the returned data objects by these calls.
$callinvocations = $this->exactly(2);
$servicemock->expects($callinvocations)
->method('call')
->willReturnCallback(function (
string $method,
array $params
) use (
$callinvocations,
$shareddrives,
$listparams,
$drivecontents,
) {
switch (self::getInvocationCount($callinvocations)) {
case 1:
$this->assertEquals('shared_drives_list', $method);
$this->assertEquals([], $params);
return (object) [
'kind' => 'drive#driveList',
'nextPageToken' => 'd838181f30b0f5',
'drives' => $shareddrives,
];
case 2:
$this->assertEquals('list', $method);
$this->assertEquals($listparams, $params);
return (object)[
'files' => $drivecontents,
];
default:
$this->fail('Unexpected call to the call() method.');
}
});
}
// Assert that the call() method is being called twice with the given arguments consecutively. In the first
// instance it is being called to fetch the shared drives (shared_drives_list), while in the second instance
// to fetch the relevant drive contents (list). Also, define the returned data objects by these calls.
$callinvocations = $this->exactly(2);
$servicemock->expects($callinvocations)
->method('call')
->willReturnCallback(function(string $method, array $params) use (
$callinvocations,
$shareddrives,
$listparams,
$drivecontents,
) {
switch (self::getInvocationCount($callinvocations)) {
case 1:
$this->assertEquals('shared_drives_list', $method);
$this->assertEquals([], $params);
return (object) [
'kind' => 'drive#driveList',
'nextPageToken' => 'd838181f30b0f5',
'drives' => $shareddrives,
];
case 2:
$this->assertEquals('list', $method);
$this->assertEquals($listparams, $params);
return (object)[
'files' => $drivecontents,
];
default:
$this->fail('Unexpected call to the call() method.');
}
});
// Set the disallowed file types (extensions).
$this->disallowedextensions = $filterextensions;
$drivebrowser = new googledocs_drive_content($servicemock, $path, $sortcontent);
@@ -272,4 +295,16 @@ final class googledocs_drive_content_test extends \googledocs_content_testcase {
],
];
}
/**
* Determines whether shared drives are supported under the current Google Drive scope.
*
* @return bool
*/
private function shared_drives_supported(): bool {
$scopes = Google_Service_Drive::DRIVE_FILE;
// Full access is needed for shared drives (not just drive.file).
return str_contains($scopes, 'auth/drive') && !str_contains($scopes, 'auth/drive.file');
}
}
@@ -16,6 +16,8 @@
namespace repository_googledocs\local\browser;
use Google_Service_Drive;
defined('MOODLE_INTERNAL') || die();
global $CFG;
@@ -36,24 +38,43 @@ final class googledocs_root_content_test extends \googledocs_content_testcase {
* @dataProvider get_content_nodes_provider
* @param array $shareddrives The array containing the existing shared drives
* @param array $expected The expected array which contains the generated repository content nodes
* @param bool $expectshared Whether shared drives should be tested
* @covers \repository_googledocs
*/
public function test_get_content_nodes(array $shareddrives, array $expected): void {
public function test_get_content_nodes(array $shareddrives, array $expected, bool $expectshared): void {
$scopessupportshared = $this->shared_drives_supported();
if ($expectshared && !$scopessupportshared) {
$this->markTestSkipped('Shared drives not supported in current OAuth scope.');
}
// Mock the service object.
$servicemock = $this->createMock(\repository_googledocs\rest::class);
// Assert that the call() method is being called only once with the given arguments to fetch the existing
// shared drives. Define the returned data object by this call.
$servicemock->expects($this->once())
->method('call')
->with('shared_drives_list', [])
->willReturn((object)[
'kind' => 'drive#driveList',
'nextPageToken' => 'd838181f30b0f5',
'drives' => $shareddrives,
]);
if ($expectshared && $scopessupportshared) {
// Expect shared drives API to be called.
// Assert that the call() method is being called only once with the given arguments to fetch the existing
// shared drives. Define the returned data object by this call.
$servicemock->expects($this->once())
->method('call')
->with('shared_drives_list', [])
->willReturn((object)[
'kind' => 'drive#driveList',
'nextPageToken' => 'd838181f30b0f5',
'drives' => $shareddrives,
]);
} else {
// If shared drives are not expected or not supported, call() should not be invoked.
$servicemock->expects($this->never())
->method('call');
}
$rootbrowser = new googledocs_root_content($servicemock,
\repository_googledocs::REPOSITORY_ROOT_ID . '|Google+Drive', false);
$showshared = $expectshared && $scopessupportshared;
$rootbrowser = new googledocs_root_content(
$servicemock,
\repository_googledocs::REPOSITORY_ROOT_ID . '|Google+Drive',
$showshared
);
$contentnodes = $rootbrowser->get_content_nodes('', [$this, 'filter']);
// Assert that the returned array of repository content nodes is equal to the expected one.
@@ -84,6 +105,7 @@ final class googledocs_root_content_test extends \googledocs_content_testcase {
get_string('shareddrives', 'repository_googledocs'),
"{$rootid}|Google+Drive"),
],
true, // Expect shared drives.
],
'Shared drives do not exist.' => [
[],
@@ -92,7 +114,20 @@ final class googledocs_root_content_test extends \googledocs_content_testcase {
get_string('mydrive', 'repository_googledocs'),
"{$rootid}|Google+Drive"),
],
false, // Do not expect shared drives.
],
];
}
/**
* Determines whether shared drives are supported under the current Google Drive scope.
*
* @return bool
*/
private function shared_drives_supported(): bool {
$scopes = Google_Service_Drive::DRIVE_FILE;
// Full access is needed for shared drives (not just drive.file).
return str_contains($scopes, 'auth/drive') && !str_contains($scopes, 'auth/drive.file');
}
}