object_manager_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "dbus/object_manager.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <string>
  9. #include <vector>
  10. #include "base/bind.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/message_loop/message_pump_type.h"
  13. #include "base/run_loop.h"
  14. #include "base/task/single_thread_task_runner.h"
  15. #include "base/test/task_environment.h"
  16. #include "base/threading/thread.h"
  17. #include "base/threading/thread_restrictions.h"
  18. #include "base/time/time.h"
  19. #include "dbus/bus.h"
  20. #include "dbus/object_path.h"
  21. #include "dbus/object_proxy.h"
  22. #include "dbus/property.h"
  23. #include "dbus/test_service.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. #include "third_party/abseil-cpp/absl/types/optional.h"
  26. namespace dbus {
  27. // The object manager test exercises the asynchronous APIs in ObjectManager,
  28. // and by extension PropertySet and Property<>.
  29. class ObjectManagerTest
  30. : public testing::Test,
  31. public ObjectManager::Interface {
  32. public:
  33. ObjectManagerTest() : timeout_expired_(false) {
  34. }
  35. struct Properties : public PropertySet {
  36. Property<std::string> name;
  37. Property<int16_t> version;
  38. Property<std::vector<std::string>> methods;
  39. Property<std::vector<ObjectPath>> objects;
  40. Properties(ObjectProxy* object_proxy,
  41. const std::string& interface_name,
  42. PropertyChangedCallback property_changed_callback)
  43. : PropertySet(object_proxy, interface_name, property_changed_callback) {
  44. RegisterProperty("Name", &name);
  45. RegisterProperty("Version", &version);
  46. RegisterProperty("Methods", &methods);
  47. RegisterProperty("Objects", &objects);
  48. }
  49. };
  50. PropertySet* CreateProperties(ObjectProxy* object_proxy,
  51. const ObjectPath& object_path,
  52. const std::string& interface_name) override {
  53. Properties* properties = new Properties(
  54. object_proxy, interface_name,
  55. base::BindRepeating(&ObjectManagerTest::OnPropertyChanged,
  56. base::Unretained(this), object_path));
  57. return static_cast<PropertySet*>(properties);
  58. }
  59. void SetUp() override {
  60. // Make the main thread not to allow IO.
  61. disallow_blocking_.emplace();
  62. // Start the D-Bus thread.
  63. dbus_thread_ = std::make_unique<base::Thread>("D-Bus Thread");
  64. base::Thread::Options thread_options;
  65. thread_options.message_pump_type = base::MessagePumpType::IO;
  66. ASSERT_TRUE(dbus_thread_->StartWithOptions(std::move(thread_options)));
  67. // Start the test service, using the D-Bus thread.
  68. TestService::Options options;
  69. options.dbus_task_runner = dbus_thread_->task_runner();
  70. test_service_ = std::make_unique<TestService>(options);
  71. ASSERT_TRUE(test_service_->StartService());
  72. test_service_->WaitUntilServiceIsStarted();
  73. ASSERT_TRUE(test_service_->HasDBusThread());
  74. // Create the client, using the D-Bus thread.
  75. Bus::Options bus_options;
  76. bus_options.bus_type = Bus::SESSION;
  77. bus_options.connection_type = Bus::PRIVATE;
  78. bus_options.dbus_task_runner = dbus_thread_->task_runner();
  79. bus_ = new Bus(bus_options);
  80. ASSERT_TRUE(bus_->HasDBusThread());
  81. object_manager_ = bus_->GetObjectManager(
  82. test_service_->service_name(),
  83. ObjectPath("/org/chromium/TestService"));
  84. object_manager_->RegisterInterface("org.chromium.TestInterface", this);
  85. WaitForObject();
  86. }
  87. void TearDown() override {
  88. bus_->ShutdownOnDBusThreadAndBlock();
  89. // Shut down the service.
  90. test_service_->ShutdownAndBlock();
  91. // Stopping a thread is considered an IO operation, so do this after
  92. // allowing IO.
  93. disallow_blocking_.reset();
  94. test_service_->Stop();
  95. base::RunLoop().RunUntilIdle();
  96. }
  97. void MethodCallback(Response* response) {
  98. method_callback_called_ = true;
  99. run_loop_->Quit();
  100. }
  101. // Called from the PropertiesChangedAsObjectsReceived test case. The test will
  102. // not run the message loop if it receives the expected PropertiesChanged
  103. // signal before the timeout. This method immediately fails the test.
  104. void PropertiesChangedTestTimeout() {
  105. timeout_expired_ = true;
  106. run_loop_->Quit();
  107. FAIL() << "Never received PropertiesChanged";
  108. }
  109. protected:
  110. // Called when an object is added.
  111. void ObjectAdded(const ObjectPath& object_path,
  112. const std::string& interface_name) override {
  113. added_objects_.push_back(std::make_pair(object_path, interface_name));
  114. run_loop_->Quit();
  115. }
  116. // Called when an object is removed.
  117. void ObjectRemoved(const ObjectPath& object_path,
  118. const std::string& interface_name) override {
  119. removed_objects_.push_back(std::make_pair(object_path, interface_name));
  120. run_loop_->Quit();
  121. }
  122. // Called when a property value is updated.
  123. void OnPropertyChanged(const ObjectPath& object_path,
  124. const std::string& name) {
  125. // Store the value of the "Name" property if that's the one that
  126. // changed.
  127. Properties* properties = static_cast<Properties*>(
  128. object_manager_->GetProperties(
  129. object_path,
  130. "org.chromium.TestInterface"));
  131. if (name == properties->name.name())
  132. last_name_value_ = properties->name.value();
  133. // Store the updated property.
  134. updated_properties_.push_back(name);
  135. run_loop_->Quit();
  136. }
  137. static const size_t kExpectedObjects = 1;
  138. static const size_t kExpectedProperties = 4;
  139. void WaitForObject() {
  140. while (added_objects_.size() < kExpectedObjects ||
  141. updated_properties_.size() < kExpectedProperties) {
  142. run_loop_ = std::make_unique<base::RunLoop>();
  143. run_loop_->Run();
  144. }
  145. for (size_t i = 0; i < kExpectedObjects; ++i)
  146. added_objects_.erase(added_objects_.begin());
  147. for (size_t i = 0; i < kExpectedProperties; ++i)
  148. updated_properties_.erase(updated_properties_.begin());
  149. }
  150. void WaitForRemoveObject() {
  151. while (removed_objects_.size() < kExpectedObjects) {
  152. run_loop_ = std::make_unique<base::RunLoop>();
  153. run_loop_->Run();
  154. }
  155. for (size_t i = 0; i < kExpectedObjects; ++i)
  156. removed_objects_.erase(removed_objects_.begin());
  157. }
  158. void WaitForMethodCallback() {
  159. run_loop_ = std::make_unique<base::RunLoop>();
  160. run_loop_->Run();
  161. method_callback_called_ = false;
  162. }
  163. void PerformAction(const std::string& action, const ObjectPath& object_path) {
  164. ObjectProxy* object_proxy = bus_->GetObjectProxy(
  165. test_service_->service_name(),
  166. ObjectPath("/org/chromium/TestObject"));
  167. MethodCall method_call("org.chromium.TestInterface", "PerformAction");
  168. MessageWriter writer(&method_call);
  169. writer.AppendString(action);
  170. writer.AppendObjectPath(object_path);
  171. object_proxy->CallMethod(&method_call, ObjectProxy::TIMEOUT_USE_DEFAULT,
  172. base::BindOnce(&ObjectManagerTest::MethodCallback,
  173. base::Unretained(this)));
  174. WaitForMethodCallback();
  175. }
  176. base::test::SingleThreadTaskEnvironment task_environment_;
  177. absl::optional<base::ScopedDisallowBlocking> disallow_blocking_;
  178. std::unique_ptr<base::RunLoop> run_loop_;
  179. std::unique_ptr<base::Thread> dbus_thread_;
  180. scoped_refptr<Bus> bus_;
  181. raw_ptr<ObjectManager> object_manager_;
  182. std::unique_ptr<TestService> test_service_;
  183. std::string last_name_value_;
  184. bool timeout_expired_;
  185. std::vector<std::pair<ObjectPath, std::string>> added_objects_;
  186. std::vector<std::pair<ObjectPath, std::string>> removed_objects_;
  187. std::vector<std::string> updated_properties_;
  188. bool method_callback_called_;
  189. };
  190. TEST_F(ObjectManagerTest, InitialObject) {
  191. ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
  192. ObjectPath("/org/chromium/TestObject"));
  193. EXPECT_NE(nullptr, object_proxy);
  194. Properties* properties = static_cast<Properties*>(
  195. object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
  196. "org.chromium.TestInterface"));
  197. EXPECT_NE(nullptr, properties);
  198. EXPECT_EQ("TestService", properties->name.value());
  199. EXPECT_EQ(10, properties->version.value());
  200. std::vector<std::string> methods = properties->methods.value();
  201. ASSERT_EQ(4U, methods.size());
  202. EXPECT_EQ("Echo", methods[0]);
  203. EXPECT_EQ("SlowEcho", methods[1]);
  204. EXPECT_EQ("AsyncEcho", methods[2]);
  205. EXPECT_EQ("BrokenMethod", methods[3]);
  206. std::vector<ObjectPath> objects = properties->objects.value();
  207. ASSERT_EQ(1U, objects.size());
  208. EXPECT_EQ(ObjectPath("/TestObjectPath"), objects[0]);
  209. }
  210. TEST_F(ObjectManagerTest, UnknownObjectProxy) {
  211. ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
  212. ObjectPath("/org/chromium/UnknownObject"));
  213. EXPECT_EQ(nullptr, object_proxy);
  214. }
  215. TEST_F(ObjectManagerTest, UnknownObjectProperties) {
  216. Properties* properties = static_cast<Properties*>(
  217. object_manager_->GetProperties(ObjectPath("/org/chromium/UnknownObject"),
  218. "org.chromium.TestInterface"));
  219. EXPECT_EQ(nullptr, properties);
  220. }
  221. TEST_F(ObjectManagerTest, UnknownInterfaceProperties) {
  222. Properties* properties = static_cast<Properties*>(
  223. object_manager_->GetProperties(ObjectPath("/org/chromium/TestObject"),
  224. "org.chromium.UnknownService"));
  225. EXPECT_EQ(nullptr, properties);
  226. }
  227. TEST_F(ObjectManagerTest, GetObjects) {
  228. std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
  229. ASSERT_EQ(1U, object_paths.size());
  230. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
  231. }
  232. TEST_F(ObjectManagerTest, GetObjectsWithInterface) {
  233. std::vector<ObjectPath> object_paths =
  234. object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
  235. ASSERT_EQ(1U, object_paths.size());
  236. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
  237. }
  238. TEST_F(ObjectManagerTest, GetObjectsWithUnknownInterface) {
  239. std::vector<ObjectPath> object_paths =
  240. object_manager_->GetObjectsWithInterface("org.chromium.UnknownService");
  241. EXPECT_EQ(0U, object_paths.size());
  242. }
  243. TEST_F(ObjectManagerTest, SameObject) {
  244. ObjectManager* object_manager = bus_->GetObjectManager(
  245. test_service_->service_name(),
  246. ObjectPath("/org/chromium/TestService"));
  247. EXPECT_EQ(object_manager_, object_manager);
  248. }
  249. TEST_F(ObjectManagerTest, DifferentObjectForService) {
  250. ObjectManager* object_manager = bus_->GetObjectManager(
  251. "org.chromium.DifferentService",
  252. ObjectPath("/org/chromium/TestService"));
  253. EXPECT_NE(object_manager_, object_manager);
  254. }
  255. TEST_F(ObjectManagerTest, DifferentObjectForPath) {
  256. ObjectManager* object_manager = bus_->GetObjectManager(
  257. test_service_->service_name(),
  258. ObjectPath("/org/chromium/DifferentService"));
  259. EXPECT_NE(object_manager_, object_manager);
  260. }
  261. TEST_F(ObjectManagerTest, SecondObject) {
  262. PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
  263. WaitForObject();
  264. ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
  265. ObjectPath("/org/chromium/SecondObject"));
  266. EXPECT_NE(nullptr, object_proxy);
  267. Properties* properties = static_cast<Properties*>(
  268. object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
  269. "org.chromium.TestInterface"));
  270. EXPECT_NE(nullptr, properties);
  271. std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
  272. ASSERT_EQ(2U, object_paths.size());
  273. std::sort(object_paths.begin(), object_paths.end());
  274. EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
  275. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
  276. object_paths =
  277. object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
  278. ASSERT_EQ(2U, object_paths.size());
  279. std::sort(object_paths.begin(), object_paths.end());
  280. EXPECT_EQ(ObjectPath("/org/chromium/SecondObject"), object_paths[0]);
  281. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[1]);
  282. }
  283. TEST_F(ObjectManagerTest, RemoveSecondObject) {
  284. PerformAction("AddObject", ObjectPath("/org/chromium/SecondObject"));
  285. WaitForObject();
  286. std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
  287. ASSERT_EQ(2U, object_paths.size());
  288. PerformAction("RemoveObject", ObjectPath("/org/chromium/SecondObject"));
  289. WaitForRemoveObject();
  290. ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
  291. ObjectPath("/org/chromium/SecondObject"));
  292. EXPECT_EQ(nullptr, object_proxy);
  293. Properties* properties = static_cast<Properties*>(
  294. object_manager_->GetProperties(ObjectPath("/org/chromium/SecondObject"),
  295. "org.chromium.TestInterface"));
  296. EXPECT_EQ(nullptr, properties);
  297. object_paths = object_manager_->GetObjects();
  298. ASSERT_EQ(1U, object_paths.size());
  299. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
  300. object_paths =
  301. object_manager_->GetObjectsWithInterface("org.chromium.TestInterface");
  302. ASSERT_EQ(1U, object_paths.size());
  303. EXPECT_EQ(ObjectPath("/org/chromium/TestObject"), object_paths[0]);
  304. }
  305. TEST_F(ObjectManagerTest, OwnershipLost) {
  306. PerformAction("ReleaseOwnership", ObjectPath("/org/chromium/TestService"));
  307. WaitForRemoveObject();
  308. std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
  309. ASSERT_EQ(0U, object_paths.size());
  310. }
  311. TEST_F(ObjectManagerTest, OwnershipLostAndRegained) {
  312. PerformAction("Ownership", ObjectPath("/org/chromium/TestService"));
  313. WaitForRemoveObject();
  314. WaitForObject();
  315. std::vector<ObjectPath> object_paths = object_manager_->GetObjects();
  316. ASSERT_EQ(1U, object_paths.size());
  317. }
  318. // Flaky: crbug.com/1174515
  319. TEST_F(ObjectManagerTest, DISABLED_PropertiesChangedAsObjectsReceived) {
  320. // Remove the existing object manager.
  321. object_manager_->UnregisterInterface("org.chromium.TestInterface");
  322. run_loop_ = std::make_unique<base::RunLoop>();
  323. EXPECT_TRUE(bus_->RemoveObjectManager(
  324. test_service_->service_name(),
  325. ObjectPath("/org/chromium/TestService"),
  326. run_loop_->QuitClosure()));
  327. run_loop_->Run();
  328. PerformAction("SetSendImmediatePropertiesChanged",
  329. ObjectPath("/org/chromium/TestService"));
  330. object_manager_ = bus_->GetObjectManager(
  331. test_service_->service_name(),
  332. ObjectPath("/org/chromium/TestService"));
  333. object_manager_->RegisterInterface("org.chromium.TestInterface", this);
  334. // The newly created object manager should call GetManagedObjects immediately
  335. // after setting up the match rule for PropertiesChanged. We should process
  336. // the PropertiesChanged event right after that. If we don't receive it within
  337. // 2 seconds, then fail the test.
  338. task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
  339. FROM_HERE,
  340. base::BindOnce(&ObjectManagerTest::PropertiesChangedTestTimeout,
  341. base::Unretained(this)),
  342. base::Seconds(2));
  343. while (last_name_value_ != "ChangedTestServiceName" && !timeout_expired_) {
  344. run_loop_ = std::make_unique<base::RunLoop>();
  345. run_loop_->Run();
  346. }
  347. }
  348. } // namespace dbus