| // Copyright 2020 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/attachments/attachment_manager.h" |
| |
| #include <lib/async/cpp/executor.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/fpromise/result.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/time.h> |
| |
| #include <cstddef> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/developer/forensics/feedback/attachments/types.h" |
| #include "src/developer/forensics/testing/gmatchers.h" |
| #include "src/developer/forensics/testing/gpretty_printers.h" |
| #include "src/developer/forensics/testing/unit_test_fixture.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace forensics::feedback { |
| namespace { |
| |
| using ::testing::Contains; |
| using ::testing::ElementsAreArray; |
| using ::testing::Eq; |
| using ::testing::HasSubstr; |
| using ::testing::IsEmpty; |
| using ::testing::Not; |
| using ::testing::Pair; |
| using ::testing::UnorderedElementsAreArray; |
| |
| class SimpleAttachmentProvider : public AttachmentProvider { |
| public: |
| SimpleAttachmentProvider(async_dispatcher_t* dispatcher, zx::duration delay, AttachmentValue data) |
| : dispatcher_(dispatcher), delay_(delay), data_(std::move(data)) {} |
| |
| ::fpromise::promise<AttachmentValue> Get(zx::duration timeout) override { |
| ::fpromise::bridge<AttachmentValue> bridge; |
| |
| async::PostDelayedTask( |
| dispatcher_, |
| [this, timeout, completer = std::move(bridge.completer)]() mutable { |
| if (delay_ <= timeout) { |
| completer.complete_ok(data_); |
| } else { |
| completer.complete_ok(AttachmentValue(Error::kTimeout)); |
| } |
| }, |
| (delay_ <= timeout) ? delay_ : timeout); |
| |
| return bridge.consumer.promise_or(::fpromise::error()); |
| } |
| |
| private: |
| async_dispatcher_t* dispatcher_; |
| zx::duration delay_; |
| AttachmentValue data_; |
| }; |
| |
| using AttachmentManagerTest = UnitTestFixture; |
| |
| TEST_F(AttachmentManagerTest, Static) { |
| async::Executor executor(dispatcher()); |
| AttachmentManager manager({"static"}, {{"static", AttachmentValue("value")}}); |
| |
| Attachments attachments; |
| executor.schedule_task( |
| manager.GetAttachments(zx::duration::infinite()) |
| .and_then([&attachments](Attachments& result) { attachments = std::move(result); }) |
| .or_else([] { FX_LOGS(FATAL) << "Unreachable branch"; })); |
| |
| RunLoopUntilIdle(); |
| EXPECT_THAT(attachments, ElementsAreArray({Pair("static", AttachmentValue("value"))})); |
| } |
| |
| TEST_F(AttachmentManagerTest, DropStatic) { |
| async::Executor executor(dispatcher()); |
| AttachmentManager manager({"static"}, {{"static", AttachmentValue("value")}}); |
| |
| manager.DropStaticAttachment("static", Error::kConnectionError); |
| manager.DropStaticAttachment("unused", Error::kConnectionError); |
| |
| Attachments attachments; |
| executor.schedule_task( |
| manager.GetAttachments(zx::duration::infinite()) |
| .and_then([&attachments](Attachments& result) { attachments = std::move(result); }) |
| .or_else([] { FX_LOGS(FATAL) << "Unreachable branch"; })); |
| |
| RunLoopUntilIdle(); |
| EXPECT_THAT(attachments, |
| ElementsAreArray({Pair("static", AttachmentValue(Error::kConnectionError))})); |
| } |
| |
| TEST_F(AttachmentManagerTest, Dynamic) { |
| async::Executor executor(dispatcher()); |
| |
| SimpleAttachmentProvider provider1(dispatcher(), zx::sec(1), AttachmentValue("value1")); |
| SimpleAttachmentProvider provider2(dispatcher(), zx::sec(3), AttachmentValue("value2")); |
| |
| AttachmentManager manager({"dynamic1", "dynamic2"}, {}, |
| { |
| {"dynamic1", &provider1}, |
| {"dynamic2", &provider2}, |
| }); |
| |
| Attachments attachments; |
| executor.schedule_task( |
| manager.GetAttachments(zx::sec(1)) |
| .and_then([&attachments](Attachments& result) { attachments = std::move(result); }) |
| .or_else([] { FX_LOGS(FATAL) << "Unreachable branch"; })); |
| |
| RunLoopFor(zx::sec(1)); |
| EXPECT_THAT(attachments, ElementsAreArray({ |
| Pair("dynamic1", AttachmentValue("value1")), |
| Pair("dynamic2", AttachmentValue(Error::kTimeout)), |
| })); |
| |
| attachments.clear(); |
| |
| executor.schedule_task( |
| manager.GetAttachments(zx::duration::infinite()) |
| .and_then([&attachments](Attachments& result) { attachments = std::move(result); }) |
| .or_else([] { FX_LOGS(FATAL) << "Unreachable branch"; })); |
| |
| RunLoopFor(zx::sec(3)); |
| EXPECT_THAT(attachments, ElementsAreArray({ |
| Pair("dynamic1", AttachmentValue("value1")), |
| Pair("dynamic2", AttachmentValue("value2")), |
| })); |
| } |
| |
| TEST_F(AttachmentManagerTest, NoProvider) { |
| ASSERT_DEATH({ AttachmentManager manager({"unknown.attachment"}); }, |
| HasSubstr("Attachment \"unknown.attachment\" collected by 0 providers")); |
| } |
| |
| } // namespace |
| } // namespace forensics::feedback |