blob: a85310d9c3be390c9b9d0ee15c28e200bb7a7d7d [file] [log] [blame]
// Copyright 2018 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/io/cpp/fidl.h>
#include <lib/async/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/inspect/cpp/reader.h>
#include <lib/inspect/testing/cpp/inspect.h>
#include "gmock/gmock.h"
#include "lib/sys/cpp/testing/test_with_environment_fixture.h"
#include "src/lib/files/glob.h"
#include "src/lib/fxl/strings/substitute.h"
namespace {
using ::fxl::Substitute;
using sys::testing::EnclosingEnvironment;
using ::testing::UnorderedElementsAre;
using namespace inspect::testing;
constexpr char kTestComponent[] =
"fuchsia-pkg://fuchsia.com/dart-inspect-vmo-test-writer#meta/"
"dart-inspect-vmo-test-writer.cmx";
constexpr char kTestProcessName[] = "dart-inspect-vmo-test-writer.cmx";
class InspectTest : public gtest::TestWithEnvironmentFixture {
protected:
InspectTest() {
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = kTestComponent;
environment_ = CreateNewEnclosingEnvironment("test", CreateServices());
environment_->CreateComponent(std::move(launch_info), controller_.NewRequest());
bool ready = false;
controller_.events().OnDirectoryReady = [&ready] { ready = true; };
RunLoopWithTimeoutOrUntil([&ready] { return ready; }, zx::sec(100));
if (!ready) {
printf("The output directory is not ready\n");
}
}
~InspectTest() { CheckShutdown(); }
void CheckShutdown() {
controller_->Kill();
bool done = false;
controller_.events().OnTerminated = [&done](int64_t code,
fuchsia::sys::TerminationReason reason) {
ASSERT_EQ(fuchsia::sys::TerminationReason::EXITED, reason);
done = true;
};
ASSERT_TRUE(RunLoopWithTimeoutOrUntil([&done] { return done; }, zx::sec(100)));
}
// Open the root object connection on the given sync pointer.
// Returns ZX_OK on success.
fpromise::result<fuchsia::io::FileSyncPtr, zx_status_t> OpenInspectVmoFile(
const std::string& file_name) {
files::Glob glob(Substitute("/hub/r/test/*/c/*/*/c/$0/*/out/diagnostics/$1.inspect",
kTestProcessName, file_name));
if (glob.size() == 0) {
printf("Size == 0\n");
return fpromise::error(ZX_ERR_NOT_FOUND);
}
fuchsia::io::FileSyncPtr file;
auto status = fdio_open(std::string(*glob.begin()).c_str(),
static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
file.NewRequest().TakeChannel().release());
if (status != ZX_OK) {
printf("Status bad %d\n", status);
return fpromise::error(status);
}
EXPECT_TRUE(file.is_bound());
return fpromise::ok(std::move(file));
}
fpromise::result<zx::vmo, zx_status_t> DescribeInspectVmoFile(
const fuchsia::io::FileSyncPtr& file) {
fuchsia::io::NodeInfo info;
auto status = file->Describe(&info);
if (status != ZX_OK) {
printf("get failed\n");
return fpromise::error(status);
}
if (!info.is_vmofile()) {
printf("not a vmofile");
return fpromise::error(ZX_ERR_NOT_FOUND);
}
return fpromise::ok(std::move(info.vmofile().vmo));
}
private:
std::unique_ptr<EnclosingEnvironment> environment_;
fuchsia::sys::ComponentControllerPtr controller_;
};
TEST_F(InspectTest, ReadHierarchy) {
auto open_file_result(InspectTest::OpenInspectVmoFile("root"));
ASSERT_TRUE(open_file_result.is_ok());
fuchsia::io::FileSyncPtr file(open_file_result.take_value());
auto describe_file_result = InspectTest::DescribeInspectVmoFile(file);
ASSERT_TRUE(describe_file_result.is_ok());
zx::vmo vmo(describe_file_result.take_value());
auto read_file_result = inspect::ReadFromVmo(std::move(vmo));
ASSERT_TRUE(read_file_result.is_ok());
inspect::Hierarchy hierarchy = read_file_result.take_value();
// TODO(36155): Remove this once root migration is complete.
auto* real_hierarchy = hierarchy.GetByPath({"root"});
if (real_hierarchy == nullptr) {
real_hierarchy = &hierarchy;
}
EXPECT_THAT(
*real_hierarchy,
AllOf(
NodeMatches(NameMatches("root")),
ChildrenMatch(UnorderedElementsAre(
AllOf(NodeMatches(
AllOf(NameMatches("runner"),
PropertyList(UnorderedElementsAre(StringIs("vm_service_port", "")))))),
AllOf(NodeMatches(AllOf(NameMatches("t1"),
PropertyList(UnorderedElementsAre(
StringIs("version", "1.0"),
ByteVectorIs("frame", std::vector<uint8_t>({0, 0, 0})),
IntIs("value", -10), BoolIs("active", true))))),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf(NameMatches("item-0x0"),
PropertyList(UnorderedElementsAre(IntIs("value", 10))))),
NodeMatches(AllOf(NameMatches("item-0x1"),
PropertyList(UnorderedElementsAre(IntIs("value", 100)))))
))),
AllOf(NodeMatches(AllOf(NameMatches("t2"),
PropertyList(UnorderedElementsAre(
StringIs("version", "1.0"),
ByteVectorIs("frame", std::vector<uint8_t>({0, 0, 0})),
IntIs("value", -10), BoolIs("active", true))))),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf(NameMatches("item-0x2"),
PropertyList(UnorderedElementsAre(IntIs("value", 4)))))))
)))));
}
TEST_F(InspectTest, DynamicGeneratesNewHierarchy) {
auto open_file_result(OpenInspectVmoFile("digits_of_numbers"));
ASSERT_TRUE(open_file_result.is_ok());
fuchsia::io::FileSyncPtr file(open_file_result.take_value());
std::vector<std::string> increments_value;
std::vector<std::string> doubles_value;
auto expectInspectOnDemandVmoFile = [&]() {
auto describe_file_result(DescribeInspectVmoFile(file));
ASSERT_TRUE(describe_file_result.is_ok());
zx::vmo vmo(describe_file_result.take_value());
auto read_file_result = inspect::ReadFromVmo(std::move(vmo));
ASSERT_TRUE(read_file_result.is_ok());
inspect::Hierarchy hierarchy = read_file_result.take_value();
// TODO(36155): Remove this once root migration is complete.
auto* real_hierarchy = hierarchy.GetByPath({"root"});
if (real_hierarchy == nullptr) {
real_hierarchy = &hierarchy;
}
EXPECT_THAT(*real_hierarchy,
AllOf(NodeMatches(NameMatches("root")),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf( // child one
NameMatches("increments"),
PropertyList(UnorderedElementsAre(
StringIs("value", ::testing::Truly([&](const std::string& val) {
increments_value.push_back(val);
return true;
})))))),
NodeMatches(AllOf( // child two
NameMatches("doubles"),
PropertyList(UnorderedElementsAre(
StringIs("value", ::testing::Truly([&](const std::string& val) {
doubles_value.push_back(val);
return true;
}))))))))));
};
expectInspectOnDemandVmoFile();
expectInspectOnDemandVmoFile();
ASSERT_EQ(2u, increments_value.size());
ASSERT_EQ(2u, doubles_value.size());
EXPECT_NE(increments_value[0], increments_value[1]);
EXPECT_NE(doubles_value[0], doubles_value[1]);
}
} // namespace