system_media_controls_linux_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. // Copyright 2019 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 "components/system_media_controls/linux/system_media_controls_linux.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/containers/flat_map.h"
  8. #include "base/run_loop.h"
  9. #include "base/strings/utf_string_conversions.h"
  10. #include "base/test/task_environment.h"
  11. #include "components/dbus/thread_linux/dbus_thread_linux.h"
  12. #include "components/system_media_controls/system_media_controls_observer.h"
  13. #include "dbus/message.h"
  14. #include "dbus/mock_bus.h"
  15. #include "dbus/mock_exported_object.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. using ::testing::_;
  19. using ::testing::Invoke;
  20. using ::testing::Return;
  21. using ::testing::Unused;
  22. using ::testing::WithArg;
  23. namespace system_media_controls {
  24. namespace internal {
  25. namespace {
  26. constexpr uint32_t kFakeSerial = 123;
  27. const char kTestProductName[] = "Foo";
  28. } // anonymous namespace
  29. class MockSystemMediaControlsObserver : public SystemMediaControlsObserver {
  30. public:
  31. MockSystemMediaControlsObserver() = default;
  32. ~MockSystemMediaControlsObserver() override = default;
  33. // SystemMediaControlsObserver implementation.
  34. MOCK_METHOD0(OnServiceReady, void());
  35. MOCK_METHOD0(OnNext, void());
  36. MOCK_METHOD0(OnPrevious, void());
  37. MOCK_METHOD0(OnPause, void());
  38. MOCK_METHOD0(OnPlayPause, void());
  39. MOCK_METHOD0(OnStop, void());
  40. MOCK_METHOD0(OnPlay, void());
  41. MOCK_METHOD1(OnSeek, void(const base::TimeDelta&));
  42. MOCK_METHOD1(OnSeekTo, void(const base::TimeDelta&));
  43. };
  44. class SystemMediaControlsLinuxTest : public testing::Test,
  45. public SystemMediaControlsObserver {
  46. public:
  47. SystemMediaControlsLinuxTest()
  48. : task_environment_(base::test::TaskEnvironment::MainThreadType::UI,
  49. base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  50. SystemMediaControlsLinuxTest(const SystemMediaControlsLinuxTest&) = delete;
  51. SystemMediaControlsLinuxTest& operator=(const SystemMediaControlsLinuxTest&) =
  52. delete;
  53. ~SystemMediaControlsLinuxTest() override = default;
  54. void SetUp() override { StartMprisServiceAndWaitForReady(); }
  55. void AddObserver(MockSystemMediaControlsObserver* observer) {
  56. service_->AddObserver(observer);
  57. }
  58. void CallMediaPlayer2PlayerMethodAndBlock(const std::string& method_name) {
  59. EXPECT_TRUE(player_interface_exported_methods_.contains(method_name));
  60. response_wait_loop_ = std::make_unique<base::RunLoop>();
  61. // We need to supply a serial or the test will crash.
  62. dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
  63. method_call.SetSerial(kFakeSerial);
  64. // Call the method and await a response.
  65. player_interface_exported_methods_[method_name].Run(
  66. &method_call,
  67. base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
  68. base::Unretained(this)));
  69. response_wait_loop_->Run();
  70. }
  71. void CallSeekAndBlock(bool is_seek_to, int64_t offset_or_position) {
  72. response_wait_loop_ = std::make_unique<base::RunLoop>();
  73. // We need to supply a serial or the test will crash.
  74. const std::string method_name = is_seek_to ? "SetPosition" : "Seek";
  75. dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
  76. method_call.SetSerial(kFakeSerial);
  77. dbus::MessageWriter writer(&method_call);
  78. if (is_seek_to)
  79. writer.AppendObjectPath(
  80. dbus::ObjectPath("/org/chromium/MediaPlayer2/TrackList/TrackFooId"));
  81. writer.AppendInt64(offset_or_position);
  82. // Call the method and await a response.
  83. player_interface_exported_methods_[method_name].Run(
  84. &method_call,
  85. base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
  86. base::Unretained(this)));
  87. response_wait_loop_->Run();
  88. }
  89. int64_t GetCurrentPositionValue() {
  90. base::RunLoop wait_loop;
  91. // We need to supply a serial or the test will crash.
  92. dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get");
  93. method_call.SetSerial(kFakeSerial);
  94. dbus::MessageWriter writer(&method_call);
  95. writer.AppendString(kMprisAPIPlayerInterfaceName);
  96. writer.AppendString("Position");
  97. int64_t position;
  98. // Call the method and await a response.
  99. properties_interface_exported_methods_["Get"].Run(
  100. &method_call, base::BindOnce(
  101. [](int64_t* position_out, base::RunLoop& wait_loop,
  102. std::unique_ptr<dbus::Response> response) {
  103. // A response of nullptr means an error has
  104. // occurred.
  105. EXPECT_NE(nullptr, response.get());
  106. dbus::MessageReader reader(response.get());
  107. ASSERT_TRUE(reader.PopVariantOfInt64(position_out));
  108. wait_loop.Quit();
  109. },
  110. &position, std::ref(wait_loop)));
  111. wait_loop.Run();
  112. return position;
  113. }
  114. SystemMediaControlsLinux* GetService() { return service_.get(); }
  115. dbus::MockExportedObject* GetExportedObject() {
  116. return mock_exported_object_.get();
  117. }
  118. void AdvanceClockMilliseconds(int ms) {
  119. task_environment_.FastForwardBy(base::Milliseconds(ms));
  120. }
  121. private:
  122. void StartMprisServiceAndWaitForReady() {
  123. service_wait_loop_ = std::make_unique<base::RunLoop>();
  124. service_ = std::make_unique<SystemMediaControlsLinux>(kTestProductName);
  125. SetUpMocks();
  126. service_->SetBusForTesting(mock_bus_);
  127. service_->AddObserver(this);
  128. service_->StartService();
  129. service_wait_loop_->Run();
  130. }
  131. // Sets up the mock Bus and ExportedObject. The ExportedObject will store the
  132. // org.mpris.MediaPlayer2.Player exported methods in the
  133. // |player_interface_exported_methods_| map so we can call them for testing.
  134. void SetUpMocks() {
  135. dbus::Bus::Options options;
  136. options.bus_type = dbus::Bus::SESSION;
  137. options.connection_type = dbus::Bus::PRIVATE;
  138. options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
  139. mock_bus_ = base::MakeRefCounted<dbus::MockBus>(options);
  140. mock_exported_object_ = base::MakeRefCounted<dbus::MockExportedObject>(
  141. mock_bus_.get(), dbus::ObjectPath(kMprisAPIObjectPath));
  142. EXPECT_CALL(*mock_bus_,
  143. GetExportedObject(dbus::ObjectPath(kMprisAPIObjectPath)))
  144. .WillOnce(Return(mock_exported_object_.get()));
  145. EXPECT_CALL(*mock_bus_, RequestOwnership(service_->GetServiceName(), _, _))
  146. .WillOnce(Invoke(this, &SystemMediaControlsLinuxTest::OnOwnership));
  147. // The service must call ShutdownAndBlock in order to properly clean up the
  148. // DBus service.
  149. EXPECT_CALL(*mock_bus_, ShutdownAndBlock());
  150. EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
  151. .WillRepeatedly(
  152. Invoke(this, &SystemMediaControlsLinuxTest::OnExported));
  153. }
  154. // Tell the service that ownership was successful.
  155. void OnOwnership(const std::string& service_name,
  156. Unused,
  157. dbus::Bus::OnOwnershipCallback callback) {
  158. std::move(callback).Run(service_name, true);
  159. }
  160. // Store the exported method if necessary and tell the service that the export
  161. // was successful.
  162. void OnExported(const std::string& interface_name,
  163. const std::string& method_name,
  164. dbus::ExportedObject::MethodCallCallback exported_method,
  165. dbus::ExportedObject::OnExportedCallback callback) {
  166. if (interface_name == kMprisAPIPlayerInterfaceName)
  167. player_interface_exported_methods_[method_name] = exported_method;
  168. if (interface_name == DBUS_INTERFACE_PROPERTIES)
  169. properties_interface_exported_methods_[method_name] = exported_method;
  170. std::move(callback).Run(interface_name, method_name, true);
  171. }
  172. void OnResponse(std::unique_ptr<dbus::Response> response) {
  173. // A response of nullptr means an error has occurred.
  174. EXPECT_NE(nullptr, response.get());
  175. if (response_wait_loop_)
  176. response_wait_loop_->Quit();
  177. }
  178. // SystemMediaControlsObserver implementation.
  179. void OnServiceReady() override {
  180. if (service_wait_loop_)
  181. service_wait_loop_->Quit();
  182. }
  183. void OnNext() override {}
  184. void OnPrevious() override {}
  185. void OnPlay() override {}
  186. void OnPause() override {}
  187. void OnPlayPause() override {}
  188. void OnStop() override {}
  189. void OnSeekTo(const base::TimeDelta& time) override {}
  190. base::test::TaskEnvironment task_environment_;
  191. std::unique_ptr<base::RunLoop> service_wait_loop_;
  192. std::unique_ptr<base::RunLoop> response_wait_loop_;
  193. std::unique_ptr<SystemMediaControlsLinux> service_;
  194. scoped_refptr<dbus::MockBus> mock_bus_;
  195. scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
  196. base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
  197. player_interface_exported_methods_;
  198. base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
  199. properties_interface_exported_methods_;
  200. };
  201. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfServiceReadyWhenAdded) {
  202. MockSystemMediaControlsObserver observer;
  203. EXPECT_CALL(observer, OnServiceReady());
  204. AddObserver(&observer);
  205. }
  206. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfNextCalls) {
  207. MockSystemMediaControlsObserver observer;
  208. EXPECT_CALL(observer, OnNext());
  209. AddObserver(&observer);
  210. CallMediaPlayer2PlayerMethodAndBlock("Next");
  211. }
  212. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPreviousCalls) {
  213. MockSystemMediaControlsObserver observer;
  214. EXPECT_CALL(observer, OnPrevious());
  215. AddObserver(&observer);
  216. CallMediaPlayer2PlayerMethodAndBlock("Previous");
  217. }
  218. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPauseCalls) {
  219. MockSystemMediaControlsObserver observer;
  220. EXPECT_CALL(observer, OnPause());
  221. AddObserver(&observer);
  222. CallMediaPlayer2PlayerMethodAndBlock("Pause");
  223. }
  224. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayPauseCalls) {
  225. MockSystemMediaControlsObserver observer;
  226. EXPECT_CALL(observer, OnPlayPause());
  227. AddObserver(&observer);
  228. CallMediaPlayer2PlayerMethodAndBlock("PlayPause");
  229. }
  230. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfStopCalls) {
  231. MockSystemMediaControlsObserver observer;
  232. EXPECT_CALL(observer, OnStop());
  233. AddObserver(&observer);
  234. CallMediaPlayer2PlayerMethodAndBlock("Stop");
  235. }
  236. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayCalls) {
  237. MockSystemMediaControlsObserver observer;
  238. EXPECT_CALL(observer, OnPlay());
  239. AddObserver(&observer);
  240. CallMediaPlayer2PlayerMethodAndBlock("Play");
  241. }
  242. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSeekCalls) {
  243. MockSystemMediaControlsObserver observer;
  244. EXPECT_CALL(observer, OnSeek(base::Seconds(3)));
  245. AddObserver(&observer);
  246. CallSeekAndBlock(/*is_seek_to=*/false, base::Seconds(3).InMicroseconds());
  247. }
  248. TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSetPositionCalls) {
  249. MockSystemMediaControlsObserver observer;
  250. EXPECT_CALL(observer, OnSeekTo(base::Seconds(7)));
  251. AddObserver(&observer);
  252. CallSeekAndBlock(/*is_seek_to=*/true, base::Seconds(7).InMicroseconds());
  253. }
  254. TEST_F(SystemMediaControlsLinuxTest, ChangingPropertyEmitsSignal) {
  255. base::RunLoop wait_for_signal;
  256. // The returned signal should give the changed property.
  257. EXPECT_CALL(*GetExportedObject(), SendSignal(_))
  258. .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
  259. EXPECT_NE(nullptr, signal);
  260. dbus::MessageReader reader(signal);
  261. std::string interface_name;
  262. ASSERT_TRUE(reader.PopString(&interface_name));
  263. EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
  264. dbus::MessageReader changed_properties_reader(nullptr);
  265. ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
  266. dbus::MessageReader dict_entry_reader(nullptr);
  267. ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
  268. // The changed property name should be "CanPlay".
  269. std::string property_name;
  270. ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
  271. EXPECT_EQ("CanGoNext", property_name);
  272. // The new value should be true.
  273. bool value;
  274. ASSERT_TRUE(dict_entry_reader.PopVariantOfBool(&value));
  275. EXPECT_EQ(true, value);
  276. // CanPlay should be the only entry.
  277. EXPECT_FALSE(changed_properties_reader.HasMoreData());
  278. wait_for_signal.Quit();
  279. }));
  280. // CanPlay is initialized as false, so setting it to true should emit an
  281. // org.freedesktop.DBus.Properties.PropertiesChanged signal.
  282. GetService()->SetIsNextEnabled(true);
  283. wait_for_signal.Run();
  284. // Setting it to true again should not re-signal.
  285. GetService()->SetIsNextEnabled(true);
  286. }
  287. TEST_F(SystemMediaControlsLinuxTest, ChangingMetadataEmitsSignal) {
  288. base::RunLoop wait_for_signal;
  289. // The returned signal should give the changed property.
  290. EXPECT_CALL(*GetExportedObject(), SendSignal(_))
  291. .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
  292. ASSERT_NE(nullptr, signal);
  293. dbus::MessageReader reader(signal);
  294. std::string interface_name;
  295. ASSERT_TRUE(reader.PopString(&interface_name));
  296. EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
  297. dbus::MessageReader changed_properties_reader(nullptr);
  298. ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
  299. dbus::MessageReader dict_entry_reader(nullptr);
  300. ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
  301. // The changed property name should be "Metadata".
  302. std::string property_name;
  303. ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
  304. EXPECT_EQ("Metadata", property_name);
  305. // The new metadata should have the new title.
  306. dbus::MessageReader metadata_variant_reader(nullptr);
  307. ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
  308. dbus::MessageReader metadata_reader(nullptr);
  309. ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
  310. dbus::MessageReader metadata_entry_reader(nullptr);
  311. ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
  312. std::string metadata_property_name;
  313. ASSERT_TRUE(metadata_entry_reader.PopString(&metadata_property_name));
  314. EXPECT_EQ("xesam:title", metadata_property_name);
  315. std::string value;
  316. ASSERT_TRUE(metadata_entry_reader.PopVariantOfString(&value));
  317. EXPECT_EQ("Foo", value);
  318. // Metadata should be the only changed property.
  319. EXPECT_FALSE(changed_properties_reader.HasMoreData());
  320. wait_for_signal.Quit();
  321. }));
  322. // Setting the title should emit an
  323. // org.freedesktop.DBus.Properties.PropertiesChanged signal.
  324. GetService()->SetTitle(u"Foo");
  325. wait_for_signal.Run();
  326. // Setting the title to the same value as before should not emit a new signal.
  327. GetService()->SetTitle(u"Foo");
  328. }
  329. TEST_F(SystemMediaControlsLinuxTest,
  330. PlayingMediaWithPositionWillContinuouslyUpdatePosition) {
  331. base::RunLoop wait_for_initial_position_update;
  332. const base::TimeDelta expected_position = base::Seconds(5);
  333. double expected_rate = 2.0;
  334. const base::TimeDelta expected_duration = base::Seconds(20);
  335. // Since the position is updated every 500ms, and the rate is 2.0, after 500ms
  336. // we should get 6 seconds as the position.
  337. const base::TimeDelta expected_updated_position = base::Seconds(6);
  338. int signal_count = 0;
  339. // The returned signal should give the changed property.
  340. EXPECT_CALL(*GetExportedObject(), SendSignal(_))
  341. .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
  342. signal_count++;
  343. EXPECT_NE(nullptr, signal);
  344. dbus::MessageReader reader(signal);
  345. // The final signal we get is a "Seeked" signal which has a different
  346. // format than the rest.
  347. if (signal_count == 4) {
  348. EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
  349. EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
  350. int64_t new_position;
  351. ASSERT_TRUE(reader.PopInt64(&new_position));
  352. EXPECT_EQ(expected_position.InMicroseconds(), new_position);
  353. wait_for_initial_position_update.Quit();
  354. return;
  355. }
  356. EXPECT_EQ(DBUS_INTERFACE_PROPERTIES, signal->GetInterface());
  357. EXPECT_EQ("PropertiesChanged", signal->GetMember());
  358. std::string interface_name;
  359. ASSERT_TRUE(reader.PopString(&interface_name));
  360. EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
  361. dbus::MessageReader changed_properties_reader(nullptr);
  362. ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
  363. dbus::MessageReader dict_entry_reader(nullptr);
  364. ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
  365. std::string property_name;
  366. std::string metadata_property_name;
  367. dbus::MessageReader metadata_variant_reader(nullptr);
  368. dbus::MessageReader metadata_reader(nullptr);
  369. dbus::MessageReader metadata_entry_reader(nullptr);
  370. std::string playback_status_value;
  371. double rate_value;
  372. int64_t duration_value;
  373. ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
  374. switch (signal_count) {
  375. case 1:
  376. // The first changed property will be the playback status to
  377. // playing.
  378. EXPECT_EQ("PlaybackStatus", property_name);
  379. ASSERT_TRUE(
  380. dict_entry_reader.PopVariantOfString(&playback_status_value));
  381. EXPECT_EQ("Playing", playback_status_value);
  382. break;
  383. case 2:
  384. // The next changed property will be rate to 1.0.
  385. EXPECT_EQ("Rate", property_name);
  386. ASSERT_TRUE(dict_entry_reader.PopVariantOfDouble(&rate_value));
  387. EXPECT_EQ(expected_rate, rate_value);
  388. break;
  389. case 3:
  390. // The next changed property will be duration to 20 seconds.
  391. EXPECT_EQ("Metadata", property_name);
  392. ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
  393. ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
  394. ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
  395. ASSERT_TRUE(
  396. metadata_entry_reader.PopString(&metadata_property_name));
  397. EXPECT_EQ("mpris:length", metadata_property_name);
  398. ASSERT_TRUE(
  399. metadata_entry_reader.PopVariantOfInt64(&duration_value));
  400. EXPECT_EQ(expected_duration.InMicroseconds(), duration_value);
  401. break;
  402. }
  403. // There should only be one entry at a time.
  404. EXPECT_FALSE(changed_properties_reader.HasMoreData());
  405. }));
  406. // Set playback status to "Playing" to ensure the position updates.
  407. GetService()->SetPlaybackStatus(
  408. SystemMediaControls::PlaybackStatus::kPlaying);
  409. // Set the initial position.
  410. media_session::MediaPosition position(expected_rate, expected_duration,
  411. expected_position,
  412. /*end_of_media=*/false);
  413. GetService()->SetPosition(position);
  414. // Wait for the initial position property updates to be signaled.
  415. wait_for_initial_position_update.Run();
  416. // After the initial position signaling, we should not receive more signals
  417. // for the position updates that happen due to typical media playback.
  418. testing::Mock::VerifyAndClearExpectations(GetExportedObject());
  419. EXPECT_CALL(*GetExportedObject(), SendSignal(_)).Times(0);
  420. // Even without signals, the property should still be updated and return the
  421. // correct new value when called after some time.
  422. AdvanceClockMilliseconds(500);
  423. EXPECT_EQ(expected_updated_position.InMicroseconds(),
  424. GetCurrentPositionValue());
  425. const base::TimeDelta expected_seeked_position = base::Seconds(14);
  426. base::RunLoop wait_for_seeked_signal;
  427. // If the position changes in a way that is inconsistent with the current
  428. // playing state (e.g. the user has seeked to a different time), then we
  429. // should receive a "Seeked" signal indicating the change.
  430. testing::Mock::VerifyAndClearExpectations(GetExportedObject());
  431. EXPECT_CALL(*GetExportedObject(), SendSignal(_))
  432. .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
  433. EXPECT_NE(nullptr, signal);
  434. EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
  435. EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
  436. dbus::MessageReader reader(signal);
  437. int64_t new_position;
  438. ASSERT_TRUE(reader.PopInt64(&new_position));
  439. EXPECT_EQ(expected_seeked_position.InMicroseconds(), new_position);
  440. wait_for_seeked_signal.Quit();
  441. }));
  442. media_session::MediaPosition seeked_position(expected_rate, expected_duration,
  443. expected_seeked_position,
  444. /*end_of_media=*/false);
  445. GetService()->SetPosition(seeked_position);
  446. wait_for_seeked_signal.Run();
  447. }
  448. TEST_F(SystemMediaControlsLinuxTest, ChangingIdEmitsSignal) {
  449. base::RunLoop wait_for_signal;
  450. // The returned signal should give the new Id.
  451. EXPECT_CALL(*GetExportedObject(), SendSignal(_))
  452. .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
  453. ASSERT_NE(nullptr, signal);
  454. dbus::MessageReader reader(signal);
  455. std::string interface_name;
  456. ASSERT_TRUE(reader.PopString(&interface_name));
  457. EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
  458. dbus::MessageReader changed_properties_reader(nullptr);
  459. ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
  460. dbus::MessageReader dict_entry_reader(nullptr);
  461. ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
  462. // The changed property name should be "Metadata".
  463. std::string property_name;
  464. ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
  465. EXPECT_EQ("Metadata", property_name);
  466. // The new metadata should have the new Id.
  467. dbus::MessageReader metadata_variant_reader(nullptr);
  468. ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
  469. dbus::MessageReader metadata_reader(nullptr);
  470. ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
  471. dbus::MessageReader metadata_entry_reader(nullptr);
  472. ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
  473. std::string metadata_property_name;
  474. ASSERT_TRUE(metadata_entry_reader.PopString(&metadata_property_name));
  475. EXPECT_EQ("mpris:trackid", metadata_property_name);
  476. dbus::ObjectPath value;
  477. ASSERT_TRUE(metadata_entry_reader.PopVariantOfObjectPath(&value));
  478. EXPECT_EQ("/org/chromium/MediaPlayer2/TrackList/TrackFooId",
  479. value.value());
  480. // Metadata should be the only changed property.
  481. EXPECT_FALSE(changed_properties_reader.HasMoreData());
  482. wait_for_signal.Quit();
  483. }));
  484. // Setting the ID should emit an
  485. // org.freedesktop.DBus.Properties.PropertiesChanged signal.
  486. const std::string given_id("FooId");
  487. GetService()->SetID(&given_id);
  488. wait_for_signal.Run();
  489. }
  490. } // namespace internal
  491. } // namespace system_media_controls