[shill] Make profiles backed with StoreInterfaces

Rely on persistence of data in StoreInterface to maintain
Service/Device/IPConfig info for entities that are not
currently active, instead of maintaining lists in Profile
objects themselves.

BUG=chromium-os:17253
TEST=unit, run on device

Change-Id: I206f44ddf16c584354f8fcadb57032f047f33d0a
Reviewed-on: http://gerrit.chromium.org/gerrit/10024
Commit-Ready: Chris Masone <cmasone@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/manager_unittest.cc b/manager_unittest.cc
index 76369da..b667dd7 100644
--- a/manager_unittest.cc
+++ b/manager_unittest.cc
@@ -15,7 +15,10 @@
 #include <gtest/gtest.h>
 
 #include "shill/adaptor_interfaces.h"
+#include "shill/ephemeral_profile.h"
 #include "shill/error.h"
+#include "shill/glib.h"
+#include "shill/key_file_store.h"
 #include "shill/key_value_store.h"
 #include "shill/mock_adaptors.h"
 #include "shill/mock_control.h"
@@ -26,6 +29,7 @@
 #include "shill/mock_store.h"
 #include "shill/mock_wifi.h"
 #include "shill/property_store_unittest.h"
+#include "shill/service_under_test.h"
 #include "shill/wifi_service.h"
 
 using std::map;
@@ -35,6 +39,7 @@
 
 namespace shill {
 using ::testing::_;
+using ::testing::AnyNumber;
 using ::testing::Ne;
 using ::testing::NiceMock;
 using ::testing::Return;
@@ -78,6 +83,23 @@
   }
   bool ServiceOrderIs(ServiceRefPtr svc1, ServiceRefPtr svc2);
 
+  Profile *CreateProfileForManager(Manager *manager, GLib *glib) {
+    Profile::Identifier id("rather", "irrelevant");
+    scoped_ptr<Profile> profile(new Profile(control_interface(),
+                                            manager,
+                                            id,
+                                            "",
+                                            false));
+    FilePath final_path(storage_path());
+    final_path = final_path.Append("test.profile");
+    scoped_ptr<KeyFileStore> storage(new KeyFileStore(glib));
+    storage->set_path(final_path);
+    if (!storage->Open())
+      return NULL;
+    profile->set_storage(storage.release());  // Passes ownership.
+    return profile.release();
+  }
+
  protected:
   scoped_refptr<MockWiFi> mock_wifi_;
   vector<scoped_refptr<MockDevice> > mock_devices_;
@@ -140,6 +162,10 @@
                   run_path(),
                   storage_path(),
                   string());
