blob: db9380287a1eac4b0e1f0f03f6ff6df5b317c86c [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/variant.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/sys/cpp/component_context.h>
#include <string>
#include <vector>
#include <test/inspect/validate/cpp/fidl.h>
using fit::holds_alternative;
using std::get;
using test::inspect::validate::Action;
using test::inspect::validate::InitializationParams;
using test::inspect::validate::NumberType;
using test::inspect::validate::ROOT_ID;
using test::inspect::validate::TestResult;
using Value =
fit::variant<fit::monostate, inspect::Node, inspect::IntProperty, inspect::UintProperty,
inspect::DoubleProperty, inspect::StringProperty, inspect::ByteVectorProperty,
inspect::IntArray, inspect::UintArray, inspect::DoubleArray,
inspect::LinearIntHistogram, inspect::LinearUintHistogram,
inspect::LinearDoubleHistogram, inspect::ExponentialIntHistogram,
inspect::ExponentialUintHistogram, inspect::ExponentialDoubleHistogram>;
class Puppet : public test::inspect::validate::Validate {
public:
explicit Puppet(std::unique_ptr<sys::ComponentContext> context) : context_(std::move(context)) {
context_->outgoing()->AddPublicService(bindings_.GetHandler(this));
}
void Initialize(InitializationParams params, InitializeCallback callback) {
value_map_.clear();
inspector_ = std::make_unique<inspect::Inspector>(
inspect::InspectSettings{.maximum_size = params.vmoSize()});
if (inspector_ == nullptr || !bool(*inspector_)) {
callback(zx::vmo(ZX_HANDLE_INVALID), TestResult::FAILED);
} else {
callback(inspector_->DuplicateVmo(), TestResult::OK);
}
}
void Act(Action action, ActCallback callback) {
switch (action.Which()) {
case Action::Tag::kCreateNode:
callback(HandleCreateNode(action));
break;
case Action::Tag::kDeleteNode:
callback(HandleDeleteNode(action));
break;
case Action::Tag::kDeleteProperty:
callback(HandleDeleteProperty(action));
break;
case Action::Tag::kCreateNumericProperty:
callback(HandleCreateNumeric(action));
break;
case Action::Tag::kCreateBytesProperty:
callback(HandleCreateBytes(action));
break;
case Action::Tag::kCreateStringProperty:
callback(HandleCreateString(action));
break;
case Action::Tag::kSetNumber:
callback(HandleSetNumber(action));
break;
case Action::Tag::kAddNumber:
callback(HandleAddNumber(action));
break;
case Action::Tag::kSubtractNumber:
callback(HandleSubtractNumber(action));
break;
case Action::Tag::kSetString:
callback(HandleSetString(action));
break;
case Action::Tag::kSetBytes:
callback(HandleSetBytes(action));
break;
case Action::Tag::kCreateArrayProperty:
callback(HandleCreateArray(action));
break;
case Action::Tag::kArraySet:
callback(HandleArraySet(action));
break;
case Action::Tag::kArrayAdd:
callback(HandleArrayAdd(action));
break;
case Action::Tag::kArraySubtract:
callback(HandleArraySubtract(action));
break;
case Action::Tag::kCreateLinearHistogram:
callback(HandleCreateLinearHistogram(action));
break;
case Action::Tag::kCreateExponentialHistogram:
callback(HandleCreateExponentialHistogram(action));
break;
case Action::Tag::kInsert:
callback(HandleInsert(action));
break;
case Action::Tag::kInsertMultiple:
callback(HandleInsertMultiple(action));
break;
default:
callback(TestResult::UNIMPLEMENTED);
break;
}
}
private:
template <typename T>
T* GetFromValueMap(uint64_t id) {
auto it = value_map_.find(id);
if (it == value_map_.end()) {
return nullptr;
}
if (!holds_alternative<T>(it->second)) {
return nullptr;
}
return &get<T>(it->second);
}
inspect::Node* GetNode(uint64_t id) {
if (id == ROOT_ID) {
return &inspector_->GetRoot();
} else {
return GetFromValueMap<inspect::Node>(id);
}
}
bool ValueMapContains(uint64_t id) { return value_map_.find(id) != value_map_.end(); }
TestResult HandleCreateNode(const Action& raw_action) {
auto& action = raw_action.create_node();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
value_map_.emplace(action.id, parent->CreateChild(action.name));
return TestResult::OK;
}
TestResult HandleDeleteNode(const Action& raw_action) {
auto& action = raw_action.delete_node();
if (!ValueMapContains(action.id)) {
return TestResult::FAILED;
}
value_map_.erase(action.id);
return TestResult::OK;
}
TestResult HandleCreateNumeric(const Action& raw_action) {
auto& action = raw_action.create_numeric_property();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
if (action.value.is_int_t()) {
value_map_.emplace(action.id, parent->CreateInt(action.name, action.value.int_t()));
} else if (action.value.is_uint_t()) {
value_map_.emplace(action.id, parent->CreateUint(action.name, action.value.uint_t()));
} else if (action.value.is_double_t()) {
value_map_.emplace(action.id, parent->CreateDouble(action.name, action.value.double_t()));
} else {
return TestResult::UNIMPLEMENTED;
}
return TestResult::OK;
}
TestResult HandleCreateBytes(const Action& raw_action) {
auto& action = raw_action.create_bytes_property();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
value_map_.emplace(action.id, parent->CreateByteVector(action.name, action.value));
return TestResult::OK;
}
TestResult HandleCreateString(const Action& raw_action) {
auto& action = raw_action.create_string_property();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
value_map_.emplace(action.id, parent->CreateString(action.name, action.value));
return TestResult::OK;
}
TestResult HandleDeleteProperty(const Action& raw_action) {
auto& action = raw_action.delete_property();
if (!ValueMapContains(action.id)) {
return TestResult::FAILED;
}
value_map_.erase(action.id);
return TestResult::OK;
}
// Helpful macro for deduplicating the 3 operations for numbers (Set, Add, and Subtract).
#define CREATE_NUMERIC_HANDLER(OP_NAME, TYPE_FUNC) \
TestResult Handle##OP_NAME##Number(const Action& raw_action) { \
auto& action = raw_action.TYPE_FUNC(); \
\
if (action.value.is_int_t()) { \
if (auto* val = GetFromValueMap<inspect::IntProperty>(action.id)) { \
val->OP_NAME(action.value.int_t()); \
return TestResult::OK; \
} \
} else if (action.value.is_uint_t()) { \
if (auto* val = GetFromValueMap<inspect::UintProperty>(action.id)) { \
val->OP_NAME(action.value.uint_t()); \
return TestResult::OK; \
} \
} else if (action.value.is_double_t()) { \
if (auto* val = GetFromValueMap<inspect::DoubleProperty>(action.id)) { \
val->OP_NAME(action.value.double_t()); \
return TestResult::OK; \
} \
} else { \
return TestResult::UNIMPLEMENTED; \
} \
\
return TestResult::FAILED; \
}
CREATE_NUMERIC_HANDLER(Add, add_number)
CREATE_NUMERIC_HANDLER(Subtract, subtract_number)
CREATE_NUMERIC_HANDLER(Set, set_number)
TestResult HandleSetString(const Action& raw_action) {
auto& action = raw_action.set_string();
if (auto* val = GetFromValueMap<inspect::StringProperty>(action.id)) {
val->Set(action.value);
return TestResult::OK;
} else {
return TestResult::FAILED;
}
}
TestResult HandleSetBytes(const Action& raw_action) {
auto& action = raw_action.set_bytes();
if (auto* val = GetFromValueMap<inspect::ByteVectorProperty>(action.id)) {
val->Set(action.value);
return TestResult::OK;
} else {
return TestResult::FAILED;
}
}
TestResult HandleCreateArray(const Action& raw_action) {
auto& action = raw_action.create_array_property();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
switch (action.number_type) {
case NumberType::INT:
value_map_.emplace(action.id, parent->CreateIntArray(action.name, action.slots));
break;
case NumberType::UINT:
value_map_.emplace(action.id, parent->CreateUintArray(action.name, action.slots));
break;
case NumberType::DOUBLE:
value_map_.emplace(action.id, parent->CreateDoubleArray(action.name, action.slots));
break;
default:
return TestResult::UNIMPLEMENTED;
};
return TestResult::OK;
}
// Helpful macro for deduplicating the 3 operations for arrays (Set, Add, and Subtract).
#define CREATE_ARRAY_HANDLER(OP_NAME, TYPE_FUNC) \
TestResult HandleArray##OP_NAME(const Action& raw_action) { \
auto& action = raw_action.TYPE_FUNC(); \
\
if (action.value.is_int_t()) { \
if (auto* val = GetFromValueMap<inspect::IntArray>(action.id)) { \
val->OP_NAME(action.index, action.value.int_t()); \
return TestResult::OK; \
} \
} else if (action.value.is_uint_t()) { \
if (auto* val = GetFromValueMap<inspect::UintArray>(action.id)) { \
val->OP_NAME(action.index, action.value.uint_t()); \
return TestResult::OK; \
} \
} else if (action.value.is_double_t()) { \
if (auto* val = GetFromValueMap<inspect::DoubleArray>(action.id)) { \
val->OP_NAME(action.index, action.value.double_t()); \
return TestResult::OK; \
} \
} else { \
return TestResult::UNIMPLEMENTED; \
} \
\
return TestResult::FAILED; \
}
CREATE_ARRAY_HANDLER(Set, array_set)
CREATE_ARRAY_HANDLER(Add, array_add)
CREATE_ARRAY_HANDLER(Subtract, array_subtract)
TestResult HandleCreateLinearHistogram(const Action& raw_action) {
auto& action = raw_action.create_linear_histogram();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
if (action.floor.is_int_t()) {
value_map_.emplace(
action.id, parent->CreateLinearIntHistogram(action.name, action.floor.int_t(),
action.step_size.int_t(), action.buckets));
} else if (action.floor.is_uint_t()) {
value_map_.emplace(
action.id, parent->CreateLinearUintHistogram(action.name, action.floor.uint_t(),
action.step_size.uint_t(), action.buckets));
} else if (action.floor.is_double_t()) {
value_map_.emplace(action.id, parent->CreateLinearDoubleHistogram(
action.name, action.floor.double_t(),
action.step_size.double_t(), action.buckets));
} else {
return TestResult::UNIMPLEMENTED;
}
return TestResult::OK;
}
TestResult HandleCreateExponentialHistogram(const Action& raw_action) {
auto& action = raw_action.create_exponential_histogram();
if (ValueMapContains(action.id)) {
return TestResult::FAILED;
}
auto* parent = GetNode(action.parent);
if (!parent) {
return TestResult::FAILED;
}
if (action.floor.is_int_t()) {
value_map_.emplace(action.id,
parent->CreateExponentialIntHistogram(
action.name, action.floor.int_t(), action.initial_step.int_t(),
action.step_multiplier.int_t(), action.buckets));
} else if (action.floor.is_uint_t()) {
value_map_.emplace(action.id,
parent->CreateExponentialUintHistogram(
action.name, action.floor.uint_t(), action.initial_step.uint_t(),
action.step_multiplier.uint_t(), action.buckets));
} else if (action.floor.is_double_t()) {
value_map_.emplace(action.id,
parent->CreateExponentialDoubleHistogram(
action.name, action.floor.double_t(), action.initial_step.double_t(),
action.step_multiplier.double_t(), action.buckets));
} else {
return TestResult::UNIMPLEMENTED;
}
return TestResult::OK;
}
TestResult HandleInsert(const Action& raw_action) {
auto& action = raw_action.insert();
if (action.value.is_int_t()) {
if (auto* val = GetFromValueMap<inspect::LinearIntHistogram>(action.id)) {
val->Insert(action.value.int_t());
} else if (auto* val = GetFromValueMap<inspect::ExponentialIntHistogram>(action.id)) {
val->Insert(action.value.int_t());
} else {
return TestResult::FAILED;
}
} else if (action.value.is_uint_t()) {
if (auto* val = GetFromValueMap<inspect::LinearUintHistogram>(action.id)) {
val->Insert(action.value.uint_t());
} else if (auto* val = GetFromValueMap<inspect::ExponentialUintHistogram>(action.id)) {
val->Insert(action.value.uint_t());
} else {
return TestResult::FAILED;
}
} else if (action.value.is_double_t()) {
if (auto* val = GetFromValueMap<inspect::LinearDoubleHistogram>(action.id)) {
val->Insert(action.value.double_t());
} else if (auto* val = GetFromValueMap<inspect::ExponentialDoubleHistogram>(action.id)) {
val->Insert(action.value.double_t());
} else {
return TestResult::FAILED;
}
} else {
return TestResult::UNIMPLEMENTED;
}
return TestResult::OK;
}
TestResult HandleInsertMultiple(const Action& raw_action) {
auto& action = raw_action.insert_multiple();
if (action.value.is_int_t()) {
if (auto* val = GetFromValueMap<inspect::LinearIntHistogram>(action.id)) {
val->Insert(action.value.int_t(), action.count);
} else if (auto* val = GetFromValueMap<inspect::ExponentialIntHistogram>(action.id)) {
val->Insert(action.value.int_t(), action.count);
} else {
return TestResult::FAILED;
}
} else if (action.value.is_uint_t()) {
if (auto* val = GetFromValueMap<inspect::LinearUintHistogram>(action.id)) {
val->Insert(action.value.uint_t(), action.count);
} else if (auto* val = GetFromValueMap<inspect::ExponentialUintHistogram>(action.id)) {
val->Insert(action.value.uint_t(), action.count);
} else {
return TestResult::FAILED;
}
} else if (action.value.is_double_t()) {
if (auto* val = GetFromValueMap<inspect::LinearDoubleHistogram>(action.id)) {
val->Insert(action.value.double_t(), action.count);
} else if (auto* val = GetFromValueMap<inspect::ExponentialDoubleHistogram>(action.id)) {
val->Insert(action.value.double_t(), action.count);
} else {
return TestResult::FAILED;
}
} else {
return TestResult::UNIMPLEMENTED;
}
return TestResult::OK;
}
std::unique_ptr<sys::ComponentContext> context_;
fidl::BindingSet<test::inspect::validate::Validate> bindings_;
std::map<uint64_t, Value> value_map_;
std::unique_ptr<inspect::Inspector> inspector_;
};
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
Puppet puppet(sys::ComponentContext::Create());
loop.Run();
return 0;
}