| // 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 "src/developer/feedback/crash_reports/main_service.h" |
| |
| #include <lib/fit/result.h> |
| #include <lib/inspect/cpp/hierarchy.h> |
| #include <lib/inspect/cpp/inspect.h> |
| #include <lib/inspect/testing/cpp/inspect.h> |
| #include <lib/zx/time.h> |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "src/developer/feedback/crash_reports/config.h" |
| #include "src/developer/feedback/crash_reports/constants.h" |
| #include "src/developer/feedback/crash_reports/info/info_context.h" |
| #include "src/developer/feedback/crash_reports/main_service.h" |
| #include "src/developer/feedback/testing/cobalt_test_fixture.h" |
| #include "src/developer/feedback/testing/stubs/cobalt_logger_factory.h" |
| #include "src/developer/feedback/testing/stubs/device_id_provider.h" |
| #include "src/developer/feedback/testing/stubs/network_reachability_provider.h" |
| #include "src/developer/feedback/testing/stubs/utc_provider.h" |
| #include "src/developer/feedback/testing/unit_test_fixture.h" |
| #include "src/lib/syslog/cpp/logger.h" |
| #include "src/lib/timekeeper/test_clock.h" |
| |
| namespace feedback { |
| namespace { |
| |
| using inspect::testing::ChildrenMatch; |
| using inspect::testing::NameMatches; |
| using inspect::testing::NodeMatches; |
| using inspect::testing::PropertyList; |
| using inspect::testing::StringIs; |
| using inspect::testing::UintIs; |
| using testing::Contains; |
| using testing::ElementsAre; |
| using testing::UnorderedElementsAre; |
| using testing::UnorderedElementsAreArray; |
| |
| constexpr char kCrashServerUrl[] = "localhost:1234"; |
| |
| class MainServiceTest : public UnitTestFixture, public CobaltTestFixture { |
| public: |
| MainServiceTest() : UnitTestFixture(), CobaltTestFixture(/*unit_test_fixture=*/this) {} |
| |
| void SetUp() override { |
| Config config = {/*crash_server=*/ |
| { |
| /*upload_policy=*/CrashServerConfig::UploadPolicy::ENABLED, |
| /*url=*/std::make_unique<std::string>(kCrashServerUrl), |
| }}; |
| inspector_ = std::make_unique<inspect::Inspector>(); |
| info_context_ = |
| std::make_shared<InfoContext>(&inspector_->GetRoot(), clock_, dispatcher(), services()); |
| |
| SetUpCobaltServer(std::make_unique<stubs::CobaltLoggerFactory>()); |
| SetUpDeviceIdProviderServer(); |
| SetUpNetworkReachabilityProviderServer(); |
| SetUpUtcProviderServer(); |
| |
| main_service_ = |
| MainService::TryCreate(dispatcher(), services(), clock_, info_context_, std::move(config)); |
| FX_CHECK(main_service_); |
| RunLoopUntilIdle(); |
| } |
| |
| protected: |
| inspect::Hierarchy InspectTree() { |
| auto result = inspect::ReadFromVmo(inspector_->DuplicateVmo()); |
| FX_CHECK(result.is_ok()); |
| return result.take_value(); |
| } |
| |
| private: |
| void SetUpDeviceIdProviderServer() { |
| device_id_provider_server_ = std::make_unique<stubs::DeviceIdProvider>("my-device-id"); |
| InjectServiceProvider(device_id_provider_server_.get()); |
| } |
| |
| void SetUpNetworkReachabilityProviderServer() { |
| network_reachability_provider_server_ = std::make_unique<stubs::NetworkReachabilityProvider>(); |
| InjectServiceProvider(network_reachability_provider_server_.get()); |
| } |
| |
| void SetUpUtcProviderServer() { |
| utc_provider_server_ = std::make_unique<stubs::UtcProvider>( |
| dispatcher(), std::vector<stubs::UtcProvider::Response>({stubs::UtcProvider::Response( |
| stubs::UtcProvider::Response::Value::kExternal, zx::nsec(0))})); |
| InjectServiceProvider(utc_provider_server_.get()); |
| } |
| |
| protected: |
| std::unique_ptr<inspect::Inspector> inspector_; |
| timekeeper::TestClock clock_; |
| std::shared_ptr<InfoContext> info_context_; |
| |
| // Stubs servers. |
| std::unique_ptr<stubs::DeviceIdProviderBase> device_id_provider_server_; |
| std::unique_ptr<stubs::NetworkReachabilityProvider> network_reachability_provider_server_; |
| std::unique_ptr<stubs::UtcProviderBase> utc_provider_server_; |
| |
| protected: |
| std::unique_ptr<MainService> main_service_; |
| }; |
| |
| TEST_F(MainServiceTest, Check_InitialInspectTree) { |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(UnorderedElementsAre( |
| AllOf(NodeMatches(NameMatches("config")), |
| ChildrenMatch(ElementsAre(NodeMatches( |
| AllOf(NameMatches(kCrashServerKey), |
| PropertyList(UnorderedElementsAreArray({ |
| StringIs(kCrashServerUploadPolicyKey, |
| ToString(CrashServerConfig::UploadPolicy::ENABLED)), |
| StringIs(kCrashServerUrlKey, kCrashServerUrl), |
| }))))))), |
| AllOf( |
| NodeMatches(NameMatches("crash_reporter")), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(AllOf(NameMatches("database"), PropertyList(ElementsAre(UintIs( |
| "max_crashpad_database_size_in_kb", |
| kCrashpadDatabaseMaxSizeInKb))))), |
| NodeMatches( |
| AllOf(NameMatches("settings"), |
| PropertyList(ElementsAre(StringIs( |
| "upload_policy", ToString(Settings::UploadPolicy::ENABLED)))))), |
| NodeMatches(NameMatches("reports")), |
| NodeMatches(NameMatches("queue")), |
| }))), |
| AllOf(NodeMatches(NameMatches("fidl")), ChildrenMatch(ElementsAre(NodeMatches(AllOf( |
| NameMatches("fuchsia.feedback.CrashReporter"), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs("current_num_connections", 0u), |
| UintIs("total_num_connections", 0u), |
| })))))))))); |
| } |
| |
| TEST_F(MainServiceTest, CrashReporter_CheckInspect) { |
| const size_t kNumConnections = 4; |
| fuchsia::feedback::CrashReporterSyncPtr crash_reporters[kNumConnections]; |
| |
| // Add 3 new connections. |
| main_service_->HandleCrashReporterRequest(crash_reporters[0].NewRequest()); |
| main_service_->HandleCrashReporterRequest(crash_reporters[1].NewRequest()); |
| main_service_->HandleCrashReporterRequest(crash_reporters[2].NewRequest()); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches("fidl")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf(NameMatches("fuchsia.feedback.CrashReporter"), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs("current_num_connections", 3u), |
| UintIs("total_num_connections", 3u), |
| })))))))))); |
| |
| // Close 1 connection. |
| crash_reporters[1].Unbind(); |
| RunLoopUntilIdle(); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches("fidl")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf(NameMatches("fuchsia.feedback.CrashReporter"), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs("current_num_connections", 2u), |
| UintIs("total_num_connections", 3u), |
| })))))))))); |
| |
| // Add 1 new connection. |
| main_service_->HandleCrashReporterRequest(crash_reporters[3].NewRequest()); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches("fidl")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf(NameMatches("fuchsia.feedback.CrashReporter"), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs("current_num_connections", 3u), |
| UintIs("total_num_connections", 4u), |
| })))))))))); |
| |
| // Close remaining connections. |
| crash_reporters[0].Unbind(); |
| crash_reporters[2].Unbind(); |
| crash_reporters[3].Unbind(); |
| RunLoopUntilIdle(); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches("fidl")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf(NameMatches("fuchsia.feedback.CrashReporter"), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs("current_num_connections", 0u), |
| UintIs("total_num_connections", 4u), |
| })))))))))); |
| } |
| |
| } // namespace |
| } // namespace feedback |