Commit 1321863c authored by Stuart Langley's avatar Stuart Langley Committed by Commit Bot

Fix breadcrumbs for "Computers" and nested computers.

This patch updates line_location.js to support deciphering paths that fall
under Google Drive > Computers.

Adds an integration test which ensures that Computers entries can be navigated,
which has the side effect of also testing that the breadcrumbs are working as
breadcrumbs are used to work out where the navigation has actually navigated to.

Bug: 884020
Change-Id: I8ea14eb6716a5060005442e65d07125b41a9c4a3
Reviewed-on: https://chromium-review.googlesource.com/c/1312178
Commit-Queue: Stuart Langley <slangley@chromium.org>
Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604761}
parent 244ff236
......@@ -201,6 +201,7 @@ WRAPPED_INSTANTIATE_TEST_CASE_P(
TestCase("fileDisplayDriveOffline").Offline().EnableDriveFs(),
TestCase("fileDisplayDriveOnline").EnableDriveFs(),
TestCase("fileDisplayDriveOnline").DisableDriveFs(),
TestCase("fileDisplayComputers").EnableDriveFs(),
TestCase("fileDisplayMtp"),
TestCase("fileDisplayUsb"),
TestCase("fileSearch"),
......
......@@ -115,7 +115,7 @@ struct AddEntriesMessage {
};
// Represents the different types of entries (e.g. file, folder).
enum EntryType { FILE, DIRECTORY, TEAM_DRIVE };
enum EntryType { FILE, DIRECTORY, TEAM_DRIVE, COMPUTER };
// Represents whether an entry appears in 'Share with Me' or not.
enum SharedOption { NONE, SHARED, SHARED_WITH_ME, NESTED_SHARED_WITH_ME };
......@@ -214,6 +214,7 @@ struct AddEntriesMessage {
const std::string& target_path,
const std::string& mime_type,
const std::string& team_drive_name,
const std::string& computer_name,
SharedOption shared_option,
const base::Time& last_modified_time,
const EntryCapabilities& capabilities,
......@@ -223,6 +224,7 @@ struct AddEntriesMessage {
source_file_name(source_file_name),
target_path(target_path),
team_drive_name(team_drive_name),
computer_name(computer_name),
mime_type(mime_type),
last_modified_time(last_modified_time),
capabilities(capabilities),
......@@ -234,6 +236,7 @@ struct AddEntriesMessage {
std::string target_path; // Target file or directory path.
std::string name_text; // Display file name.
std::string team_drive_name; // Name of team drive this entry is in.
std::string computer_name; // Name of the computer this entry is in.
std::string mime_type; // File entry content mime type.
base::Time last_modified_time; // Entry last modified time.
EntryCapabilities capabilities; // Entry permissions.
......@@ -250,6 +253,8 @@ struct AddEntriesMessage {
converter->RegisterStringField("nameText", &TestEntryInfo::name_text);
converter->RegisterStringField("teamDriveName",
&TestEntryInfo::team_drive_name);
converter->RegisterStringField("computerName",
&TestEntryInfo::computer_name);
converter->RegisterStringField("mimeType", &TestEntryInfo::mime_type);
converter->RegisterCustomField("sharedOption",
&TestEntryInfo::shared_option,
......@@ -270,6 +275,8 @@ struct AddEntriesMessage {
*type = DIRECTORY;
else if (value == "team_drive")
*type = TEAM_DRIVE;
else if (value == "Computer")
*type = COMPUTER;
else
return false;
return true;
......@@ -456,6 +463,10 @@ class LocalTestVolume : public TestVolume {
NOTREACHED() << "Can't create a team drive in a local volume: "
<< target_path.value();
break;
case AddEntriesMessage::COMPUTER:
NOTREACHED() << "Can't create a computer in a local volume: "
<< target_path.value();
break;
}
ASSERT_TRUE(UpdateModifiedTime(entry));
......@@ -572,13 +583,13 @@ class FakeTestVolume : public LocalTestVolume {
// Note: must be kept in sync with BASIC_FAKE_ENTRY_SET defined in the
// integration_tests/file_manager JS code.
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::FILE, "text.txt", "hello.txt", std::string(),
"text/plain", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
AddEntriesMessage::FILE, "text.txt", "hello.txt", "text/plain",
std::string(), std::string(), AddEntriesMessage::SharedOption::NONE,
base::Time::Now(), AddEntriesMessage::EntryCapabilities(), false));
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::DIRECTORY, std::string(), "A", std::string(),
std::string(), AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
std::string(), std::string(), AddEntriesMessage::SharedOption::NONE,
base::Time::Now(), AddEntriesMessage::EntryCapabilities(), false));
base::RunLoop().RunUntilIdle();
return true;
}
......@@ -588,21 +599,21 @@ class FakeTestVolume : public LocalTestVolume {
return false;
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::DIRECTORY, "", "DCIM", std::string(), "",
AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::DIRECTORY, "", "DCIM", std::string(), std::string(),
"", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::FILE, "image2.png", "image2.png", std::string(),
"image/png", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
std::string(), "image/png", AddEntriesMessage::SharedOption::NONE,
base::Time::Now(), AddEntriesMessage::EntryCapabilities(), false));
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::FILE, "image3.jpg", "DCIM/image3.jpg", std::string(),
"image/jpeg", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
std::string(), "image/jpeg", AddEntriesMessage::SharedOption::NONE,
base::Time::Now(), AddEntriesMessage::EntryCapabilities(), false));
CreateEntry(AddEntriesMessage::TestEntryInfo(
AddEntriesMessage::FILE, "text.txt", "DCIM/hello.txt", std::string(),
"text/plain", AddEntriesMessage::SharedOption::NONE, base::Time::Now(),
AddEntriesMessage::EntryCapabilities(), false));
std::string(), "text/plain", AddEntriesMessage::SharedOption::NONE,
base::Time::Now(), AddEntriesMessage::EntryCapabilities(), false));
base::RunLoop().RunUntilIdle();
return true;
}
......@@ -709,6 +720,9 @@ class DriveTestVolume : public TestVolume {
case AddEntriesMessage::TEAM_DRIVE:
CreateTeamDrive(entry.team_drive_name, team_drive_capabilities);
break;
case AddEntriesMessage::COMPUTER:
NOTREACHED() << "Can't create a computer in a drive test volume: "
<< entry.computer_name;
}
// Any file or directory created above, will only appear in Drive after
......@@ -902,6 +916,9 @@ class DriveFsTestVolume : public DriveTestVolume {
ASSERT_TRUE(base::CreateDirectory(target_path))
<< "Failed to create a team drive: " << target_path.value();
break;
case AddEntriesMessage::COMPUTER:
ASSERT_TRUE(base::CreateDirectory(target_path))
<< "Failed to create a computer: " << target_path.value();
}
ASSERT_TRUE(UpdateModifiedTime(entry));
......@@ -913,6 +930,7 @@ class DriveFsTestVolume : public DriveTestVolume {
CreateDriveFsConnectionDelegate() override {
CHECK(base::CreateDirectory(GetMyDrivePath()));
CHECK(base::CreateDirectory(GetTeamDriveGrandRoot()));
CHECK(base::CreateDirectory(GetComputerGrandRoot()));
if (!fake_drivefs_helper_) {
fake_drivefs_helper_ =
......@@ -934,6 +952,7 @@ class DriveFsTestVolume : public DriveTestVolume {
// Update the modified time of parent directories because they may be
// also affected by the update of child items.
if (path.DirName() != GetTeamDriveGrandRoot() &&
path.DirName() != GetComputerGrandRoot() &&
path.DirName() != GetMyDrivePath() &&
path.DirName() != GetSharedWithMePath()) {
const auto it = entries_.find(path.DirName());
......@@ -963,6 +982,9 @@ class DriveFsTestVolume : public DriveTestVolume {
if (!entry.team_drive_name.empty()) {
return GetTeamDrivePath(entry.team_drive_name);
}
if (!entry.computer_name.empty()) {
return GetComputerPath(entry.computer_name);
}
return GetMyDrivePath();
}
......@@ -982,6 +1004,10 @@ class DriveFsTestVolume : public DriveTestVolume {
return mount_path().Append("team_drives");
}
base::FilePath GetComputerGrandRoot() {
return mount_path().Append("Computers");
}
base::FilePath GetSharedWithMePath() {
return mount_path().Append(".files-by-id/123");
}
......@@ -990,6 +1016,10 @@ class DriveFsTestVolume : public DriveTestVolume {
return GetTeamDriveGrandRoot().Append(team_drive_name);
}
base::FilePath GetComputerPath(const std::string& computer_name) {
return GetComputerGrandRoot().Append(computer_name);
}
Profile* const profile_;
std::map<base::FilePath, const AddEntriesMessage::TestEntryInfo> entries_;
std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_;
......
......@@ -108,6 +108,11 @@ LocationLine.prototype.getComponents_ = function(entry) {
displayRootUrl, VolumeManagerCommon.TEAM_DRIVES_DIRECTORY_PATH);
components.push(new LocationLine.PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
} else if (locationInfo.rootType === VolumeManagerCommon.RootType.COMPUTER) {
displayRootUrl = this.replaceRootName_(
displayRootUrl, VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH);
components.push(new LocationLine.PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
} else {
components.push(new LocationLine.PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
......@@ -119,6 +124,10 @@ LocationLine.prototype.getComponents_ = function(entry) {
VolumeManagerCommon.TEAM_DRIVES_DIRECTORY_PATH)) {
relativePath = entry.fullPath.slice(
VolumeManagerCommon.TEAM_DRIVES_DIRECTORY_PATH.length);
} else if (entry.fullPath.startsWith(
VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH)) {
relativePath = entry.fullPath.slice(
VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH.length);
}
if (relativePath.indexOf('/') === 0) {
relativePath = relativePath.slice(1);
......
......@@ -425,7 +425,7 @@ test.addEntries = function(downloads, drive, crostini) {
.fileSystem);
fsDrive.populate(
test.TestEntryInfo.getMockFileSystemPopulateRows(drive, '/root/'), true);
fsDrive.populate(['/team_drives/']);
fsDrive.populate(['/team_drives/', '/Computers/']);
const fsCrostini = /** @type {MockFileSystem} */ (
mockVolumeManager
......
......@@ -251,6 +251,17 @@ var TEAM_DRIVE_ENTRY_SET = [
ENTRIES.teamDriveBFile,
];
/**
* Entry set for Drive that includes Computers, including nested computers with
* files and nested "USB and External Devices" with nested devices.
*/
let COMPUTERS_ENTRY_SET = [
ENTRIES.hello,
ENTRIES.computerA,
ENTRIES.computerAFile,
ENTRIES.computerAdirectoryA,
];
/**
* Opens a Files app's main window.
*
......
......@@ -159,6 +159,48 @@ testcase.fileDisplayDriveOnline = function() {
]);
};
/**
* Tests files display in the "Computers" section of Google Drive. Testing that
* we can navigate to folders inside /Computers also has the side effect of
* testing that the breadcrumbs are working.
*/
testcase.fileDisplayComputers = function() {
let appId;
StepsRunner.run([
// Open Files app on Drive with Computers registered.
function() {
setupAndWaitUntilReady(
null, RootPath.DRIVE, this.next, [], COMPUTERS_ENTRY_SET);
},
function(result) {
appId = result.windowId;
// Navigate to Comuter Grand Root.
return remoteCall
.navigateWithDirectoryTree(appId, '/Computers', 'Computers')
.then(this.next);
},
function() {
// Navigiate to a Computer Root.
return remoteCall
.navigateWithDirectoryTree(
appId, '/Computers/Computer A', 'Computers')
.then(this.next);
},
function() {
// Navigiate to a subdirectory under a Computer Root.
return remoteCall
.navigateWithDirectoryTree(
appId, '/Computers/Computer A/A', 'Computers')
.then(this.next);
},
function() {
checkIfNoErrorsOccured(this.next);
},
]);
};
/**
* Tests files display in an MTP volume.
*/
......
......@@ -552,7 +552,9 @@ RemoteCallFilesApp.prototype.navigateWithDirectoryTree = function(
.then(() => {
// Entries within Drive starts with /root/ but it isn't displayed in the
// breadcrubms used by waitUntilCurrentDirectoryIsChanged.
path = path.replace(/^\/root/, '').replace(/^\/team_drives/, '');
path = path.replace(/^\/root/, '')
.replace(/^\/team_drives/, '')
.replace(/^\/Computers/, '');
// Wait until the Files app is navigated to the path.
return this.waitUntilCurrentDirectoryIsChanged(
......
......@@ -228,6 +228,7 @@ var EntryType = Object.freeze({
FILE: 'file',
DIRECTORY: 'directory',
TEAM_DRIVE: 'team_drive',
COMPUTER: 'Computer'
});
/**
......@@ -314,6 +315,11 @@ TestEntryInfoOptions.prototype.targetPath;
* string (no team drive). Team Drive names must be unique.
*/
TestEntryInfoOptions.prototype.teamDriveName;
/**
* @type {string} Name of the computer this entry is in. Defaults to a blank
* string (no computer). Computer names must be unique.
*/
TestEntryInfoOptions.prototype.computerName;
/**
* @type {string|undefined} Mime type.
*/
......@@ -358,6 +364,7 @@ function TestEntryInfo(options) {
this.sourceFileName = options.sourceFileName || '';
this.targetPath = options.targetPath;
this.teamDriveName = options.teamDriveName || '';
this.computerName = options.computerName || '';
this.mimeType = options.mimeType || '';
this.sharedOption = options.sharedOption || SharedOption.NONE;
this.lastModifiedTime = options.lastModifiedTime;
......@@ -750,6 +757,41 @@ var ENTRIES = {
},
}),
// Computer entries.
computerA: new TestEntryInfo({
type: EntryType.COMPUTER,
computerName: 'Computer A',
}),
computerAFile: new TestEntryInfo({
type: EntryType.FILE,
sourceFileName: 'text.txt',
targetPath: 'computerAFile.txt',
mimeType: 'text/plain',
lastModifiedTime: 'Sep 4, 1998, 12:34 PM',
nameText: 'computerAFile.txt',
sizeText: '51 bytes',
typeText: 'Plain text',
computerName: 'Computer A',
capabilities: {
canCopy: true,
canDelete: true,
canRename: true,
canAddChildren: false,
canShare: true,
},
}),
computerAdirectoryA: new TestEntryInfo({
type: EntryType.DIRECTORY,
targetPath: 'A',
lastModifiedTime: 'Jan 1, 2000, 1:00 AM',
computerName: 'Computer A',
nameText: 'A',
sizeText: '--',
typeText: 'Folder'
}),
// Read-only and write-restricted entries.
// TODO(sashab): Generate all combinations of capabilities inside the test, to
// ensure maximum coverage.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment