123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- // Copyright 2019 The Chromium 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 "components/system_media_controls/linux/system_media_controls_linux.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/containers/flat_map.h"
- #include "base/run_loop.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/task_environment.h"
- #include "components/dbus/thread_linux/dbus_thread_linux.h"
- #include "components/system_media_controls/system_media_controls_observer.h"
- #include "dbus/message.h"
- #include "dbus/mock_bus.h"
- #include "dbus/mock_exported_object.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using ::testing::_;
- using ::testing::Invoke;
- using ::testing::Return;
- using ::testing::Unused;
- using ::testing::WithArg;
- namespace system_media_controls {
- namespace internal {
- namespace {
- constexpr uint32_t kFakeSerial = 123;
- const char kTestProductName[] = "Foo";
- } // anonymous namespace
- class MockSystemMediaControlsObserver : public SystemMediaControlsObserver {
- public:
- MockSystemMediaControlsObserver() = default;
- ~MockSystemMediaControlsObserver() override = default;
- // SystemMediaControlsObserver implementation.
- MOCK_METHOD0(OnServiceReady, void());
- MOCK_METHOD0(OnNext, void());
- MOCK_METHOD0(OnPrevious, void());
- MOCK_METHOD0(OnPause, void());
- MOCK_METHOD0(OnPlayPause, void());
- MOCK_METHOD0(OnStop, void());
- MOCK_METHOD0(OnPlay, void());
- MOCK_METHOD1(OnSeek, void(const base::TimeDelta&));
- MOCK_METHOD1(OnSeekTo, void(const base::TimeDelta&));
- };
- class SystemMediaControlsLinuxTest : public testing::Test,
- public SystemMediaControlsObserver {
- public:
- SystemMediaControlsLinuxTest()
- : task_environment_(base::test::TaskEnvironment::MainThreadType::UI,
- base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- SystemMediaControlsLinuxTest(const SystemMediaControlsLinuxTest&) = delete;
- SystemMediaControlsLinuxTest& operator=(const SystemMediaControlsLinuxTest&) =
- delete;
- ~SystemMediaControlsLinuxTest() override = default;
- void SetUp() override { StartMprisServiceAndWaitForReady(); }
- void AddObserver(MockSystemMediaControlsObserver* observer) {
- service_->AddObserver(observer);
- }
- void CallMediaPlayer2PlayerMethodAndBlock(const std::string& method_name) {
- EXPECT_TRUE(player_interface_exported_methods_.contains(method_name));
- response_wait_loop_ = std::make_unique<base::RunLoop>();
- // We need to supply a serial or the test will crash.
- dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
- method_call.SetSerial(kFakeSerial);
- // Call the method and await a response.
- player_interface_exported_methods_[method_name].Run(
- &method_call,
- base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
- base::Unretained(this)));
- response_wait_loop_->Run();
- }
- void CallSeekAndBlock(bool is_seek_to, int64_t offset_or_position) {
- response_wait_loop_ = std::make_unique<base::RunLoop>();
- // We need to supply a serial or the test will crash.
- const std::string method_name = is_seek_to ? "SetPosition" : "Seek";
- dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
- method_call.SetSerial(kFakeSerial);
- dbus::MessageWriter writer(&method_call);
- if (is_seek_to)
- writer.AppendObjectPath(
- dbus::ObjectPath("/org/chromium/MediaPlayer2/TrackList/TrackFooId"));
- writer.AppendInt64(offset_or_position);
- // Call the method and await a response.
- player_interface_exported_methods_[method_name].Run(
- &method_call,
- base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
- base::Unretained(this)));
- response_wait_loop_->Run();
- }
- int64_t GetCurrentPositionValue() {
- base::RunLoop wait_loop;
- // We need to supply a serial or the test will crash.
- dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get");
- method_call.SetSerial(kFakeSerial);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(kMprisAPIPlayerInterfaceName);
- writer.AppendString("Position");
- int64_t position;
- // Call the method and await a response.
- properties_interface_exported_methods_["Get"].Run(
- &method_call, base::BindOnce(
- [](int64_t* position_out, base::RunLoop& wait_loop,
- std::unique_ptr<dbus::Response> response) {
- // A response of nullptr means an error has
- // occurred.
- EXPECT_NE(nullptr, response.get());
- dbus::MessageReader reader(response.get());
- ASSERT_TRUE(reader.PopVariantOfInt64(position_out));
- wait_loop.Quit();
- },
- &position, std::ref(wait_loop)));
- wait_loop.Run();
- return position;
- }
- SystemMediaControlsLinux* GetService() { return service_.get(); }
- dbus::MockExportedObject* GetExportedObject() {
- return mock_exported_object_.get();
- }
- void AdvanceClockMilliseconds(int ms) {
- task_environment_.FastForwardBy(base::Milliseconds(ms));
- }
- private:
- void StartMprisServiceAndWaitForReady() {
- service_wait_loop_ = std::make_unique<base::RunLoop>();
- service_ = std::make_unique<SystemMediaControlsLinux>(kTestProductName);
- SetUpMocks();
- service_->SetBusForTesting(mock_bus_);
- service_->AddObserver(this);
- service_->StartService();
- service_wait_loop_->Run();
- }
- // Sets up the mock Bus and ExportedObject. The ExportedObject will store the
- // org.mpris.MediaPlayer2.Player exported methods in the
- // |player_interface_exported_methods_| map so we can call them for testing.
- void SetUpMocks() {
- dbus::Bus::Options options;
- options.bus_type = dbus::Bus::SESSION;
- options.connection_type = dbus::Bus::PRIVATE;
- options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
- mock_bus_ = base::MakeRefCounted<dbus::MockBus>(options);
- mock_exported_object_ = base::MakeRefCounted<dbus::MockExportedObject>(
- mock_bus_.get(), dbus::ObjectPath(kMprisAPIObjectPath));
- EXPECT_CALL(*mock_bus_,
- GetExportedObject(dbus::ObjectPath(kMprisAPIObjectPath)))
- .WillOnce(Return(mock_exported_object_.get()));
- EXPECT_CALL(*mock_bus_, RequestOwnership(service_->GetServiceName(), _, _))
- .WillOnce(Invoke(this, &SystemMediaControlsLinuxTest::OnOwnership));
- // The service must call ShutdownAndBlock in order to properly clean up the
- // DBus service.
- EXPECT_CALL(*mock_bus_, ShutdownAndBlock());
- EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
- .WillRepeatedly(
- Invoke(this, &SystemMediaControlsLinuxTest::OnExported));
- }
- // Tell the service that ownership was successful.
- void OnOwnership(const std::string& service_name,
- Unused,
- dbus::Bus::OnOwnershipCallback callback) {
- std::move(callback).Run(service_name, true);
- }
- // Store the exported method if necessary and tell the service that the export
- // was successful.
- void OnExported(const std::string& interface_name,
- const std::string& method_name,
- dbus::ExportedObject::MethodCallCallback exported_method,
- dbus::ExportedObject::OnExportedCallback callback) {
- if (interface_name == kMprisAPIPlayerInterfaceName)
- player_interface_exported_methods_[method_name] = exported_method;
- if (interface_name == DBUS_INTERFACE_PROPERTIES)
- properties_interface_exported_methods_[method_name] = exported_method;
- std::move(callback).Run(interface_name, method_name, true);
- }
- void OnResponse(std::unique_ptr<dbus::Response> response) {
- // A response of nullptr means an error has occurred.
- EXPECT_NE(nullptr, response.get());
- if (response_wait_loop_)
- response_wait_loop_->Quit();
- }
- // SystemMediaControlsObserver implementation.
- void OnServiceReady() override {
- if (service_wait_loop_)
- service_wait_loop_->Quit();
- }
- void OnNext() override {}
- void OnPrevious() override {}
- void OnPlay() override {}
- void OnPause() override {}
- void OnPlayPause() override {}
- void OnStop() override {}
- void OnSeekTo(const base::TimeDelta& time) override {}
- base::test::TaskEnvironment task_environment_;
- std::unique_ptr<base::RunLoop> service_wait_loop_;
- std::unique_ptr<base::RunLoop> response_wait_loop_;
- std::unique_ptr<SystemMediaControlsLinux> service_;
- scoped_refptr<dbus::MockBus> mock_bus_;
- scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
- base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
- player_interface_exported_methods_;
- base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
- properties_interface_exported_methods_;
- };
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfServiceReadyWhenAdded) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnServiceReady());
- AddObserver(&observer);
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfNextCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnNext());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("Next");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPreviousCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnPrevious());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("Previous");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPauseCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnPause());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("Pause");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayPauseCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnPlayPause());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("PlayPause");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfStopCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnStop());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("Stop");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnPlay());
- AddObserver(&observer);
- CallMediaPlayer2PlayerMethodAndBlock("Play");
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSeekCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnSeek(base::Seconds(3)));
- AddObserver(&observer);
- CallSeekAndBlock(/*is_seek_to=*/false, base::Seconds(3).InMicroseconds());
- }
- TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSetPositionCalls) {
- MockSystemMediaControlsObserver observer;
- EXPECT_CALL(observer, OnSeekTo(base::Seconds(7)));
- AddObserver(&observer);
- CallSeekAndBlock(/*is_seek_to=*/true, base::Seconds(7).InMicroseconds());
- }
- TEST_F(SystemMediaControlsLinuxTest, ChangingPropertyEmitsSignal) {
- base::RunLoop wait_for_signal;
- // The returned signal should give the changed property.
- EXPECT_CALL(*GetExportedObject(), SendSignal(_))
- .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
- EXPECT_NE(nullptr, signal);
- dbus::MessageReader reader(signal);
- std::string interface_name;
- ASSERT_TRUE(reader.PopString(&interface_name));
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
- dbus::MessageReader changed_properties_reader(nullptr);
- ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
- dbus::MessageReader dict_entry_reader(nullptr);
- ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
- // The changed property name should be "CanPlay".
- std::string property_name;
- ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
- EXPECT_EQ("CanGoNext", property_name);
- // The new value should be true.
- bool value;
- ASSERT_TRUE(dict_entry_reader.PopVariantOfBool(&value));
- EXPECT_EQ(true, value);
- // CanPlay should be the only entry.
- EXPECT_FALSE(changed_properties_reader.HasMoreData());
- wait_for_signal.Quit();
- }));
- // CanPlay is initialized as false, so setting it to true should emit an
- // org.freedesktop.DBus.Properties.PropertiesChanged signal.
- GetService()->SetIsNextEnabled(true);
- wait_for_signal.Run();
- // Setting it to true again should not re-signal.
- GetService()->SetIsNextEnabled(true);
- }
- TEST_F(SystemMediaControlsLinuxTest, ChangingMetadataEmitsSignal) {
- base::RunLoop wait_for_signal;
- // The returned signal should give the changed property.
- EXPECT_CALL(*GetExportedObject(), SendSignal(_))
- .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
- ASSERT_NE(nullptr, signal);
- dbus::MessageReader reader(signal);
- std::string interface_name;
- ASSERT_TRUE(reader.PopString(&interface_name));
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
- dbus::MessageReader changed_properties_reader(nullptr);
- ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
- dbus::MessageReader dict_entry_reader(nullptr);
- ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
- // The changed property name should be "Metadata".
- std::string property_name;
- ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
- EXPECT_EQ("Metadata", property_name);
- // The new metadata should have the new title.
- dbus::MessageReader metadata_variant_reader(nullptr);
- ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
- dbus::MessageReader metadata_reader(nullptr);
- ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
- dbus::MessageReader metadata_entry_reader(nullptr);
- ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
- std::string metadata_property_name;
- ASSERT_TRUE(metadata_entry_reader.PopString(&metadata_property_name));
- EXPECT_EQ("xesam:title", metadata_property_name);
- std::string value;
- ASSERT_TRUE(metadata_entry_reader.PopVariantOfString(&value));
- EXPECT_EQ("Foo", value);
- // Metadata should be the only changed property.
- EXPECT_FALSE(changed_properties_reader.HasMoreData());
- wait_for_signal.Quit();
- }));
- // Setting the title should emit an
- // org.freedesktop.DBus.Properties.PropertiesChanged signal.
- GetService()->SetTitle(u"Foo");
- wait_for_signal.Run();
- // Setting the title to the same value as before should not emit a new signal.
- GetService()->SetTitle(u"Foo");
- }
- TEST_F(SystemMediaControlsLinuxTest,
- PlayingMediaWithPositionWillContinuouslyUpdatePosition) {
- base::RunLoop wait_for_initial_position_update;
- const base::TimeDelta expected_position = base::Seconds(5);
- double expected_rate = 2.0;
- const base::TimeDelta expected_duration = base::Seconds(20);
- // Since the position is updated every 500ms, and the rate is 2.0, after 500ms
- // we should get 6 seconds as the position.
- const base::TimeDelta expected_updated_position = base::Seconds(6);
- int signal_count = 0;
- // The returned signal should give the changed property.
- EXPECT_CALL(*GetExportedObject(), SendSignal(_))
- .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
- signal_count++;
- EXPECT_NE(nullptr, signal);
- dbus::MessageReader reader(signal);
- // The final signal we get is a "Seeked" signal which has a different
- // format than the rest.
- if (signal_count == 4) {
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
- EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
- int64_t new_position;
- ASSERT_TRUE(reader.PopInt64(&new_position));
- EXPECT_EQ(expected_position.InMicroseconds(), new_position);
- wait_for_initial_position_update.Quit();
- return;
- }
- EXPECT_EQ(DBUS_INTERFACE_PROPERTIES, signal->GetInterface());
- EXPECT_EQ("PropertiesChanged", signal->GetMember());
- std::string interface_name;
- ASSERT_TRUE(reader.PopString(&interface_name));
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
- dbus::MessageReader changed_properties_reader(nullptr);
- ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
- dbus::MessageReader dict_entry_reader(nullptr);
- ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
- std::string property_name;
- std::string metadata_property_name;
- dbus::MessageReader metadata_variant_reader(nullptr);
- dbus::MessageReader metadata_reader(nullptr);
- dbus::MessageReader metadata_entry_reader(nullptr);
- std::string playback_status_value;
- double rate_value;
- int64_t duration_value;
- ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
- switch (signal_count) {
- case 1:
- // The first changed property will be the playback status to
- // playing.
- EXPECT_EQ("PlaybackStatus", property_name);
- ASSERT_TRUE(
- dict_entry_reader.PopVariantOfString(&playback_status_value));
- EXPECT_EQ("Playing", playback_status_value);
- break;
- case 2:
- // The next changed property will be rate to 1.0.
- EXPECT_EQ("Rate", property_name);
- ASSERT_TRUE(dict_entry_reader.PopVariantOfDouble(&rate_value));
- EXPECT_EQ(expected_rate, rate_value);
- break;
- case 3:
- // The next changed property will be duration to 20 seconds.
- EXPECT_EQ("Metadata", property_name);
- ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
- ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
- ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
- ASSERT_TRUE(
- metadata_entry_reader.PopString(&metadata_property_name));
- EXPECT_EQ("mpris:length", metadata_property_name);
- ASSERT_TRUE(
- metadata_entry_reader.PopVariantOfInt64(&duration_value));
- EXPECT_EQ(expected_duration.InMicroseconds(), duration_value);
- break;
- }
- // There should only be one entry at a time.
- EXPECT_FALSE(changed_properties_reader.HasMoreData());
- }));
- // Set playback status to "Playing" to ensure the position updates.
- GetService()->SetPlaybackStatus(
- SystemMediaControls::PlaybackStatus::kPlaying);
- // Set the initial position.
- media_session::MediaPosition position(expected_rate, expected_duration,
- expected_position,
- /*end_of_media=*/false);
- GetService()->SetPosition(position);
- // Wait for the initial position property updates to be signaled.
- wait_for_initial_position_update.Run();
- // After the initial position signaling, we should not receive more signals
- // for the position updates that happen due to typical media playback.
- testing::Mock::VerifyAndClearExpectations(GetExportedObject());
- EXPECT_CALL(*GetExportedObject(), SendSignal(_)).Times(0);
- // Even without signals, the property should still be updated and return the
- // correct new value when called after some time.
- AdvanceClockMilliseconds(500);
- EXPECT_EQ(expected_updated_position.InMicroseconds(),
- GetCurrentPositionValue());
- const base::TimeDelta expected_seeked_position = base::Seconds(14);
- base::RunLoop wait_for_seeked_signal;
- // If the position changes in a way that is inconsistent with the current
- // playing state (e.g. the user has seeked to a different time), then we
- // should receive a "Seeked" signal indicating the change.
- testing::Mock::VerifyAndClearExpectations(GetExportedObject());
- EXPECT_CALL(*GetExportedObject(), SendSignal(_))
- .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
- EXPECT_NE(nullptr, signal);
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
- EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
- dbus::MessageReader reader(signal);
- int64_t new_position;
- ASSERT_TRUE(reader.PopInt64(&new_position));
- EXPECT_EQ(expected_seeked_position.InMicroseconds(), new_position);
- wait_for_seeked_signal.Quit();
- }));
- media_session::MediaPosition seeked_position(expected_rate, expected_duration,
- expected_seeked_position,
- /*end_of_media=*/false);
- GetService()->SetPosition(seeked_position);
- wait_for_seeked_signal.Run();
- }
- TEST_F(SystemMediaControlsLinuxTest, ChangingIdEmitsSignal) {
- base::RunLoop wait_for_signal;
- // The returned signal should give the new Id.
- EXPECT_CALL(*GetExportedObject(), SendSignal(_))
- .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
- ASSERT_NE(nullptr, signal);
- dbus::MessageReader reader(signal);
- std::string interface_name;
- ASSERT_TRUE(reader.PopString(&interface_name));
- EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
- dbus::MessageReader changed_properties_reader(nullptr);
- ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
- dbus::MessageReader dict_entry_reader(nullptr);
- ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
- // The changed property name should be "Metadata".
- std::string property_name;
- ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
- EXPECT_EQ("Metadata", property_name);
- // The new metadata should have the new Id.
- dbus::MessageReader metadata_variant_reader(nullptr);
- ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
- dbus::MessageReader metadata_reader(nullptr);
- ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
- dbus::MessageReader metadata_entry_reader(nullptr);
- ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
- std::string metadata_property_name;
- ASSERT_TRUE(metadata_entry_reader.PopString(&metadata_property_name));
- EXPECT_EQ("mpris:trackid", metadata_property_name);
- dbus::ObjectPath value;
- ASSERT_TRUE(metadata_entry_reader.PopVariantOfObjectPath(&value));
- EXPECT_EQ("/org/chromium/MediaPlayer2/TrackList/TrackFooId",
- value.value());
- // Metadata should be the only changed property.
- EXPECT_FALSE(changed_properties_reader.HasMoreData());
- wait_for_signal.Quit();
- }));
- // Setting the ID should emit an
- // org.freedesktop.DBus.Properties.PropertiesChanged signal.
- const std::string given_id("FooId");
- GetService()->SetID(&given_id);
- wait_for_signal.Run();
- }
- } // namespace internal
- } // namespace system_media_controls
|