[shill] Enable Device objects to persist themselves to disk
BUG=chromium-os:17254
TEST=unit
Change-Id: Ia00bc2658e0fe03e13e399d7afab81cc09aa0195
Reviewed-on: http://gerrit.chromium.org/gerrit/5309
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/control_interface.h b/control_interface.h
index 680ac63..4e5204e 100644
--- a/control_interface.h
+++ b/control_interface.h
@@ -5,6 +5,11 @@
#ifndef SHILL_CONTROL_INTERFACE_
#define SHILL_CONTROL_INTERFACE_
+#include <algorithm>
+#include <string>
+
+#include <base/logging.h>
+
namespace shill {
class Device;
@@ -28,6 +33,11 @@
virtual ManagerAdaptorInterface *CreateManagerAdaptor(Manager *manager) = 0;
virtual ProfileAdaptorInterface *CreateProfileAdaptor(Profile *profile) = 0;
virtual ServiceAdaptorInterface *CreateServiceAdaptor(Service *service) = 0;
+
+ static void RpcIdToStorageId(std::string *rpc_id) {
+ CHECK(rpc_id);
+ std::replace(rpc_id->begin(), rpc_id->end(), '/', '_');
+ }
};
} // namespace shill
diff --git a/device.cc b/device.cc
index fed0824..51615b9 100644
--- a/device.cc
+++ b/device.cc
@@ -12,6 +12,7 @@
#include <base/logging.h>
#include <base/memory/ref_counted.h>
+#include <base/stringprintf.h>
#include <chromeos/dbus/service_constants.h>
#include "shill/control_interface.h"
@@ -25,11 +26,20 @@
#include "shill/rtnl_handler.h"
#include "shill/service.h"
#include "shill/shill_event.h"
+#include "shill/store_interface.h"
+using base::StringPrintf;
using std::string;
using std::vector;
namespace shill {
+
+// static
+const char Device::kStoragePowered[] = "Powered";
+
+// static
+const char Device::kStorageIPConfigs[] = "IPConfigs";
+
Device::Device(ControlInterface *control_interface,
EventDispatcher *dispatcher,
Manager *manager,
@@ -120,6 +130,12 @@
return adaptor_->GetRpcIdentifier();
}
+string Device::GetStorageIdentifier() {
+ string id = GetRpcIdentifier();
+ ControlInterface::RpcIdToStorageId(&id);
+ return id;
+}
+
const string& Device::FriendlyName() const {
return link_name_;
}
@@ -128,6 +144,25 @@
return unique_id_;
}
+bool Device::Load(StoreInterface *storage) {
+ const string id = GetStorageIdentifier();
+ if (!storage->ContainsGroup(id)) {
+ LOG(WARNING) << "Device is not available in the persistent store: " << id;
+ return false;
+ }
+ storage->GetBool(id, kStoragePowered, &powered_);
+ // TODO(cmasone): What does it mean to load an IPConfig identifier??
+ return true;
+}
+
+bool Device::Save(StoreInterface *storage) {
+ const string id = GetStorageIdentifier();
+ storage->SetBool(id, kStoragePowered, powered_);
+ if (ipconfig_.get())
+ storage->SetString(id, kStorageIPConfigs, SerializeIPConfigsForStorage());
+ return true;
+}
+
void Device::DestroyIPConfig() {
if (ipconfig_.get()) {
RTNLHandler::GetInstance()->RemoveInterfaceAddress(interface_index_,
@@ -164,6 +199,12 @@
}
}
+string Device::SerializeIPConfigsForStorage() {
+ return StringPrintf("%s:%s",
+ ipconfig_->GetStorageIdentifier().c_str(),
+ ipconfig_->type().c_str());
+}
+
vector<string> Device::AvailableIPConfigs() {
string id = (ipconfig_.get() ? ipconfig_->GetRpcIdentifier() : string());
return vector<string>(1, id);
diff --git a/device.h b/device.h
index 069b158..08548e6 100644
--- a/device.h
+++ b/device.h
@@ -61,6 +61,7 @@
virtual void ConfigIP() {}
std::string GetRpcIdentifier();
+ std::string GetStorageIdentifier();
const std::string &link_name() const { return link_name_; }
int interface_index() const { return interface_index_; }
@@ -73,11 +74,15 @@
PropertyStore *store() { return &store_; }
+ bool Load(StoreInterface *storage);
+ bool Save(StoreInterface *storage);
+
protected:
FRIEND_TEST(DeviceTest, AcquireDHCPConfig);
FRIEND_TEST(DeviceTest, DestroyIPConfig);
FRIEND_TEST(DeviceTest, DestroyIPConfigNULL);
FRIEND_TEST(DeviceTest, GetProperties);
+ FRIEND_TEST(DeviceTest, Save);
// If there's an IP configuration in |ipconfig_|, releases the IP address and
// destroys the configuration instance.
@@ -111,9 +116,17 @@
private:
friend class DeviceAdaptorInterface;
+ static const char kStoragePowered[];
+ static const char kStorageIPConfigs[];
+
// Callback invoked on every IP configuration update.
void IPConfigUpdatedCallback(const IPConfigRefPtr &ipconfig, bool success);
+ // Right now, Devices reference IPConfigs directly when persisted to disk
+ // It's not clear that this makes sense long-term, but that's how it is now.
+ // This call generates a string in the right format for this persisting.
+ std::string SerializeIPConfigsForStorage();
+
std::vector<std::string> AvailableIPConfigs();
std::string GetRpcConnectionIdentifier();
diff --git a/device_unittest.cc b/device_unittest.cc
index 8d5c2cc..8142277 100644
--- a/device_unittest.cc
+++ b/device_unittest.cc
@@ -20,6 +20,7 @@
#include "shill/mock_control.h"
#include "shill/mock_device.h"
#include "shill/mock_glib.h"
+#include "shill/mock_store.h"
#include "shill/property_store_unittest.h"
#include "shill/shill_event.h"
@@ -27,6 +28,7 @@
using std::string;
using std::vector;
using ::testing::_;
+using ::testing::AtLeast;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Test;
@@ -122,4 +124,27 @@
EXPECT_TRUE(device_->ipconfig_->update_callback_.get());
}
+TEST_F(DeviceTest, Load) {
+ NiceMock<MockStore> storage;
+ const string id = device_->GetStorageIdentifier();
+ EXPECT_CALL(storage, ContainsGroup(id)).WillOnce(Return(true));
+ EXPECT_CALL(storage, GetBool(id, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(device_->Load(&storage));
+}
+
+TEST_F(DeviceTest, Save) {
+ NiceMock<MockStore> storage;
+ const string id = device_->GetStorageIdentifier();
+ device_->ipconfig_ = new IPConfig(&control_interface_, kDeviceName);
+ EXPECT_CALL(storage, SetString(id, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(storage, SetBool(id, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(device_->Save(&storage));
+}
+
} // namespace shill
diff --git a/ipconfig.cc b/ipconfig.cc
index cb652f9..8b45703 100644
--- a/ipconfig.cc
+++ b/ipconfig.cc
@@ -4,8 +4,6 @@
#include "shill/ipconfig.h"
-#include <algorithm>
-
#include <base/logging.h>
#include <chromeos/dbus/service_constants.h>
@@ -19,7 +17,7 @@
namespace shill {
// static
-const char IPConfig::kStorageType[] = "Mode";
+const char IPConfig::kStorageType[] = "Method";
// static
const char IPConfig::kType[] = "ip";
// static
@@ -74,6 +72,12 @@
return adaptor_->GetRpcIdentifier();
}
+string IPConfig::GetStorageIdentifier() {
+ string id = GetRpcIdentifier();
+ ControlInterface::RpcIdToStorageId(&id);
+ return id;
+}
+
bool IPConfig::RequestIP() {
return false;
}
@@ -115,10 +119,4 @@
update_callback_.reset(callback);
}
-string IPConfig::GetStorageIdentifier() {
- string id = adaptor_->GetRpcIdentifier();
- std::replace(id.begin(), id.end(), '/', '_');
- return id;
-}
-
} // namespace shill
diff --git a/ipconfig.h b/ipconfig.h
index 8feee05..de4f32b 100644
--- a/ipconfig.h
+++ b/ipconfig.h
@@ -58,6 +58,7 @@
uint serial() const { return serial_; }
std::string GetRpcIdentifier();
+ std::string GetStorageIdentifier();
// Registers a callback that's executed every time the configuration
// properties change. Takes ownership of |callback|. Pass NULL to remove a
@@ -109,7 +110,6 @@
scoped_ptr<Callback2<const IPConfigRefPtr&, bool>::Type> update_callback_;
void Init();
- std::string GetStorageIdentifier();
DISALLOW_COPY_AND_ASSIGN(IPConfig);
};