shill: Create mockable ModemManagerProxy on appearance of new ModemManagers.

BUG=chromium-os:17649
TEST=unit tests, tested on device

Change-Id: Id9e6500168d63493eb94bd7939e379b964bef063
Reviewed-on: http://gerrit.chromium.org/gerrit/4269
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
diff --git a/Makefile b/Makefile
index 855a094..fc2cbeb 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,6 @@
 # disable some errors, which occur repeateadly the dbus-c++ headers.
 CXXFLAGS += -Wno-ignored-qualifiers -Wno-unused
 CPPFLAGS ?= -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-AR ?= ar
 PKG_CONFIG ?= pkg-config
 DBUSXX_XML2CPP = dbusxx-xml2cpp
 
@@ -25,7 +24,6 @@
 	gdk-2.0 gtk+-2.0)
 
 TEST_LIBS = $(BASE_LIBS) -lgmock -lgtest
-TEST_INCLUDE_DIRS = $(INCLUDE_DIRS)
 TEST_LIB_DIRS = $(LIB_DIRS)
 
 DBUS_ADAPTOR_HEADERS = \
@@ -37,6 +35,7 @@
 
 DBUS_PROXY_HEADERS = \
 	dhcpcd.h \
+	mm.h \
 	supplicant-bss.h \
 	supplicant-interface.h \
 	supplicant-network.h \
@@ -75,9 +74,11 @@
 	manager_dbus_adaptor.o \
 	modem_info.o \
 	modem_manager.o \
+	modem_manager_proxy.o \
 	profile.o \
 	profile_dbus_adaptor.o \
 	property_store.o \
+	proxy_factory.o \
 	rtnl_handler.o \
 	rtnl_listener.o \
 	service.o \
@@ -129,8 +130,13 @@
 	testrunner.o \
 	wifi_unittest.o
 
+.PHONY: all clean
+
 all: $(SHILL_BIN) $(TEST_BIN)
 
+mm.xml: $(SYSROOT)/usr/share/dbus-1/interfaces/org.freedesktop.ModemManager.xml
+	cat $< > $@
+
 $(DBUS_PROXY_HEADERS): %.h: %.xml
 	$(DBUSXX_XML2CPP) $< --proxy=$@
 
@@ -148,8 +154,7 @@
 
 $(TEST_BIN): CXXFLAGS += -DUNIT_TEST
 $(TEST_BIN): $(TEST_OBJS) $(SHILL_OBJS)
-	$(CXX) $(CXXFLAGS) $(TEST_INCLUDE_DIRS) $(TEST_LIB_DIRS) $(LDFLAGS) $^ \
-		$(TEST_LIBS) -o $@
+	$(CXX) $(CXXFLAGS) $(TEST_LIB_DIRS) $(LDFLAGS) $^ $(TEST_LIBS) -o $@
 
 clean:
-	rm -rf *.o $(DBUS_HEADERS) $(SHILL_BIN) $(TEST_BIN)
+	rm -rf *.o mm.xml $(DBUS_HEADERS) $(SHILL_BIN) $(TEST_BIN)
diff --git a/dhcpcd_proxy.h b/dhcpcd_proxy.h
index ebb61b5..672411a 100644
--- a/dhcpcd_proxy.h
+++ b/dhcpcd_proxy.h
@@ -15,6 +15,8 @@
 
 class DHCPProvider;
 
+// TODO(petkov): Convert this to match ModemManagerProxy model.
+
 // The DHCPCD listener is a singleton proxy that listens to signals from all
 // DHCP clients and dispatches them through the DHCP provider to the appropriate
 // client based on the PID.
diff --git a/mock_modem_manager_proxy.h b/mock_modem_manager_proxy.h
new file mode 100644
index 0000000..0810a8d
--- /dev/null
+++ b/mock_modem_manager_proxy.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MOCK_MODEM_MANAGER_PROXY_H_
+#define SHILL_MOCK_MODEM_MANAGER_PROXY_H_
+
+#include <gmock/gmock.h>
+
+#include "shill/modem_manager_proxy_interface.h"
+
+namespace shill {
+
+class MockModemManagerProxy : public ModemManagerProxyInterface {
+ public:
+  MOCK_METHOD0(EnumerateDevices, std::vector<DBus::Path>());
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MOCK_MODEM_MANAGER_PROXY_H_
diff --git a/modem_manager.cc b/modem_manager.cc
index df4c4ae..94536fb 100644
--- a/modem_manager.cc
+++ b/modem_manager.cc
@@ -6,6 +6,9 @@
 
 #include <base/logging.h>
 
+#include "shill/modem_manager_proxy.h"
+#include "shill/proxy_factory.h"
+
 using std::string;
 
 namespace shill {
@@ -30,6 +33,7 @@
 void ModemManager::Start() {
   LOG(INFO) << "Start watching modem manager service: " << service_;
   CHECK_EQ(0, watcher_id_);
+  // TODO(petkov): Implement DBus name watching through dbus-c++.
   watcher_id_ = glib_->BusWatchName(G_BUS_TYPE_SYSTEM,
                                     service_.c_str(),
                                     G_BUS_NAME_WATCHER_FLAGS_NONE,
@@ -50,12 +54,13 @@
 
 void ModemManager::Connect(const string &owner) {
   owner_ = owner;
-  // TODO(petkov): Create a proxy to the manager and enumerate its devices.
+  proxy_.reset(
+      ProxyFactory::factory()->CreateModemManagerProxy(this, path_, owner_));
 }
 
 void ModemManager::Disconnect() {
   owner_.clear();
-  // TODO(petkov): Destroy manager's proxy and its devices.
+  proxy_.reset();
 }
 
 void ModemManager::OnAppear(GDBusConnection *connection,
diff --git a/modem_manager.h b/modem_manager.h
index 96d18ef..14d3a4f 100644
--- a/modem_manager.h
+++ b/modem_manager.h
@@ -6,6 +6,7 @@
 #define SHILL_MODEM_MANAGER_
 
 #include <base/basictypes.h>
+#include <base/memory/scoped_ptr.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "shill/glib.h"
@@ -15,6 +16,7 @@
 class ControlInterface;
 class EventDispatcher;
 class Manager;
+class ModemManagerProxyInterface;
 
 // Handles a modem manager service and creates and destroys cellular devices.
 class ModemManager {
@@ -63,8 +65,8 @@
   const std::string path_;
   guint watcher_id_;
 
-  // DBus service owner.
-  std::string owner_;
+  std::string owner_;  // DBus service owner.
+  scoped_ptr<ModemManagerProxyInterface> proxy_;  // DBus service proxy.
 
   ControlInterface *control_interface_;
   EventDispatcher *dispatcher_;
diff --git a/modem_manager_proxy.cc b/modem_manager_proxy.cc
new file mode 100644
index 0000000..21a0a93
--- /dev/null
+++ b/modem_manager_proxy.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/modem_manager_proxy.h"
+
+#include <base/logging.h>
+
+using std::string;
+using std::vector;
+
+namespace shill {
+
+ModemManagerProxy::ModemManagerProxy(ModemManager *manager,
+                                     const string &path,
+                                     const string &service)
+    : connection_(DBus::Connection::SystemBus()),
+      proxy_(manager, &connection_, path, service) {}
+
+ModemManagerProxy::~ModemManagerProxy() {}
+
+vector<DBus::Path> ModemManagerProxy::EnumerateDevices() {
+  return proxy_.EnumerateDevices();
+}
+
+ModemManagerProxy::Proxy::Proxy(ModemManager *manager,
+                                DBus::Connection *connection,
+                                const string &path,
+                                const string &service)
+    : DBus::ObjectProxy(*connection, path, service.c_str()),
+      manager_(manager) {}
+
+ModemManagerProxy::Proxy::~Proxy() {}
+
+void ModemManagerProxy::Proxy::DeviceAdded(const DBus::Path &device) {
+  LOG(INFO) << "Modem device added: " << device;
+}
+
+void ModemManagerProxy::Proxy::DeviceRemoved(const DBus::Path &device) {
+  LOG(INFO) << "Modem device removed: " << device;
+}
+
+}  // namespace shill
diff --git a/modem_manager_proxy.h b/modem_manager_proxy.h
new file mode 100644
index 0000000..b782267
--- /dev/null
+++ b/modem_manager_proxy.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MODEM_MANAGER_PROXY_
+#define SHILL_MODEM_MANAGER_PROXY_
+
+#include <base/basictypes.h>
+
+#include "shill/mm.h"
+#include "shill/modem_manager_proxy_interface.h"
+
+namespace shill {
+
+class ModemManager;
+
+// There's a single proxy per ModemManager service identified by its DBus |path|
+// and owner name |service|.
+class ModemManagerProxy : public ModemManagerProxyInterface {
+ public:
+  ModemManagerProxy(ModemManager *manager,
+                    const std::string &path,
+                    const std::string &service);
+  virtual ~ModemManagerProxy();
+
+  // Inherited from ModemManagerProxyInterface.
+  virtual std::vector<DBus::Path> EnumerateDevices();
+
+ private:
+  class Proxy : public org::freedesktop::ModemManager_proxy,
+                public DBus::ObjectProxy {
+   public:
+    Proxy(ModemManager *manager,
+          DBus::Connection *connection,
+          const std::string &path,
+          const std::string &service);
+    virtual ~Proxy();
+
+   private:
+    // Signal callbacks inherited from ModemManager_proxy.
+    virtual void DeviceAdded(const DBus::Path &device);
+    virtual void DeviceRemoved(const DBus::Path &device);
+
+    // The owner of this proxy.
+    ModemManager *manager_;
+
+    DISALLOW_COPY_AND_ASSIGN(Proxy);
+  };
+
+  DBus::Connection connection_;
+  Proxy proxy_;
+
+  DISALLOW_COPY_AND_ASSIGN(ModemManagerProxy);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MODEM_MANAGER_PROXY_
diff --git a/modem_manager_proxy_interface.h b/modem_manager_proxy_interface.h
new file mode 100644
index 0000000..e294eea
--- /dev/null
+++ b/modem_manager_proxy_interface.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MODEM_MANAGER_PROXY_INTERFACE_
+#define SHILL_MODEM_MANAGER_PROXY_INTERFACE_
+
+#include <vector>
+
+#include <dbus-c++/types.h>
+
+namespace shill {
+
+// These are the methods that a ModemManager proxy must support. The interface
+// is provided so that it can be mocked in tests.
+class ModemManagerProxyInterface {
+ public:
+  virtual ~ModemManagerProxyInterface() {}
+
+  virtual std::vector<DBus::Path> EnumerateDevices() = 0;
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MODEM_MANAGER_PROXY_INTERFACE_
diff --git a/modem_manager_unittest.cc b/modem_manager_unittest.cc
index c7c83d0..89362f7 100644
--- a/modem_manager_unittest.cc
+++ b/modem_manager_unittest.cc
@@ -7,8 +7,11 @@
 #include "shill/manager.h"
 #include "shill/mock_control.h"
 #include "shill/mock_glib.h"
+#include "shill/mock_modem_manager_proxy.h"
 #include "shill/modem_manager.h"
+#include "shill/proxy_factory.h"
 
+using std::string;
 using testing::_;
 using testing::Return;
 using testing::StrEq;
@@ -25,13 +28,34 @@
                        &control_interface_,
                        &dispatcher_,
                        &manager_,
-                       &glib_) {}
+                       &glib_),
+        proxy_factory_(&proxy_) {
+    ProxyFactory::set_factory(&proxy_factory_);
+  }
 
   virtual void TearDown() {
     modem_manager_.watcher_id_ = 0;
+    ModemManagerProxyInterface *proxy = modem_manager_.proxy_.release();
+    EXPECT_TRUE(proxy == NULL || proxy == &proxy_);
+    ProxyFactory::set_factory(NULL);
   }
 
  protected:
+  class TestProxyFactory : public ProxyFactory {
+   public:
+    TestProxyFactory(ModemManagerProxyInterface *proxy) : proxy_(proxy) {}
+
+    virtual ModemManagerProxyInterface *CreateModemManagerProxy(
+        ModemManager *manager,
+        const string &path,
+        const string &service) {
+      return proxy_;
+    }
+
+   private:
+    ModemManagerProxyInterface *proxy_;
+  };
+
   static const char kService[];
   static const char kPath[];
 
@@ -40,6 +64,8 @@
   EventDispatcher dispatcher_;
   Manager manager_;
   ModemManager modem_manager_;
+  MockModemManagerProxy proxy_;
+  TestProxyFactory proxy_factory_;
 };
 
 const char ModemManagerTest::kService[] = "test.dbus.service";
diff --git a/proxy_factory.cc b/proxy_factory.cc
new file mode 100644
index 0000000..f2092e9
--- /dev/null
+++ b/proxy_factory.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/proxy_factory.h"
+
+#include "shill/modem_manager_proxy.h"
+
+namespace shill {
+
+ProxyFactory *ProxyFactory::factory_ = NULL;
+
+ProxyFactory::ProxyFactory() {}
+
+ProxyFactory::~ProxyFactory() {}
+
+ModemManagerProxyInterface *ProxyFactory::CreateModemManagerProxy(
+    ModemManager *manager,
+    const std::string &path,
+    const std::string &service) {
+  return new ModemManagerProxy(manager, path, service);
+}
+
+}  // namespace shill
diff --git a/proxy_factory.h b/proxy_factory.h
new file mode 100644
index 0000000..fffcd05
--- /dev/null
+++ b/proxy_factory.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_PROXY_FACTORY_
+#define SHILL_PROXY_FACTORY_
+
+#include <string>
+
+#include <base/basictypes.h>
+
+namespace shill {
+
+class ModemManager;
+class ModemManagerProxyInterface;
+
+// TODO(petkov): Merge supplicant proxy factory into this one.
+
+// Global DBus proxy factory that can be mocked out in tests.
+class ProxyFactory {
+ public:
+  ProxyFactory();
+  virtual ~ProxyFactory();
+
+  virtual ModemManagerProxyInterface *CreateModemManagerProxy(
+      ModemManager *manager,
+      const std::string &path,
+      const std::string &service);
+
+  static ProxyFactory *factory() { return factory_; }
+  static void set_factory(ProxyFactory *factory) { factory_ = factory; }
+
+ private:
+  static ProxyFactory *factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyFactory);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_PROXY_FACTORY_
diff --git a/shill_main.cc b/shill_main.cc
index 16703cd..ded1341 100644
--- a/shill_main.cc
+++ b/shill_main.cc
@@ -15,6 +15,7 @@
 #include "shill/dbus_control.h"
 #include "shill/dhcp_provider.h"
 #include "shill/glib.h"
+#include "shill/proxy_factory.h"
 #include "shill/shill_config.h"
 #include "shill/shill_daemon.h"
 #include "shill/supplicant_proxy_factory.h"
@@ -98,6 +99,9 @@
   shill::SupplicantProxyFactory live_proxy_factory;
   shill::WiFi::set_proxy_factory(&live_proxy_factory);
 
+  shill::ProxyFactory proxy_factory;
+  shill::ProxyFactory::set_factory(&proxy_factory);
+
   // TODO(pstew): This should be chosen based on config
   shill::DBusControl *dbus_control = new shill::DBusControl();
   dbus_control->Init();