blob: 5f8349a7b9ba979f8dbe7fe7416c6b68abe27c6f [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/inspect/deprecated/cpp/fidl.h>
#include <fuchsia/sys/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/sys/cpp/testing/test_with_environment.h>
#include "gmock/gmock.h"
#include "src/lib/files/glob.h"
#include "src/lib/fxl/strings/substitute.h"
#include "src/lib/inspect_deprecated/deprecated/expose.h"
namespace component {
namespace {
using ::fxl::Substitute;
using sys::testing::EnclosingEnvironment;
using ::testing::ElementsAre;
using ::testing::UnorderedElementsAre;
using ByteVector = ::component::Property::ByteVector;
const char kTestComponent[] =
"fuchsia-pkg://fuchsia.com/inspect_integration_tests#meta/"
"inspect_test_app.cmx";
const char kTestProcessName[] = "inspect_test_app.cmx";
class InspectTest : public sys::testing::TestWithEnvironment {
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; };
RunLoopUntil([&ready] { return ready; });
}
~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;
};
RunLoopUntil([&done] { return done; });
}
// Open the root object connection on the given sync pointer.
// Returns ZX_OK on success.
zx_status_t GetInspectConnection(fuchsia::inspect::deprecated::InspectSyncPtr* out_ptr) {
files::Glob glob(Substitute("/hub/r/test/*/c/$0/*/out/diagnostics", kTestProcessName));
if (glob.size() == 0) {
return ZX_ERR_NOT_FOUND;
}
std::string path = Substitute("$0/$1", std::string(*glob.begin()),
std::string(fuchsia::inspect::deprecated::Inspect::Name_));
return fdio_service_connect(path.c_str(), out_ptr->NewRequest().TakeChannel().release());
}
// Traverse from the current location of ptr down the object tree to a child
// with the given name.
// Returns true on success, otherwise false is returned and ptr is not
// changed.
bool Traverse(fuchsia::inspect::deprecated::InspectSyncPtr* ptr, const std::string& name) {
fuchsia::inspect::deprecated::InspectSyncPtr child;
bool ret;
(*ptr)->OpenChild(name, child.NewRequest(), &ret);
if (ret) {
*ptr = std::move(child);
}
return ret;
}
private:
std::unique_ptr<EnclosingEnvironment> environment_;
fuchsia::sys::ComponentControllerPtr controller_;
};
TEST_F(InspectTest, InspectTopLevel) {
fuchsia::inspect::deprecated::InspectSyncPtr inspect;
ASSERT_EQ(ZX_OK, GetInspectConnection(&inspect));
std::vector<std::string> children;
inspect->ListChildren(&children);
EXPECT_THAT(children, UnorderedElementsAre("table-t1", "table-t2", "lazy_child"));
}
MATCHER_P2(StringProperty, name, value, "") {
return arg.value.is_str() && arg.key == name && arg.value.str() == value;
}
MATCHER_P2(VectorProperty, name, value, "") {
return arg.value.is_bytes() && arg.key == name && arg.value.bytes() == value;
}
MATCHER_P2(UIntMetric, name, value, "") {
return arg.key == name && arg.value.is_uint_value() && arg.value.uint_value() == (uint64_t)value;
}
MATCHER_P2(IntMetric, name, value, "") {
return arg.key == name && arg.value.is_int_value() && arg.value.int_value() == (int64_t)value;
}
TEST_F(InspectTest, InspectOpenRead) {
fuchsia::inspect::deprecated::InspectSyncPtr inspect;
ASSERT_EQ(ZX_OK, GetInspectConnection(&inspect));
ASSERT_TRUE(Traverse(&inspect, "table-t1"));
std::vector<std::string> children;
ASSERT_EQ(ZX_OK, inspect->ListChildren(&children));
EXPECT_THAT(children, UnorderedElementsAre("item-0x0", "item-0x1"));
fuchsia::inspect::deprecated::Object obj;
ASSERT_EQ(ZX_OK, inspect->ReadData(&obj));
EXPECT_EQ("table-t1", obj.name);
EXPECT_THAT(obj.properties,
UnorderedElementsAre(StringProperty("version", "1.0"),
VectorProperty("frame", ByteVector({0x10, 0x00, 0x10})),
VectorProperty("\x10\x10", ByteVector({0x00, 0x00, 0x00}))));
EXPECT_THAT(obj.metrics,
UnorderedElementsAre(UIntMetric("item_size", 32), IntMetric("\x10", -10)));
ASSERT_EQ(ZX_OK, GetInspectConnection(&inspect));
ASSERT_TRUE(Traverse(&inspect, "table-t2"));
children.clear();
ASSERT_EQ(ZX_OK, inspect->ListChildren(&children));
EXPECT_THAT(children, UnorderedElementsAre("item-0x2", "table-subtable"));
obj = fuchsia::inspect::deprecated::Object();
ASSERT_EQ(ZX_OK, inspect->ReadData(&obj));
EXPECT_EQ("table-t2", obj.name);
fuchsia::inspect::deprecated::Object subtable;
fuchsia::inspect::deprecated::InspectSyncPtr child_request;
bool ok = false;
ASSERT_EQ(ZX_OK, inspect->OpenChild("table-subtable", child_request.NewRequest(), &ok));
ASSERT_TRUE(ok);
child_request->ReadData(&subtable);
EXPECT_EQ(subtable.name, "table-subtable");
children.clear();
ASSERT_EQ(ZX_OK, child_request->ListChildren(&children));
EXPECT_THAT(children, UnorderedElementsAre("item-0x3"));
EXPECT_THAT(subtable.metrics,
UnorderedElementsAre(UIntMetric("item_size", 16), IntMetric("\x10", -10)));
ASSERT_EQ(ZX_OK, GetInspectConnection(&inspect));
fuchsia::inspect::deprecated::InspectSyncPtr lazy_child;
bool open_ok;
inspect->OpenChild("lazy_child", lazy_child.NewRequest(), &open_ok);
ASSERT_TRUE(open_ok);
obj = fuchsia::inspect::deprecated::Object();
lazy_child->ReadData(&obj);
EXPECT_THAT(obj.properties, UnorderedElementsAre(StringProperty("version", "1")));
}
} // namespace
} // namespace component