blob: 63b1624f1f87e1cd1ed11dd180e624e4b1af237a [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 <fuchsia/inspect/cpp/fidl.h>
#include <lib/async/cpp/executor.h>
#include <lib/gtest/real_loop_fixture.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/inspect/service/cpp/reader.h>
#include <lib/inspect/service/cpp/service.h>
#include <lib/inspect/testing/cpp/inspect.h>
#include <gmock/gmock.h>
using inspect::Inspector;
namespace {
class InspectServiceTest : public gtest::RealLoopFixture {
public:
InspectServiceTest()
: executor_(dispatcher()),
inspector_(),
handler_(inspect::MakeTreeHandler(&inspector_, dispatcher())) {}
protected:
inspect::Node& root() { return inspector_.GetRoot(); }
fuchsia::inspect::TreePtr Connect() {
fuchsia::inspect::TreePtr ret;
handler_(ret.NewRequest());
return ret;
}
void MakePrivateSnapshotHandler() {
handler_ = inspect::MakeTreeHandler(
&inspector_, dispatcher(), inspect::TreeHandlerSettings{.force_private_snapshot = true});
}
async::Executor executor_;
private:
Inspector inspector_;
fidl::InterfaceRequestHandler<fuchsia::inspect::Tree> handler_;
};
TEST_F(InspectServiceTest, SingleTree) {
inspect::ValueList values;
root().CreateInt("val", 1, &values);
auto ptr = Connect();
ptr.set_error_handler(
[](zx_status_t status) { ASSERT_TRUE(false) << "Error detected on connection"; });
std::vector<std::string> names;
bool done = false;
fuchsia::inspect::TreeNameIteratorPtr name_iter;
ptr->ListChildNames(name_iter.NewRequest());
executor_.schedule_task(inspect::ReadAllChildNames(std::move(name_iter))
.and_then([&](std::vector<std::string>& promised_names) {
names = std::move(promised_names);
done = true;
}));
RunLoopUntil([&] { return done; });
EXPECT_TRUE(names.empty());
}
TEST_F(InspectServiceTest, SingleTreeGetContent) {
auto val = root().CreateInt("val", 1);
auto ptr = Connect();
ptr.set_error_handler(
[](zx_status_t status) { ASSERT_TRUE(false) << "Error detected on connection"; });
fit::result<fuchsia::inspect::TreeContent> content;
ptr->GetContent([&](fuchsia::inspect::TreeContent returned_content) {
content = fit::ok(std::move(returned_content));
});
RunLoopUntil([&] { return !!content; });
val.Add(1);
auto hierarchy = inspect::ReadFromVmo(std::move(content.take_value().buffer().vmo));
ASSERT_TRUE(hierarchy.is_ok());
const inspect::IntPropertyValue* val_prop =
hierarchy.value().node().get_property<inspect::IntPropertyValue>("val");
ASSERT_NE(nullptr, val_prop);
EXPECT_EQ(2, val_prop->value());
}
TEST_F(InspectServiceTest, SingleTreeGetContentPrivate) {
auto val = root().CreateInt("val", 1);
MakePrivateSnapshotHandler();
auto ptr = Connect();
ptr.set_error_handler(
[](zx_status_t status) { ASSERT_TRUE(false) << "Error detected on connection"; });
fit::result<fuchsia::inspect::TreeContent> content;
ptr->GetContent([&](fuchsia::inspect::TreeContent returned_content) {
content = fit::ok(std::move(returned_content));
});
RunLoopUntil([&] { return !!content; });
val.Add(1);
auto hierarchy = inspect::ReadFromVmo(std::move(content.take_value().buffer().vmo));
ASSERT_TRUE(hierarchy.is_ok());
const inspect::IntPropertyValue* val_prop =
hierarchy.value().node().get_property<inspect::IntPropertyValue>("val");
ASSERT_NE(nullptr, val_prop);
EXPECT_EQ(1, val_prop->value());
}
TEST_F(InspectServiceTest, ListChildNames) {
inspect::ValueList values;
root().CreateLazyNode(
"a", []() { return fit::make_result_promise<Inspector>(fit::error()); }, &values);
root().CreateLazyNode(
"b", []() { return fit::make_result_promise<Inspector>(fit::error()); }, &values);
auto ptr = Connect();
ptr.set_error_handler(
[](zx_status_t status) { ASSERT_TRUE(false) << "Error detected on connection"; });
std::vector<std::string> names;
bool done = false;
fuchsia::inspect::TreeNameIteratorPtr name_iter;
ptr->ListChildNames(name_iter.NewRequest());
executor_.schedule_task(inspect::ReadAllChildNames(std::move(name_iter))
.and_then([&](std::vector<std::string>& promised_names) {
names = std::move(promised_names);
done = true;
}));
RunLoopUntil([&] { return done; });
EXPECT_EQ(names, std::vector<std::string>({"a-0", "b-1"}));
}
TEST_F(InspectServiceTest, OpenChild) {
inspect::ValueList values;
root().CreateInt("val", 20, &values);
root().CreateLazyNode(
"valid",
[]() {
Inspector insp;
insp.GetRoot().CreateInt("val", 10, &insp);
return fit::make_ok_promise(insp);
},
&values);
root().CreateLazyNode(
"invalid", [] { return fit::make_result_promise<Inspector>(fit::error()); }, &values);
auto ptr = Connect();
ptr.set_error_handler(
[](zx_status_t status) { ASSERT_TRUE(false) << "Error detected on connection"; });
std::vector<std::string> names;
bool list_done = false;
fuchsia::inspect::TreeNameIteratorPtr name_iter;
fit::result<fuchsia::inspect::TreeContent> root, child;
ptr->ListChildNames(name_iter.NewRequest());
executor_.schedule_task(inspect::ReadAllChildNames(std::move(name_iter))
.and_then([&](std::vector<std::string>& promised_names) {
names = std::move(promised_names);
list_done = true;
}));
ptr->GetContent(
[&](fuchsia::inspect::TreeContent content) { root = fit::ok(std::move(content)); });
fuchsia::inspect::TreePtr child_ptr;
ptr->OpenChild("valid-0", child_ptr.NewRequest());
child_ptr->GetContent(
[&](fuchsia::inspect::TreeContent content) { child = fit::ok(std::move(content)); });
bool read_error_done = false;
bool missing_error_done = false;
fuchsia::inspect::TreePtr read_error_ptr, missing_error_ptr;
read_error_ptr.set_error_handler([&](zx_status_t status) { read_error_done = true; });
missing_error_ptr.set_error_handler([&](zx_status_t status) { missing_error_done = true; });
ptr->OpenChild("invalid-1", read_error_ptr.NewRequest());
ptr->OpenChild("missing", missing_error_ptr.NewRequest());
read_error_ptr->GetContent([](fuchsia::inspect::TreeContent unused) {});
missing_error_ptr->GetContent([](fuchsia::inspect::TreeContent unused) {});
RunLoopUntil([&] {
return list_done && root.is_ok() && child.is_ok() && read_error_done && missing_error_done;
});
EXPECT_EQ(names, std::vector<std::string>({"invalid-1", "valid-0"}));
auto root_hierarchy = inspect::ReadFromVmo(root.take_value().buffer().vmo).take_value();
ASSERT_EQ(1u, root_hierarchy.node().properties().size());
EXPECT_EQ("val", root_hierarchy.node().properties()[0].name());
auto child_hierarchy = inspect::ReadFromVmo(child.take_value().buffer().vmo).take_value();
ASSERT_EQ(1u, child_hierarchy.node().properties().size());
EXPECT_EQ("val", child_hierarchy.node().properties()[0].name());
}
} // namespace