| // Copyright 2021 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/modular/testing/cpp/fidl.h> |
| #include <lib/async/cpp/executor.h> |
| #include <lib/fpromise/result.h> |
| #include <lib/inspect/contrib/cpp/archive_reader.h> |
| #include <lib/inspect/cpp/health.h> |
| #include <lib/inspect/testing/cpp/inspect.h> |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <gmock/gmock.h> |
| |
| #include "src/modular/lib/modular_config/modular_config.h" |
| #include "src/modular/lib/modular_config/modular_config_constants.h" |
| #include "src/modular/lib/modular_test_harness/cpp/fake_session_shell.h" |
| #include "src/modular/lib/modular_test_harness/cpp/launch_counter.h" |
| #include "src/modular/lib/modular_test_harness/cpp/test_harness_fixture.h" |
| #include "src/modular/lib/modular_test_harness/cpp/test_harness_impl.h" |
| |
| namespace { |
| |
| using ::testing::HasSubstr; |
| |
| constexpr char kBasemgrSelector[] = "*_inspect/basemgr.cmx:root"; |
| constexpr char kBasemgrName[] = "basemgr.cmx"; |
| |
| class InspectBasemgrTest : public modular_testing::TestHarnessFixture { |
| protected: |
| InspectBasemgrTest() |
| : fake_session_shell_(modular_testing::FakeSessionShell::CreateWithDefaultOptions()), |
| executor_(dispatcher()) {} |
| |
| void RunHarnessAndInterceptSessionShell() { |
| fuchsia::modular::testing::TestHarnessSpec spec; |
| spec.set_environment_suffix("inspect"); |
| modular_testing::TestHarnessBuilder builder(std::move(spec)); |
| builder.InterceptSessionShell(session_shell_launch_counter_.WrapInterceptOptions( |
| fake_session_shell_->BuildInterceptOptions())); |
| builder.BuildAndRun(test_harness()); |
| |
| // Wait for our session shell to start. |
| RunLoopUntil([&] { return fake_session_shell_->is_running(); }); |
| } |
| |
| fpromise::result<inspect::contrib::DiagnosticsData> GetInspectDiagnosticsData() { |
| auto archive = real_services()->Connect<fuchsia::diagnostics::ArchiveAccessor>(); |
| |
| inspect::contrib::ArchiveReader reader(std::move(archive), {kBasemgrSelector}); |
| fpromise::result<std::vector<inspect::contrib::DiagnosticsData>, std::string> result; |
| executor_.schedule_task( |
| reader.SnapshotInspectUntilPresent({kBasemgrName}) |
| .then([&](fpromise::result<std::vector<inspect::contrib::DiagnosticsData>, std::string>& |
| rest) { result = std::move(rest); })); |
| RunLoopUntil([&] { return result.is_ok() || result.is_error(); }); |
| |
| if (result.is_error()) { |
| EXPECT_FALSE(result.is_error()) << "Error was " << result.error(); |
| return fpromise::error(); |
| } |
| |
| if (result.value().size() != 1) { |
| EXPECT_EQ(1u, result.value().size()) << "Expected only one component"; |
| return fpromise::error(); |
| } |
| |
| return fpromise::ok(std::move(result.value()[0])); |
| } |
| |
| std::unique_ptr<modular_testing::FakeSessionShell> fake_session_shell_; |
| modular_testing::LaunchCounter session_shell_launch_counter_; |
| async::Executor executor_; |
| }; |
| |
| // Tests that basemgr exposes its configuration in Inspect. |
| TEST_F(InspectBasemgrTest, ExposesConfig) { |
| RunHarnessAndInterceptSessionShell(); |
| |
| auto inspect_result = GetInspectDiagnosticsData(); |
| ASSERT_TRUE(inspect_result.is_ok()); |
| auto inspect_data = inspect_result.take_value(); |
| |
| // The inspect property should contain configuration that uses |session_shell|. |
| const auto& config_value = inspect_data.GetByPath({"root", modular_config::kInspectConfig}); |
| ASSERT_TRUE(config_value.IsString()); |
| EXPECT_THAT(config_value.GetString(), HasSubstr(fake_session_shell_->url())); |
| } |
| |
| // Tests that basemgr exposes a fuchsia.inspect.Health entry. |
| TEST_F(InspectBasemgrTest, Health) { |
| RunHarnessAndInterceptSessionShell(); |
| |
| auto inspect_result = GetInspectDiagnosticsData(); |
| ASSERT_TRUE(inspect_result.is_ok()); |
| auto inspect_data = inspect_result.take_value(); |
| |
| const auto& health_status = inspect_data.GetByPath({"root", inspect::kHealthNodeName, "status"}); |
| ASSERT_TRUE(health_status.IsString()); |
| EXPECT_EQ(inspect::kHealthOk, std::string(health_status.GetString())); |
| |
| const auto& start_timestamp = |
| inspect_data.GetByPath({"root", inspect::kHealthNodeName, inspect::kStartTimestamp}); |
| ASSERT_TRUE(start_timestamp.IsNumber()); |
| } |
| |
| // Tests that basemgr exposes a session startup timestamp. |
| TEST_F(InspectBasemgrTest, SessionStartedAt) { |
| RunHarnessAndInterceptSessionShell(); |
| |
| auto inspect_result = GetInspectDiagnosticsData(); |
| ASSERT_TRUE(inspect_result.is_ok()); |
| auto inspect_data = inspect_result.take_value(); |
| |
| const auto& config_value = inspect_data.GetByPath({"root", "session_started_at", "0", "@time"}); |
| ASSERT_TRUE(config_value.IsNumber()); |
| } |
| |
| // Tests that basemgr exposes a second session startup timestamp when the session is restarted. |
| TEST_F(InspectBasemgrTest, SessionStartedAtRestart) { |
| RunHarnessAndInterceptSessionShell(); |
| |
| { |
| auto inspect_result = GetInspectDiagnosticsData(); |
| ASSERT_TRUE(inspect_result.is_ok()); |
| auto inspect_data = inspect_result.take_value(); |
| |
| // Inspect should initially contain one timestamp from the initial session. |
| const auto& first_time = inspect_data.GetByPath({"root", "session_started_at", "0", "@time"}); |
| ASSERT_TRUE(first_time.IsNumber()); |
| } |
| |
| // Restart the session. |
| fake_session_shell_->session_shell_context()->Restart(); |
| |
| // Wait for the session shell to start again. |
| RunLoopUntil([&] { return session_shell_launch_counter_.launch_count() >= 2; }); |
| |
| { |
| // Read the inspect data again. |
| auto inspect_result = GetInspectDiagnosticsData(); |
| ASSERT_TRUE(inspect_result.is_ok()); |
| auto inspect_data = inspect_result.take_value(); |
| |
| // Inspect should now contain a second timestamp from the restarted session. |
| const auto& second_time = inspect_data.GetByPath({"root", "session_started_at", "1", "@time"}); |
| ASSERT_TRUE(second_time.IsNumber()); |
| } |
| } |
| |
| } // namespace |