blob: 57940cdd596418552337df89a24eeabe10a7baa7 [file] [log] [blame]
// 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" // IWYU pragma: keep
#include "src/developer/forensics/testing/unit_test_fixture.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, std::string data)
: dispatcher_(dispatcher), delay_(delay), data_(std::move(data)) {}
::fpromise::promise<AttachmentValue> Get(const uint64_t ticket) override {
::fpromise::bridge<AttachmentValue> bridge;
completers_[ticket] = std::move(bridge.completer);
async::PostDelayedTask(
dispatcher_,
[this, ticket]() mutable {
if (completers_[ticket]) {
completers_[ticket].complete_ok(AttachmentValue(data_));
}
},
delay_);
return bridge.consumer.promise_or(::fpromise::error());
}
void ForceCompletion(const uint64_t ticket, const Error error) override {
if (completers_[ticket] && completers_.contains(ticket)) {
completers_[ticket].complete_ok(error);
}
}
private:
async_dispatcher_t* dispatcher_;
zx::duration delay_;
std::string data_;
std::map<uint64_t, ::fpromise::completer<AttachmentValue>> completers_;
};
using AttachmentManagerTest = UnitTestFixture;
TEST_F(AttachmentManagerTest, Dynamic) {
async::Executor executor(dispatcher());
SimpleAttachmentProvider provider1(dispatcher(), zx::sec(1), "value1");
SimpleAttachmentProvider provider2(dispatcher(), zx::sec(3), "value2");
AttachmentManager manager(dispatcher(), {"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", AttachmentValueIs("value1")),
Pair("dynamic2", AttachmentValueIs(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", AttachmentValueIs("value1")),
Pair("dynamic2", AttachmentValueIs("value2")),
}));
}
TEST_F(AttachmentManagerTest, NoProvider) {
ASSERT_DEATH(
{ AttachmentManager manager(dispatcher(), {"unknown.attachment"}); },
HasSubstr("Attachment \"unknown.attachment\" collected by 0 providers"));
}
} // namespace
} // namespace forensics::feedback