blob: 4c8e3d1b1dd6da7a100eafeb3a34952eefe58d13 [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/inspect/query/read.h"
#include <fuchsia/io/cpp/fidl.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <lib/fdio/namespace.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/inspect/inspect.h>
#include <lib/inspect/query/source.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
#include <lib/vfs/cpp/vmo_file.h>
#include <src/lib/fxl/strings/join_strings.h>
#include "fixture.h"
#include "fuchsia/inspect/cpp/fidl.h"
#include "lib/inspect/hierarchy.h"
#include "lib/inspect/query/location.h"
#include "lib/inspect/reader.h"
#include "lib/inspect/testing/inspect.h"
using namespace inspect::testing;
namespace {
class TestDataWrapper {
public:
explicit TestDataWrapper(inspect::Object object)
: object_(std::move(object)) {
version_ = object_.CreateStringProperty("version", "1.0");
child_test_ = object_.CreateChild("test");
count_ = child_test_.CreateIntMetric("count", 2);
}
private:
inspect::Object object_;
inspect::Object child_test_;
inspect::StringProperty version_;
inspect::IntMetric count_;
};
class ReadTest : public TestFixture {
public:
ReadTest()
: tree_(inspector_.CreateTree("root")),
fidl_dir_(component::ObjectDir::Make("root")),
fidl_test_data_(inspect::Object(fidl_dir_)),
vmo_test_data_(std::move(tree_.GetRoot())) {
// Host a FIDL and VMO inspect interface under /test in the global
// namespace.
root_dir_.AddEntry(fuchsia::inspect::Inspect::Name_,
std::make_unique<vfs::Service>(
bindings_.GetHandler(fidl_dir_.object().get())));
root_dir_.AddEntry("root.inspect",
std::make_unique<vfs::VmoFile>(
zx::unowned_vmo(tree_.GetVmo()), 0, 4096));
fuchsia::io::DirectoryPtr ptr;
root_dir_.Serve(
fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE,
ptr.NewRequest().TakeChannel());
ZX_ASSERT(fdio_ns_get_installed(&ns_) == ZX_OK);
ZX_ASSERT(fdio_ns_bind(ns_, "/test", ptr.Unbind().TakeChannel().release()) ==
ZX_OK);
}
~ReadTest() {
if (ns_) {
ZX_ASSERT(fdio_ns_unbind(ns_, "/test") == ZX_OK);
}
}
protected:
inspect::Inspector inspector_;
inspect::Tree tree_;
component::ObjectDir fidl_dir_;
TestDataWrapper fidl_test_data_, vmo_test_data_;
fidl::BindingSet<fuchsia::inspect::Inspect> bindings_;
vfs::PseudoDir root_dir_;
fdio_ns_t* ns_;
};
TEST_F(ReadTest, ReadLocations) {
const std::vector<std::string> paths = {"/test/root.inspect", "/test"};
for (const auto& path : paths) {
fit::result<inspect::Source, std::string> result;
SchedulePromise(
inspect::ReadLocation(inspect::Location::Parse(path).take_value())
.then([&](fit::result<inspect::Source, std::string>& res) {
result = std::move(res);
}));
RunLoopWithTimeoutOrUntil([&] { return !!result; });
ASSERT_TRUE(result.is_ok())
<< "for " << path << " error " << result.error().c_str();
EXPECT_THAT(
result.take_value().GetHierarchy(),
::testing::AllOf(
NodeMatches(::testing::AllOf(
NameMatches("root"), PropertyList(::testing::ElementsAre(
StringPropertyIs("version", "1.0"))))),
ChildrenMatch(::testing::ElementsAre(NodeMatches(::testing::AllOf(
NameMatches("test"), MetricList(::testing::ElementsAre(
IntMetricIs("count", 2)))))))));
}
}
TEST_F(ReadTest, ReadLocationsChild) {
const std::vector<std::string> paths = {"/test/root.inspect#test",
"/test#test"};
for (const auto& path : paths) {
fit::result<inspect::Source, std::string> result;
SchedulePromise(
inspect::ReadLocation(inspect::Location::Parse(path).take_value())
.then([&](fit::result<inspect::Source, std::string>& res) {
result = std::move(res);
}));
RunLoopWithTimeoutOrUntil([&] { return !!result; });
ASSERT_TRUE(result.is_ok())
<< "for " << path << " error " << result.error().c_str();
EXPECT_THAT(
result.take_value().GetHierarchy(),
NodeMatches(::testing::AllOf(
NameMatches("test"),
MetricList(::testing::ElementsAre(IntMetricIs("count", 2))))));
}
}
TEST_F(ReadTest, ReadLocationsError) {
const std::vector<std::string> paths = {
"/test/root.inspect#missing", "/test#missing", "/",
"/test/missing.inspect", "/test/missing",
};
for (const auto& path : paths) {
fit::result<inspect::Source, std::string> result;
SchedulePromise(
inspect::ReadLocation(inspect::Location::Parse(path).take_value())
.then([&](fit::result<inspect::Source, std::string>& res) {
result = std::move(res);
}));
RunLoopWithTimeoutOrUntil([&] { return !!result; });
ASSERT_TRUE(result.is_error());
}
}
} // namespace