Commit 09afcec7 authored by Harry Cutts's avatar Harry Cutts Committed by Commit Bot

Add `GetProperty` to gesture props D-Bus service

See go/cros-gesture-properties-dbus-design (Google internal only, sorry)
for more details about the full design.

Bug: 952054
Test: call the `GetProperty` method with this command (substituting a
valid device ID):
    dbus-send --print-reply --system \
	--dest=org.chromium.GesturePropertiesService \
	/org/chromium/GesturePropertiesService \
	org.chromium.GesturePropertiesServiceInterface.GetProperty \
	int32:"$DEVICE_ID" string:"Log Path"

Change-Id: I4b663486cf22a50f9e46611e50d35da287099fcd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1589449
Commit-Queue: Harry Cutts <hcutts@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678448}
parent c856ab97
......@@ -39,6 +39,12 @@ void GesturePropertiesServiceProvider::Start(
base::BindRepeating(&GesturePropertiesServiceProvider::ListProperties,
weak_ptr_factory_.GetWeakPtr()),
on_exported);
exported_object->ExportMethod(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceGetPropertyMethod,
base::BindRepeating(&GesturePropertiesServiceProvider::GetProperty,
weak_ptr_factory_.GetWeakPtr()),
on_exported);
}
void GesturePropertiesServiceProvider::OnExported(
......@@ -51,6 +57,78 @@ void GesturePropertiesServiceProvider::OnExported(
namespace {
void GetPropertyCallback(
dbus::MethodCall* method_call,
std::unique_ptr<dbus::Response> response,
const dbus::ExportedObject::ResponseSender& response_sender,
bool is_read_only,
ui::ozone::mojom::GesturePropValuePtr values) {
if (values.is_null()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"The device ID or property name specified was not found."));
return;
}
dbus::MessageWriter writer(response.get());
dbus::MessageWriter variant_writer(nullptr);
dbus::MessageWriter array_writer(nullptr);
writer.AppendBool(is_read_only);
switch (values->which()) {
case ui::ozone::mojom::GesturePropValue::Tag::INTS: {
writer.AppendUint32(values->get_ints().size());
writer.OpenVariant("ai", &variant_writer);
variant_writer.AppendArrayOfInt32s(values->get_ints().data(),
values->get_ints().size());
writer.CloseContainer(&variant_writer);
break;
}
case ui::ozone::mojom::GesturePropValue::Tag::SHORTS: {
writer.AppendUint32(values->get_shorts().size());
writer.OpenVariant("an", &variant_writer);
variant_writer.OpenArray("n", &array_writer);
for (int16_t value : values->get_shorts()) {
array_writer.AppendInt16(value);
}
variant_writer.CloseContainer(&array_writer);
writer.CloseContainer(&variant_writer);
break;
}
case ui::ozone::mojom::GesturePropValue::Tag::BOOLS: {
writer.AppendUint32(values->get_bools().size());
writer.OpenVariant("ab", &variant_writer);
variant_writer.OpenArray("b", &array_writer);
for (bool value : values->get_bools()) {
array_writer.AppendBool(value);
}
variant_writer.CloseContainer(&array_writer);
writer.CloseContainer(&variant_writer);
break;
}
case ui::ozone::mojom::GesturePropValue::Tag::STR: {
writer.AppendUint32(1);
writer.AppendVariantOfString(values->get_str());
break;
}
case ui::ozone::mojom::GesturePropValue::Tag::REALS: {
writer.AppendUint32(values->get_reals().size());
writer.OpenVariant("ad", &variant_writer);
variant_writer.AppendArrayOfDoubles(values->get_reals().data(),
values->get_reals().size());
writer.CloseContainer(&variant_writer);
break;
}
default: {
// This should never happen.
LOG(WARNING) << "No value set on GesturePropValue union; not returning "
"values to GetProperty call.";
writer.AppendUint32(0);
break;
}
}
response_sender.Run(std::move(response));
}
void ListDevicesCallback(
std::unique_ptr<dbus::Response> response,
const dbus::ExportedObject::ResponseSender& response_sender,
......@@ -112,6 +190,30 @@ void GesturePropertiesServiceProvider::ListProperties(
response_sender));
}
void GesturePropertiesServiceProvider::GetProperty(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
dbus::MessageReader reader(method_call);
int32_t device_id;
std::string property_name;
if (!reader.PopInt32(&device_id) || !reader.PopString(&property_name)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"The device ID (int32) and/or property name (string) is missing."));
return;
}
std::unique_ptr<dbus::Response> response =
dbus::Response::FromMethodCall(method_call);
GetService()->GetProperty(
device_id, property_name,
base::BindOnce(&GetPropertyCallback, method_call, std::move(response),
response_sender));
}
ui::ozone::mojom::GesturePropertiesService*
GesturePropertiesServiceProvider::GetService() {
if (service_for_test_ != nullptr)
......
......@@ -55,6 +55,10 @@ class ASH_EXPORT GesturePropertiesServiceProvider
void ListProperties(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
// Called on UI thread in response to a D-Bus request.
void GetProperty(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
ui::ozone::mojom::GesturePropertiesService* GetService();
ui::ozone::mojom::GesturePropertiesServicePtr service_;
......
......@@ -21,6 +21,18 @@ namespace ash {
namespace {
bool expect_bool(dbus::MessageReader* reader) {
bool result;
EXPECT_TRUE(reader->PopBool(&result));
return result;
}
int16_t expect_int16(dbus::MessageReader* reader) {
int16_t result;
EXPECT_TRUE(reader->PopInt16(&result));
return result;
}
uint32_t expect_uint32(dbus::MessageReader* reader) {
uint32_t result;
EXPECT_TRUE(reader->PopUint32(&result));
......@@ -39,6 +51,12 @@ std::string expect_string(dbus::MessageReader* reader) {
return result;
}
double expect_double(dbus::MessageReader* reader) {
double result;
EXPECT_TRUE(reader->PopDouble(&result));
return result;
}
} // namespace
class GesturePropertiesServiceProviderTest : public testing::Test {
......@@ -52,7 +70,9 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
ON_CALL(*mock_service_, ListProperties(_, _))
.WillByDefault(Invoke(
this, &GesturePropertiesServiceProviderTest::FakeListProperties));
ON_CALL(*mock_service_, GetProperty(_, _, _))
.WillByDefault(Invoke(
this, &GesturePropertiesServiceProviderTest::FakeGetProperty));
service_provider_ = std::make_unique<GesturePropertiesServiceProvider>();
service_provider_->set_service_for_test(mock_service_.get());
}
......@@ -72,6 +92,15 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
std::move(callback).Run(list_properties_response_);
}
void FakeGetProperty(
Unused,
Unused,
ui::ozone::mojom::GesturePropertiesService::GetPropertyCallback
callback) {
std::move(callback).Run(get_property_read_only_,
std::move(get_property_response_));
}
protected:
void CallDBusMethod(std::string name,
dbus::MethodCall* method_call,
......@@ -92,6 +121,19 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
CallDBusMethod(name, std::move(method_call), response);
}
void CallGetProperty(int32_t device_id,
std::string name,
std::unique_ptr<dbus::Response>& response) {
dbus::MethodCall* method_call = new dbus::MethodCall(
chromeos::kGesturePropertiesServiceInterface,
chromeos::kGesturePropertiesServiceGetPropertyMethod);
dbus::MessageWriter writer(method_call);
writer.AppendInt32(device_id);
writer.AppendString(name);
CallDBusMethod(chromeos::kGesturePropertiesServiceGetPropertyMethod,
std::move(method_call), response);
}
void CheckMethodErrorsWithNoParameters(std::string name) {
std::unique_ptr<dbus::Response> response = nullptr;
CallWithoutParameters(name, response);
......@@ -100,6 +142,8 @@ class GesturePropertiesServiceProviderTest : public testing::Test {
base::flat_map<int, std::string> list_devices_response_ = {};
std::vector<std::string> list_properties_response_ = {};
bool get_property_read_only_ = true;
ui::ozone::mojom::GesturePropValuePtr get_property_response_ = nullptr;
std::unique_ptr<MockGesturePropertiesService> mock_service_;
......@@ -203,4 +247,126 @@ TEST_F(GesturePropertiesServiceProviderTest, ListPropertiesMissingParameter) {
chromeos::kGesturePropertiesServiceListPropertiesMethod);
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessInts) {
get_property_read_only_ = false;
get_property_response_ =
ui::ozone::mojom::GesturePropValue::NewInts({1, 2, 4});
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
dbus::MessageReader reader(response.get());
EXPECT_EQ(false, expect_bool(&reader));
EXPECT_EQ(3u, expect_uint32(&reader));
dbus::MessageReader variant_reader(nullptr);
ASSERT_TRUE(reader.PopVariant(&variant_reader));
dbus::MessageReader array_reader(nullptr);
ASSERT_TRUE(variant_reader.PopArray(&array_reader));
EXPECT_EQ(1, expect_int32(&array_reader));
EXPECT_EQ(2, expect_int32(&array_reader));
EXPECT_EQ(4, expect_int32(&array_reader));
EXPECT_FALSE(array_reader.HasMoreData());
EXPECT_FALSE(reader.HasMoreData());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessShorts) {
get_property_read_only_ = false;
get_property_response_ =
ui::ozone::mojom::GesturePropValue::NewShorts({1, 2, 4});
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
dbus::MessageReader reader(response.get());
EXPECT_EQ(false, expect_bool(&reader));
EXPECT_EQ(3u, expect_uint32(&reader));
dbus::MessageReader variant_reader(nullptr);
ASSERT_TRUE(reader.PopVariant(&variant_reader));
dbus::MessageReader array_reader(nullptr);
ASSERT_TRUE(variant_reader.PopArray(&array_reader));
EXPECT_EQ(1, expect_int16(&array_reader));
EXPECT_EQ(2, expect_int16(&array_reader));
EXPECT_EQ(4, expect_int16(&array_reader));
EXPECT_FALSE(array_reader.HasMoreData());
EXPECT_FALSE(reader.HasMoreData());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessBools) {
get_property_read_only_ = false;
get_property_response_ =
ui::ozone::mojom::GesturePropValue::NewBools({true, false});
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
dbus::MessageReader reader(response.get());
EXPECT_EQ(false, expect_bool(&reader));
EXPECT_EQ(2u, expect_uint32(&reader));
dbus::MessageReader variant_reader(nullptr);
ASSERT_TRUE(reader.PopVariant(&variant_reader));
dbus::MessageReader array_reader(nullptr);
ASSERT_TRUE(variant_reader.PopArray(&array_reader));
EXPECT_EQ(true, expect_bool(&array_reader));
EXPECT_EQ(false, expect_bool(&array_reader));
EXPECT_FALSE(array_reader.HasMoreData());
EXPECT_FALSE(reader.HasMoreData());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessStr) {
get_property_read_only_ = false;
get_property_response_ = ui::ozone::mojom::GesturePropValue::NewStr("llama");
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
dbus::MessageReader reader(response.get());
EXPECT_EQ(false, expect_bool(&reader));
EXPECT_EQ(1u, expect_uint32(&reader));
dbus::MessageReader variant_reader(nullptr);
ASSERT_TRUE(reader.PopVariant(&variant_reader));
EXPECT_EQ("llama", expect_string(&variant_reader));
EXPECT_FALSE(reader.HasMoreData());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertySuccessReals) {
get_property_read_only_ = false;
get_property_response_ =
ui::ozone::mojom::GesturePropValue::NewReals({3.14, 6.28});
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
dbus::MessageReader reader(response.get());
EXPECT_EQ(false, expect_bool(&reader));
EXPECT_EQ(2u, expect_uint32(&reader));
dbus::MessageReader variant_reader(nullptr);
ASSERT_TRUE(reader.PopVariant(&variant_reader));
dbus::MessageReader array_reader(nullptr);
ASSERT_TRUE(variant_reader.PopArray(&array_reader));
EXPECT_EQ(3.14, expect_double(&array_reader));
EXPECT_EQ(6.28, expect_double(&array_reader));
EXPECT_FALSE(array_reader.HasMoreData());
EXPECT_FALSE(reader.HasMoreData());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertyPropertyDoesntExist) {
get_property_read_only_ = true;
get_property_response_ = nullptr;
EXPECT_CALL(*mock_service_, GetProperty(4, "prop 1", _));
std::unique_ptr<dbus::Response> response = nullptr;
CallGetProperty(4, "prop 1", response);
EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
}
TEST_F(GesturePropertiesServiceProviderTest, GetPropertyMissingParameters) {
CheckMethodErrorsWithNoParameters(
chromeos::kGesturePropertiesServiceGetPropertyMethod);
}
} // namespace ash
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