Create MM1 object and start to talk to it.

TEST=unit tests.  sees mm-next and modems attached to it
BUG=chromium-os:27014

Change-Id: I31cab744d326ab8c2c8ea320e5bb72bf87decb85
Reviewed-on: https://gerrit.chromium.org/gerrit/17410
Commit-Ready: David Rochberg <rochberg@chromium.org>
Reviewed-by: David Rochberg <rochberg@chromium.org>
Tested-by: David Rochberg <rochberg@chromium.org>
diff --git a/modem_manager_unittest.cc b/modem_manager_unittest.cc
index 4df3150..d48f4f3 100644
--- a/modem_manager_unittest.cc
+++ b/modem_manager_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "shill/manager.h"
 #include "shill/mock_control.h"
+#include "shill/mock_dbus_objectmanager_proxy.h"
 #include "shill/mock_glib.h"
 #include "shill/mock_manager.h"
 #include "shill/mock_metrics.h"
@@ -17,49 +18,49 @@
 #include "shill/proxy_factory.h"
 
 using std::string;
+using std::tr1::shared_ptr;
 using std::vector;
 using testing::_;
+using testing::Invoke;
 using testing::Return;
 using testing::StrEq;
 using testing::Test;
 
 namespace shill {
 
+// A testing subclass of ModemManager.
+class ModemManagerCore : public ModemManager {
+ public:
+  ModemManagerCore(const string &service,
+                   const string &path,
+                   ControlInterface *control_interface,
+                   EventDispatcher *dispatcher,
+                   Metrics *metrics,
+                   Manager *manager,
+                   GLib *glib,
+                   mobile_provider_db *provider_db)
+      : ModemManager(service,
+                     path,
+                     control_interface,
+                     dispatcher,
+                     metrics,
+                     manager,
+                     glib,
+                     provider_db) {}
+
+  virtual ~ModemManagerCore() {}
+
+  MOCK_METHOD1(Connect, void(const string &owner));
+  MOCK_METHOD0(Disconnect, void());
+  MOCK_METHOD1(InitModem, void(shared_ptr<Modem> modem));
+};
+
 class ModemManagerTest : public Test {
  public:
   ModemManagerTest()
-      : manager_(&control_interface_, &dispatcher_, &metrics_, &glib_),
-        modem_manager_(kService,
-                       kPath,
-                       &control_interface_,
-                       &dispatcher_,
-                       &metrics_,
-                       &manager_,
-                       &glib_,
-                       NULL),
-        proxy_(new MockModemManagerProxy()),
-        proxy_factory_(this) {
+      : manager_(&control_interface_, &dispatcher_, &metrics_, &glib_) {
   }
-
-  virtual void SetUp();
-  virtual void TearDown();
-
  protected:
-  class TestProxyFactory : public ProxyFactory {
-   public:
-    explicit TestProxyFactory(ModemManagerTest *test) : test_(test) {}
-
-    virtual ModemManagerProxyInterface *CreateModemManagerProxy(
-        ModemManagerClassic */*manager*/,
-        const string &/*path*/,
-        const string &/*service*/) {
-      return test_->proxy_.release();
-    }
-
-   private:
-    ModemManagerTest *test_;
-  };
-
   static const char kService[];
   static const char kPath[];
   static const char kOwner[];
@@ -70,26 +71,38 @@
   EventDispatcher dispatcher_;
   MockMetrics metrics_;
   MockManager manager_;
-  ModemManagerClassic modem_manager_;
-  scoped_ptr<MockModemManagerProxy> proxy_;
-  TestProxyFactory proxy_factory_;
 };
 
 const char ModemManagerTest::kService[] = "org.chromium.ModemManager";
 const char ModemManagerTest::kPath[] = "/org/chromium/ModemManager";
 const char ModemManagerTest::kOwner[] = ":1.17";
-const char ModemManagerTest::kModemPath[] = "/org/chromium/ModemManager/Gobi/0";
+const char ModemManagerTest::kModemPath[] = "/org/blah/Modem/blah/0";
 
-void ModemManagerTest::SetUp() {
-  modem_manager_.proxy_factory_ = &proxy_factory_;
-}
+class ModemManagerCoreTest : public ModemManagerTest {
+ public:
+  ModemManagerCoreTest()
+      : ModemManagerTest(),
+        modem_manager_(kService,
+                       kPath,
+                       &control_interface_,
+                       &dispatcher_,
+                       &metrics_,
+                       &manager_,
+                       &glib_,
+                       NULL) {}
+  virtual void SetUp() {
+  }
 
-void ModemManagerTest::TearDown() {
-  modem_manager_.watcher_id_ = 0;
-  modem_manager_.proxy_factory_ = NULL;
-}
+  virtual void TearDown() {
+    modem_manager_.watcher_id_ = 0;
+  }
 
-TEST_F(ModemManagerTest, Start) {
+ protected:
+  ModemManagerCore modem_manager_;
+};
+
+
+TEST_F(ModemManagerCoreTest, Start) {
   const int kWatcher = 123;
   EXPECT_CALL(glib_, BusWatchName(G_BUS_TYPE_SYSTEM,
                                   StrEq(kService),
@@ -104,48 +117,45 @@
   EXPECT_EQ(kWatcher, modem_manager_.watcher_id_);
 }
 
-TEST_F(ModemManagerTest, Stop) {
+TEST_F(ModemManagerCoreTest, Stop) {
   const int kWatcher = 345;
   modem_manager_.watcher_id_ = kWatcher;
   modem_manager_.owner_ = kOwner;
   EXPECT_CALL(glib_, BusUnwatchName(kWatcher)).Times(1);
+  EXPECT_CALL(modem_manager_, Disconnect());
   modem_manager_.Stop();
-  EXPECT_EQ(0, modem_manager_.watcher_id_);
-  EXPECT_EQ("", modem_manager_.owner_);
 }
 
-TEST_F(ModemManagerTest, Connect) {
+TEST_F(ModemManagerCoreTest, OnAppearVanish) {
   EXPECT_EQ("", modem_manager_.owner_);
-  EXPECT_CALL(*proxy_, EnumerateDevices())
-      .WillOnce(Return(vector<DBus::Path>(1, kModemPath)));
-  modem_manager_.Connect(kOwner);
-  EXPECT_EQ(kOwner, modem_manager_.owner_);
-  EXPECT_EQ(1, modem_manager_.modems_.size());
-  ASSERT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
-}
-
-TEST_F(ModemManagerTest, Disconnect) {
-  modem_manager_.owner_ = kOwner;
-  modem_manager_.Disconnect();
-  EXPECT_EQ("", modem_manager_.owner_);
-}
-
-TEST_F(ModemManagerTest, OnAppear) {
-  EXPECT_EQ("", modem_manager_.owner_);
-  EXPECT_CALL(*proxy_, EnumerateDevices())
-      .WillOnce(Return(vector<DBus::Path>()));
+  EXPECT_CALL(modem_manager_, Connect(kOwner));
+  EXPECT_CALL(modem_manager_, Disconnect());
   ModemManager::OnAppear(NULL, kService, kOwner, &modem_manager_);
+  ModemManager::OnVanish(NULL, kService, &modem_manager_);
+}
+
+TEST_F(ModemManagerCoreTest, Connect) {
+  EXPECT_EQ("", modem_manager_.owner_);
+  modem_manager_.ModemManager::Connect(kOwner);
   EXPECT_EQ(kOwner, modem_manager_.owner_);
 }
 
-TEST_F(ModemManagerTest, OnVanish) {
+TEST_F(ModemManagerCoreTest, Disconnect) {
+  EXPECT_CALL(modem_manager_, InitModem(_));
+
   modem_manager_.owner_ = kOwner;
-  ModemManager::OnVanish(NULL, kService, &modem_manager_);
+  modem_manager_.AddModem(kModemPath);
+  EXPECT_EQ(1, modem_manager_.modems_.size());
+
+  modem_manager_.ModemManager::Disconnect();
   EXPECT_EQ("", modem_manager_.owner_);
+  EXPECT_EQ(0, modem_manager_.modems_.size());
 }
 
-TEST_F(ModemManagerTest, AddRemoveModem) {
+TEST_F(ModemManagerCoreTest, AddRemoveModem) {
   modem_manager_.owner_ = kOwner;
+  EXPECT_CALL(modem_manager_, InitModem(_));
+
   modem_manager_.AddModem(kModemPath);
   EXPECT_EQ(1, modem_manager_.modems_.size());
   ASSERT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
@@ -154,4 +164,167 @@
   EXPECT_EQ(0, modem_manager_.modems_.size());
 }
 
+
+class ModemManagerClassicTest : public ModemManagerTest {
+ public:
+  ModemManagerClassicTest()
+      : ModemManagerTest(),
+        modem_manager_(kService,
+                       kPath,
+                       &control_interface_,
+                       &dispatcher_,
+                       &metrics_,
+                       &manager_,
+                       &glib_,
+                       NULL),
+        proxy_(new MockModemManagerProxy()),
+        proxy_factory_(this) {
+  }
+
+ protected:
+  class TestProxyFactory : public ProxyFactory {
+   public:
+    explicit TestProxyFactory(ModemManagerClassicTest *test) : test_(test) {}
+
+    virtual ModemManagerProxyInterface *CreateModemManagerProxy(
+        ModemManagerClassic */*manager*/,
+        const string &/*path*/,
+        const string &/*service*/) {
+      return test_->proxy_.release();
+    }
+
+   private:
+    ModemManagerClassicTest *test_;
+  };
+
+  virtual void SetUp() {
+    modem_manager_.proxy_factory_ = &proxy_factory_;
+  }
+
+  virtual void TearDown() {
+    modem_manager_.proxy_factory_ = NULL;
+  }
+
+  ModemManagerClassic modem_manager_;
+  scoped_ptr<MockModemManagerProxy> proxy_;
+  TestProxyFactory proxy_factory_;
+};
+
+TEST_F(ModemManagerClassicTest, Connect) {
+  EXPECT_EQ("", modem_manager_.owner_);
+
+  EXPECT_CALL(*proxy_, EnumerateDevices())
+      .WillOnce(Return(vector<DBus::Path>(1, kModemPath)));
+
+  modem_manager_.Connect(kOwner);
+  EXPECT_EQ(kOwner, modem_manager_.owner_);
+  EXPECT_EQ(1, modem_manager_.modems_.size());
+  ASSERT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
+}
+
+
+class ModemManager1Test : public ModemManagerTest {
+ public:
+  ModemManager1Test()
+      : ModemManagerTest(),
+        modem_manager_(kService,
+                       kPath,
+                       &control_interface_,
+                       &dispatcher_,
+                       &metrics_,
+                       &manager_,
+                       &glib_,
+                       NULL),
+        proxy_(new MockDBusObjectManagerProxy()),
+        proxy_factory_(this) {
+  }
+
+ protected:
+  class TestProxyFactory : public ProxyFactory {
+   public:
+    explicit TestProxyFactory(ModemManager1Test *test) : test_(test) {}
+
+    virtual DBusObjectManagerProxyInterface *CreateDBusObjectManagerProxy(
+        DBusObjectManagerProxyDelegate */*manager*/,
+        const string &/*path*/,
+        const string &/*service*/) {
+      return test_->proxy_.release();
+    }
+
+   private:
+    ModemManager1Test *test_;
+  };
+
+  virtual void SetUp() {
+    modem_manager_.proxy_factory_ = &proxy_factory_;
+  }
+
+  virtual void TearDown() {
+    modem_manager_.proxy_factory_ = NULL;
+  }
+
+  static DBusObjectsWithProperties GetModemWithProperties() {
+    DBusPropertiesMap o_fd_mm1_modem;
+
+    DBusInterfaceToProperties i_to_p;
+    i_to_p[ModemManager1::kDBusInterfaceModem] = o_fd_mm1_modem;
+
+    DBusObjectsWithProperties objects_with_properties;
+    objects_with_properties[kModemPath] = i_to_p;
+
+    return objects_with_properties;
+  }
+
+  ModemManager1 modem_manager_;
+  scoped_ptr<MockDBusObjectManagerProxy> proxy_;
+  TestProxyFactory proxy_factory_;
+};
+
+TEST_F(ModemManager1Test, Connect) {
+  Error e;
+
+  EXPECT_CALL(*proxy_, GetManagedObjects(_, _));
+
+  modem_manager_.Connect(kOwner);
+  modem_manager_.OnGetManagedObjectsCallback(GetModemWithProperties(), e, NULL);
+  EXPECT_EQ(1, modem_manager_.modems_.size());
+  EXPECT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
+  // TODO(rochberg): As mm1::connect gets more interesting, this will
+  // need to expand
+}
+
+TEST_F(ModemManager1Test, AddRemoveInterfaces) {
+  EXPECT_CALL(*proxy_, GetManagedObjects(_, _));
+  modem_manager_.Connect(kOwner);
+
+  // Have nothing come back from GetManagedObjects
+  modem_manager_.OnGetManagedObjectsCallback(DBusObjectsWithProperties(),
+                                             Error(),
+                                             NULL);
+  EXPECT_EQ(0, modem_manager_.modems_.size());
+
+  // Add an object that doesn't have a modem interface.  Nothing should be added
+  modem_manager_.OnInterfacesAdded(kModemPath,
+                                   DBusInterfaceToProperties());
+  EXPECT_EQ(0, modem_manager_.modems_.size());
+
+  // Actually add a modem
+  modem_manager_.OnInterfacesAdded(kModemPath,
+                                   GetModemWithProperties()[kModemPath]);
+  EXPECT_EQ(1, modem_manager_.modems_.size());
+
+  // Remove an irrelevant interface
+  vector<string> not_including_modem_interface;
+  not_including_modem_interface.push_back("not.a.modem.interface");
+  modem_manager_.OnInterfacesRemoved(kModemPath,
+                                     not_including_modem_interface);
+  EXPECT_EQ(1, modem_manager_.modems_.size());
+
+  // Remove the modem
+  vector<string> with_modem_interface;
+  with_modem_interface.push_back(ModemManager1::kDBusInterfaceModem);
+  modem_manager_.OnInterfacesRemoved(kModemPath,
+                                     with_modem_interface);
+  EXPECT_EQ(0, modem_manager_.modems_.size());
+}
 }  // namespace shill