Commit c7077414 authored by Jae Hoon Kim's avatar Jae Hoon Kim Committed by Commit Bot

Expose dlcservice DBus API with DlcserviceClient

This creates the DlcserviceClient to call into dlcservice daemon's exposed
DBus API. The dlcservice daemon provides management of DLC
(Downloadable Content) modules. Exposures from DlcserviceClient is to
allow for Install/Uninstall/GetInstalled in a manner that wraps the
respective DBus API exported from the dlcservice daemon in a Chrome
style callable interface.

Information on building a DLC and how what dlcservice daemon is can be
followed at:
https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/dlcservice

Bug: 1000711
Test: autoninja -C out/Default chromeos_unittests && testing/xvfb.py out/Default/chromeos_unittests --gtest_filter=DlcserviceClientTest*
Test: autoninja -C out/Default unit_tests && testing/xvfb.py ./out/Default/unit_tests
Test: autoninja -C out_${SDK_BOARD}/Release chrome nacl_helper && deploy_chrome --build-dir=out_${SDK_BOARD}/Release --to=$TEST_IP
Test: modifications to actually call into to DlcserviceClient with nebraska.py as payload path server. $> restart ui
Test: Custom CHROMEOS_AUSERVER within /mnt/stateful_partition/etc/lsb-release on DUT with local nebraska.py port.
Change-Id: Ia269cab18d7fcc4c1c6d0ee72fb3383b11af38a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1802682
Commit-Queue: Jae Hoon Kim <kimjae@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#697691}
parent 6ea2b48a
...@@ -108,6 +108,8 @@ source_set("chromeos") { ...@@ -108,6 +108,8 @@ source_set("chromeos") {
"//chromeos/dbus/cryptohome:cryptohome_proto", "//chromeos/dbus/cryptohome:cryptohome_proto",
"//chromeos/dbus/cryptohome:cryptohome_signkey_proto", "//chromeos/dbus/cryptohome:cryptohome_signkey_proto",
"//chromeos/dbus/cups_proxy", "//chromeos/dbus/cups_proxy",
"//chromeos/dbus/dlcservice",
"//chromeos/dbus/dlcservice:dlcservice_proto",
"//chromeos/dbus/kerberos", "//chromeos/dbus/kerberos",
"//chromeos/dbus/kerberos:kerberos_proto", "//chromeos/dbus/kerberos:kerberos_proto",
"//chromeos/dbus/machine_learning", "//chromeos/dbus/machine_learning",
...@@ -2902,6 +2904,7 @@ source_set("unit_tests") { ...@@ -2902,6 +2904,7 @@ source_set("unit_tests") {
"//chromeos/dbus/auth_policy", "//chromeos/dbus/auth_policy",
"//chromeos/dbus/cryptohome", "//chromeos/dbus/cryptohome",
"//chromeos/dbus/cryptohome:attestation_proto", "//chromeos/dbus/cryptohome:attestation_proto",
"//chromeos/dbus/dlcservice:test_support",
"//chromeos/dbus/power", "//chromeos/dbus/power",
"//chromeos/dbus/services:test_support", "//chromeos/dbus/services:test_support",
"//chromeos/dbus/session_manager", "//chromeos/dbus/session_manager",
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "chromeos/dbus/cros_healthd/cros_healthd_client.h" #include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
#include "chromeos/dbus/cups_proxy/cups_proxy_client.h" #include "chromeos/dbus/cups_proxy/cups_proxy_client.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/dlcservice/dlcservice_client.h"
#include "chromeos/dbus/initialize_dbus_client.h" #include "chromeos/dbus/initialize_dbus_client.h"
#include "chromeos/dbus/kerberos/kerberos_client.h" #include "chromeos/dbus/kerberos/kerberos_client.h"
#include "chromeos/dbus/machine_learning/machine_learning_client.h" #include "chromeos/dbus/machine_learning/machine_learning_client.h"
...@@ -63,6 +64,7 @@ void InitializeDBus() { ...@@ -63,6 +64,7 @@ void InitializeDBus() {
InitializeDBusClient<CrosHealthdClient>(bus); InitializeDBusClient<CrosHealthdClient>(bus);
InitializeDBusClient<CryptohomeClient>(bus); InitializeDBusClient<CryptohomeClient>(bus);
InitializeDBusClient<CupsProxyClient>(bus); InitializeDBusClient<CupsProxyClient>(bus);
InitializeDBusClient<DlcserviceClient>(bus);
InitializeDBusClient<KerberosClient>(bus); InitializeDBusClient<KerberosClient>(bus);
InitializeDBusClient<MachineLearningClient>(bus); InitializeDBusClient<MachineLearningClient>(bus);
InitializeDBusClient<MediaAnalyticsClient>(bus); InitializeDBusClient<MediaAnalyticsClient>(bus);
...@@ -98,6 +100,7 @@ void ShutdownDBus() { ...@@ -98,6 +100,7 @@ void ShutdownDBus() {
MediaAnalyticsClient::Shutdown(); MediaAnalyticsClient::Shutdown();
MachineLearningClient::Shutdown(); MachineLearningClient::Shutdown();
KerberosClient::Shutdown(); KerberosClient::Shutdown();
DlcserviceClient::Shutdown();
CupsProxyClient::Shutdown(); CupsProxyClient::Shutdown();
CryptohomeClient::Shutdown(); CryptohomeClient::Shutdown();
CrosHealthdClient::Shutdown(); CrosHealthdClient::Shutdown();
......
...@@ -210,6 +210,7 @@ source_set("unit_tests") { ...@@ -210,6 +210,7 @@ source_set("unit_tests") {
"//chromeos/dbus/biod:test_support", "//chromeos/dbus/biod:test_support",
"//chromeos/dbus/cryptohome", "//chromeos/dbus/cryptohome",
"//chromeos/dbus/cryptohome:attestation_proto", "//chromeos/dbus/cryptohome:attestation_proto",
"//chromeos/dbus/dlcservice:test_support",
"//chromeos/dbus/power:power_manager_proto", "//chromeos/dbus/power:power_manager_proto",
"//chromeos/dbus/power:test_support", "//chromeos/dbus/power:test_support",
"//chromeos/dbus/session_manager", "//chromeos/dbus/session_manager",
......
# 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.
import("//third_party/protobuf/proto_library.gni")
assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
component("dlcservice") {
defines = [ "IS_DLCSERVICE_CLIENT_IMPL" ]
public_deps = [
":dlcservice_proto",
"//chromeos/dbus:common",
"//chromeos/dbus:dbus",
]
deps = [
"//base",
"//dbus",
]
sources = [
"dlcservice_client.cc",
"dlcservice_client.h",
"fake_dlcservice_client.cc",
"fake_dlcservice_client.h",
]
}
source_set("test_support") {
testonly = true
public_deps = [
":dlcservice",
]
deps = [
":dlcservice_proto",
"//base",
"//base/test:test_support",
"//dbus:test_support",
"//testing/gmock",
"//testing/gtest",
]
sources = [
"dlcservice_client_unittest.cc",
]
}
proto_library("dlcservice_proto") {
sources = [
"//third_party/cros_system_api/dbus/dlcservice/dlcservice.proto",
]
proto_out_dir = "chromeos/dbus/dlcservice"
}
// Copyright (c) 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 "chromeos/dbus/dlcservice/dlcservice_client.h"
#include <stdint.h>
#include <algorithm>
#include <deque>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/dbus/constants/dbus_switches.h"
#include "chromeos/dbus/dlcservice/fake_dlcservice_client.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
namespace {
const char kOnInstallStatus[] = "OnInstallStatus";
DlcserviceClient* g_instance = nullptr;
class DlcserviceErrorResponseHandler {
public:
explicit DlcserviceErrorResponseHandler(dbus::ErrorResponse* err_response)
: err(dlcservice::kErrorInternal) {
if (err_response && dbus::MessageReader(err_response).PopString(&err_msg) &&
DlcserviceErrorFromString(err_msg, &err)) {
VLOG(1) << "Handling error response err=" << err
<< " err_msg=" << err_msg;
} else {
LOG(ERROR) << "Failed to set err based on error response "
<< "defaulted to kErrorInternal.";
}
}
~DlcserviceErrorResponseHandler() = default;
std::string get_err() { return err; }
std::string get_err_msg() { return err_msg; }
private:
bool DlcserviceErrorFromString(const std::string& err_msg, std::string* err) {
static const base::NoDestructor<std::unordered_set<std::string>> err_set({
dlcservice::kErrorNone,
dlcservice::kErrorInternal,
dlcservice::kErrorBusy,
dlcservice::kErrorNeedReboot,
dlcservice::kErrorInvalidDlc,
});
static const std::pair<std::string, std::string> delims = {"dlcservice/",
":"};
if (!err) {
LOG(ERROR) << "err passed is nullptr.";
return false;
}
// Clear to empty out |err|.
err->clear();
// Verify dlcservice error code.
if (err_msg.find(delims.first) == std::string::npos) {
LOG(ERROR) << "Dlcservice did not send valid error message: " << err_msg;
*err = dlcservice::kErrorInternal;
return true;
}
// Extract the dlcservice error code.
size_t padding = delims.first.size();
size_t second_idx = err_msg.find(delims.second, padding);
*err = err_msg.substr(padding, second_idx - padding);
// Lookup the dlcservice error code and provide default on failure.
auto itr = err_set->find(*err);
*err = itr != err_set->end() ? *itr : dlcservice::kErrorInternal;
return true;
}
// Holds the dlcservice specific error.
std::string err;
// Holds the entire error message from error response.
std::string err_msg;
DISALLOW_COPY_AND_ASSIGN(DlcserviceErrorResponseHandler);
};
} // namespace
// The DlcserviceClient implementation used in production.
class DlcserviceClientImpl : public DlcserviceClient {
public:
DlcserviceClientImpl() : dlcservice_proxy_(nullptr) {}
~DlcserviceClientImpl() override = default;
void Install(const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) override {
if (!service_available_) {
pending_tasks_.emplace_back(base::BindOnce(
&DlcserviceClientImpl::Install, weak_ptr_factory_.GetWeakPtr(),
std::move(dlc_module_list), std::move(callback)));
return;
}
if (install_callback_holder_.has_value()) {
pending_installs_.emplace_back(base::BindOnce(
&DlcserviceClientImpl::Install, weak_ptr_factory_.GetWeakPtr(),
std::move(dlc_module_list), std::move(callback)));
return;
}
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kInstallMethod);
dbus::MessageWriter writer(&method_call);
writer.AppendProtoAsArrayOfBytes(dlc_module_list);
install_callback_holder_ = std::move(callback);
VLOG(1) << "Requesting to install DLC(s).";
dlcservice_proxy_->CallMethodWithErrorResponse(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&DlcserviceClientImpl::OnInstall,
weak_ptr_factory_.GetWeakPtr()));
}
void Uninstall(const std::string& dlc_id,
UninstallCallback callback) override {
if (!service_available_) {
pending_tasks_.emplace_back(base::BindOnce(
&DlcserviceClientImpl::Uninstall, weak_ptr_factory_.GetWeakPtr(),
dlc_id, std::move(callback)));
return;
}
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kUninstallMethod);
dbus::MessageWriter writer(&method_call);
writer.AppendString(dlc_id);
VLOG(1) << "Requesting to uninstall DLC=" << dlc_id;
dlcservice_proxy_->CallMethodWithErrorResponse(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&DlcserviceClientImpl::OnUninstall,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void GetInstalled(GetInstalledCallback callback) override {
if (!service_available_) {
pending_tasks_.emplace_back(
base::BindOnce(&DlcserviceClientImpl::GetInstalled,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
return;
}
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kGetInstalledMethod);
VLOG(1) << "Requesting to get installed DLC(s).";
dlcservice_proxy_->CallMethodWithErrorResponse(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&DlcserviceClientImpl::OnGetInstalled,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void Init(dbus::Bus* bus) {
dlcservice_proxy_ = bus->GetObjectProxy(
dlcservice::kDlcServiceServiceName,
dbus::ObjectPath(dlcservice::kDlcServiceServicePath));
// TODO(kimjae): Use from cros_system_api the const once sync'ed for
// kOnInstallStatus as dlcservice::kOnInstallStatus and delete the
// definition of kOnInstallStatus.
dlcservice_proxy_->ConnectToSignal(
dlcservice::kDlcServiceInterface, kOnInstallStatus,
base::Bind(&DlcserviceClientImpl::OnInstallStatus,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&DlcserviceClientImpl::OnInstallStatusConnected,
weak_ptr_factory_.GetWeakPtr()));
}
private:
void OnInstallStatus(dbus::Signal* signal) {
if (!install_callback_holder_.has_value())
return;
dlcservice::InstallStatus install_status;
if (!dbus::MessageReader(signal).PopArrayOfBytesAsProto(&install_status)) {
LOG(ERROR) << "Failed to parse proto as install status.";
return;
}
auto SendSignal = [this, &install_status]() {
base::Optional<InstallCallback> install_callback;
std::swap(install_callback, install_callback_holder_);
std::move(install_callback.value())
.Run(install_status.error_code(), install_status.dlc_module_list());
};
switch (install_status.status()) {
case dlcservice::Status::COMPLETED:
VLOG(1) << "DLC(s) install successful.";
SendSignal();
break;
case dlcservice::Status::RUNNING:
VLOG(2) << "Install in progress: " << install_status.progress();
// Need to return here since we don't want to try starting another
// pending install from the queue (would waste time checking).
return;
case dlcservice::Status::FAILED:
LOG(ERROR) << "Failed to install with error code: "
<< install_status.error_code();
SendSignal();
break;
default:
NOTREACHED();
}
// Try to run a pending install since we have complete/failed the current
// install, but do not waste trying to run a pending install when the
// current install is running at the moment.
if (!pending_installs_.empty()) {
std::move(pending_installs_.front()).Run();
pending_installs_.pop_front();
}
}
void OnInstallStatusConnected(const std::string& interface,
const std::string& signal,
bool success) {
// When the connected to dlcservice daemon's |OnInstallStatus| signal we can
// go ahead and mark the service as being available and not queue up tasks
// that came in before dlcservice daemon was available.
if (success) {
service_available_ = true;
std::vector<base::OnceClosure> callbacks;
callbacks.swap(pending_tasks_);
for (auto&& callback : callbacks) {
std::move(callback).Run();
}
} else {
LOG(ERROR) << "Failed to connect to install status signal.";
pending_tasks_.clear();
}
}
void OnInstall(dbus::Response* response, dbus::ErrorResponse* err_response) {
if (response)
return;
base::Optional<InstallCallback> install_callback;
std::swap(install_callback, install_callback_holder_);
std::move(install_callback.value())
.Run(DlcserviceErrorResponseHandler(err_response).get_err(),
dlcservice::DlcModuleList());
}
void OnUninstall(UninstallCallback callback,
dbus::Response* response,
dbus::ErrorResponse* err_response) {
if (response) {
std::move(callback).Run(dlcservice::kErrorNone);
return;
}
std::move(callback).Run(
DlcserviceErrorResponseHandler(err_response).get_err());
}
void OnGetInstalled(GetInstalledCallback callback,
dbus::Response* response,
dbus::ErrorResponse* err_response) {
dlcservice::DlcModuleList dlc_module_list;
if (response && dbus::MessageReader(response).PopArrayOfBytesAsProto(
&dlc_module_list)) {
std::move(callback).Run(dlcservice::kErrorNone, dlc_module_list);
return;
}
std::move(callback).Run(
DlcserviceErrorResponseHandler(err_response).get_err(),
dlcservice::DlcModuleList());
}
dbus::ObjectProxy* dlcservice_proxy_;
// True after dlcservice's D-Bus service has become available.
bool service_available_ = false;
// The cached callback to call on a finished |Install()|.
base::Optional<InstallCallback> install_callback_holder_;
// A list of postponed calls to dlcservice to install only used after
// the dlcservice is already available.
std::deque<base::OnceClosure> pending_installs_;
// A list of postponed calls to dlcservice to be called after it becomes
// available.
std::vector<base::OnceClosure> pending_tasks_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<DlcserviceClientImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DlcserviceClientImpl);
};
DlcserviceClient::DlcserviceClient() {
CHECK(!g_instance);
g_instance = this;
}
DlcserviceClient::~DlcserviceClient() {
CHECK_EQ(this, g_instance);
g_instance = nullptr;
}
// static
void DlcserviceClient::Initialize(dbus::Bus* bus) {
CHECK(bus);
(new DlcserviceClientImpl())->Init(bus);
}
// static
void DlcserviceClient::InitializeFake() {
new FakeDlcserviceClient();
}
// static
void DlcserviceClient::Shutdown() {
CHECK(g_instance);
delete g_instance;
}
// static
DlcserviceClient* DlcserviceClient::Get() {
return g_instance;
}
} // namespace chromeos
// Copyright (c) 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.
#ifndef CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
#define CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
#include <stdint.h>
#include <string>
#include "base/callback.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "chromeos/dbus/dbus_client.h"
#include "chromeos/dbus/dbus_client_implementation_type.h"
#include "chromeos/dbus/dlcservice/dlcservice.pb.h"
#include "dbus/message.h"
#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
namespace chromeos {
// DlcserviceClient is used to communicate with the dlcservice daemon which
// manages DLC (Downloadable Content) modules. DlcserviceClient will allow for
// CrOS features to be installed and uninstalled at runtime of the system. If
// more details about dlcservice are required, please consult
// https://chromium.git.corp.google.com/chromiumos/platform2/+/HEAD/dlcservice
class COMPONENT_EXPORT(DLCSERVICE_CLIENT) DlcserviceClient {
public:
// The callback used for |Install()|, if the error is something other than
// |dlcservice::kErrorNone| the call has failed. For large DLC(s) to install,
// there may be delay between the time of this call and the callback being
// invoked.
using InstallCallback = base::OnceCallback<void(
const std::string& err,
const dlcservice::DlcModuleList& dlc_module_list)>;
// The callback used for |Uninstall()|, if the error is something other than
// |dlcservice::kErrorNone| the call has failed.
using UninstallCallback = base::OnceCallback<void(const std::string& err)>;
// The callback used for |GetInstalled()|, if the error is something other
// than |dlcservice::kErrorNone| the call has failed. It is very rare case for
// |GetInstalled()| call to fail.
using GetInstalledCallback = base::OnceCallback<void(
const std::string& err,
const dlcservice::DlcModuleList& dlc_module_list)>;
virtual void Install(const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) = 0;
virtual void Uninstall(const std::string& dlc_id,
UninstallCallback callback) = 0;
virtual void GetInstalled(GetInstalledCallback callback) = 0;
// Creates and initializes the global instance. |bus| must not be nullptr.
static void Initialize(dbus::Bus* bus);
// Creates and initializes a fake global instance if not already created.
static void InitializeFake();
// Destroys the global instance.
static void Shutdown();
// Returns the global instance which may be nullptr if not initialized.
static DlcserviceClient* Get();
protected:
friend class DlcserviceClientTest;
// Initialize/Shutdown should be used instead.
DlcserviceClient();
virtual ~DlcserviceClient();
private:
DISALLOW_COPY_AND_ASSIGN(DlcserviceClient);
};
} // namespace chromeos
#endif // CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
// Copyright (c) 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 "chromeos/dbus/dlcservice/dlcservice_client.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_object_proxy.h"
#include "dbus/object_path.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::WithArg;
namespace chromeos {
class DlcserviceClientTest : public testing::Test {
public:
void SetUp() override {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
mock_bus_ = base::MakeRefCounted<::testing::NiceMock<dbus::MockBus>>(
dbus::Bus::Options());
mock_proxy_ = base::MakeRefCounted<dbus::MockObjectProxy>(
mock_bus_.get(), dlcservice::kDlcServiceServiceName,
dbus::ObjectPath(dlcservice::kDlcServiceServicePath));
EXPECT_CALL(
*mock_bus_.get(),
GetObjectProxy(dlcservice::kDlcServiceServiceName,
dbus::ObjectPath(dlcservice::kDlcServiceServicePath)))
.WillOnce(Return(mock_proxy_.get()));
EXPECT_CALL(*mock_proxy_.get(),
DoConnectToSignal(dlcservice::kDlcServiceInterface, _, _, _))
.WillOnce(Invoke(this, &DlcserviceClientTest::ConnectToSignal));
EXPECT_CALL(*mock_proxy_.get(), DoCallMethodWithErrorResponse(_, _, _))
.WillOnce(
Invoke(this, &DlcserviceClientTest::CallMethodWithErrorResponse));
DlcserviceClient::Initialize(mock_bus_.get());
client_ = DlcserviceClient::Get();
base::RunLoop().RunUntilIdle();
}
void TearDown() override { DlcserviceClient::Shutdown(); }
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
DlcserviceClient* client_;
scoped_refptr<dbus::MockBus> mock_bus_;
scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
std::unique_ptr<dbus::Response> response_;
std::unique_ptr<dbus::ErrorResponse> err_response_;
private:
void ConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback signal_callback,
dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
EXPECT_EQ(interface_name, dlcservice::kDlcServiceInterface);
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(std::move(*on_connected_callback), interface_name,
signal_name, true /* success */));
}
void CallMethodWithErrorResponse(
dbus::MethodCall* method_call,
int timeout_ms,
dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(*callback), response_.get(),
err_response_.get()));
}
};
TEST_F(DlcserviceClientTest, GetInstalledSuccessTest) {
response_ = dbus::Response::CreateEmpty();
dbus::MessageWriter writer(response_.get());
dlcservice::DlcModuleList dlc_module_list;
writer.AppendProtoAsArrayOfBytes(dlc_module_list);
DlcserviceClient::GetInstalledCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorNone, err);
});
client_->GetInstalled(std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, GetInstalledFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kGetInstalledMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::GetInstalledCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->GetInstalled(std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, UninstallSuccessTest) {
response_ = dbus::Response::CreateEmpty();
DlcserviceClient::UninstallCallback callback = base::BindOnce(
[](const std::string& err) { EXPECT_EQ(dlcservice::kErrorNone, err); });
client_->Uninstall("some-dlc-id", std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, UninstallFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kUninstallMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::UninstallCallback callback =
base::BindOnce([](const std::string& err) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->Uninstall("some-dlc-id", std::move(callback));
base::RunLoop().RunUntilIdle();
}
// TODO(kimjae): Add test for |DlcserviceClient::Install()|.
TEST_F(DlcserviceClientTest, InstallFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kInstallMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::InstallCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->Install(dlcservice::DlcModuleList(), std::move(callback));
base::RunLoop().RunUntilIdle();
}
} // namespace chromeos
// Copyright (c) 2012 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 "chromeos/dbus/dlcservice/fake_dlcservice_client.h"
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
namespace chromeos {
FakeDlcserviceClient::FakeDlcserviceClient() = default;
FakeDlcserviceClient::~FakeDlcserviceClient() = default;
void FakeDlcserviceClient::Install(
const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) {
VLOG(1) << "Requesting to install DLC(s).";
std::move(callback).Run(dlcservice::kErrorNone, dlcservice::DlcModuleList());
}
void FakeDlcserviceClient::Uninstall(const std::string& dlc_id,
UninstallCallback callback) {
VLOG(1) << "Requesting to uninstall DLC=" << dlc_id;
std::move(callback).Run(dlcservice::kErrorNone);
}
void FakeDlcserviceClient::GetInstalled(GetInstalledCallback callback) {
VLOG(1) << "Requesting to get installed DLC(s).";
std::move(callback).Run(dlcservice::kErrorNone, dlcservice::DlcModuleList());
}
} // namespace chromeos
// Copyright (c) 2012 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.
#ifndef CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
#define CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
#include <string>
#include "base/component_export.h"
#include "base/containers/queue.h"
#include "chromeos/dbus/dlcservice/dlcservice_client.h"
namespace chromeos {
// A fake implementation of DlcserviceClient. The user of this class can
// use set_update_engine_client_status() to set a fake last Status and
// GetLastStatus() returns the fake with no modification. Other methods do
// nothing.
class COMPONENT_EXPORT(DLCSERVICE_CLIENT) FakeDlcserviceClient
: public DlcserviceClient {
public:
FakeDlcserviceClient();
~FakeDlcserviceClient() override;
// DlcserviceClient:
void Install(const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) override;
void Uninstall(const std::string& dlc_id,
UninstallCallback callback) override;
void GetInstalled(GetInstalledCallback callback) override;
};
} // namespace chromeos
#endif // CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment