| // 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/fit/single_threaded_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::Hierarchy; |
| using inspect::Inspector; |
| using ::testing::AllOf; |
| using ::testing::UnorderedElementsAre; |
| using namespace inspect::testing; |
| |
| namespace { |
| |
| class InspectReaderTest : public gtest::RealLoopFixture { |
| public: |
| InspectReaderTest() |
| : executor_(dispatcher()), |
| inspector_(), |
| handler_(inspect::MakeTreeHandler(&inspector_, dispatcher())) {} |
| |
| protected: |
| inspect::Node& root() { return inspector_.GetRoot(); } |
| |
| fuchsia::inspect::TreePtr Connect(async_dispatcher_t* dispatcher = nullptr) { |
| fuchsia::inspect::TreePtr ret; |
| handler_(ret.NewRequest(dispatcher)); |
| return ret; |
| } |
| |
| void ResetHandler(async_dispatcher_t* dispatcher) { |
| handler_ = inspect::MakeTreeHandler(&inspector_, dispatcher); |
| } |
| |
| async::Executor executor_; |
| |
| private: |
| Inspector inspector_; |
| fidl::InterfaceRequestHandler<fuchsia::inspect::Tree> handler_; |
| }; |
| |
| inspect::ValueList RecordValues(inspect::Node& root) { |
| inspect::ValueList values; |
| root.CreateInt("val", 1, &values); |
| root.CreateLazyNode( |
| "test", |
| [] { |
| Inspector insp; |
| insp.GetRoot().CreateInt("val2", 2, &insp); |
| insp.GetRoot().CreateLazyValues( |
| "tempvals", |
| [] { |
| Inspector insp; |
| insp.GetRoot().CreateInt("val3", 3, &insp); |
| return fit::make_ok_promise(std::move(insp)); |
| }, |
| &insp); |
| return fit::make_ok_promise(std::move(insp)); |
| }, |
| &values); |
| root.CreateLazyNode( |
| "next", |
| [] { |
| Inspector insp; |
| insp.GetRoot().CreateInt("val4", 4, &insp); |
| return fit::make_ok_promise(std::move(insp)); |
| }, |
| &values); |
| root.CreateLazyNode( |
| "node_error", [] { return fit::make_result_promise<Inspector>(fit::error()); }, &values); |
| root.CreateLazyNode( |
| "values_error", [] { return fit::make_result_promise<Inspector>(fit::error()); }, &values); |
| |
| return values; |
| } |
| |
| TEST_F(InspectReaderTest, ReadHierarchy) { |
| inspect::ValueList values; |
| fit::result<Hierarchy> hierarchy; |
| auto value_list = RecordValues(root()); |
| bool done = false; |
| |
| executor_.schedule_task( |
| inspect::ReadFromTree(Connect()).then([&](fit::result<Hierarchy>& result) { |
| hierarchy = std::move(result); |
| done = true; |
| })); |
| |
| RunLoopUntil([&] { return done; }); |
| |
| ASSERT_TRUE(hierarchy.is_ok()); |
| |
| EXPECT_THAT( |
| hierarchy.value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre( |
| AllOf(NodeMatches( |
| AllOf(NameMatches("test"), |
| PropertyList(UnorderedElementsAre(IntIs("val2", 2), IntIs("val3", 3)))))), |
| AllOf(NodeMatches(AllOf(NameMatches("next"), |
| PropertyList(UnorderedElementsAre(IntIs("val4", 4)))))))))); |
| } |
| |
| TEST_F(InspectReaderTest, ReadHierarchyWithDifferentDispatcher) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| ResetHandler(loop.dispatcher()); |
| inspect::ValueList values; |
| fit::result<Hierarchy> hierarchy; |
| auto value_list = RecordValues(root()); |
| bool done = false; |
| |
| async::Executor local_executor(loop.dispatcher()); |
| local_executor.schedule_task( |
| inspect::ReadFromTree(Connect(loop.dispatcher())).then([&](fit::result<Hierarchy>& result) { |
| hierarchy = std::move(result); |
| done = true; |
| })); |
| |
| while (true) { |
| loop.Run(zx::deadline_after(zx::msec(10))); |
| if (done) { |
| break; |
| } |
| } |
| |
| ASSERT_TRUE(hierarchy.is_ok()); |
| |
| EXPECT_THAT( |
| hierarchy.value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre( |
| AllOf(NodeMatches( |
| AllOf(NameMatches("test"), |
| PropertyList(UnorderedElementsAre(IntIs("val2", 2), IntIs("val3", 3)))))), |
| AllOf(NodeMatches(AllOf(NameMatches("next"), |
| PropertyList(UnorderedElementsAre(IntIs("val4", 4)))))))))); |
| } |
| |
| } // namespace |