| // 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/forensics/feedback_data/annotations/channel_provider.h" |
| |
| #include <lib/async/cpp/executor.h> |
| #include <lib/fit/promise.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/time.h> |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/developer/forensics/feedback_data/annotations/types.h" |
| #include "src/developer/forensics/feedback_data/constants.h" |
| #include "src/developer/forensics/testing/stubs/channel_control.h" |
| #include "src/developer/forensics/testing/stubs/cobalt_logger_factory.h" |
| #include "src/developer/forensics/testing/unit_test_fixture.h" |
| #include "src/developer/forensics/utils/cobalt/event.h" |
| #include "src/developer/forensics/utils/errors.h" |
| |
| namespace forensics { |
| namespace feedback_data { |
| namespace { |
| |
| using testing::IsEmpty; |
| using testing::Pair; |
| using testing::UnorderedElementsAreArray; |
| |
| class ChannelProviderTest : public UnitTestFixture { |
| public: |
| ChannelProviderTest() : executor_(dispatcher()) {} |
| |
| protected: |
| void SetUpChannelProviderServer(std::unique_ptr<stubs::ChannelControlBase> server) { |
| channel_provider_server_ = std::move(server); |
| if (channel_provider_server_) { |
| InjectServiceProvider(channel_provider_server_.get()); |
| } |
| } |
| |
| Annotations GetChannels(const AnnotationKeys& allowlist = {kAnnotationSystemUpdateChannelCurrent, |
| kAnnotationSystemUpdateChannelTarget}, |
| const zx::duration timeout = zx::sec(1)) { |
| SetUpCobaltServer(std::make_unique<stubs::CobaltLoggerFactory>()); |
| cobalt::Logger cobalt(dispatcher(), services()); |
| |
| ChannelProvider provider(dispatcher(), services(), &cobalt); |
| auto promise = provider.GetAnnotations(timeout, allowlist); |
| |
| bool was_called = false; |
| Annotations channels; |
| executor_.schedule_task( |
| std::move(promise).then([&was_called, &channels](::fit::result<Annotations>& res) { |
| was_called = true; |
| |
| if (res.is_error()) { |
| return; |
| } |
| |
| channels = std::move(res).value(); |
| })); |
| RunLoopFor(timeout); |
| |
| FX_CHECK(was_called); |
| |
| return channels; |
| } |
| |
| async::Executor executor_; |
| |
| private: |
| std::unique_ptr<stubs::ChannelControlBase> channel_provider_server_; |
| }; |
| |
| TEST_F(ChannelProviderTest, Succeed_BothChannels) { |
| auto channel_provider_server = |
| std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{ |
| .current = "current-channel", |
| .target = "target-channel", |
| }); |
| SetUpChannelProviderServer(std::move(channel_provider_server)); |
| |
| const auto result = GetChannels(); |
| |
| EXPECT_THAT(result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr("current-channel")), |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr("target-channel")), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Succeed_OnlyCurrentChannel) { |
| auto channel_provider_server = |
| std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{ |
| .current = "current-channel", |
| .target = std::nullopt, |
| }); |
| SetUpChannelProviderServer(std::move(channel_provider_server)); |
| |
| const auto result = GetChannels({kAnnotationSystemUpdateChannelCurrent}); |
| |
| EXPECT_THAT(result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr("current-channel")), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Succeed_OnlyTargetChannel) { |
| auto channel_provider_server = |
| std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{ |
| .current = std::nullopt, |
| .target = "target-channel", |
| }); |
| SetUpChannelProviderServer(std::move(channel_provider_server)); |
| |
| const auto result = GetChannels({kAnnotationSystemUpdateChannelTarget}); |
| |
| EXPECT_THAT(result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr("target-channel")), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Succeed_EmptyChannel) { |
| SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlReturnsEmptyChannel>()); |
| |
| const auto result = GetChannels(); |
| |
| EXPECT_THAT(result, UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr("")), |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr("")), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Succeed_NoRequestedKeysInAllowlist) { |
| SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlReturnsEmptyChannel>()); |
| |
| const auto result = GetChannels({"not-returned-by-channel-provider"}); |
| |
| EXPECT_THAT(result, IsEmpty()); |
| } |
| |
| TEST_F(ChannelProviderTest, Fail_ChannelProviderServerNotAvailable) { |
| SetUpChannelProviderServer(nullptr); |
| |
| const auto result = GetChannels(); |
| |
| EXPECT_THAT( |
| result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr(Error::kConnectionError)), |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr(Error::kConnectionError)), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Fail_ChannelProviderServerClosesConnection) { |
| SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlClosesConnection>()); |
| |
| const auto result = GetChannels(); |
| |
| EXPECT_THAT( |
| result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr(Error::kConnectionError)), |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr(Error::kConnectionError)), |
| })); |
| } |
| |
| TEST_F(ChannelProviderTest, Fail_ChannelProviderServerNeverReturns) { |
| SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlNeverReturns>()); |
| |
| const auto result = GetChannels(); |
| |
| EXPECT_THAT(result, |
| UnorderedElementsAreArray({ |
| Pair(kAnnotationSystemUpdateChannelCurrent, AnnotationOr(Error::kTimeout)), |
| Pair(kAnnotationSystemUpdateChannelTarget, AnnotationOr(Error::kTimeout)), |
| })); |
| EXPECT_THAT(ReceivedCobaltEvents(), UnorderedElementsAreArray({ |
| cobalt::Event(cobalt::TimedOutData::kChannel), |
| })); |
| } |
| |
| } // namespace |
| } // namespace feedback_data |
| } // namespace forensics |