+  ProfileRefPtr profile(CreateProfileForManager(&manager, &glib));
+  ASSERT_TRUE(profile.get());
+  manager.AdoptProfile(profile);
+
   scoped_refptr<MockService> mock_service(
       new NiceMock<MockService>(control_interface(),
                                 dispatcher(),
@@ -174,6 +200,66 @@
   manager.Stop();
 }
 
+TEST_F(ManagerTest, RegisterKnownService) {
+  // It's much easier and safer to use a real GLib for this test.
+  GLib glib;
+  Manager manager(control_interface(),
+                  dispatcher(),
+                  &glib,
+                  run_path(),
+                  storage_path(),
+                  string());
+  ProfileRefPtr profile(CreateProfileForManager(&manager, &glib));
+  ASSERT_TRUE(profile.get());
+  manager.AdoptProfile(profile);
+  {
+    ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
+                                                dispatcher(),
+                                                &manager));
+    service1->set_favorite(!service1->favorite());
+    ASSERT_TRUE(profile->AdoptService(service1));
+    ASSERT_TRUE(profile->ContainsService(service1));
+  }  // Force destruction of service1.
+
+  ServiceRefPtr service2(new ServiceUnderTest(control_interface(),
+                                              dispatcher(),
+                                              &manager));
+  manager.RegisterService(service2);
+  EXPECT_EQ(service2->profile().get(), profile.get());
+  manager.Stop();
+}
+
+TEST_F(ManagerTest, RegisterUnknownService) {
+  // It's much easier and safer to use a real GLib for this test.
+  GLib glib;
+  Manager manager(control_interface(),
+                  dispatcher(),
+                  &glib,
+                  run_path(),
+                  storage_path(),
+                  string());
+  ProfileRefPtr profile(CreateProfileForManager(&manager, &glib));
+  ASSERT_TRUE(profile.get());
+  manager.AdoptProfile(profile);
+  {
+    ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
+                                                dispatcher(),
+                                                &manager));
+    service1->set_favorite(!service1->favorite());
+    ASSERT_TRUE(profile->AdoptService(service1));
+    ASSERT_TRUE(profile->ContainsService(service1));
+  }  // Force destruction of service1.
+  scoped_refptr<MockService> mock_service2(
+      new NiceMock<MockService>(control_interface(),
+                                dispatcher(),
+                                &manager));
+  EXPECT_CALL(*mock_service2.get(), GetStorageIdentifier())
+      .WillRepeatedly(Return(mock_service2->UniqueName()));
+  manager.RegisterService(mock_service2);
+  EXPECT_NE(mock_service2->profile().get(), profile.get());
+  manager.Stop();
+}
+
 TEST_F(ManagerTest, GetProperties) {
   ProfileRefPtr profile(new MockProfile(control_interface(), manager(), ""));
   manager()->AdoptProfile(profile);
@@ -221,62 +307,43 @@
 }
 
 TEST_F(ManagerTest, MoveService) {
-  // It's much easier and safer to use a real GLib for this test.
-  GLib glib;
   Manager manager(control_interface(),
                   dispatcher(),
-                  &glib,
+                  glib(),
                   run_path(),
                   storage_path(),
                   string());
+  scoped_refptr<MockService> s2(new MockService(control_interface(),
+                                                dispatcher(),
+                                                &manager));
+  // Inject an actual profile, backed by a fake StoreInterface
   {
-    Profile::Identifier id;
-    id.identifier = "irrelevant";
+    Profile::Identifier id("irrelevant");
     ProfileRefPtr profile(
         new Profile(control_interface(), &manager, id, "", false));
     MockStore *storage = new MockStore;
-    EXPECT_CALL(*storage, Flush()).WillOnce(Return(true));
+    // Say we don't have |s2| the first time asked, then that we do.
+    EXPECT_CALL(*storage, ContainsGroup(s2->GetStorageIdentifier()))
+        .WillOnce(Return(false))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*storage, Flush())
+        .Times(AnyNumber())
+        .WillRepeatedly(Return(true));
     profile->set_storage(storage);
     manager.AdoptProfile(profile);
   }
-  // I want to ensure that the Profiles are managing this Service object
-  // lifetime properly, so I can't hold a ref to it here.
-  ProfileRefPtr profile(new MockProfile(control_interface(), &manager, ""));
-  string service_name;
-  {
-    scoped_refptr<MockService> s2(
-        new MockService(control_interface(),
-                        dispatcher(),
-                        &manager));
-    EXPECT_CALL(*s2.get(), Save(_)).WillOnce(Return(true));
+  // Create a profile that already has |s2| in it.
+  ProfileRefPtr profile(new EphemeralProfile(control_interface(), &manager));
+  profile->AdoptService(s2);
 
-    profile->AdoptService(s2);
-    s2->set_profile(profile);
-    service_name = s2->UniqueName();
-  }
-
-  // Now, move the |service| to another profile.
-  ASSERT_TRUE(manager.MoveToActiveProfile(profile,
-                                           profile->FindService(service_name)));
+  // Now, move the Service |s2| to another profile.
+  EXPECT_CALL(*s2.get(), Save(_)).WillOnce(Return(true));
+  ASSERT_TRUE(manager.MoveServiceToProfile(s2, manager.ActiveProfile()));
 
   // Force destruction of the original Profile, to ensure that the Service
   // is kept alive and populated with data.
   profile = NULL;
-  {
-    ServiceRefPtr serv(manager.ActiveProfile()->FindService(service_name));
-    ASSERT_TRUE(serv.get() != NULL);
-    Error error(Error::kInvalidProperty, "");
-    ::DBus::Error dbus_error;
-    map<string, ::DBus::Variant> props;
-    bool expected = true;
-    serv->mutable_store()->SetBoolProperty(flimflam::kAutoConnectProperty,
-                                           expected,
-                                           &error);
-    DBusAdaptor::GetProperties(serv->store(), &props, &dbus_error);
-    ASSERT_TRUE(ContainsKey(props, flimflam::kAutoConnectProperty));
-    EXPECT_EQ(props[flimflam::kAutoConnectProperty].reader().get_bool(),
-              expected);
-  }
+  ASSERT_TRUE(manager.ActiveProfile()->ContainsService(s2));
   manager.Stop();
 }