PM: Add a DBus backend to the shill provider.
This change integrates the necessary logic for the shill provider to
actually talk to shill over DBus.
* RealShillProviders now takes a DbusInterface object. PolicyManager and
RealState were extended to propagate this object, accordingly.
* New provider_utils and general glib_utils modules.
* Minor touch-ups: removal of redundant includes and unwarranted 'using'
clauses.
BUG=chromium:338585
TEST=Unit tests.
Change-Id: I4082b845557eff2a02a928c60c348dde0e784a2c
Reviewed-on: https://chromium-review.googlesource.com/189045
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/policy_manager/fake_shill_provider.h b/policy_manager/fake_shill_provider.h
index f75ef2c..b05a147 100644
--- a/policy_manager/fake_shill_provider.h
+++ b/policy_manager/fake_shill_provider.h
@@ -18,11 +18,11 @@
protected:
virtual bool DoInit() {
set_var_is_connected(
- new FakeVariable<bool>("is_connected", kVariableModeAsync));
+ new FakeVariable<bool>("is_connected", kVariableModePoll));
set_var_conn_type(
- new FakeVariable<ShillConnType>("conn_type", kVariableModeAsync));
+ new FakeVariable<ShillConnType>("conn_type", kVariableModePoll));
set_var_conn_last_changed(
- new FakeVariable<Time>("conn_last_changed", kVariableModeAsync));
+ new FakeVariable<base::Time>("conn_last_changed", kVariableModePoll));
return true;
}
diff --git a/policy_manager/policy_manager.cc b/policy_manager/policy_manager.cc
index 146c177..027a4fe 100644
--- a/policy_manager/policy_manager.cc
+++ b/policy_manager/policy_manager.cc
@@ -17,12 +17,13 @@
return handle_ptr->get() && (*handle_ptr)->Init();
}
-bool PolicyManager::Init() {
+bool PolicyManager::Init(chromeos_update_engine::DBusWrapperInterface* dbus,
+ chromeos_update_engine::ClockInterface* clock) {
// TODO(deymo): Make it possible to replace this policy with a different
// implementation with a build-time flag.
policy_.reset(new ChromeOSPolicy());
- state_.reset(new RealState());
+ state_.reset(new RealState(dbus, clock));
return state_->Init();
}
diff --git a/policy_manager/policy_manager.h b/policy_manager/policy_manager.h
index 3966ec5..291ff32 100644
--- a/policy_manager/policy_manager.h
+++ b/policy_manager/policy_manager.h
@@ -11,6 +11,8 @@
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_ptr.h>
+#include "update_engine/clock_interface.h"
+#include "update_engine/dbus_wrapper_interface.h"
#include "update_engine/policy_manager/default_policy.h"
#include "update_engine/policy_manager/policy.h"
#include "update_engine/policy_manager/state.h"
@@ -24,7 +26,8 @@
// Initializes the PolicyManager instance. Returns whether the initialization
// succeeded.
- bool Init();
+ bool Init(chromeos_update_engine::DBusWrapperInterface* dbus,
+ chromeos_update_engine::ClockInterface* clock);
// PolicyRequest() evaluates the given policy with the provided arguments and
// returns the result. The |policy_method| is the pointer-to-method of the
diff --git a/policy_manager/policy_manager_unittest.cc b/policy_manager/policy_manager_unittest.cc
index 9e28ebc..fd43045 100644
--- a/policy_manager/policy_manager_unittest.cc
+++ b/policy_manager/policy_manager_unittest.cc
@@ -8,10 +8,11 @@
#include <base/bind.h>
#include <base/memory/scoped_ptr.h>
-#include <base/time.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include "update_engine/fake_clock.h"
+#include "update_engine/mock_dbus_wrapper.h"
#include "update_engine/policy_manager/default_policy.h"
#include "update_engine/policy_manager/mock_policy.h"
#include "update_engine/policy_manager/pmtest_utils.h"
@@ -20,24 +21,34 @@
using base::Bind;
using base::Callback;
-using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::MockDBusWrapper;
using std::pair;
using std::string;
using std::vector;
-
-using testing::_;
+using testing::NiceMock;
using testing::Return;
using testing::StrictMock;
+using testing::_;
+
+namespace {
+
+DBusGConnection* const kFakeConnection = reinterpret_cast<DBusGConnection*>(1);
+
+} // namespace
namespace chromeos_policy_manager {
class PmPolicyManagerTest : public ::testing::Test {
protected:
virtual void SetUp() {
- EXPECT_TRUE(pmut_.Init());
+ EXPECT_CALL(mock_dbus_, BusGet(_, _)).WillOnce(Return(kFakeConnection));
+ EXPECT_TRUE(pmut_.Init(&mock_dbus_, &fake_clock_));
}
- PolicyManager pmut_; // PolicyManager undert test.
+ NiceMock<MockDBusWrapper> mock_dbus_;
+ FakeClock fake_clock_;
+ PolicyManager pmut_;
};
// The FailingPolicy implements a single method and make it always fail. This
diff --git a/policy_manager/real_shill_provider.cc b/policy_manager/real_shill_provider.cc
index 279266d..60a953f 100644
--- a/policy_manager/real_shill_provider.cc
+++ b/policy_manager/real_shill_provider.cc
@@ -2,25 +2,206 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "update_engine/policy_manager/generic_variables.h"
#include "update_engine/policy_manager/real_shill_provider.h"
+#include <string>
+
+#include <base/logging.h>
+#include <chromeos/dbus/service_constants.h>
+
+#include "update_engine/policy_manager/generic_variables.h"
+#include "update_engine/utils.h"
+
+using std::string;
+
+namespace {
+
+// Looks up a key in a hash table and returns the string inside of the returned
+// GValue.
+const char* GetStrProperty(GHashTable* hash_table, const char* key) {
+ auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
+ return (gval ? g_value_get_string(gval) : NULL);
+}
+
+}; // namespace
+
+
namespace chromeos_policy_manager {
-// ShillProvider implementation.
+const ShillConnector::ConnStrToType ShillConnector::shill_conn_str_to_type[] = {
+ {shill::kTypeEthernet, kShillConnTypeEthernet},
+ {shill::kTypeWifi, kShillConnTypeWifi},
+ {shill::kTypeWimax, kShillConnTypeWimax},
+ {shill::kTypeBluetooth, kShillConnTypeBluetooth},
+ {shill::kTypeCellular, kShillConnTypeCellular},
+};
-bool RealShillProvider::DoInit(void) {
- // TODO(garnold) Initialize with actual (or fake) DBus connection.
+bool ShillConnector::Init() {
+ GError* error = NULL;
+ connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
+ if (!connection_) {
+ LOG(ERROR) << "Failed to initialize DBus connection: "
+ << chromeos_update_engine::utils::GetAndFreeGError(&error);
+ return false;
+ }
+ manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
+ shill::kFlimflamManagerInterface);
+ return true;
+}
+bool ShillConnector::GetDefaultConnection(bool* is_connected_p,
+ string* default_service_path_p) {
+ GHashTable* hash_table = NULL;
+ if (!GetProperties(manager_proxy_, &hash_table))
+ return false;
+ GValue* value = reinterpret_cast<GValue*>(
+ g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
+ const char* default_service_path_str = NULL;
+ bool success = false;
+ if (value && (default_service_path_str = g_value_get_string(value))) {
+ success = true;
+ *is_connected_p = strcmp(default_service_path_str, "/");
+ if (*is_connected_p)
+ *default_service_path_p = default_service_path_str;
+ }
+ g_hash_table_unref(hash_table);
+
+ return success;
+}
+
+bool ShillConnector::GetConnectionType(const string& service_path,
+ ShillConnType* conn_type_p) {
+ // Obtain a proxy for the service path.
+ DBusGProxy* service_proxy = GetProxy(service_path.c_str(),
+ shill::kFlimflamServiceInterface);
+
+ GHashTable* hash_table = NULL;
+ bool success = false;
+ bool is_vpn = false;
+ if (GetProperties(service_proxy, &hash_table)) {
+ const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
+ if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
+ is_vpn = true;
+ type_str = GetStrProperty(hash_table, shill::kPhysicalTechnologyProperty);
+ }
+ if (type_str) {
+ success = true;
+ *conn_type_p = ParseConnType(type_str);
+ }
+ g_hash_table_unref(hash_table);
+ }
+
+ if (!success) {
+ LOG(ERROR) << "Could not find type of "
+ << (is_vpn ? "physical connection underlying VPN " : "")
+ << "connection (" << service_path << ")";
+ }
+
+ dbus_->ProxyUnref(service_proxy);
+ return success;
+}
+
+DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) {
+ return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
+ path, interface);
+}
+
+ShillConnType ShillConnector::ParseConnType(const char* str) {
+ for (unsigned i = 0; i < arraysize(shill_conn_str_to_type); i++)
+ if (!strcmp(str, shill_conn_str_to_type[i].str))
+ return shill_conn_str_to_type[i].type;
+
+ return kShillConnTypeUnknown;
+}
+
+// Issues a GetProperties call through a given |proxy|, storing the result to
+// |*result_p|. Returns |true| on success.
+bool ShillConnector::GetProperties(DBusGProxy* proxy, GHashTable** result_p) {
+ GError* error = NULL;
+ if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
+ result_p)) {
+ LOG(ERROR) << "Calling shill via DBus proxy failed: "
+ << chromeos_update_engine::utils::GetAndFreeGError(&error);
+ return false;
+ }
+ return true;
+}
+
+// A variable returning whether or not we have a network connection.
+class IsConnectedVariable : public Variable<bool> {
+ public:
+ IsConnectedVariable(const string& name, ShillConnector* connector,
+ LastValueTracker<bool>* is_connected_tracker)
+ : Variable<bool>(name, kVariableModePoll),
+ connector_(connector),
+ is_connected_tracker_(is_connected_tracker) {}
+
+ protected:
+ virtual const bool* GetValue(base::TimeDelta timeout, string* errmsg) {
+ bool is_connected;
+ string default_service_path;
+ if (!connector_->GetDefaultConnection(&is_connected, &default_service_path))
+ return NULL;;
+
+ return new bool(is_connected_tracker_->Update(is_connected));
+ }
+
+ private:
+ ShillConnector* connector_;
+ LastValueTracker<bool>* is_connected_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsConnectedVariable);
+};
+
+// A variable returning the curent connection type.
+class ConnTypeVariable : public Variable<ShillConnType> {
+ public:
+ ConnTypeVariable(const string& name, ShillConnector* connector,
+ LastValueTracker<bool>* is_connected_tracker)
+ : Variable<ShillConnType>(name, kVariableModePoll),
+ connector_(connector),
+ is_connected_tracker_(is_connected_tracker) {}
+
+ protected:
+ virtual const ShillConnType* GetValue(base::TimeDelta timeout,
+ string* errmsg) {
+ bool is_connected;
+ string default_service_path;
+ ShillConnType conn_type;
+ if (!(connector_->GetDefaultConnection(&is_connected,
+ &default_service_path) &&
+ is_connected &&
+ connector_->GetConnectionType(default_service_path, &conn_type)))
+ return NULL;
+
+ is_connected_tracker_->Update(is_connected);
+ return new ShillConnType(conn_type);
+ }
+
+ private:
+ ShillConnector* connector_;
+ LastValueTracker<bool>* is_connected_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnTypeVariable);
+};
+
+// A real implementation of the ShillProvider.
+bool RealShillProvider::DoInit() {
+ // Initialize a DBus connection and obtain the shill manager proxy.
+ connector_.reset(new ShillConnector(dbus_));
+ if (!connector_->Init())
+ return false;
+
+ // Initialize variables.
set_var_is_connected(
- new CopyVariable<bool>("is_connected", kVariableModeAsync,
- is_connected_));
+ new IsConnectedVariable("is_connected", connector_.get(),
+ &is_connected_tracker_));
set_var_conn_type(
- new CopyVariable<ShillConnType>("conn_type", kVariableModeAsync,
- conn_type_));
+ new ConnTypeVariable("conn_type", connector_.get(),
+ &is_connected_tracker_));
set_var_conn_last_changed(
- new CopyVariable<Time>("conn_last_changed", kVariableModeAsync,
- conn_last_changed_));
+ new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll,
+ conn_last_changed_));
return true;
}
diff --git a/policy_manager/real_shill_provider.h b/policy_manager/real_shill_provider.h
index 1a120b7..26de44f 100644
--- a/policy_manager/real_shill_provider.h
+++ b/policy_manager/real_shill_provider.h
@@ -5,36 +5,124 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_SHILL_PROVIDER_H
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_SHILL_PROVIDER_H
+// TODO(garnold) Much of the functionality in this module was adapted from the
+// update engine's connection_manager. We need to make sure to deprecate use of
+// connection manager when the time comes.
+
+#include <string>
+
+#include <base/time.h>
+
+#include "update_engine/clock_interface.h"
+#include "update_engine/dbus_wrapper_interface.h"
#include "update_engine/policy_manager/shill_provider.h"
-using base::Time;
+using chromeos_update_engine::ClockInterface;
+using chromeos_update_engine::DBusWrapperInterface;
namespace chromeos_policy_manager {
+// A tracker for the last reported value. Whenever Update() is called with a new
+// value, the current time is written to a pointed time object.
+template<typename T>
+class LastValueTracker {
+ public:
+ LastValueTracker(ClockInterface* clock, T init_val, base::Time* time_p)
+ : clock_(clock), last_val_(init_val), time_p_(time_p) {}
+
+ const T& Update(const T& curr_val) {
+ if (curr_val != last_val_) {
+ last_val_ = curr_val;
+ *time_p_ = clock_->GetWallclockTime();
+ }
+ return curr_val;
+ }
+
+ private:
+ ClockInterface* const clock_;
+ T last_val_;
+ base::Time* time_p_;
+};
+
+// A DBus connector for making shill queries.
+class ShillConnector {
+ public:
+ ShillConnector(DBusWrapperInterface* dbus) : dbus_(dbus) {}
+
+ ~ShillConnector() {
+ if (manager_proxy_)
+ dbus_->ProxyUnref(manager_proxy_);
+ }
+
+ // Initializes the DBus connector. Returns |true| on success.
+ bool Init();
+
+ // Obtains the default network connection, storing the connection status to
+ // |*is_connected_p| and (if connected) the service path for the default
+ // connection in |*default_service_path_p|. Returns |true| on success; |false|
+ // on failure, in which case no values are written.
+ bool GetDefaultConnection(bool* is_connected_p,
+ std::string* default_service_path_p);
+
+ // Obtains the type of a network connection described by |service_path|,
+ // storing it to |*conn_type_p|. Returns |true| on success; |false| on
+ // failure, in which case no value is written.
+ bool GetConnectionType(const std::string& service_path,
+ ShillConnType* conn_type_p);
+
+ private:
+ typedef struct {
+ const char *str;
+ ShillConnType type;
+ } ConnStrToType;
+
+ // A mapping from shill connection type strings to enum values.
+ static const ConnStrToType shill_conn_str_to_type[];
+
+ // The DBus interface and connection, and a shill manager proxy.
+ DBusWrapperInterface* dbus_;
+ DBusGConnection* connection_ = NULL;
+ DBusGProxy* manager_proxy_ = NULL;
+
+ // Return a DBus proxy for a given |path| and |interface| within shill.
+ DBusGProxy* GetProxy(const char* path, const char* interface);
+
+ // Converts a shill connection type string into a symbolic value.
+ ShillConnType ParseConnType(const char* str);
+
+ // Issues a GetProperties call through a given |proxy|, storing the result to
+ // |*result_p|. Returns |true| on success.
+ bool GetProperties(DBusGProxy* proxy, GHashTable** result_p);
+
+ DISALLOW_COPY_AND_ASSIGN(ShillConnector);
+};
+
// ShillProvider concrete implementation.
-//
-// TODO(garnold) Much of the functionality in this module was adapted from
-// connection_manager, with slight changes (annotated inline). We need to make
-// sure to deprecate use of connection manager when the time comes.
class RealShillProvider : public ShillProvider {
public:
- // TODO(garnold) This should take a DBus object for communicating with shill.
- RealShillProvider()
- : is_connected_(false), conn_type_(kShillConnTypeUnknown),
- conn_last_changed_(Time::Now()) {}
+ RealShillProvider(DBusWrapperInterface* dbus, ClockInterface* clock)
+ : conn_last_changed_(clock->GetWallclockTime()),
+ dbus_(dbus), clock_(clock),
+ is_connected_tracker_(clock, false, &conn_last_changed_) {}
protected:
virtual bool DoInit();
private:
- // Whether we have network connectivity.
- bool is_connected_;
-
- // The current network connection type as reported by shill.
- ShillConnType conn_type_;
-
// The time when the connection type last changed.
- Time conn_last_changed_;
+ base::Time conn_last_changed_;
+
+ // A shill DBus connector.
+ scoped_ptr<ShillConnector> connector_;
+
+ // The DBus interface object (mockable).
+ DBusWrapperInterface* const dbus_;
+
+ // A clock abstraction (mockable).
+ ClockInterface* const clock_;
+
+ // Tracker for the latest connection status.
+ LastValueTracker<bool> is_connected_tracker_;
DISALLOW_COPY_AND_ASSIGN(RealShillProvider);
};
diff --git a/policy_manager/real_shill_provider_unittest.cc b/policy_manager/real_shill_provider_unittest.cc
index 6bc544c..ded5d63 100644
--- a/policy_manager/real_shill_provider_unittest.cc
+++ b/policy_manager/real_shill_provider_unittest.cc
@@ -4,38 +4,208 @@
#include <base/memory/scoped_ptr.h>
#include <base/time.h>
+#include <chromeos/dbus/service_constants.h>
+#include <glib.h>
#include <gtest/gtest.h>
+#include "update_engine/fake_clock.h"
+#include "update_engine/mock_dbus_wrapper.h"
#include "update_engine/policy_manager/real_shill_provider.h"
#include "update_engine/policy_manager/pmtest_utils.h"
using base::Time;
using base::TimeDelta;
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::MockDBusWrapper;
+using std::pair;
+using testing::_;
+using testing::NiceMock;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::StrEq;
+using testing::StrictMock;
+
+namespace {
+
+// Fake dbus-glib objects. These should be different values, to ease diagnosis
+// of errors.
+DBusGConnection* const kFakeConnection = reinterpret_cast<DBusGConnection*>(1);
+DBusGProxy* const kFakeManagerProxy = reinterpret_cast<DBusGProxy*>(2);
+DBusGProxy* const kFakeEthernetServiceProxy = reinterpret_cast<DBusGProxy*>(3);
+DBusGProxy* const kFakeWifiServiceProxy = reinterpret_cast<DBusGProxy*>(4);
+DBusGProxy* const kFakeWimaxServiceProxy = reinterpret_cast<DBusGProxy*>(5);
+DBusGProxy* const kFakeBluetoothServiceProxy = reinterpret_cast<DBusGProxy*>(6);
+DBusGProxy* const kFakeCellularServiceProxy = reinterpret_cast<DBusGProxy*>(7);
+DBusGProxy* const kFakeVpnServiceProxy = reinterpret_cast<DBusGProxy*>(8);
+DBusGProxy* const kFakeUnknownServiceProxy = reinterpret_cast<DBusGProxy*>(9);
+
+// Fake service paths.
+const char* const kFakeEthernetServicePath = "/fake-ethernet-service";
+const char* const kFakeWifiServicePath = "/fake-wifi-service";
+const char* const kFakeWimaxServicePath = "/fake-wimax-service";
+const char* const kFakeBluetoothServicePath = "/fake-bluetooth-service";
+const char* const kFakeCellularServicePath = "/fake-cellular-service";
+const char* const kFakeVpnServicePath = "/fake-vpn-service";
+const char* const kFakeUnknownServicePath = "/fake-unknown-service";
+
+// Allocates, initializes and returns a string GValue object.
+GValue* GValueNewString(const char* str) {
+ GValue* gval = new GValue();
+ g_value_init(gval, G_TYPE_STRING);
+ g_value_set_string(gval, str);
+ return gval;
+}
+
+// Frees a GValue object and its allocated resources.
+void GValueFree(gpointer arg) {
+ auto gval = reinterpret_cast<GValue*>(arg);
+ g_value_unset(gval);
+ delete gval;
+}
+
+} // namespace
namespace chromeos_policy_manager {
class PmRealShillProviderTest : public ::testing::Test {
protected:
virtual void SetUp() {
- default_timeout_ = TimeDelta::FromSeconds(1);
-
// The provider initializes correctly.
- time_before_init_ = Time::Now();
- provider_.reset(new RealShillProvider());
- time_after_init_ = Time::Now();
+ fake_clock_.SetWallclockTime(init_time_);
+ // A DBus connection should only be obtained once.
+ EXPECT_CALL(mock_dbus_, BusGet(_, _)).WillOnce(Return(kFakeConnection));
+ provider_.reset(new RealShillProvider(&mock_dbus_, &fake_clock_));
PMTEST_ASSERT_NOT_NULL(provider_.get());
+ // A manager proxy should only be obtained once.
+ EXPECT_CALL(mock_dbus_, ProxyNewForName(
+ kFakeConnection, StrEq(shill::kFlimflamServiceName),
+ StrEq(shill::kFlimflamServicePath),
+ StrEq(shill::kFlimflamManagerInterface)))
+ .WillOnce(Return(kFakeManagerProxy));
ASSERT_TRUE(provider_->Init());
}
- TimeDelta default_timeout_;
- Time time_before_init_;
- Time time_after_init_;
+ virtual void TearDown() {
+ // Make sure the manager proxy gets unreffed (once).
+ EXPECT_CALL(mock_dbus_, ProxyUnref(kFakeManagerProxy)).WillOnce(Return());
+ provider_.reset();
+ // Verify and clear all expectations.
+ testing::Mock::VerifyAndClear(&mock_dbus_);
+ }
+
+ // Sets up a mock "GetProperties" call on |proxy| that returns a hash table
+ // containing |num_entries| entries formed by subsequent key/value pairs. Keys
+ // and values are plain C strings (const char*). Mock will be expected to call
+ // exactly once, unless |allow_multiple_calls| is true, in which case it's
+ // allowed to be called multiple times. Returns a pointer to a newly allocated
+ // hash table, which should be unreffed with g_hash_table_unref() when done.
+ GHashTable* MockGetProperties(DBusGProxy* proxy, bool allow_multiple_calls,
+ size_t num_entries,
+ pair<const char*, const char*>* key_val_pairs) {
+ // Allocate and populate the hash table.
+ auto properties = g_hash_table_new_full(g_str_hash, g_str_equal, free,
+ GValueFree);
+ for (size_t i = 0; i < num_entries; i++) {
+ g_hash_table_insert(properties, strdup(key_val_pairs[i].first),
+ GValueNewString(key_val_pairs[i].second));
+ }
+
+ // Set mock expectation and actions.
+ auto action = DoAll(SetArgPointee<3>(g_hash_table_ref(properties)),
+ Return(true));
+ if (allow_multiple_calls) {
+ EXPECT_CALL(mock_dbus_, ProxyCall_0_1(
+ proxy, StrEq(shill::kGetPropertiesFunction), _, _))
+ .WillRepeatedly(action);
+ } else {
+ EXPECT_CALL(mock_dbus_, ProxyCall_0_1(
+ proxy, StrEq(shill::kGetPropertiesFunction), _, _))
+ .WillOnce(action);
+ }
+
+ return properties;
+ }
+
+ // Programs the mock DBus interface to return an non-VPN service and ensures
+ // that the shill provider reads it correctly, including updating the last
+ // changed time on each of the queries.
+ void SetConnectionAndTestType(const char* service_path,
+ DBusGProxy* service_proxy,
+ const char* shill_type_str,
+ ShillConnType expected_conn_type) {
+ // Mock logic for returning a default service path.
+ pair<const char*, const char*> manager_pairs[] = {
+ {shill::kDefaultServiceProperty, service_path},
+ };
+ auto manager_properties = MockGetProperties(
+ kFakeManagerProxy, true, arraysize(manager_pairs), manager_pairs);
+
+ // Query the connection status, ensure last change time reported correctly.
+ const Time change_time = Time::Now();
+ fake_clock_.SetWallclockTime(change_time);
+ scoped_ptr<const bool> is_connected(
+ provider_->var_is_connected()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(is_connected.get());
+ EXPECT_TRUE(*is_connected);
+
+ scoped_ptr<const Time> conn_last_changed_1(
+ provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed_1.get());
+ EXPECT_EQ(change_time, *conn_last_changed_1);
+
+ // Mock logic for querying the type of the default service.
+ EXPECT_CALL(mock_dbus_, ProxyNewForName(
+ kFakeConnection, StrEq(shill::kFlimflamServiceName),
+ StrEq(service_path),
+ StrEq(shill::kFlimflamServiceInterface)))
+ .WillOnce(Return(service_proxy));
+ EXPECT_CALL(mock_dbus_, ProxyUnref(service_proxy))
+ .WillOnce(Return());
+ pair<const char*, const char*> service_pairs[] = {
+ {shill::kTypeProperty, shill_type_str},
+ };
+ auto service_properties = MockGetProperties(
+ service_proxy, false, arraysize(service_pairs),
+ service_pairs);
+
+ // Query the connection type, ensure last change time reported correctly.
+ fake_clock_.SetWallclockTime(change_time + TimeDelta::FromSeconds(5));
+ scoped_ptr<const ShillConnType> conn_type(
+ provider_->var_conn_type()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_type.get());
+ EXPECT_EQ(expected_conn_type, *conn_type);
+
+ scoped_ptr<const Time> conn_last_changed_2(
+ provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed_2.get());
+ EXPECT_EQ(change_time, *conn_last_changed_2);
+
+ // Release properties hash tables.
+ g_hash_table_unref(service_properties);
+ g_hash_table_unref(manager_properties);
+ }
+
+ const TimeDelta default_timeout_ = TimeDelta::FromSeconds(1);
+ const Time init_time_ = Time::Now();
+ StrictMock<MockDBusWrapper> mock_dbus_;
+ FakeClock fake_clock_;
scoped_ptr<RealShillProvider> provider_;
};
+// Programs the mock DBus interface to indicate no default connection; this is
+// in line with the default values the variables should be initialized with, and
+// so the last changed time should not be updated. Also note that reading the
+// connection type should not induce getting of a per-service proxy, as no
+// default service is reported.
+TEST_F(PmRealShillProviderTest, ReadDefaultValues) {
+ // Mock logic for returning no default connection.
+ pair<const char*, const char*> manager_pairs[] = {
+ {shill::kDefaultServiceProperty, "/"},
+ };
+ auto manager_properties = MockGetProperties(
+ kFakeManagerProxy, true, arraysize(manager_pairs), manager_pairs);
-TEST_F(PmRealShillProviderTest, DefaultValues) {
- // Tests that initial values were set correctly.
+ // Query the provider variables.
scoped_ptr<const bool> is_connected(
provider_->var_is_connected()->GetValue(default_timeout_, NULL));
PMTEST_ASSERT_NOT_NULL(is_connected.get());
@@ -43,14 +213,100 @@
scoped_ptr<const ShillConnType> conn_type(
provider_->var_conn_type()->GetValue(default_timeout_, NULL));
- PMTEST_ASSERT_NOT_NULL(conn_type.get());
- EXPECT_EQ(kShillConnTypeUnknown, *conn_type);
+ PMTEST_ASSERT_NULL(conn_type.get());
scoped_ptr<const Time> conn_last_changed(
provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
PMTEST_ASSERT_NOT_NULL(conn_last_changed.get());
- EXPECT_LE(time_before_init_, *conn_last_changed);
- EXPECT_GE(time_after_init_, *conn_last_changed);
+ EXPECT_EQ(init_time_, *conn_last_changed);
+
+ // Release properties hash table.
+ g_hash_table_unref(manager_properties);
+}
+
+// Test that Ethernet connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaEthernet) {
+ SetConnectionAndTestType(kFakeEthernetServicePath,
+ kFakeEthernetServiceProxy,
+ shill::kTypeEthernet,
+ kShillConnTypeEthernet);
+}
+
+// Test that Wifi connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaWifi) {
+ SetConnectionAndTestType(kFakeWifiServicePath,
+ kFakeWifiServiceProxy,
+ shill::kTypeWifi,
+ kShillConnTypeWifi);
+}
+
+// Test that Wimax connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaWimax) {
+ SetConnectionAndTestType(kFakeWimaxServicePath,
+ kFakeWimaxServiceProxy,
+ shill::kTypeWimax,
+ kShillConnTypeWimax);
+}
+
+// Test that Bluetooth connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaBluetooth) {
+ SetConnectionAndTestType(kFakeBluetoothServicePath,
+ kFakeBluetoothServiceProxy,
+ shill::kTypeBluetooth,
+ kShillConnTypeBluetooth);
+}
+
+// Test that Cellular connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaCellular) {
+ SetConnectionAndTestType(kFakeCellularServicePath,
+ kFakeCellularServiceProxy,
+ shill::kTypeCellular,
+ kShillConnTypeCellular);
+}
+
+// Test that an unknown connection is identified as such.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaUnknown) {
+ SetConnectionAndTestType(kFakeUnknownServicePath,
+ kFakeUnknownServiceProxy,
+ "FooConnectionType",
+ kShillConnTypeUnknown);
+}
+
+// Tests that VPN connection is identified correctly.
+TEST_F(PmRealShillProviderTest, ReadChangedValuesConnectedViaVpn) {
+ // Mock logic for returning a default service path and its type.
+ pair<const char*, const char*> manager_pairs[] = {
+ {shill::kDefaultServiceProperty, kFakeVpnServicePath},
+ };
+ auto manager_properties = MockGetProperties(
+ kFakeManagerProxy, false, arraysize(manager_pairs), manager_pairs);
+ EXPECT_CALL(mock_dbus_, ProxyNewForName(
+ kFakeConnection, StrEq(shill::kFlimflamServiceName),
+ StrEq(kFakeVpnServicePath), StrEq(shill::kFlimflamServiceInterface)))
+ .WillOnce(Return(kFakeVpnServiceProxy));
+ EXPECT_CALL(mock_dbus_, ProxyUnref(kFakeVpnServiceProxy)).WillOnce(Return());
+ pair<const char*, const char*> service_pairs[] = {
+ {shill::kTypeProperty, shill::kTypeVPN},
+ {shill::kPhysicalTechnologyProperty, shill::kTypeWifi},
+ };
+ auto service_properties = MockGetProperties(
+ kFakeVpnServiceProxy, false, arraysize(service_pairs), service_pairs);
+
+ // Query the connection type, ensure last change time reported correctly.
+ fake_clock_.SetWallclockTime(Time::Now());
+ scoped_ptr<const ShillConnType> conn_type(
+ provider_->var_conn_type()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_type.get());
+ EXPECT_EQ(kShillConnTypeWifi, *conn_type);
+
+ scoped_ptr<const Time> conn_last_changed(
+ provider_->var_conn_last_changed()->GetValue(default_timeout_, NULL));
+ PMTEST_ASSERT_NOT_NULL(conn_last_changed.get());
+ EXPECT_EQ(fake_clock_.GetWallclockTime(), *conn_last_changed);
+
+ // Release properties hash tables.
+ g_hash_table_unref(service_properties);
+ g_hash_table_unref(manager_properties);
}
} // namespace chromeos_policy_manager
diff --git a/policy_manager/real_state.cc b/policy_manager/real_state.cc
index 90b0b3d..4e140d6 100644
--- a/policy_manager/real_state.cc
+++ b/policy_manager/real_state.cc
@@ -2,15 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "update_engine/policy_manager/real_state.h"
+
#include "update_engine/policy_manager/real_random_provider.h"
#include "update_engine/policy_manager/real_shill_provider.h"
-#include "update_engine/policy_manager/real_state.h"
namespace chromeos_policy_manager {
-RealState::RealState() {
+// TODO(garnold) We should be injecting actual provider objects here.
+RealState::RealState(chromeos_update_engine::DBusWrapperInterface* dbus,
+ chromeos_update_engine::ClockInterface* clock) {
set_random_provider(new RealRandomProvider());
- set_shill_provider(new RealShillProvider());
+ set_shill_provider(new RealShillProvider(dbus, clock));
}
} // namespace chromeos_policy_manager
diff --git a/policy_manager/real_state.h b/policy_manager/real_state.h
index b46126e..808a692 100644
--- a/policy_manager/real_state.h
+++ b/policy_manager/real_state.h
@@ -5,6 +5,8 @@
#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_STATE_H
#define CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_REAL_STATE_H
+#include "update_engine/clock_interface.h"
+#include "update_engine/dbus_wrapper_interface.h"
#include "update_engine/policy_manager/state.h"
namespace chromeos_policy_manager {
@@ -12,7 +14,8 @@
// State implementation class.
class RealState : public State {
public:
- RealState();
+ RealState(chromeos_update_engine::DBusWrapperInterface* dbus,
+ chromeos_update_engine::ClockInterface* clock);
~RealState() {}
private:
diff --git a/policy_manager/real_state_unittest.cc b/policy_manager/real_state_unittest.cc
index c0249d9..48491d5 100644
--- a/policy_manager/real_state_unittest.cc
+++ b/policy_manager/real_state_unittest.cc
@@ -4,13 +4,30 @@
#include <gtest/gtest.h>
+#include "update_engine/fake_clock.h"
+#include "update_engine/mock_dbus_wrapper.h"
#include "update_engine/policy_manager/real_state.h"
#include "update_engine/policy_manager/pmtest_utils.h"
+using chromeos_update_engine::FakeClock;
+using chromeos_update_engine::MockDBusWrapper;
+using testing::_;
+using testing::NiceMock;
+using testing::Return;
+
+namespace {
+
+DBusGConnection* const kFakeConnection = reinterpret_cast<DBusGConnection*>(1);
+
+} // namespace
+
namespace chromeos_policy_manager {
TEST(PmRealStateTest, InitTest) {
- RealState state;
+ NiceMock<MockDBusWrapper> mock_dbus;
+ FakeClock fake_clock;
+ EXPECT_CALL(mock_dbus, BusGet(_, _)).WillOnce(Return(kFakeConnection));
+ RealState state(&mock_dbus, &fake_clock);
EXPECT_TRUE(state.Init());
// Check that the providers are being initialized.
PMTEST_ASSERT_NOT_NULL(state.random_provider());
diff --git a/policy_manager/shill_provider.h b/policy_manager/shill_provider.h
index 12f15a2..4423f78 100644
--- a/policy_manager/shill_provider.h
+++ b/policy_manager/shill_provider.h
@@ -11,8 +11,6 @@
#include "update_engine/policy_manager/provider.h"
#include "update_engine/policy_manager/variable.h"
-using base::Time;
-
namespace chromeos_policy_manager {
// TODO(garnold) Adapted from connection_manager.h.
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index 28a9fb2..822ab3b 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -141,7 +141,9 @@
friend class PmRealRandomProviderTest;
FRIEND_TEST(PmRealRandomProviderTest, GetRandomValues);
friend class PmRealShillProviderTest;
- FRIEND_TEST(PmRealShillProviderTest, DefaultValues);
+ FRIEND_TEST(PmRealShillProviderTest, ReadDefaultValues);
+ FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedViaEthernet);
+ FRIEND_TEST(PmRealShillProviderTest, ReadChangedValuesConnectedViaVpn);
Variable(const std::string& name, VariableMode mode)
: BaseVariable(name, mode) {}