blob: f84e2600ee945a26d6e3dd218a197312c467ffea [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"
#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