summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsidor@chromium.org <sidor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-13 04:38:25 +0000
committersidor@chromium.org <sidor@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-13 04:38:25 +0000
commit0e55c84770b95a2f2c80fc9edaaf81bbf4e691ad (patch)
tree918aab7662202f229a93652277e2c4d539369f4e
parent0edd1aaf8bdfa4c137945bdc2bbff9014160da01 (diff)
downloadchromium_src-0e55c84770b95a2f2c80fc9edaaf81bbf4e691ad.zip
chromium_src-0e55c84770b95a2f2c80fc9edaaf81bbf4e691ad.tar.gz
chromium_src-0e55c84770b95a2f2c80fc9edaaf81bbf4e691ad.tar.bz2
Adding a format device button to UI.
Additionally local path translation is now supported by filebrowser extension in formatting routine. BUG=chromium-os:4541, chromium-os:17071 TEST=Try to format removable device Review URL: http://codereview.chromium.org/7583041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96682 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/chromeos/cros/mount_library.cc30
-rw-r--r--chrome/browser/extensions/extension_file_browser_private_api.cc82
-rw-r--r--chrome/browser/extensions/extension_file_browser_private_api.h28
-rw-r--r--chrome/browser/extensions/extension_file_browser_private_apitest.cc6
-rw-r--r--chrome/browser/resources/file_manager/js/file_manager.js84
-rw-r--r--chrome/browser/resources/file_manager/js/mock_chrome.js1
-rw-r--r--chrome/test/data/extensions/api_test/filebrowser_mount/test.html4
8 files changed, 178 insertions, 60 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 89ec2d5..bc48cad 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8956,6 +8956,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_FILE_BROWSER_UNMOUNT_ARCHIVE" desc="Title of the action for unmounting the archive file.">
Close archive
</message>
+ <message name="IDS_FILE_BROWSER_FORMAT_DEVICE" desc="Title of the action for formatting removable device.">
+ Format device
+ </message>
<message name="IDS_FILE_BROWSER_CONFIRM_OVERWRITE_FILE" desc="Asks the user if they are sure they want to overwrite an existing file with another one.">
A file named "$1" already exists. Do you want to replace it?
diff --git a/chrome/browser/chromeos/cros/mount_library.cc b/chrome/browser/chromeos/cros/mount_library.cc
index 6b32eb2..77a06a2c 100644
--- a/chrome/browser/chromeos/cros/mount_library.cc
+++ b/chrome/browser/chromeos/cros/mount_library.cc
@@ -180,9 +180,8 @@ class MountLibraryImpl : public MountLibrary {
break;
}
}
-
if (!disk) {
- OnFormatDevice(disk->device_path().c_str(),
+ OnFormatDevice(mount_path,
false,
MOUNT_METHOD_ERROR_LOCAL,
"Device with this mount path not found.");
@@ -190,7 +189,7 @@ class MountLibraryImpl : public MountLibrary {
}
if (formatting_pending_.find(disk->device_path()) !=
formatting_pending_.end()) {
- OnFormatDevice(disk->device_path().c_str(),
+ OnFormatDevice(mount_path,
false,
MOUNT_METHOD_ERROR_LOCAL,
"Formatting is already pending.");
@@ -297,12 +296,18 @@ class MountLibraryImpl : public MountLibrary {
// Callback for FormatRemovableDevice method.
static void FormatDeviceCallback(void* object,
- const char* device_path,
+ const char* file_path,
bool success,
MountMethodErrorType error,
const char* error_message) {
DCHECK(object);
MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
+ const char* device_path = self->FilePathToDevicePath(file_path);
+ if (!device_path) {
+ LOG(ERROR) << "Error while handling disks metadata. Cannot find "
+ << "device that is being formatted.";
+ return;
+ }
self->OnFormatDevice(device_path, success, error, error_message);
}
@@ -615,6 +620,14 @@ class MountLibraryImpl : public MountLibrary {
break;
}
case FORMATTING_FINISHED: {
+ // FORMATTING_FINISHED actually returns file path instead of device
+ // path.
+ device_path = FilePathToDevicePath(device_path);
+ if (!device_path) {
+ LOG(ERROR) << "Error while handling disks metadata. Cannot find "
+ << "device that is being formatted.";
+ return;
+ }
type = MOUNT_FORMATTING_FINISHED;
break;
}
@@ -658,6 +671,15 @@ class MountLibraryImpl : public MountLibrary {
mount_info));
}
+ const char* FilePathToDevicePath(const char* file_path) {
+ for (MountLibrary::DiskMap::iterator it = disks_.begin();
+ it != disks_.end(); ++it) {
+ if (it->second->file_path().compare(file_path) == 0)
+ return it->second->device_path().c_str();
+ }
+ return NULL;
+ }
+
// Mount event change observers.
ObserverList<Observer> observers_;
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc
index 29d3d7d..7856eb9 100644
--- a/chrome/browser/extensions/extension_file_browser_private_api.cc
+++ b/chrome/browser/extensions/extension_file_browser_private_api.cc
@@ -650,7 +650,6 @@ class ExecuteTasksFileSystemCallbackDispatcher
// handler (target) extension and its renderer process.
bool SetupFileAccessPermissions(const GURL& origin_file_url,
GURL* target_file_url, FilePath* file_path, bool* is_directory) {
-
if (!extension_.get())
return false;
@@ -1283,19 +1282,38 @@ bool FormatDeviceFunction::RunImpl() {
return false;
}
- std::string volume_mount_path;
- if (!args_->GetString(0, &volume_mount_path)) {
+ std::string volume_file_url;
+ if (!args_->GetString(0, &volume_file_url)) {
NOTREACHED();
return false;
}
+ UrlList file_paths;
+ file_paths.push_back(GURL(volume_file_url));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this,
+ &FormatDeviceFunction::GetLocalPathsOnFileThread,
+ file_paths, reinterpret_cast<void*>(NULL)));
+ return true;
+}
+
+void FormatDeviceFunction::GetLocalPathsResponseOnUIThread(
+ const FilePathList& files, void* context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (files.size() != 1) {
+ SendResponse(false);
+ return;
+ }
+
#ifdef OS_CHROMEOS
chromeos::CrosLibrary::Get()->GetMountLibrary()->FormatMountedDevice(
- volume_mount_path.c_str());
+ files[0].value().c_str());
#endif
SendResponse(true);
- return true;
}
GetVolumeMetadataFunction::GetVolumeMetadataFunction() {
@@ -1325,8 +1343,13 @@ bool GetVolumeMetadataFunction::RunImpl() {
chromeos::MountLibrary::Disk* volume = volume_it->second;
DictionaryValue* volume_info = new DictionaryValue();
result_.reset(volume_info);
+ // Localising mount path.
+ FilePath relative_mount_path;
+ FileManagerUtil::ConvertFileToRelativeFileSystemPath(profile_,
+ FilePath(volume->mount_path()), &relative_mount_path);
+
volume_info->SetString("devicePath", volume->device_path());
- volume_info->SetString("mountPath", volume->mount_path());
+ volume_info->SetString("mountPath", relative_mount_path.value());
volume_info->SetString("systemPath", volume->system_path());
volume_info->SetString("filePath", volume->file_path());
volume_info->SetString("deviceLabel", volume->device_label());
@@ -1405,6 +1428,7 @@ bool FileDialogStringsFunction::RunImpl() {
SET_STRING(IDS_FILE_BROWSER, ARCHIVE_MOUNT_FAILED);
SET_STRING(IDS_FILE_BROWSER, MOUNT_ARCHIVE);
SET_STRING(IDS_FILE_BROWSER, UNMOUNT_ARCHIVE);
+ SET_STRING(IDS_FILE_BROWSER, FORMAT_DEVICE);
SET_STRING(IDS_FILE_BROWSER, CONFIRM_OVERWRITE_FILE);
SET_STRING(IDS_FILE_BROWSER, FILE_ALREADY_EXISTS);
@@ -1469,29 +1493,29 @@ bool FileDialogStringsFunction::RunImpl() {
SET_STRING(IDS_FILE_BROWSER, PLAYBACK_ERROR);
// MP3 metadata extractor plugin
- SET_STRING(IDS_FILE_BROWSER, ID3_ALBUM); // TALB
- SET_STRING(IDS_FILE_BROWSER, ID3_BPM); // TBPM
- SET_STRING(IDS_FILE_BROWSER, ID3_COMPOSER); // TCOM
- SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT_MESSAGE); // TCOP
- SET_STRING(IDS_FILE_BROWSER, ID3_DATE); // TDAT
- SET_STRING(IDS_FILE_BROWSER, ID3_PLAYLIST_DELAY); // TDLY
- SET_STRING(IDS_FILE_BROWSER, ID3_ENCODED_BY); // TENC
- SET_STRING(IDS_FILE_BROWSER, ID3_LYRICIST); // TEXT
- SET_STRING(IDS_FILE_BROWSER, ID3_FILE_TYPE); // TFLT
- SET_STRING(IDS_FILE_BROWSER, ID3_TIME); // TIME
- SET_STRING(IDS_FILE_BROWSER, ID3_TITLE); // TIT2
- SET_STRING(IDS_FILE_BROWSER, ID3_LENGTH); // TLEN
- SET_STRING(IDS_FILE_BROWSER, ID3_FILE_OWNER); // TOWN
- SET_STRING(IDS_FILE_BROWSER, ID3_LEAD_PERFORMER); // TPE1
- SET_STRING(IDS_FILE_BROWSER, ID3_BAND); // TPE2
- SET_STRING(IDS_FILE_BROWSER, ID3_TRACK_NUMBER); // TRCK
- SET_STRING(IDS_FILE_BROWSER, ID3_YEAR); // TYER
- SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT); // WCOP
- SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_FILE_WEBPAGE); // WOAF
- SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_ARTIST); // WOAR
- SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE); // WOAS
- SET_STRING(IDS_FILE_BROWSER, ID3_PUBLISHERS_OFFICIAL_WEBPAGE); // WPUB
- SET_STRING(IDS_FILE_BROWSER, ID3_USER_DEFINED_URL_LINK_FRAME); // WXXX
+ SET_STRING(IDS_FILE_BROWSER, ID3_ALBUM); // TALB
+ SET_STRING(IDS_FILE_BROWSER, ID3_BPM); // TBPM
+ SET_STRING(IDS_FILE_BROWSER, ID3_COMPOSER); // TCOM
+ SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT_MESSAGE); // TCOP
+ SET_STRING(IDS_FILE_BROWSER, ID3_DATE); // TDAT
+ SET_STRING(IDS_FILE_BROWSER, ID3_PLAYLIST_DELAY); // TDLY
+ SET_STRING(IDS_FILE_BROWSER, ID3_ENCODED_BY); // TENC
+ SET_STRING(IDS_FILE_BROWSER, ID3_LYRICIST); // TEXT
+ SET_STRING(IDS_FILE_BROWSER, ID3_FILE_TYPE); // TFLT
+ SET_STRING(IDS_FILE_BROWSER, ID3_TIME); // TIME
+ SET_STRING(IDS_FILE_BROWSER, ID3_TITLE); // TIT2
+ SET_STRING(IDS_FILE_BROWSER, ID3_LENGTH); // TLEN
+ SET_STRING(IDS_FILE_BROWSER, ID3_FILE_OWNER); // TOWN
+ SET_STRING(IDS_FILE_BROWSER, ID3_LEAD_PERFORMER); // TPE1
+ SET_STRING(IDS_FILE_BROWSER, ID3_BAND); // TPE2
+ SET_STRING(IDS_FILE_BROWSER, ID3_TRACK_NUMBER); // TRCK
+ SET_STRING(IDS_FILE_BROWSER, ID3_YEAR); // TYER
+ SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT); // WCOP
+ SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_FILE_WEBPAGE); // WOAF
+ SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_ARTIST); // WOAR
+ SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE); // WOAS
+ SET_STRING(IDS_FILE_BROWSER, ID3_PUBLISHERS_OFFICIAL_WEBPAGE); // WPUB
+ SET_STRING(IDS_FILE_BROWSER, ID3_USER_DEFINED_URL_LINK_FRAME); // WXXX
SET_STRING(IDS_FILEBROWSER, ENQUEUE);
#undef SET_STRING
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.h b/chrome/browser/extensions/extension_file_browser_private_api.h
index 83a3767..7c7716d 100644
--- a/chrome/browser/extensions/extension_file_browser_private_api.h
+++ b/chrome/browser/extensions/extension_file_browser_private_api.h
@@ -134,8 +134,8 @@ class FileBrowserFunction
void* context);
// Callback with converted local paths.
- virtual void GetLocalPathsResponseOnUIThread(
- const FilePathList& files, void* context) {}
+ virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
+ void* context) {}
// Figure out the tab_id of the hosting tab.
int32 GetTabId() const;
@@ -174,8 +174,8 @@ class ViewFilesFunction
virtual bool RunImpl() OVERRIDE;
// FileBrowserFunction overrides.
- virtual void GetLocalPathsResponseOnUIThread(
- const FilePathList& files, void* context) OVERRIDE;
+ virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
+ void* context) OVERRIDE;
private:
DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.viewFiles");
@@ -194,8 +194,8 @@ class SelectFilesFunction
virtual bool RunImpl() OVERRIDE;
// FileBrowserFunction overrides.
- virtual void GetLocalPathsResponseOnUIThread(
- const FilePathList& files, void* context) OVERRIDE;
+ virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
+ void* context) OVERRIDE;
private:
DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.selectFiles");
@@ -229,8 +229,8 @@ class AddMountFunction
virtual bool RunImpl() OVERRIDE;
// FileBrowserFunction overrides.
- virtual void GetLocalPathsResponseOnUIThread(
- const FilePathList& files, void* context) OVERRIDE;
+ virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
+ void* context) OVERRIDE;
private:
struct MountParamaters {
@@ -257,7 +257,7 @@ class RemoveMountFunction
// FileBrowserFunction overrides.
virtual bool RunImpl() OVERRIDE;
virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
- void* context) OVERRIDE;
+ void* context) OVERRIDE;
private:
DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.removeMount");
@@ -279,15 +279,19 @@ class GetMountPointsFunction
// Formats Device given its mount path.
class FormatDeviceFunction
- : public SyncExtensionFunction {
- public:
- FormatDeviceFunction();
+ : public FileBrowserFunction {
+ public:
+ FormatDeviceFunction();
protected:
virtual ~FormatDeviceFunction();
virtual bool RunImpl() OVERRIDE;
+// FileBrowserFunction overrides.
+ virtual void GetLocalPathsResponseOnUIThread(const FilePathList& files,
+ void* context) OVERRIDE;
+
private:
DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.formatDevice");
};
diff --git a/chrome/browser/extensions/extension_file_browser_private_apitest.cc b/chrome/browser/extensions/extension_file_browser_private_apitest.cc
index f381104..9ceda8c 100644
--- a/chrome/browser/extensions/extension_file_browser_private_apitest.cc
+++ b/chrome/browser/extensions/extension_file_browser_private_apitest.cc
@@ -49,7 +49,7 @@ class ExtensionFileBrowserPrivateApiTest : public ExtensionApiTest {
std::pair<std::string, chromeos::MountLibrary::Disk*>(
"device_path1",
new chromeos::MountLibrary::Disk("device_path1",
- "mount_path1",
+ "/media/removable/mount_path1",
"system_path1",
"file_path1",
"device_label1",
@@ -65,7 +65,7 @@ class ExtensionFileBrowserPrivateApiTest : public ExtensionApiTest {
std::pair<std::string, chromeos::MountLibrary::Disk*>(
"device_path2",
new chromeos::MountLibrary::Disk("device_path2",
- "mount_path2",
+ "/media/removable/mount_path2",
"system_path2",
"file_path2",
"device_label2",
@@ -81,7 +81,7 @@ class ExtensionFileBrowserPrivateApiTest : public ExtensionApiTest {
std::pair<std::string, chromeos::MountLibrary::Disk*>(
"device_path3",
new chromeos::MountLibrary::Disk("device_path3",
- "mount_path3",
+ "/media/removable/mount_path3",
"system_path3",
"file_path3",
"device_label3",
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index 17b9939..f63753f 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -1516,6 +1516,7 @@ FileManager.prototype = {
if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) {
// Since unmount task cannot be defined in terms of file patterns,
// we manually include it here, if all selected items are mount points.
+ this.taskButtons_.innerHTML = '';
chrome.fileBrowserPrivate.getFileTasks(
selection.urls,
this.onTasksFound_.bind(this,
@@ -1594,8 +1595,6 @@ FileManager.prototype = {
title: ''
});
}
-
- this.taskButtons_.innerHTML = '';
for (var i = 0; i < tasksList.length; i++) {
var task = tasksList[i];
@@ -1631,20 +1630,79 @@ FileManager.prototype = {
task.title = str('UNMOUNT_ARCHIVE');
}
}
+ this.renderTaskButton_(task);
+ }
+ // This needs to be done in sparate function, as check requires
+ // asynchronous function calls.
+ this.maybeRenderFormattingTask_();
+ };
+
+ FileManager.prototype.renderTaskButton_ = function(task) {
+ var button = this.document_.createElement('button');
+ button.addEventListener('click', this.onTaskButtonClicked_.bind(this));
+ button.className = 'task-button';
+ button.task = task;
+
+ var img = this.document_.createElement('img');
+ img.src = task.iconUrl;
- var button = this.document_.createElement('button');
- button.addEventListener('click', this.onTaskButtonClicked_.bind(this));
- button.className = 'task-button';
- button.task = task;
+ button.appendChild(img);
+ button.appendChild(this.document_.createTextNode(task.title));
+
+ this.taskButtons_.appendChild(button);
+ };
+
+ /**
+ * Checks whether formatting task should be displayed and if the answer is
+ * affirmative renders it. Includes asynchronous calls, so it's splitted into
+ * three parts.
+ */
+ FileManager.prototype.maybeRenderFormattingTask_ = function() {
+ // Not to make unnecesary getMountPoints() call we doublecheck if there is
+ // only one selected entry.
+ if (this.selection.entries.length != 1)
+ return;
+ var self = this;
+ function onMountPointsFound(mountPoints) {
+ self.mountPoints_ = mountPoints;
- var img = this.document_.createElement('img');
- img.src = task.iconUrl;
+ function normalize(x) {
+ if (x[0] == '/')
+ return x.slice(1);
+ else
+ return x;
+ }
- button.appendChild(img);
- button.appendChild(this.document_.createTextNode(task.title));
+ function onVolumeMetadataFound(volumeMetadata) {
+ if (volumeMetadata.deviceType == "flash") {
+ if (self.selection.entries.length != 1 ||
+ normalize(self.selection.entries[0].fullPath) !=
+ normalize(volumeMetadata.mountPath)) {
+ return;
+ }
+ var task = {
+ taskId: self.getExtensionId_() + '|format-device',
+ iconUrl: chrome.extension.getURL('images/filetype_generic.png'),
+ title: str('FORMAT_DEVICE')
+ };
+ self.renderTaskButton_(task);
+ }
+ }
- this.taskButtons_.appendChild(button);
+ if (self.selection.entries.length != 1)
+ return;
+ var selectedPath = self.selection.entries[0].fullPath;
+ for (var i = 0; i < mountPoints.length; i++) {
+ if (mountPoints[i].mountType == "device" &&
+ normalize(mountPoints[i].mountPath) == normalize(selectedPath)) {
+ chrome.fileBrowserPrivate.getVolumeMetadata(mountPoints[i].sourceUrl,
+ onVolumeMetadataFound);
+ return;
+ }
+ }
}
+
+ chrome.fileBrowserPrivate.getMountPoints(onMountPointsFound);
};
FileManager.prototype.getExtensionId_ = function() {
@@ -1720,6 +1778,10 @@ FileManager.prototype = {
for (var index = 0; index < urls.length; ++index) {
chrome.fileBrowserPrivate.removeMount(urls[index]);
}
+ } else if (id == 'format-device') {
+ this.confirm.show(str('FORMATTING_WARNING'), function() {
+ chrome.fileBrowserPrivate.formatDevice(urls[0]);
+ });
}
};
diff --git a/chrome/browser/resources/file_manager/js/mock_chrome.js b/chrome/browser/resources/file_manager/js/mock_chrome.js
index 453041d..70bb972 100644
--- a/chrome/browser/resources/file_manager/js/mock_chrome.js
+++ b/chrome/browser/resources/file_manager/js/mock_chrome.js
@@ -221,6 +221,7 @@ chrome.fileBrowserPrivate = {
MOUNT_ARCHIVE: 'Open archive',
UNMOUNT_ARCHIVE: 'Close archive',
+ FORMAT_DEVICE: 'Format device',
CONFIRM_OVERWRITE_FILE: 'A file named "$1" already exists. Do you want to replace it?',
FILE_ALREADY_EXISTS: 'The file named "$1" already exists. Please choose a different name.',
diff --git a/chrome/test/data/extensions/api_test/filebrowser_mount/test.html b/chrome/test/data/extensions/api_test/filebrowser_mount/test.html
index f3cdb90..387bc7e 100644
--- a/chrome/test/data/extensions/api_test/filebrowser_mount/test.html
+++ b/chrome/test/data/extensions/api_test/filebrowser_mount/test.html
@@ -2,7 +2,7 @@
// These have to be sync'd with extension_file_browser_private_apitest.cc
var expectedVolume1 = {
devicePath: 'device_path1',
- mountPath: 'mount_path1',
+ mountPath: 'removable/mount_path1',
systemPath: 'system_path1',
filePath: 'file_path1',
deviceLabel: 'device_label1',
@@ -18,6 +18,7 @@ var expectedVolume1 = {
var expectedVolume2 = {
devicePath: 'device_path2',
mountPath: 'mount_path2',
+ mountPath: 'removable/mount_path2',
systemPath: 'system_path2',
filePath: 'file_path2',
deviceLabel: 'device_label2',
@@ -33,6 +34,7 @@ var expectedVolume2 = {
var expectedVolume3 = {
devicePath: 'device_path3',
mountPath: 'mount_path3',
+ mountPath: 'removable/mount_path3',
systemPath: 'system_path3',
filePath: 'file_path3',
deviceLabel: 'device_label3',