|
@@ -1,497 +0,0 @@
|
|
|
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
-From: Maksim Sisov <[email protected]>
|
|
|
-Date: Tue, 7 Jan 2025 23:46:56 -0800
|
|
|
-Subject: Check for unit to activate before notifying about success
|
|
|
-
|
|
|
-Portal's globalShortcuts interface relies on the unit name to
|
|
|
-properly assign a client for the bound commands. However, in
|
|
|
-some scenarious, there is a race between the service to be
|
|
|
-created, changed its name and activated. As a result, shortcuts
|
|
|
-might be bound before the name is changed. As a result, shortcuts
|
|
|
-might not correctly work and the client will not receive any
|
|
|
-signals.
|
|
|
-
|
|
|
-This is mostly not an issue for Chromium as it creates the
|
|
|
-global shortcuts portal linux object way earlier than it gets
|
|
|
-commands from the command service. But downstream project, which
|
|
|
-try to bind shortcuts at the same time as that instance is created,
|
|
|
-may experience this issue. As a result, they might not have
|
|
|
-shortcuts working correctly after system reboot or app restart as
|
|
|
-there is a race between those operations.
|
|
|
-
|
|
|
-Bug: None
|
|
|
-Change-Id: I8346d65e051d9587850c76ca0b8807669c161667
|
|
|
-Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6110782
|
|
|
-Reviewed-by: Thomas Anderson <[email protected]>
|
|
|
-Commit-Queue: Maksim Sisov <[email protected]>
|
|
|
-Cr-Commit-Position: refs/heads/main@{#1403434}
|
|
|
-
|
|
|
-diff --git a/components/dbus/xdg/systemd.cc b/components/dbus/xdg/systemd.cc
|
|
|
-index 362a16447bf578923cb8a84674c277ae6c98228f..3cd9a55d540c07a4c53f5a62bec5cbea37c11838 100644
|
|
|
---- a/components/dbus/xdg/systemd.cc
|
|
|
-+++ b/components/dbus/xdg/systemd.cc
|
|
|
-@@ -4,9 +4,12 @@
|
|
|
-
|
|
|
- #include "components/dbus/xdg/systemd.h"
|
|
|
-
|
|
|
-+#include <string>
|
|
|
- #include <vector>
|
|
|
-
|
|
|
- #include "base/environment.h"
|
|
|
-+#include "base/functional/bind.h"
|
|
|
-+#include "base/functional/callback_helpers.h"
|
|
|
- #include "base/memory/scoped_refptr.h"
|
|
|
- #include "base/no_destructor.h"
|
|
|
- #include "base/sequence_checker.h"
|
|
|
-@@ -17,7 +20,9 @@
|
|
|
- #include "components/dbus/utils/name_has_owner.h"
|
|
|
- #include "dbus/bus.h"
|
|
|
- #include "dbus/message.h"
|
|
|
-+#include "dbus/object_path.h"
|
|
|
- #include "dbus/object_proxy.h"
|
|
|
-+#include "dbus/property.h"
|
|
|
- #include "third_party/abseil-cpp/absl/types/variant.h"
|
|
|
-
|
|
|
- namespace dbus_xdg {
|
|
|
-@@ -37,6 +42,10 @@ constexpr char kServiceNameSystemd[] = "org.freedesktop.systemd1";
|
|
|
- constexpr char kObjectPathSystemd[] = "/org/freedesktop/systemd1";
|
|
|
- constexpr char kInterfaceSystemdManager[] = "org.freedesktop.systemd1.Manager";
|
|
|
- constexpr char kMethodStartTransientUnit[] = "StartTransientUnit";
|
|
|
-+constexpr char kMethodGetUnit[] = "GetUnit";
|
|
|
-+
|
|
|
-+constexpr char kInterfaceSystemdUnit[] = "org.freedesktop.systemd1.Unit";
|
|
|
-+constexpr char kActiveStateProp[] = "ActiveState";
|
|
|
-
|
|
|
- constexpr char kUnitNameFormat[] = "app-$1$2-$3.scope";
|
|
|
-
|
|
|
-@@ -67,6 +76,81 @@ const char* GetAppNameSuffix(const std::string& channel) {
|
|
|
- return "";
|
|
|
- }
|
|
|
-
|
|
|
-+// Declare this helper for SystemdUnitActiveStateWatcher to be used.
|
|
|
-+void SetStateAndRunCallbacks(SystemdUnitStatus result);
|
|
|
-+
|
|
|
-+// Watches the object to become active and fires callbacks via
|
|
|
-+// SetStateAndRunCallbacks. The callbacks are fired whenever a response with the
|
|
|
-+// state being "active" or "failed" (or similar) comes.
|
|
|
-+//
|
|
|
-+// PS firing callbacks results in destroying this object. So any references
|
|
|
-+// to this become invalid.
|
|
|
-+class SystemdUnitActiveStateWatcher : public dbus::PropertySet {
|
|
|
-+ public:
|
|
|
-+ SystemdUnitActiveStateWatcher(scoped_refptr<dbus::Bus> bus,
|
|
|
-+ dbus::ObjectProxy* object_proxy)
|
|
|
-+ : dbus::PropertySet(object_proxy,
|
|
|
-+ kInterfaceSystemdUnit,
|
|
|
-+ base::BindRepeating(
|
|
|
-+ &SystemdUnitActiveStateWatcher::OnPropertyChanged,
|
|
|
-+ base::Unretained(this))),
|
|
|
-+ bus_(bus) {
|
|
|
-+ RegisterProperty(kActiveStateProp, &active_state_);
|
|
|
-+ ConnectSignals();
|
|
|
-+ GetAll();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ~SystemdUnitActiveStateWatcher() override {
|
|
|
-+ bus_->RemoveObjectProxy(kServiceNameSystemd, object_proxy()->object_path(),
|
|
|
-+ base::DoNothing());
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ private:
|
|
|
-+ void OnPropertyChanged(const std::string& property_name) {
|
|
|
-+ DCHECK(active_state_.is_valid());
|
|
|
-+ const std::string state_value = active_state_.value();
|
|
|
-+ if (callbacks_called_ || state_value == "activating" ||
|
|
|
-+ state_value == "reloading") {
|
|
|
-+ // Ignore if callbacks have already been fired or continue waiting until
|
|
|
-+ // the state changes to something else.
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ // There are other states as failed, inactive, and deactivating. Treat all
|
|
|
-+ // of them as failed.
|
|
|
-+ callbacks_called_ = true;
|
|
|
-+ SetStateAndRunCallbacks(state_value == "active"
|
|
|
-+ ? SystemdUnitStatus::kUnitStarted
|
|
|
-+ : SystemdUnitStatus::kFailedToStart);
|
|
|
-+ MaybeDeleteSelf();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ void OnGetAll(dbus::Response* response) override {
|
|
|
-+ dbus::PropertySet::OnGetAll(response);
|
|
|
-+ keep_alive_ = false;
|
|
|
-+ MaybeDeleteSelf();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ void MaybeDeleteSelf() {
|
|
|
-+ if (!keep_alive_ && callbacks_called_) {
|
|
|
-+ delete this;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ // Registered property that this listens updates to.
|
|
|
-+ dbus::Property<std::string> active_state_;
|
|
|
-+
|
|
|
-+ // Indicates whether callbacks for the unit's state have been called.
|
|
|
-+ bool callbacks_called_ = false;
|
|
|
-+
|
|
|
-+ // Control variable that helps to defer the destruction of |this| as deleting
|
|
|
-+ // self when the state changes to active during |OnGetAll| will result in a
|
|
|
-+ // segfault.
|
|
|
-+ bool keep_alive_ = true;
|
|
|
-+
|
|
|
-+ scoped_refptr<dbus::Bus> bus_;
|
|
|
-+};
|
|
|
-+
|
|
|
- // Global state for cached result or pending callbacks.
|
|
|
- StatusOrCallbacks& GetUnitNameState() {
|
|
|
- static base::NoDestructor<StatusOrCallbacks> state(
|
|
|
-@@ -83,10 +167,52 @@ void SetStateAndRunCallbacks(SystemdUnitStatus result) {
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
--void OnStartTransientUnitResponse(dbus::Response* response) {
|
|
|
-+void OnGetPathResponse(scoped_refptr<dbus::Bus> bus, dbus::Response* response) {
|
|
|
-+ dbus::MessageReader reader(response);
|
|
|
-+ dbus::ObjectPath obj_path;
|
|
|
-+ if (!response || !reader.PopObjectPath(&obj_path) || !obj_path.IsValid()) {
|
|
|
-+ // We didn't get a valid response. Treat this as failed service.
|
|
|
-+ SetStateAndRunCallbacks(SystemdUnitStatus::kFailedToStart);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ dbus::ObjectProxy* unit_proxy =
|
|
|
-+ bus->GetObjectProxy(kServiceNameSystemd, obj_path);
|
|
|
-+ // Create the active state property watcher. It will destroy itself once
|
|
|
-+ // it gets notified about the state change.
|
|
|
-+ std::unique_ptr<SystemdUnitActiveStateWatcher> active_state_watcher =
|
|
|
-+ std::make_unique<SystemdUnitActiveStateWatcher>(bus, unit_proxy);
|
|
|
-+ active_state_watcher.release();
|
|
|
-+}
|
|
|
-+
|
|
|
-+void WaitUnitActivateAndRunCallbacks(scoped_refptr<dbus::Bus> bus,
|
|
|
-+ std::string unit_name) {
|
|
|
-+ // Get the path of the unit, which looks similar to
|
|
|
-+ // /org/freedesktop/systemd1/unit/app_2dorg_2echromium_2eChromium_2d3182191_2escope
|
|
|
-+ // and then wait for it activation.
|
|
|
-+ dbus::ObjectProxy* systemd = bus->GetObjectProxy(
|
|
|
-+ kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
|
|
|
-+
|
|
|
-+ dbus::MethodCall method_call(kInterfaceSystemdManager, kMethodGetUnit);
|
|
|
-+ dbus::MessageWriter writer(&method_call);
|
|
|
-+ writer.AppendString(unit_name);
|
|
|
-+
|
|
|
-+ systemd->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
|
|
|
-+ base::BindOnce(&OnGetPathResponse, std::move(bus)));
|
|
|
-+}
|
|
|
-+
|
|
|
-+void OnStartTransientUnitResponse(scoped_refptr<dbus::Bus> bus,
|
|
|
-+ std::string unit_name,
|
|
|
-+ dbus::Response* response) {
|
|
|
- SystemdUnitStatus result = response ? SystemdUnitStatus::kUnitStarted
|
|
|
- : SystemdUnitStatus::kFailedToStart;
|
|
|
-- SetStateAndRunCallbacks(result);
|
|
|
-+ // If the start of the unit failed, immediately notify the client. Otherwise,
|
|
|
-+ // wait for its activation.
|
|
|
-+ if (result == SystemdUnitStatus::kFailedToStart) {
|
|
|
-+ SetStateAndRunCallbacks(result);
|
|
|
-+ } else {
|
|
|
-+ WaitUnitActivateAndRunCallbacks(std::move(bus), unit_name);
|
|
|
-+ }
|
|
|
- }
|
|
|
-
|
|
|
- void OnNameHasOwnerResponse(scoped_refptr<dbus::Bus> bus,
|
|
|
-@@ -128,8 +254,9 @@ void OnNameHasOwnerResponse(scoped_refptr<dbus::Bus> bus,
|
|
|
- properties.Write(&writer);
|
|
|
- // No auxiliary units.
|
|
|
- Dict<VarDict>().Write(&writer);
|
|
|
-- systemd->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
|
|
|
-- base::BindOnce(&OnStartTransientUnitResponse));
|
|
|
-+ systemd->CallMethod(
|
|
|
-+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
|
|
|
-+ base::BindOnce(&OnStartTransientUnitResponse, std::move(bus), unit_name));
|
|
|
- }
|
|
|
-
|
|
|
- } // namespace
|
|
|
-diff --git a/components/dbus/xdg/systemd_unittest.cc b/components/dbus/xdg/systemd_unittest.cc
|
|
|
-index 2e3baecabc4b479000c78d4f6bd30cb1f6e61d2e..67278d7033664d52fbbda02749a2aaa43352f402 100644
|
|
|
---- a/components/dbus/xdg/systemd_unittest.cc
|
|
|
-+++ b/components/dbus/xdg/systemd_unittest.cc
|
|
|
-@@ -16,7 +16,9 @@
|
|
|
- #include "dbus/message.h"
|
|
|
- #include "dbus/mock_bus.h"
|
|
|
- #include "dbus/mock_object_proxy.h"
|
|
|
-+#include "dbus/object_path.h"
|
|
|
- #include "dbus/object_proxy.h"
|
|
|
-+#include "dbus/property.h"
|
|
|
- #include "testing/gmock/include/gmock/gmock.h"
|
|
|
- #include "testing/gtest/include/gtest/gtest.h"
|
|
|
-
|
|
|
-@@ -32,6 +34,27 @@ constexpr char kServiceNameSystemd[] = "org.freedesktop.systemd1";
|
|
|
- constexpr char kObjectPathSystemd[] = "/org/freedesktop/systemd1";
|
|
|
- constexpr char kInterfaceSystemdManager[] = "org.freedesktop.systemd1.Manager";
|
|
|
- constexpr char kMethodStartTransientUnit[] = "StartTransientUnit";
|
|
|
-+constexpr char kMethodGetUnit[] = "GetUnit";
|
|
|
-+
|
|
|
-+constexpr char kFakeUnitPath[] = "/fake/unit/path";
|
|
|
-+constexpr char kActiveState[] = "ActiveState";
|
|
|
-+constexpr char kStateActive[] = "active";
|
|
|
-+constexpr char kStateInactive[] = "inactive";
|
|
|
-+
|
|
|
-+std::unique_ptr<dbus::Response> CreateActiveStateGetAllResponse(
|
|
|
-+ const std::string& state) {
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ dbus::MessageWriter array_writer(nullptr);
|
|
|
-+ dbus::MessageWriter dict_entry_writer(nullptr);
|
|
|
-+ writer.OpenArray("{sv}", &array_writer);
|
|
|
-+ array_writer.OpenDictEntry(&dict_entry_writer);
|
|
|
-+ dict_entry_writer.AppendString(kActiveState);
|
|
|
-+ dict_entry_writer.AppendVariantOfString(state);
|
|
|
-+ array_writer.CloseContainer(&dict_entry_writer);
|
|
|
-+ writer.CloseContainer(&array_writer);
|
|
|
-+ return response;
|
|
|
-+}
|
|
|
-
|
|
|
- class SetSystemdScopeUnitNameForXdgPortalTest : public ::testing::Test {
|
|
|
- public:
|
|
|
-@@ -124,17 +147,48 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, StartTransientUnitSuccess) {
|
|
|
-
|
|
|
- EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
- dbus::ObjectPath(kObjectPathSystemd)))
|
|
|
-- .WillOnce(Return(mock_systemd_proxy.get()));
|
|
|
-+ .Times(2)
|
|
|
-+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
|
|
|
-+
|
|
|
-+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
|
|
|
-+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
-+ dbus::ObjectPath(kFakeUnitPath)))
|
|
|
-+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
|
|
|
-
|
|
|
- EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
|
|
|
- .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
- dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ // Expect kMethodStartTransientUnit first.
|
|
|
- EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
- EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
|
|
|
-
|
|
|
- // Simulate a successful response
|
|
|
- auto response = dbus::Response::CreateEmpty();
|
|
|
- std::move(*callback).Run(response.get());
|
|
|
-+ }))
|
|
|
-+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
|
|
|
-+ dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ // Then expect kMethodGetUnit. A valid path must be provided.
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
|
|
|
-+
|
|
|
-+ // Simulate a successful response and provide a fake path to the object.
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
|
|
|
-+ // Simulate a successful response with "active" state.
|
|
|
-+ auto response = CreateActiveStateGetAllResponse(kStateActive);
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
- }));
|
|
|
-
|
|
|
- std::optional<SystemdUnitStatus> status;
|
|
|
-@@ -189,6 +243,142 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, StartTransientUnitFailure) {
|
|
|
- EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
|
|
|
- }
|
|
|
-
|
|
|
-+TEST_F(SetSystemdScopeUnitNameForXdgPortalTest,
|
|
|
-+ StartTransientUnitInvalidUnitPath) {
|
|
|
-+ scoped_refptr<dbus::MockBus> bus =
|
|
|
-+ base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
|
|
|
-+
|
|
|
-+ auto mock_dbus_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(
|
|
|
-+ *bus, GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)))
|
|
|
-+ .WillRepeatedly(Return(mock_dbus_proxy.get()));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_dbus_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ writer.AppendBool(true);
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ auto mock_systemd_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
-+ dbus::ObjectPath(kObjectPathSystemd)))
|
|
|
-+ .Times(2)
|
|
|
-+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
|
|
|
-+
|
|
|
-+ // Simulate a successful response
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
|
|
|
-+
|
|
|
-+ // Simulate a failure response.
|
|
|
-+ std::move(*callback).Run(nullptr);
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ std::optional<SystemdUnitStatus> status;
|
|
|
-+
|
|
|
-+ SetSystemdScopeUnitNameForXdgPortal(
|
|
|
-+ bus.get(), base::BindLambdaForTesting(
|
|
|
-+ [&](SystemdUnitStatus result) { status = result; }));
|
|
|
-+
|
|
|
-+ EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
|
|
|
-+}
|
|
|
-+
|
|
|
-+TEST_F(SetSystemdScopeUnitNameForXdgPortalTest,
|
|
|
-+ StartTransientUnitFailToActivate) {
|
|
|
-+ scoped_refptr<dbus::MockBus> bus =
|
|
|
-+ base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
|
|
|
-+
|
|
|
-+ auto mock_dbus_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(
|
|
|
-+ *bus, GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)))
|
|
|
-+ .WillRepeatedly(Return(mock_dbus_proxy.get()));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_dbus_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ writer.AppendBool(true);
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ auto mock_systemd_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
-+ dbus::ObjectPath(kObjectPathSystemd)))
|
|
|
-+ .Times(2)
|
|
|
-+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
|
|
|
-+
|
|
|
-+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
|
|
|
-+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
-+ dbus::ObjectPath(kFakeUnitPath)))
|
|
|
-+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
|
|
|
-+
|
|
|
-+ // Simulate a successful response
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }))
|
|
|
-+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
|
|
|
-+ dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
|
|
|
-+
|
|
|
-+ // Simulate a successful response
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ // Then expect kMethodGetUnit. A valid path must be provided.
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
|
|
|
-+
|
|
|
-+ // Simulate a successful response, but with inactive state.
|
|
|
-+ auto response = CreateActiveStateGetAllResponse(kStateInactive);
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ std::optional<SystemdUnitStatus> status;
|
|
|
-+
|
|
|
-+ SetSystemdScopeUnitNameForXdgPortal(
|
|
|
-+ bus.get(), base::BindLambdaForTesting(
|
|
|
-+ [&](SystemdUnitStatus result) { status = result; }));
|
|
|
-+
|
|
|
-+ EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
|
|
|
-+}
|
|
|
-+
|
|
|
- TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
|
|
|
- scoped_refptr<dbus::MockBus> bus =
|
|
|
- base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
|
|
|
-@@ -220,7 +410,14 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
|
|
|
-
|
|
|
- EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
- dbus::ObjectPath(kObjectPathSystemd)))
|
|
|
-- .WillOnce(Return(mock_systemd_proxy.get()));
|
|
|
-+ .Times(2)
|
|
|
-+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
|
|
|
-+
|
|
|
-+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
|
|
|
-+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
|
|
|
-+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
|
|
|
-+ dbus::ObjectPath(kFakeUnitPath)))
|
|
|
-+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
|
|
|
-
|
|
|
- EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
|
|
|
- .WillOnce(Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-@@ -256,6 +453,30 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
|
|
|
-
|
|
|
- auto response = dbus::Response::CreateEmpty();
|
|
|
- std::move(*callback).Run(response.get());
|
|
|
-+ }))
|
|
|
-+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
|
|
|
-+ dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
|
|
|
-+
|
|
|
-+ // Simulate a successful response
|
|
|
-+ auto response = dbus::Response::CreateEmpty();
|
|
|
-+ dbus::MessageWriter writer(response.get());
|
|
|
-+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
-+ }));
|
|
|
-+
|
|
|
-+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
|
|
|
-+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
|
|
|
-+ dbus::ObjectProxy::ResponseCallback* callback) {
|
|
|
-+ // Then expect kMethodGetUnit. A valid path must be provided.
|
|
|
-+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
|
|
|
-+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
|
|
|
-+
|
|
|
-+ // Simulate a successful response
|
|
|
-+ auto response = CreateActiveStateGetAllResponse(kStateActive);
|
|
|
-+ std::move(*callback).Run(response.get());
|
|
|
- }));
|
|
|
-
|
|
|
- std::optional<SystemdUnitStatus> status;
|