buffet: Add D-Bus serialization support for buffet Array types
Added methods for converting native_types::Array to chromeos::Any,
containing std::vector<T> and back. These are used to marshal
ArrayPropValue over D-Bus when sending commands to vendor daemons
for processing.
BUG=brillo:107
TEST=`FEATURES=test emerge-link buffet`
Change-Id: I44197ef9cf2379c298b081d7ce6522e6d22facfa
Reviewed-on: https://chromium-review.googlesource.com/262206
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/commands/prop_types.cc b/buffet/commands/prop_types.cc
index 74e2be6..6365dcc 100644
--- a/buffet/commands/prop_types.cc
+++ b/buffet/commands/prop_types.cc
@@ -520,6 +520,36 @@
return true;
}
+chromeos::Any ObjectPropType::ConvertArrayToDBusVariant(
+ const native_types::Array& source) const {
+ std::vector<chromeos::VariantDictionary> result;
+ result.reserve(source.size());
+ for (const auto& prop_value : source) {
+ chromeos::Any dict = PropValueToDBusVariant(prop_value.get());
+ result.push_back(std::move(*dict.GetPtr<chromeos::VariantDictionary>()));
+ }
+ return result;
+}
+
+bool ObjectPropType::ConvertDBusVariantToArray(
+ const chromeos::Any& source,
+ native_types::Array* result,
+ chromeos::ErrorPtr* error) const {
+ if (!source.IsTypeCompatible<std::vector<chromeos::VariantDictionary>>())
+ return GenerateErrorValueTypeMismatch(error);
+
+ const auto& source_array =
+ source.Get<std::vector<chromeos::VariantDictionary>>();
+ result->reserve(source_array.size());
+ for (const auto& value : source_array) {
+ auto prop_value = PropValueFromDBusVariant(this, value, error);
+ if (!prop_value)
+ return false;
+ result->push_back(std::move(prop_value));
+ }
+ return true;
+}
+
void ObjectPropType::SetObjectSchema(
std::unique_ptr<const ObjectSchema> schema) {
object_schema_.value = std::move(schema);
diff --git a/buffet/commands/prop_types.h b/buffet/commands/prop_types.h
index 473a6c8..4841db6 100644
--- a/buffet/commands/prop_types.h
+++ b/buffet/commands/prop_types.h
@@ -89,6 +89,21 @@
virtual std::unique_ptr<PropValue> CreateValue(
const chromeos::Any& val, chromeos::ErrorPtr* error) const = 0;
+ // Converts an array of PropValue containing the values of the types described
+ // by this instance of PropType into an Any containing std::vector<T>, where
+ // T corresponds to the native representation of this PropType.
+ virtual chromeos::Any ConvertArrayToDBusVariant(
+ const native_types::Array& source) const = 0;
+
+ // ConvertAnyToArray is the opposite of ConvertArrayToAny().
+ // Given an Any containing std::vector<T>, converts each value into the
+ // corresponding PropValue of type of this PropType and adds them to
+ // |result| array. If type conversion fails, this function returns false
+ // and specifies the error details in |error|.
+ virtual bool ConvertDBusVariantToArray(const chromeos::Any& source,
+ native_types::Array* result,
+ chromeos::ErrorPtr* error) const = 0;
+
// Saves the parameter type definition as a JSON object.
// If |full_schema| is set to true, the full type definition is saved,
// otherwise only the overridden properties and attributes from the base
@@ -184,12 +199,15 @@
template<class Derived, class Value, typename T>
class PropTypeBase : public PropType {
public:
+ // Overrides from PropType.
ValueType GetType() const override { return GetValueType<T>(); }
+
std::unique_ptr<PropValue> CreateValue() const override {
if (GetDefaultValue())
return GetDefaultValue()->Clone();
return std::unique_ptr<PropValue>{new Value{Clone()}};
}
+
std::unique_ptr<PropValue> CreateValue(
const chromeos::Any& v, chromeos::ErrorPtr* error) const override {
std::unique_ptr<PropValue> prop_value;
@@ -203,6 +221,34 @@
}
return prop_value;
}
+
+ chromeos::Any ConvertArrayToDBusVariant(
+ const native_types::Array& source) const override {
+ std::vector<T> result;
+ result.reserve(source.size());
+ for (const auto& prop_value : source) {
+ result.push_back(PropValueToDBusVariant(prop_value.get()).Get<T>());
+ }
+ return result;
+ }
+
+ bool ConvertDBusVariantToArray(const chromeos::Any& source,
+ native_types::Array* result,
+ chromeos::ErrorPtr* error) const override {
+ if (!source.IsTypeCompatible<std::vector<T>>())
+ return GenerateErrorValueTypeMismatch(error);
+
+ const auto& source_array = source.Get<std::vector<T>>();
+ result->reserve(source_array.size());
+ for (const auto& value : source_array) {
+ auto prop_value = PropValueFromDBusVariant(this, value, error);
+ if (!prop_value)
+ return false;
+ result->push_back(std::move(prop_value));
+ }
+ return true;
+ }
+
bool ConstraintsFromJson(const base::DictionaryValue* value,
std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) override;
@@ -307,6 +353,13 @@
std::set<std::string>* processed_keys,
chromeos::ErrorPtr* error) override;
+ chromeos::Any ConvertArrayToDBusVariant(
+ const native_types::Array& source) const override;
+
+ bool ConvertDBusVariantToArray(const chromeos::Any& source,
+ native_types::Array* result,
+ chromeos::ErrorPtr* error) const override;
+
// Returns a schema for Object-type parameter.
inline const ObjectSchema* GetObjectSchemaPtr() const {
return object_schema_.value.get();
diff --git a/buffet/commands/schema_utils.cc b/buffet/commands/schema_utils.cc
index 06e5ded..47b757f 100644
--- a/buffet/commands/schema_utils.cc
+++ b/buffet/commands/schema_utils.cc
@@ -267,9 +267,15 @@
}
chromeos::Any PropValueToDBusVariant(const PropValue* value) {
- if (value->GetType() != ValueType::Object)
- return value->GetValueAsAny();
- return ObjectToDBusVariant(value->GetObject()->GetValue());
+ if (value->GetType() == ValueType::Object)
+ return ObjectToDBusVariant(value->GetObject()->GetValue());
+
+ if (value->GetType() == ValueType::Array) {
+ const PropType* item_type =
+ value->GetPropType()->GetArray()->GetItemTypePtr();
+ return item_type->ConvertArrayToDBusVariant(value->GetArray()->GetValue());
+ }
+ return value->GetValueAsAny();
}
chromeos::VariantDictionary
@@ -291,13 +297,21 @@
const chromeos::Any& value,
chromeos::ErrorPtr* error) {
std::unique_ptr<const PropValue> result;
- if (type->GetType() == ValueType::Object) {
+ if (type->GetType() == ValueType::Array) {
+ // Special case for array types.
+ // We expect the |value| to contain std::vector<T>, while PropValue must use
+ // native_types::Array instead. Do the conversion.
+ native_types::Array arr;
+ const PropType* item_type = type->GetArray()->GetItemTypePtr();
+ if (item_type->ConvertDBusVariantToArray(value, &arr, error))
+ result = type->CreateValue(arr, error);
+ } else if (type->GetType() == ValueType::Object) {
// Special case for object types.
// We expect the |value| to contain chromeos::VariantDictionary, while
// PropValue must use native_types::Object instead. Do the conversion.
if (!value.IsTypeCompatible<chromeos::VariantDictionary>()) {
type->GenerateErrorValueTypeMismatch(error);
- return {};
+ return result;
}
CHECK(nullptr != type->GetObject()->GetObjectSchemaPtr())
<< "An object type must have a schema defined for it";
@@ -305,8 +319,9 @@
if (!ObjectFromDBusVariant(type->GetObject()->GetObjectSchemaPtr(),
value.Get<chromeos::VariantDictionary>(),
&obj,
- error))
- return {};
+ error)) {
+ return result;
+ }
result = type->CreateValue(std::move(obj), error);
} else {
diff --git a/buffet/commands/schema_utils_unittest.cc b/buffet/commands/schema_utils_unittest.cc
index 25fa553..8405722 100644
--- a/buffet/commands/schema_utils_unittest.cc
+++ b/buffet/commands/schema_utils_unittest.cc
@@ -249,6 +249,18 @@
PropValueToDBusVariant(prop_value.get()).Get<VariantDictionary>();
EXPECT_EQ(20, dict["height"].Get<int>());
EXPECT_EQ(10, dict["width"].Get<int>());
+
+ buffet::ArrayPropType arr_type;
+ arr_type.SetItemType(str_type.Clone());
+ buffet::native_types::Array arr;
+ arr.push_back(str_type.CreateValue(std::string{"foo"}, nullptr));
+ arr.push_back(str_type.CreateValue(std::string{"bar"}, nullptr));
+ arr.push_back(str_type.CreateValue(std::string{"baz"}, nullptr));
+ prop_value = arr_type.CreateValue(arr, nullptr);
+ chromeos::Any any = PropValueToDBusVariant(prop_value.get());
+ ASSERT_TRUE(any.IsTypeCompatible<std::vector<std::string>>());
+ EXPECT_EQ((std::vector<std::string>{"foo", "bar", "baz"}),
+ any.Get<std::vector<std::string>>());
}
TEST(CommandSchemaUtils, PropValueFromDBusVariant_Int) {
@@ -340,3 +352,26 @@
ASSERT_NE(nullptr, error.get());
EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
}
+
+TEST(CommandSchemaUtils, PropValueFromDBusVariant_Array) {
+ buffet::ArrayPropType arr_type;
+ buffet::IntPropType int_type;
+ int_type.AddMinMaxConstraint(0, 100);
+ arr_type.SetItemType(int_type.Clone());
+ std::vector<int> data{0, 1, 1, 100};
+ auto prop_value = PropValueFromDBusVariant(&arr_type, data, nullptr);
+ ASSERT_NE(nullptr, prop_value.get());
+ auto arr = prop_value->GetValueAsAny().Get<buffet::native_types::Array>();
+ ASSERT_EQ(4u, arr.size());
+ EXPECT_EQ(0, arr[0]->GetInt()->GetValue());
+ EXPECT_EQ(1, arr[1]->GetInt()->GetValue());
+ EXPECT_EQ(1, arr[2]->GetInt()->GetValue());
+ EXPECT_EQ(100, arr[3]->GetInt()->GetValue());
+
+ chromeos::ErrorPtr error;
+ data.push_back(-1); // This value is out of bounds for |int_type|.
+ prop_value = PropValueFromDBusVariant(&arr_type, data, &error);
+ EXPECT_EQ(nullptr, prop_value.get());
+ ASSERT_NE(nullptr, error.get());
+ EXPECT_EQ(buffet::errors::commands::kOutOfRange, error->GetCode());
+}