blob: be635b1fc2c319cbd432586b61eeeeb66313b9ee [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/async/cpp/executor.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/service/cpp/reader.h>
#include <lib/inspect/testing/cpp/inspect.h>
#include <lib/sys/cpp/testing/test_with_environment.h>
#include <stdlib.h>
#include <string.h>
#include <fs/vnode.h>
#include <gmock/gmock.h>
#include <src/lib/files/file.h>
#include <src/lib/files/glob.h>
#include "src/lib/fxl/strings/substitute.h"
namespace component {
namespace {
using ::fxl::Substitute;
using sys::testing::EnclosingEnvironment;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::UnorderedElementsAre;
using namespace inspect::testing;
constexpr char kTestComponent[] =
"fuchsia-pkg://fuchsia.com/memory_monitor_inspect_integration_tests#meta/"
"memory_monitor_test_app.cmx";
constexpr char kTestProcessName[] = "memory_monitor_test_app.cmx";
class InspectTest : public sys::testing::TestWithEnvironment {
protected:
InspectTest() : test_case_(::testing::UnitTest::GetInstance()->current_test_info()->name()) {
auto env_services = sys::ServiceDirectory::CreateFromNamespace();
fuchsia::sys::EnvironmentPtr parent_env;
env_services->Connect(parent_env.NewRequest());
auto services = sys::testing::EnvironmentServices::Create(parent_env);
services->AllowParentService("fuchsia.kernel.Stats");
environment_ = CreateNewEnclosingEnvironment(test_case_, std::move(services));
Connect();
}
~InspectTest() { CheckShutdown(); }
void Connect() {
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = kTestComponent;
environment_->CreateComponent(std::move(launch_info), controller_.NewRequest());
bool ready = false;
controller_.events().OnDirectoryReady = [&ready] { ready = true; };
RunLoopUntil([&ready] { return ready; });
if (!ready) {
printf("The output directory is not ready\n");
}
}
void CheckShutdown() {
controller_->Kill();
sys::testing::TerminationResult result;
ASSERT_TRUE(RunComponentUntilTerminated(std::move(controller_), &result));
ASSERT_EQ(fuchsia::sys::TerminationReason::EXITED, result.reason);
}
// Open the root object connection on the given sync pointer.
// Returns ZX_OK on success.
fit::result<inspect::Hierarchy> GetInspectHierarchy() {
files::Glob glob(Substitute("/hub/r/$1/*/c/$0/*/out/diagnostics/fuchsia.inspect.Tree",
kTestProcessName, std::string_view(test_case_)));
if (glob.size() == 0) {
return fit::error();
}
auto path = std::string(*glob.begin());
fuchsia::inspect::TreePtr tree_ptr;
zx_status_t status;
status = fdio_service_connect(path.c_str(), tree_ptr.NewRequest().TakeChannel().release());
if (status != ZX_OK) {
return fit::error();
}
EXPECT_TRUE(tree_ptr.is_bound());
async::Executor executor(dispatcher());
fit::result<inspect::Hierarchy> ret;
executor.schedule_task(
inspect::ReadFromTree(std::move(tree_ptr)).then([&](fit::result<inspect::Hierarchy>& res) {
ret = std::move(res);
}));
RunLoopUntil([&] { return ret.is_ok() || ret.is_error(); });
return ret;
}
private:
std::unique_ptr<EnclosingEnvironment> environment_;
fuchsia::sys::ComponentControllerPtr controller_;
const char* test_case_;
};
TEST_F(InspectTest, FirstLaunch) {
auto result = GetInspectHierarchy();
ASSERT_TRUE(result.is_ok());
auto hierarchy = result.take_value();
EXPECT_THAT(hierarchy,
AllOf(NodeMatches(AllOf(NameMatches("root"),
PropertyList(UnorderedElementsAre(
StringIs("current", Not(IsEmpty())),
StringIs("current_digest", Not(IsEmpty())),
StringIs("high_water", Not(IsEmpty())),
StringIs("high_water_digest", Not(IsEmpty())))))),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf(NameMatches("values"), PropertyList(Not(IsEmpty()))))))));
}
TEST_F(InspectTest, SecondLaunch) {
// Make sure that the high_water_previous_boot property is made visible only upon the second
// run.
auto result = GetInspectHierarchy();
ASSERT_TRUE(result.is_ok());
auto hierarchy = result.take_value();
EXPECT_THAT(hierarchy,
AllOf(NodeMatches(AllOf(NameMatches("root"),
PropertyList(UnorderedElementsAre(
StringIs("current", Not(IsEmpty())),
StringIs("current_digest", Not(IsEmpty())),
StringIs("high_water", Not(IsEmpty())),
StringIs("high_water_digest", Not(IsEmpty())))))),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf(NameMatches("values"), PropertyList(Not(IsEmpty()))))))));
CheckShutdown();
Connect();
result = GetInspectHierarchy();
ASSERT_TRUE(result.is_ok());
hierarchy = result.take_value();
EXPECT_THAT(
hierarchy,
AllOf(NodeMatches(AllOf(
NameMatches("root"),
PropertyList(UnorderedElementsAre(
StringIs("current", Not(IsEmpty())), StringIs("current_digest", Not(IsEmpty())),
StringIs("high_water_previous_boot", Not(IsEmpty())),
StringIs("high_water_digest_previous_boot", Not(IsEmpty())),
StringIs("high_water", Not(IsEmpty())),
StringIs("high_water_digest", Not(IsEmpty())))))),
ChildrenMatch(UnorderedElementsAre(
NodeMatches(AllOf(NameMatches("values"), PropertyList(Not(IsEmpty()))))))));
}
} // namespace
} // namespace component