| // 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 "src/developer/feedback/crashpad_agent/inspect_manager.h" |
| |
| #include <lib/inspect/cpp/hierarchy.h> |
| #include <lib/inspect/cpp/inspect.h> |
| #include <lib/inspect/cpp/reader.h> |
| #include <lib/timekeeper/test_clock.h> |
| #include <lib/zx/time.h> |
| |
| #include <memory> |
| |
| #include "sdk/lib/inspect/testing/cpp/inspect.h" |
| #include "src/developer/feedback/crashpad_agent/config.h" |
| #include "src/developer/feedback/crashpad_agent/constants.h" |
| #include "src/developer/feedback/crashpad_agent/settings.h" |
| #include "src/lib/fxl/logging.h" |
| #include "src/lib/fxl/test/test_settings.h" |
| #include "src/lib/syslog/cpp/logger.h" |
| #include "third_party/googletest/googlemock/include/gmock/gmock.h" |
| #include "third_party/googletest/googletest/include/gtest/gtest.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::IsEmpty; |
| using testing::Not; |
| using testing::UnorderedElementsAreArray; |
| |
| constexpr zx::time_utc kTime1(0); |
| constexpr zx::time_utc kTime2((zx::hour(7) + zx::min(14) + zx::sec(52)).get()); |
| constexpr zx::time_utc kTime3((zx::hour(3) * 24 + zx::hour(15) + zx::min(33) + zx::sec(17)).get()); |
| |
| constexpr char kTime1Str[] = "1970-01-01 00:00:00 GMT"; |
| constexpr char kTime2Str[] = "1970-01-01 07:14:52 GMT"; |
| constexpr char kTime3Str[] = "1970-01-04 15:33:17 GMT"; |
| |
| constexpr CrashServerConfig::UploadPolicy kConfigDisabled = |
| CrashServerConfig::UploadPolicy::DISABLED; |
| constexpr CrashServerConfig::UploadPolicy kConfigEnabled = CrashServerConfig::UploadPolicy::ENABLED; |
| constexpr CrashServerConfig::UploadPolicy kConfigReadFromPrivacySettings = |
| CrashServerConfig::UploadPolicy::READ_FROM_PRIVACY_SETTINGS; |
| |
| constexpr Settings::UploadPolicy kSettingsDisabled = Settings::UploadPolicy::DISABLED; |
| constexpr Settings::UploadPolicy kSettingsEnabled = Settings::UploadPolicy::ENABLED; |
| constexpr Settings::UploadPolicy kSettingsLimbo = Settings::UploadPolicy::LIMBO; |
| |
| class InspectManagerTest : public testing::Test { |
| public: |
| void SetUp() override { |
| inspector_ = std::make_unique<inspect::Inspector>(); |
| clock_ = std::make_unique<timekeeper::TestClock>(); |
| inspect_manager_ = std::make_unique<InspectManager>(&inspector_->GetRoot(), clock_.get()); |
| } |
| |
| protected: |
| inspect::Hierarchy InspectTree() { |
| auto result = inspect::ReadFromVmo(inspector_->DuplicateVmo()); |
| FXL_CHECK(result.is_ok()); |
| return result.take_value(); |
| } |
| |
| std::unique_ptr<timekeeper::TestClock> clock_; |
| std::unique_ptr<InspectManager> inspect_manager_; |
| |
| private: |
| std::unique_ptr<inspect::Inspector> inspector_; |
| }; |
| |
| TEST_F(InspectManagerTest, InitialInspectTree) { |
| EXPECT_THAT(InspectTree(), ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(NameMatches(kInspectConfigName)), |
| NodeMatches(NameMatches(kInspectSettingsName)), |
| NodeMatches(NameMatches(kInspectReportsName)), |
| }))); |
| } |
| |
| TEST_F(InspectManagerTest, Succeed_AddReport_UniqueReports) { |
| clock_->Set(kTime1); |
| EXPECT_TRUE(inspect_manager_->AddReport("program_1", "local_report_id_1")); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains( |
| AllOf(NodeMatches(NameMatches(kInspectReportsName)), |
| ChildrenMatch(ElementsAre(AllOf( |
| NodeMatches(NameMatches("program_1")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf( |
| NameMatches("local_report_id_1"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime1Str)))))))))))))); |
| |
| clock_->Set(kTime2); |
| EXPECT_TRUE(inspect_manager_->AddReport("program_1", "local_report_id_2")); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectReportsName)), |
| ChildrenMatch(ElementsAre(AllOf(NodeMatches(NameMatches("program_1")), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(AllOf(NameMatches("local_report_id_1"), |
| PropertyList(ElementsAre(StringIs( |
| "creation_time", kTime1Str))))), |
| NodeMatches(AllOf(NameMatches("local_report_id_2"), |
| PropertyList(ElementsAre(StringIs( |
| "creation_time", kTime2Str))))), |
| }))))))))); |
| |
| clock_->Set(kTime3); |
| EXPECT_TRUE(inspect_manager_->AddReport("program_2", "local_report_id_3")); |
| EXPECT_TRUE(inspect_manager_->AddReport("program_2", "local_report_id_4")); |
| EXPECT_TRUE(inspect_manager_->AddReport("program_2", "local_report_id_5")); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectReportsName)), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| AllOf(NodeMatches(NameMatches("program_1")), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches( |
| AllOf(NameMatches("local_report_id_1"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime1Str))))), |
| NodeMatches( |
| AllOf(NameMatches("local_report_id_2"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime2Str))))), |
| }))), |
| AllOf(NodeMatches(NameMatches("program_2")), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches( |
| AllOf(NameMatches("local_report_id_3"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime3Str))))), |
| NodeMatches( |
| AllOf(NameMatches("local_report_id_4"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime3Str))))), |
| NodeMatches( |
| AllOf(NameMatches("local_report_id_5"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime3Str))))), |
| }))), |
| })))))); |
| } |
| |
| TEST_F(InspectManagerTest, Fail_AddReport_DuplicateReport) { |
| clock_->Set(kTime2); |
| EXPECT_TRUE(inspect_manager_->AddReport("program", "local_report_id")); |
| clock_->Set(kTime3); |
| EXPECT_FALSE(inspect_manager_->AddReport("program", "local_report_id")); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains( |
| AllOf(NodeMatches(NameMatches(kInspectReportsName)), |
| ChildrenMatch(ElementsAre(AllOf( |
| NodeMatches(NameMatches("program")), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf( |
| NameMatches("local_report_id"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime2Str)))))))))))))); |
| } |
| |
| TEST_F(InspectManagerTest, Succeed_MarkReportAsUploaded) { |
| clock_->Set(kTime2); |
| EXPECT_TRUE(inspect_manager_->AddReport("program", "local_report_id")); |
| clock_->Set(kTime3); |
| EXPECT_TRUE(inspect_manager_->MarkReportAsUploaded("local_report_id", "server_report_id")); |
| EXPECT_THAT(InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectReportsName)), |
| ChildrenMatch(ElementsAre(AllOf( |
| NodeMatches(NameMatches("program")), |
| ChildrenMatch(ElementsAre(AllOf( |
| NodeMatches(AllOf( |
| NameMatches("local_report_id"), |
| PropertyList(ElementsAre(StringIs("creation_time", kTime2Str))))), |
| ChildrenMatch(ElementsAre(NodeMatches(AllOf( |
| NameMatches("crash_server"), PropertyList(UnorderedElementsAreArray({ |
| StringIs("creation_time", kTime3Str), |
| StringIs("id", "server_report_id"), |
| })))))))))))))))); |
| } |
| |
| TEST_F(InspectManagerTest, Fail_MarkReportAsUploaded_UnknownReport) { |
| EXPECT_FALSE(inspect_manager_->MarkReportAsUploaded("unknown_report", "server_report_id")); |
| EXPECT_THAT(InspectTree(), |
| ChildrenMatch(Contains( |
| AllOf(NodeMatches(NameMatches(kInspectReportsName)), ChildrenMatch(IsEmpty()))))); |
| } |
| |
| TEST_F(InspectManagerTest, ExposeConfig_UploadEnabled) { |
| inspect_manager_->ExposeConfig(Config{ |
| /*crashpad_database=*/ |
| { |
| /*max_size_in_kb=*/1234, |
| }, |
| /*crash_server=*/ |
| { |
| /*upload_policy=*/kConfigEnabled, |
| /*url=*/std::make_unique<std::string>("http://localhost:1234"), |
| }}); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectConfigName)), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(AllOf(NameMatches(kCrashpadDatabaseKey), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs(kCrashpadDatabaseMaxSizeInKbKey, 1234), |
| })))), |
| NodeMatches(AllOf(NameMatches(kCrashServerKey), |
| PropertyList(UnorderedElementsAreArray({ |
| StringIs(kCrashServerUploadPolicyKey, ToString(kConfigEnabled)), |
| StringIs(kCrashServerUrlKey, "http://localhost:1234"), |
| })))), |
| })))))); |
| } |
| |
| TEST_F(InspectManagerTest, ExposeConfig_UploadDisabled) { |
| inspect_manager_->ExposeConfig(Config{/*crashpad_database=*/ |
| { |
| /*max_size_in_kb=*/1234, |
| }, |
| /*crash_server=*/ |
| { |
| /*upload_policy=*/kConfigDisabled, |
| /*url=*/nullptr, |
| }}); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectConfigName)), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(AllOf(NameMatches(kCrashpadDatabaseKey), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs(kCrashpadDatabaseMaxSizeInKbKey, 1234), |
| })))), |
| NodeMatches(AllOf(NameMatches(kCrashServerKey), |
| PropertyList(ElementsAre(StringIs(kCrashServerUploadPolicyKey, |
| ToString(kConfigDisabled)))))), |
| })))))); |
| } |
| |
| TEST_F(InspectManagerTest, ExposeConfig_UploadReadFromPrivacySettings) { |
| inspect_manager_->ExposeConfig(Config{/*crashpad_database=*/ |
| { |
| /*max_size_in_kb=*/1234, |
| }, |
| /*crash_server=*/ |
| { |
| /*upload_policy=*/kConfigReadFromPrivacySettings, |
| /*url=*/nullptr, |
| }}); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(AllOf( |
| NodeMatches(NameMatches(kInspectConfigName)), |
| ChildrenMatch(UnorderedElementsAreArray({ |
| NodeMatches(AllOf(NameMatches(kCrashpadDatabaseKey), |
| PropertyList(UnorderedElementsAreArray({ |
| UintIs(kCrashpadDatabaseMaxSizeInKbKey, 1234), |
| })))), |
| NodeMatches(AllOf( |
| NameMatches(kCrashServerKey), |
| PropertyList(ElementsAre(StringIs(kCrashServerUploadPolicyKey, |
| ToString(kConfigReadFromPrivacySettings)))))), |
| })))))); |
| } |
| |
| TEST_F(InspectManagerTest, ExposeSettings_TrackUploadPolicyChanges) { |
| Settings settings; |
| settings.set_upload_policy(kSettingsEnabled); |
| inspect_manager_->ExposeSettings(&settings); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(NodeMatches(AllOf( |
| NameMatches(kInspectSettingsName), |
| PropertyList(ElementsAre(StringIs("upload_policy", ToString(kSettingsEnabled))))))))); |
| |
| settings.set_upload_policy(kSettingsDisabled); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(NodeMatches(AllOf( |
| NameMatches(kInspectSettingsName), |
| PropertyList(ElementsAre(StringIs("upload_policy", ToString(kSettingsDisabled))))))))); |
| |
| settings.set_upload_policy(kSettingsLimbo); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(NodeMatches( |
| AllOf(NameMatches(kInspectSettingsName), |
| PropertyList(ElementsAre(StringIs("upload_policy", ToString(kSettingsLimbo))))))))); |
| |
| settings.set_upload_policy(kSettingsEnabled); |
| EXPECT_THAT( |
| InspectTree(), |
| ChildrenMatch(Contains(NodeMatches(AllOf( |
| NameMatches(kInspectSettingsName), |
| PropertyList(ElementsAre(StringIs("upload_policy", ToString(kSettingsEnabled))))))))); |
| } |
| |
| } // namespace |
| } // namespace feedback |
| |
| int main(int argc, char** argv) { |
| if (!fxl::SetTestSettings(argc, argv)) { |
| return EXIT_FAILURE; |
| } |
| |
| testing::InitGoogleTest(&argc, argv); |
| syslog::InitLogger({"feedback", "test"}); |
| return RUN_ALL_TESTS(); |
| } |