Commit cafadf5b authored by yamaguchi's avatar yamaguchi Committed by Commit bot

Refactor disk_mount_manager_unittest by replacing gmock with a dedicated mock...

Refactor disk_mount_manager_unittest by replacing gmock with a dedicated mock class of DiskMountManagerObserver.

This change is based on
https://codereview.chromium.org/2333983004/
which was once merged but reverted by
https://codereview.chromium.org/2343593002/

BUG=641943
TEST=chromeos_unittest build with is_asan and is_lsan = true in gn args, and run with ASAN_OPTIONS="detect_leaks=1 symbolize=1" environment variable.

Review-Url: https://codereview.chromium.org/2341923003
Cr-Commit-Position: refs/heads/master@{#418811}
parent 7db5d42e
...@@ -6,22 +6,23 @@ ...@@ -6,22 +6,23 @@
#include <stdint.h> #include <stdint.h>
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_cros_disks_client.h" #include "chromeos/dbus/fake_cros_disks_client.h"
#include "chromeos/disks/disk_mount_manager.h" #include "chromeos/disks/disk_mount_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using base::MakeUnique;
using base::StringPrintf;
using chromeos::disks::DiskMountManager; using chromeos::disks::DiskMountManager;
using chromeos::CrosDisksClient; using chromeos::CrosDisksClient;
using chromeos::DBusThreadManager; using chromeos::DBusThreadManager;
using chromeos::FakeCrosDisksClient; using chromeos::FakeCrosDisksClient;
using testing::_; using chromeos::MountType;
using testing::Field; using chromeos::disks::MountCondition;
using testing::InSequence;
using testing::InvokeWithoutArgs;
namespace { namespace {
...@@ -152,31 +153,260 @@ const TestMountPointInfo kTestMountPoints[] = { ...@@ -152,31 +153,260 @@ const TestMountPointInfo kTestMountPoints[] = {
}, },
}; };
// Mocks DiskMountManager observer. // Represents which function in |DiskMountManager::Observer| was invoked.
class MockDiskMountManagerObserver : public DiskMountManager::Observer { enum ObserverEventType {
DEVICE_EVENT, // OnDeviceEvent()
DISK_EVENT, // OnDiskEvent()
FORMAT_EVENT, // OnFormatEvent()
MOUNT_EVENT // OnMountEvent()
};
// Represents every event notified to |DiskMountManager::Observer|.
struct ObserverEvent {
public: public:
virtual ~MockDiskMountManagerObserver() {} virtual ObserverEventType type() const = 0;
virtual ~ObserverEvent() {};
MOCK_METHOD2(OnDiskEvent, void(DiskMountManager::DiskEvent event, };
const DiskMountManager::Disk* disk));
MOCK_METHOD2(OnDeviceEvent, void(DiskMountManager::DeviceEvent event, // Represents an invocation of |DiskMountManager::Observer::OnDeviceEvent()|.
const std::string& device_path)); struct DeviceEvent : public ObserverEvent {
MOCK_METHOD3(OnMountEvent, DiskMountManager::DeviceEvent event;
void(DiskMountManager::MountEvent event, std::string device_path;
DeviceEvent() {}
DeviceEvent(DiskMountManager::DeviceEvent event,
const std::string& device_path)
: event(event), device_path(device_path) {}
ObserverEventType type() const override { return DEVICE_EVENT; }
bool operator==(const DeviceEvent& other) const {
return event == other.event && device_path == other.device_path;
}
std::string DebugString() const {
return StringPrintf("OnDeviceEvent(%d, %s)", event, device_path.c_str());
}
};
// Represents an invocation of |DiskMountManager::Observer::OnDiskEvent()|.
struct DiskEvent : public ObserverEvent {
DiskMountManager::DiskEvent event;
std::unique_ptr<DiskMountManager::Disk> disk;
DiskEvent(DiskMountManager::DiskEvent event,
const DiskMountManager::Disk& disk)
: event(event),
disk(std::unique_ptr<DiskMountManager::Disk>(
new DiskMountManager::Disk(disk))) {}
DiskEvent(DiskEvent&& other)
: event(other.event), disk(std::move(other.disk)) {}
ObserverEventType type() const override { return DISK_EVENT; }
bool operator==(const DiskEvent& other) const {
return event == other.event && disk == other.disk;
}
std::string DebugString() const {
return StringPrintf("OnDiskEvent(event=%d, device_path=%s, mount_path=%s",
event, disk->device_path().c_str(),
disk->mount_path().c_str());
}
};
// Represents an invocation of |DiskMountManager::Observer::OnFormatEvent()|.
struct FormatEvent : public ObserverEvent {
DiskMountManager::FormatEvent event;
chromeos::FormatError error_code;
std::string device_path;
FormatEvent() {}
FormatEvent(DiskMountManager::FormatEvent event,
chromeos::FormatError error_code,
const std::string& device_path)
: event(event), error_code(error_code), device_path(device_path) {}
ObserverEventType type() const override { return FORMAT_EVENT; }
bool operator==(const FormatEvent& other) const {
return event == other.event && error_code == other.error_code &&
device_path == other.device_path;
}
std::string DebugString() const {
return StringPrintf("OnFormatEvent(%d, %d, %s)", event, error_code,
device_path.c_str());
}
};
// Represents an invocation of |DiskMountManager::Observer::OnMountEvent()|.
struct MountEvent : public ObserverEvent {
DiskMountManager::MountEvent event;
chromeos::MountError error_code;
DiskMountManager::MountPointInfo mount_point;
// Not passed to callback, but read by handlers. So it's captured upon
// callback.
std::unique_ptr<DiskMountManager::Disk> disk;
MountEvent(MountEvent&& other)
: event(other.event),
error_code(other.error_code),
mount_point(other.mount_point),
disk(std::move(other.disk)) {}
MountEvent(DiskMountManager::MountEvent event,
chromeos::MountError error_code, chromeos::MountError error_code,
const DiskMountManager::MountPointInfo& mount_point)); const DiskMountManager::MountPointInfo& mount_point,
MOCK_METHOD3(OnFormatEvent, const DiskMountManager::Disk& disk)
void(DiskMountManager::FormatEvent event, : event(event),
error_code(error_code),
mount_point(mount_point),
disk(new DiskMountManager::Disk(disk)) {}
ObserverEventType type() const override { return MOUNT_EVENT; }
bool operator==(const MountEvent& other) const;
std::string DebugString() const {
return StringPrintf("OnMountEvent(%d, %d, %s, %s, %d, %d)", event,
error_code, mount_point.source_path.c_str(),
mount_point.mount_path.c_str(), mount_point.mount_type,
mount_point.mount_condition);
}
};
// A mock |Observer| class which records all invocation of the methods invoked
// from DiskMountManager and all the arguments passed to them.
class MockDiskMountManagerObserver : public DiskMountManager::Observer {
public:
MockDiskMountManagerObserver(const DiskMountManager* manager)
: manager_(manager) {}
~MockDiskMountManagerObserver() override {}
// Mock notify methods.
void OnDeviceEvent(DiskMountManager::DeviceEvent event,
const std::string& device_path) override {
events_.push_back(MakeUnique<DeviceEvent>(event, device_path));
}
void OnDiskEvent(DiskMountManager::DiskEvent event,
const DiskMountManager::Disk* disk) override {
// Take a snapshot (copy) of the Disk object at the time of invocation for
// later verification.
events_.push_back(MakeUnique<DiskEvent>(event, *disk));
}
void OnFormatEvent(DiskMountManager::FormatEvent event,
chromeos::FormatError error_code, chromeos::FormatError error_code,
const std::string& device_path)); const std::string& device_path) override {
events_.push_back(MakeUnique<FormatEvent>(event, error_code, device_path));
}
void OnMountEvent(
DiskMountManager::MountEvent event,
chromeos::MountError error_code,
const DiskMountManager::MountPointInfo& mount_point) override {
// Take a snapshot (copy) of a Disk object at the time of invocation.
// It can be verified later besides the arguments.
events_.push_back(MakeUnique<MountEvent>(
event, error_code, mount_point,
*manager_->disks().find(mount_point.source_path)->second));
}
// Gets invocation history to be verified by testcases.
// Verifies if the |index|th invocation is OnDeviceEvent() and returns
// details.
const DeviceEvent& GetDeviceEvent(size_t index) {
DCHECK_GT(events_.size(), index);
DCHECK_EQ(DEVICE_EVENT, events_[index]->type());
return static_cast<const DeviceEvent&>(*events_[index]);
}
// Verifies if the |index|th invocation is OnDiskEvent() and returns details.
const DiskEvent& GetDiskEvent(size_t index) {
DCHECK_GT(events_.size(), index);
DCHECK_EQ(DISK_EVENT, events_[index]->type());
return static_cast<const DiskEvent&>(*events_[index]);
}
// Verifies if the |index|th invocation is OnFormatEvent() and returns
// details.
const FormatEvent& GetFormatEvent(size_t index) {
DCHECK_GT(events_.size(), index);
DCHECK_EQ(FORMAT_EVENT, events_[index]->type());
return static_cast<const FormatEvent&>(*events_[index]);
}
// Verifies if the |index|th invocation is OnMountEvent() and returns details.
const MountEvent& GetMountEvent(size_t index) {
DCHECK_GT(events_.size(), index);
DCHECK_EQ(MOUNT_EVENT, events_[index]->type());
return static_cast<const MountEvent&>(*events_[index]);
}
// Returns number of callback invocations happened so far.
size_t GetEventCount() { return events_.size(); }
// Counts the number of |MountEvent| recorded so far that matches the given
// condition.
size_t CountMountEvents(DiskMountManager::MountEvent mount_event_type,
chromeos::MountError error_code,
const std::string& mount_path) {
size_t num_matched = 0;
for (const auto& it : events_) {
if (it->type() != MOUNT_EVENT)
continue;
const MountEvent& mount_event = static_cast<const MountEvent&>(*it);
if (mount_event.event == mount_event_type &&
mount_event.error_code == error_code &&
mount_event.mount_point.mount_path == mount_path)
num_matched++;
}
return num_matched;
}
// Counts the number of |FormatEvent| recorded so far that matches with
// |format_event|.
size_t CountFormatEvents(const FormatEvent& exptected_format_event) {
size_t num_matched = 0;
for (const auto& it : events_) {
if (it->type() != FORMAT_EVENT)
continue;
if (static_cast<const FormatEvent&>(*it) == exptected_format_event)
num_matched++;
}
return num_matched;
}
private:
// Pointer to the manager object to which this |Observer| is registered.
const DiskMountManager* manager_;
// Records all invocations.
std::vector<std::unique_ptr<ObserverEvent>> events_;
}; };
// Expect |is_read_only| value of a disk object keyed by |source_path|. // Shift operators of ostream.
void ExpectDiskReadOnly(const DiskMountManager* manager, // Needed to print values in case of EXPECT_* failure in gtest.
const std::string& source_path, std::ostream& operator<<(std::ostream& stream,
bool expected) { const DeviceEvent& device_event) {
EXPECT_EQ(expected, return stream << device_event.DebugString();
manager->disks().find(source_path)->second->is_read_only()); }
std::ostream& operator<<(std::ostream& stream, const DiskEvent& disk_event) {
return stream << disk_event.DebugString();
}
std::ostream& operator<<(std::ostream& stream,
const FormatEvent& format_event) {
return stream << format_event.DebugString();
}
std::ostream& operator<<(std::ostream& stream, const MountEvent& mount_event) {
return stream << mount_event.DebugString();
} }
class DiskMountManagerTest : public testing::Test { class DiskMountManagerTest : public testing::Test {
...@@ -196,12 +426,14 @@ class DiskMountManagerTest : public testing::Test { ...@@ -196,12 +426,14 @@ class DiskMountManagerTest : public testing::Test {
InitDisksAndMountPoints(); InitDisksAndMountPoints();
DiskMountManager::GetInstance()->AddObserver(&observer_); observer_.reset(
new MockDiskMountManagerObserver(DiskMountManager::GetInstance()));
DiskMountManager::GetInstance()->AddObserver(observer_.get());
} }
// Shuts down dbus thread manager and disk moutn manager used in the test. // Shuts down dbus thread manager and disk moutn manager used in the test.
void TearDown() override { void TearDown() override {
DiskMountManager::GetInstance()->RemoveObserver(&observer_); DiskMountManager::GetInstance()->RemoveObserver(observer_.get());
DiskMountManager::Shutdown(); DiskMountManager::Shutdown();
DBusThreadManager::Shutdown(); DBusThreadManager::Shutdown();
} }
...@@ -265,39 +497,38 @@ class DiskMountManagerTest : public testing::Test { ...@@ -265,39 +497,38 @@ class DiskMountManagerTest : public testing::Test {
protected: protected:
chromeos::FakeCrosDisksClient* fake_cros_disks_client_; chromeos::FakeCrosDisksClient* fake_cros_disks_client_;
MockDiskMountManagerObserver observer_; std::unique_ptr<MockDiskMountManagerObserver> observer_;
base::MessageLoopForUI message_loop_; base::MessageLoopForUI message_loop_;
}; };
// Tests that the observer gets notified on attempt to format non existent mount // Tests that the observer gets notified on attempt to format non existent mount
// point. // point.
TEST_F(DiskMountManagerTest, Format_NotMounted) { TEST_F(DiskMountManagerTest, Format_NotMounted) {
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN,
"/mount/non_existent"))
.Times(1);
DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent"); DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
ASSERT_EQ(1U, observer_->GetEventCount());
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/mount/non_existent"),
observer_->GetFormatEvent(0));
} }
// Tests that the observer gets notified on attempt to format read-only mount // Tests that the observer gets notified on attempt to format read-only mount
// point. // point.
TEST_F(DiskMountManagerTest, Format_ReadOnly) { TEST_F(DiskMountManagerTest, Format_ReadOnly) {
EXPECT_CALL(observer_,
OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_DEVICE_NOT_ALLOWED,
kReadOnlyMountpath))
.Times(1);
DiskMountManager::GetInstance()->FormatMountedDevice(kReadOnlyMountpath); DiskMountManager::GetInstance()->FormatMountedDevice(kReadOnlyMountpath);
ASSERT_EQ(1U, observer_->GetEventCount());
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_DEVICE_NOT_ALLOWED,
kReadOnlyMountpath),
observer_->GetFormatEvent(0));
} }
// Tests that it is not possible to format archive mount point. // Tests that it is not possible to format archive mount point.
TEST_F(DiskMountManagerTest, Format_Archive) { TEST_F(DiskMountManagerTest, Format_Archive) {
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN,
"/archive/source_path"))
.Times(1);
DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
ASSERT_EQ(1U, observer_->GetEventCount());
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/archive/source_path"),
observer_->GetFormatEvent(0));
} }
// Tests that format fails if the device cannot be unmounted. // Tests that format fails if the device cannot be unmounted.
...@@ -306,25 +537,6 @@ TEST_F(DiskMountManagerTest, Format_FailToUnmount) { ...@@ -306,25 +537,6 @@ TEST_F(DiskMountManagerTest, Format_FailToUnmount) {
// In this test unmount will fail, and there should be no attempt to // In this test unmount will fail, and there should be no attempt to
// format the device. // format the device.
// Set up expectations for observer mock.
// Observer should be notified that unmount attempt fails and format task
// failed to start.
{
InSequence s;
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_INTERNAL,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN,
"/device/source_path"))
.Times(1);
}
fake_cros_disks_client_->MakeUnmountFail(); fake_cros_disks_client_->MakeUnmountFail();
// Start test. // Start test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
...@@ -332,6 +544,17 @@ TEST_F(DiskMountManagerTest, Format_FailToUnmount) { ...@@ -332,6 +544,17 @@ TEST_F(DiskMountManagerTest, Format_FailToUnmount) {
// Cros disks will respond asynchronoulsy, so let's drain the message loop. // Cros disks will respond asynchronoulsy, so let's drain the message loop.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
// Observer should be notified that unmount attempt fails and format task
// failed to start.
ASSERT_EQ(2U, observer_->GetEventCount());
const MountEvent& mount_event = observer_->GetMountEvent(0);
EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
EXPECT_EQ(chromeos::MOUNT_ERROR_INTERNAL, mount_event.error_code);
EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
observer_->GetFormatEvent(1));
EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count()); EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
EXPECT_EQ("/device/mount_path", EXPECT_EQ("/device/mount_path",
fake_cros_disks_client_->last_unmount_device_path()); fake_cros_disks_client_->last_unmount_device_path());
...@@ -350,25 +573,6 @@ TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) { ...@@ -350,25 +573,6 @@ TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) {
// In this test, unmount will succeed, but call to Format method will // In this test, unmount will succeed, but call to Format method will
// fail. // fail.
// Set up expectations for observer mock.
// Observer should be notified that the device was unmounted and format task
// failed to start.
{
InSequence s;
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN,
"/device/source_path"))
.Times(1);
}
fake_cros_disks_client_->MakeFormatFail(); fake_cros_disks_client_->MakeFormatFail();
// Start the test. // Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
...@@ -376,6 +580,18 @@ TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) { ...@@ -376,6 +580,18 @@ TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) {
// Cros disks will respond asynchronoulsy, so let's drain the message loop. // Cros disks will respond asynchronoulsy, so let's drain the message loop.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
// Observer should be notified that the device was unmounted and format task
// failed to start.
ASSERT_EQ(2U, observer_->GetEventCount());
const MountEvent& mount_event = observer_->GetMountEvent(0);
EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, mount_event.error_code);
EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
observer_->GetFormatEvent(1));
EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count()); EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
EXPECT_EQ("/device/mount_path", EXPECT_EQ("/device/mount_path",
fake_cros_disks_client_->last_unmount_device_path()); fake_cros_disks_client_->last_unmount_device_path());
...@@ -397,7 +613,16 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) { ...@@ -397,7 +613,16 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) {
// CrosDisksClient will report that the format process for the first request // CrosDisksClient will report that the format process for the first request
// is successfully started. // is successfully started.
// Set up expectations for observer mock. fake_cros_disks_client_->set_unmount_listener(
base::Bind(&FakeCrosDisksClient::MakeUnmountFail,
base::Unretained(fake_cros_disks_client_)));
// Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
// Cros disks will respond asynchronoulsy, so let's drain the message loop.
base::RunLoop().RunUntilIdle();
// The observer should get a FORMAT_STARTED event for one format request and a // The observer should get a FORMAT_STARTED event for one format request and a
// FORMAT_COMPLETED with an error code for the other format request. The // FORMAT_COMPLETED with an error code for the other format request. The
// formatting will be started only for the first request. // formatting will be started only for the first request.
...@@ -407,36 +632,18 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) { ...@@ -407,36 +632,18 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) {
// //
// Note that in this test the format completion signal will not be simulated, // Note that in this test the format completion signal will not be simulated,
// so the observer should not get FORMAT_COMPLETED signal. // so the observer should not get FORMAT_COMPLETED signal.
{
InSequence s;
EXPECT_CALL(observer_, ASSERT_EQ(3U, observer_->GetEventCount());
OnMountEvent(DiskMountManager::UNMOUNTING, const MountEvent& mount_event = observer_->GetMountEvent(0);
chromeos::MOUNT_ERROR_NONE, EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
Field(&DiskMountManager::MountPointInfo::mount_path, EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, mount_event.error_code);
"/device/mount_path"))) EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
.Times(1); EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED, observer_->GetFormatEvent(1));
chromeos::FORMAT_ERROR_UNKNOWN, EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
"/device/source_path")) chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
.Times(1); observer_->GetFormatEvent(2));
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(1);
}
fake_cros_disks_client_->set_unmount_listener(
base::Bind(&FakeCrosDisksClient::MakeUnmountFail,
base::Unretained(fake_cros_disks_client_)));
// Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
// Cros disks will respond asynchronoulsy, so let's drain the message loop.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count()); EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
EXPECT_EQ("/device/mount_path", EXPECT_EQ("/device/mount_path",
...@@ -453,37 +660,22 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) { ...@@ -453,37 +660,22 @@ TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) {
EXPECT_FALSE(HasMountPoint("/device/mount_path")); EXPECT_FALSE(HasMountPoint("/device/mount_path"));
} }
// Verifies a |MountEvent| with the given condition. This function only checks
// the |mount_path| in |MountPointInfo| to make sure to match the event with
// preceding mount invocations.
void VerifyMountEvent(const MountEvent& mount_event,
DiskMountManager::MountEvent mount_event_type,
chromeos::MountError error_code,
const std::string& mount_path) {
EXPECT_EQ(mount_event_type, mount_event.event);
EXPECT_EQ(error_code, mount_event.error_code);
EXPECT_EQ(mount_path, mount_event.mount_point.mount_path);
}
// Tests the case when the format process actually starts and fails. // Tests the case when the format process actually starts and fails.
TEST_F(DiskMountManagerTest, Format_FormatFails) { TEST_F(DiskMountManagerTest, Format_FormatFails) {
// Both unmount and format device cals are successful in this test. // Both unmount and format device cals are successful in this test.
// Set up expectations for observer mock.
// The observer should get notified that the device was unmounted and that
// formatting has started.
// After the formatting starts, the test will simulate failing
// FORMAT_COMPLETED signal, so the observer should also be notified the
// formatting has failed (FORMAT_COMPLETED event).
{
InSequence s;
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN,
"/device/source_path"))
.Times(1);
}
// Start the test. // Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
...@@ -508,6 +700,21 @@ TEST_F(DiskMountManagerTest, Format_FormatFails) { ...@@ -508,6 +700,21 @@ TEST_F(DiskMountManagerTest, Format_FormatFails) {
// soon). // soon).
fake_cros_disks_client_->SendFormatCompletedEvent( fake_cros_disks_client_->SendFormatCompletedEvent(
chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"); chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path");
// The observer should get notified that the device was unmounted and that
// formatting has started.
// After the formatting starts, the test will simulate failing
// FORMAT_COMPLETED signal, so the observer should also be notified the
// formatting has failed (FORMAT_COMPLETED event).
ASSERT_EQ(3U, observer_->GetEventCount());
VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE, "/device/mount_path");
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
observer_->GetFormatEvent(1));
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
observer_->GetFormatEvent(2));
} }
// Tests the case when formatting completes successfully. // Tests the case when formatting completes successfully.
...@@ -515,30 +722,6 @@ TEST_F(DiskMountManagerTest, Format_FormatSuccess) { ...@@ -515,30 +722,6 @@ TEST_F(DiskMountManagerTest, Format_FormatSuccess) {
// Set up cros disks client mocks. // Set up cros disks client mocks.
// Both unmount and format device cals are successful in this test. // Both unmount and format device cals are successful in this test.
// Set up expectations for observer mock.
// The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
// events (all of them without an error set).
{
InSequence s;
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(1);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(1);
}
// Start the test. // Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
...@@ -561,6 +744,18 @@ TEST_F(DiskMountManagerTest, Format_FormatSuccess) { ...@@ -561,6 +744,18 @@ TEST_F(DiskMountManagerTest, Format_FormatSuccess) {
// Simulate cros_disks reporting success. // Simulate cros_disks reporting success.
fake_cros_disks_client_->SendFormatCompletedEvent( fake_cros_disks_client_->SendFormatCompletedEvent(
chromeos::FORMAT_ERROR_NONE, "/device/source_path"); chromeos::FORMAT_ERROR_NONE, "/device/source_path");
// The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
// events (all of them without an error set).
ASSERT_EQ(3U, observer_->GetEventCount());
VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE, "/device/mount_path");
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
observer_->GetFormatEvent(1));
EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
observer_->GetFormatEvent(2));
} }
// Tests that it's possible to format the device twice in a row (this may not be // Tests that it's possible to format the device twice in a row (this may not be
...@@ -569,36 +764,6 @@ TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) { ...@@ -569,36 +764,6 @@ TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) {
// All unmount and format device cals are successful in this test. // All unmount and format device cals are successful in this test.
// Each of the should be made twice (once for each formatting task). // Each of the should be made twice (once for each formatting task).
// Set up expectations for observer mock.
// The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
// events (all of them without an error set) twice (once for each formatting
// task).
// Also, there should be a MOUNTING event when the device remounting is
// simulated.
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(2);
EXPECT_CALL(observer_, OnFormatEvent(DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE,
"/device/source_path"))
.Times(2);
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(2);
EXPECT_CALL(observer_,
OnMountEvent(DiskMountManager::MOUNTING,
chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
"/device/mount_path")))
.Times(1);
// Start the test. // Start the test.
DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path"); DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
...@@ -650,6 +815,29 @@ TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) { ...@@ -650,6 +815,29 @@ TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) {
// Simulate cros_disks reporting success. // Simulate cros_disks reporting success.
fake_cros_disks_client_->SendFormatCompletedEvent( fake_cros_disks_client_->SendFormatCompletedEvent(
chromeos::FORMAT_ERROR_NONE, "/device/source_path"); chromeos::FORMAT_ERROR_NONE, "/device/source_path");
// The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
// events (all of them without an error set) twice (once for each formatting
// task).
// Also, there should be a MOUNTING event when the device remounting is
// simulated.
EXPECT_EQ(7U, observer_->GetEventCount());
EXPECT_EQ(2U, observer_->CountFormatEvents(FormatEvent(
DiskMountManager::FORMAT_COMPLETED,
chromeos::FORMAT_ERROR_NONE, "/device/source_path")));
EXPECT_EQ(2U, observer_->CountFormatEvents(FormatEvent(
DiskMountManager::FORMAT_STARTED,
chromeos::FORMAT_ERROR_NONE, "/device/source_path")));
EXPECT_EQ(2U, observer_->CountMountEvents(DiskMountManager::UNMOUNTING,
chromeos::MOUNT_ERROR_NONE,
"/device/mount_path"));
EXPECT_EQ(1U, observer_->CountMountEvents(DiskMountManager::MOUNTING,
chromeos::MOUNT_ERROR_NONE,
"/device/mount_path"));
} }
TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) { TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) {
...@@ -662,27 +850,6 @@ TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) { ...@@ -662,27 +850,6 @@ TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) {
const std::string kMountPath1 = "/media/foo"; const std::string kMountPath1 = "/media/foo";
const std::string kMountPath2 = "/media/bar"; const std::string kMountPath2 = "/media/bar";
// Event handlers of observers should be called.
EXPECT_CALL(
observer_,
OnMountEvent(
DiskMountManager::MOUNTING, chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path, kMountPath1)));
// For the 2nd source, the disk (block device) is not read-only but the
// test will mount it in read-only mode.
// Observers query |disks_| from |DiskMountManager| in its event handler for
// a mount completion event. Therefore |disks_| must be updated with correct
// |read_only| value before notifying to observers.
EXPECT_CALL(
observer_,
OnMountEvent(
DiskMountManager::MOUNTING, chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path, kMountPath2)))
.WillOnce(InvokeWithoutArgs(
// Verify if the disk appears read-only at the time of notification
// to observers.
[&]() { ExpectDiskReadOnly(manager, kSourcePath2, true); }));
manager->MountPath(kSourcePath1, kSourceFormat, std::string(), manager->MountPath(kSourcePath1, kSourceFormat, std::string(),
chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_TYPE_DEVICE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE); chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
...@@ -697,6 +864,24 @@ TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) { ...@@ -697,6 +864,24 @@ TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) {
chromeos::MOUNT_ERROR_NONE, kSourcePath2, chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_ERROR_NONE, kSourcePath2, chromeos::MOUNT_TYPE_DEVICE,
kMountPath2); kMountPath2);
// Event handlers of observers should be called.
ASSERT_EQ(2U, observer_->GetEventCount());
VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::MOUNTING,
chromeos::MOUNT_ERROR_NONE, kMountPath1);
// For the 2nd source, the disk (block device) is not read-only but the
// test will mount it in read-only mode.
// Observers query |disks_| from |DiskMountManager| in its event handler for
// a mount completion event. Therefore |disks_| must be updated with correct
// |read_only| value before notifying to observers.
const MountEvent& secondMountEvent = observer_->GetMountEvent(1);
EXPECT_EQ(DiskMountManager::MOUNTING, secondMountEvent.event);
EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, secondMountEvent.error_code);
EXPECT_EQ(kMountPath2, secondMountEvent.mount_point.mount_path);
// Verify if the disk appears read-only at the time of notification to
// observers.
EXPECT_TRUE(secondMountEvent.disk->is_read_only());
// Verify the final state of manager->disks.
const DiskMountManager::DiskMap& disks = manager->disks(); const DiskMountManager::DiskMap& disks = manager->disks();
ASSERT_GT(disks.count(kSourcePath1), 0U); ASSERT_GT(disks.count(kSourcePath1), 0U);
EXPECT_FALSE(disks.find(kSourcePath1)->second->is_read_only()); EXPECT_FALSE(disks.find(kSourcePath1)->second->is_read_only());
...@@ -709,13 +894,6 @@ TEST_F(DiskMountManagerTest, MountPath_ReadOnlyDevice) { ...@@ -709,13 +894,6 @@ TEST_F(DiskMountManagerTest, MountPath_ReadOnlyDevice) {
const std::string kSourceFormat = std::string(); const std::string kSourceFormat = std::string();
const std::string kMountLabel = std::string(); // N/A for MOUNT_TYPE_DEVICE const std::string kMountLabel = std::string(); // N/A for MOUNT_TYPE_DEVICE
// Event handlers of observers should be called.
EXPECT_CALL(
observer_,
OnMountEvent(DiskMountManager::MOUNTING, chromeos::MOUNT_ERROR_NONE,
Field(&DiskMountManager::MountPointInfo::mount_path,
kReadOnlyMountpath)));
// Attempt to mount a read-only device in read-write mode. // Attempt to mount a read-only device in read-write mode.
manager->MountPath(kReadOnlyDeviceSource, kSourceFormat, std::string(), manager->MountPath(kReadOnlyDeviceSource, kSourceFormat, std::string(),
chromeos::MOUNT_TYPE_DEVICE, chromeos::MOUNT_TYPE_DEVICE,
...@@ -725,6 +903,10 @@ TEST_F(DiskMountManagerTest, MountPath_ReadOnlyDevice) { ...@@ -725,6 +903,10 @@ TEST_F(DiskMountManagerTest, MountPath_ReadOnlyDevice) {
chromeos::MOUNT_ERROR_NONE, kReadOnlyDeviceSource, chromeos::MOUNT_ERROR_NONE, kReadOnlyDeviceSource,
chromeos::MOUNT_TYPE_DEVICE, kReadOnlyMountpath); chromeos::MOUNT_TYPE_DEVICE, kReadOnlyMountpath);
// Event handlers of observers should be called.
ASSERT_EQ(1U, observer_->GetEventCount());
VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::MOUNTING,
chromeos::MOUNT_ERROR_NONE, kReadOnlyMountpath);
const DiskMountManager::DiskMap& disks = manager->disks(); const DiskMountManager::DiskMap& disks = manager->disks();
ASSERT_GT(disks.count(kReadOnlyDeviceSource), 0U); ASSERT_GT(disks.count(kReadOnlyDeviceSource), 0U);
// The mounted disk should preserve the read-only flag of the block device. // The mounted disk should preserve the read-only flag of the block device.
......
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