| // 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/cobalt/bin/app/system_data_updater_impl.h" |
| |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/gtest/test_loop_fixture.h> |
| #include <lib/inspect/cpp/inspect.h> |
| #include <lib/inspect/testing/cpp/inspect.h> |
| #include <lib/sys/cpp/component_context.h> |
| #include <lib/sys/cpp/testing/component_context_provider.h> |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <fstream> |
| |
| #include "fuchsia/cobalt/cpp/fidl.h" |
| |
| namespace cobalt { |
| |
| using encoder::SystemData; |
| using fidl::VectorPtr; |
| using fuchsia::cobalt::SoftwareDistributionInfo; |
| using FuchsiaStatus = fuchsia::cobalt::Status; |
| using fuchsia::cobalt::SystemDataUpdaterPtr; |
| using inspect::testing::ChildrenMatch; |
| using inspect::testing::IntIs; |
| using inspect::testing::NameMatches; |
| using inspect::testing::NodeMatches; |
| using inspect::testing::PropertyList; |
| using inspect::testing::StringIs; |
| using ::testing::UnorderedElementsAre; |
| |
| class CobaltAppForTest { |
| public: |
| CobaltAppForTest(std::unique_ptr<sys::ComponentContext> context) |
| : system_data_("test", "test", ReleaseStage::DEBUG), context_(std::move(context)) { |
| system_data_updater_impl_.reset(new SystemDataUpdaterImpl( |
| inspector_.GetRoot().CreateChild("system_data"), &system_data_, "/tmp/test_")); |
| |
| context_->outgoing()->AddPublicService( |
| system_data_updater_bindings_.GetHandler(system_data_updater_impl_.get())); |
| } |
| |
| void ClearData() { system_data_updater_impl_->ClearData(); } |
| |
| const SystemData& system_make_data() { return system_data_; } |
| |
| const inspect::Inspector& inspector() { return inspector_; } |
| |
| private: |
| inspect::Inspector inspector_; |
| SystemData system_data_; |
| |
| std::unique_ptr<sys::ComponentContext> context_; |
| |
| std::unique_ptr<SystemDataUpdaterImpl> system_data_updater_impl_; |
| fidl::BindingSet<fuchsia::cobalt::SystemDataUpdater> system_data_updater_bindings_; |
| }; |
| |
| class SystemDataUpdaterImplTests : public gtest::TestLoopFixture { |
| public: |
| void SetUp() override { |
| TestLoopFixture::SetUp(); |
| cobalt_app_.reset(new CobaltAppForTest(context_provider_.TakeContext())); |
| } |
| |
| void TearDown() override { |
| cobalt_app_->ClearData(); |
| cobalt_app_.reset(); |
| TestLoopFixture::TearDown(); |
| } |
| |
| protected: |
| SystemDataUpdaterPtr GetSystemDataUpdater() { |
| SystemDataUpdaterPtr system_data_updater; |
| context_provider_.ConnectToPublicService(system_data_updater.NewRequest()); |
| return system_data_updater; |
| } |
| |
| const std::string& channel() { |
| return cobalt_app_->system_make_data().system_profile().channel(); |
| } |
| |
| const std::string& realm() { return cobalt_app_->system_make_data().system_profile().realm(); } |
| |
| inspect::Hierarchy InspectHierarchy() { |
| fpromise::result<inspect::Hierarchy> result = |
| inspect::ReadFromVmo(cobalt_app_->inspector().DuplicateVmo()); |
| return result.take_value(); |
| } |
| |
| private: |
| sys::testing::ComponentContextProvider context_provider_; |
| std::unique_ptr<CobaltAppForTest> cobalt_app_; |
| }; |
| |
| TEST_F(SystemDataUpdaterImplTests, SetSoftwareDistributionInfo) { |
| SystemDataUpdaterPtr system_data_updater = GetSystemDataUpdater(); |
| |
| EXPECT_EQ(channel(), "<unset>"); |
| EXPECT_EQ(realm(), "<unset>"); |
| EXPECT_THAT(InspectHierarchy(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 0), |
| StringIs("channel", "<unset>"), |
| StringIs("realm", "<unset>"))))))))); |
| |
| SoftwareDistributionInfo info = SoftwareDistributionInfo(); |
| info.set_current_realm(""); |
| system_data_updater->SetSoftwareDistributionInfo(std::move(info), [](FuchsiaStatus s) {}); |
| RunLoopUntilIdle(); |
| |
| EXPECT_EQ(channel(), "<unset>"); |
| EXPECT_EQ(realm(), "<unknown>"); |
| EXPECT_THAT(InspectHierarchy(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 1), |
| StringIs("channel", "<unset>"), |
| StringIs("realm", "<unknown>"))))))))); |
| |
| info = SoftwareDistributionInfo(); |
| info.set_current_realm("dogfood"); |
| info.set_current_channel("fishfood_release"); |
| system_data_updater->SetSoftwareDistributionInfo(std::move(info), [](FuchsiaStatus s) {}); |
| RunLoopUntilIdle(); |
| |
| EXPECT_EQ(channel(), "fishfood_release"); |
| EXPECT_EQ(realm(), "dogfood"); |
| EXPECT_THAT(InspectHierarchy(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 2), |
| StringIs("channel", "fishfood_release"), |
| StringIs("realm", "dogfood"))))))))); |
| |
| // Set one software distribution field without overriding the other. |
| info = SoftwareDistributionInfo(); |
| info.set_current_channel("test_channel"); |
| system_data_updater->SetSoftwareDistributionInfo(std::move(info), [](FuchsiaStatus s) {}); |
| RunLoopUntilIdle(); |
| |
| EXPECT_EQ(channel(), "test_channel"); |
| EXPECT_EQ(realm(), "dogfood"); |
| EXPECT_THAT(InspectHierarchy(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 3), |
| StringIs("channel", "test_channel"), |
| StringIs("realm", "dogfood"))))))))); |
| } |
| |
| namespace { |
| |
| std::unique_ptr<SystemData> make_data() { |
| return std::make_unique<SystemData>("test", "test", ReleaseStage::DEBUG); |
| } |
| |
| std::unique_ptr<SystemDataUpdaterImpl> make_updater(inspect::Node node, SystemData* data) { |
| return std::make_unique<SystemDataUpdaterImpl>(std::move(node), data, "/tmp/test_"); |
| } |
| |
| } // namespace |
| |
| TEST(SystemDataUpdaterImpl, TestSoftwareDistributionInfoPersistence) { |
| inspect::Inspector inspector; |
| auto system_data = make_data(); |
| auto updater = make_updater(inspector.GetRoot().CreateChild("system_data"), system_data.get()); |
| |
| EXPECT_EQ(system_data->system_profile().channel(), "<unset>"); |
| EXPECT_EQ(system_data->system_profile().realm(), "<unset>"); |
| EXPECT_THAT(inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 0), |
| StringIs("channel", "<unset>"), |
| StringIs("realm", "<unset>"))))))))); |
| |
| SoftwareDistributionInfo info = SoftwareDistributionInfo(); |
| info.set_current_realm("dogfood"); |
| info.set_current_channel("fishfood_release"); |
| updater->SetSoftwareDistributionInfo(std::move(info), [](FuchsiaStatus s) {}); |
| EXPECT_EQ(system_data->system_profile().realm(), "dogfood"); |
| EXPECT_EQ(system_data->system_profile().channel(), "fishfood_release"); |
| EXPECT_THAT(inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 1), |
| StringIs("channel", "fishfood_release"), |
| StringIs("realm", "dogfood"))))))))); |
| |
| // Test restoring data. |
| inspector = inspect::Inspector(); |
| system_data = make_data(); |
| updater = make_updater(inspector.GetRoot().CreateChild("system_data"), system_data.get()); |
| EXPECT_EQ(system_data->system_profile().realm(), "dogfood"); |
| EXPECT_EQ(system_data->system_profile().channel(), "fishfood_release"); |
| EXPECT_THAT(inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 0), |
| StringIs("channel", "fishfood_release"), |
| StringIs("realm", "dogfood"))))))))); |
| |
| // Test default behavior with no data. |
| updater->ClearData(); |
| inspector = inspect::Inspector(); |
| system_data = make_data(); |
| updater = make_updater(inspector.GetRoot().CreateChild("system_data"), system_data.get()); |
| EXPECT_EQ(system_data->system_profile().channel(), "<unset>"); |
| EXPECT_EQ(system_data->system_profile().realm(), "<unset>"); |
| EXPECT_THAT(inspect::ReadFromVmo(inspector.DuplicateVmo()).take_value(), |
| AllOf(NodeMatches(NameMatches("root")), |
| ChildrenMatch(UnorderedElementsAre(NodeMatches(AllOf( |
| NameMatches("system_data"), |
| PropertyList(UnorderedElementsAre(IntIs("fidl_calls", 0), |
| StringIs("channel", "<unset>"), |
| StringIs("realm", "<unset>"))))))))); |
| } |
| |
| } // namespace cobalt |