blob: 1d438e005a6fe79a3914c3f5382551806bb69734 [file] [log] [blame]
// Copyright 2021 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/last_reboot.h"
#include <fuchsia/feedback/cpp/fidl.h>
#include <fuchsia/hardware/power/statecontrol/cpp/fidl.h>
#include <lib/inspect/cpp/vmo/types.h>
#include <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/developer/forensics/feedback/reboot_log/reboot_log.h"
#include "src/developer/forensics/last_reboot/reporter.h"
#include "src/developer/forensics/testing/stubs/cobalt_logger.h"
#include "src/developer/forensics/testing/stubs/cobalt_logger_factory.h"
#include "src/developer/forensics/testing/stubs/crash_reporter.h"
#include "src/developer/forensics/testing/stubs/reboot_methods_watcher_register.h"
#include "src/developer/forensics/testing/unit_test_fixture.h"
#include "src/developer/forensics/utils/cobalt/logger.h"
#include "src/lib/files/path.h"
#include "src/lib/timekeeper/async_test_clock.h"
namespace forensics::feedback {
namespace {
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAreArray;
class LastRebootTest : public UnitTestFixture {
public:
LastRebootTest()
: clock_(dispatcher()),
cobalt_(dispatcher(), services(), &clock_),
reboot_watcher_register_server_(
std::make_unique<stubs::RebootMethodsWatcherRegisterHangs>()) {
SetUpCobaltServer(std::make_unique<stubs::CobaltLoggerFactory>());
InjectServiceProvider(reboot_watcher_register_server_.get());
}
void TearDown() override {
files::DeletePath("/tmp/has_reported_on_reboot_log.txt", /*recursive=*/false);
}
protected:
void SetUpCrashReporterServer(std::unique_ptr<stubs::CrashReporterBase> crash_reporter_server) {
crash_reporter_server_ = std::move(crash_reporter_server);
}
cobalt::Logger* Cobalt() { return &cobalt_; }
RedactorBase* Redactor() { return &redactor_; }
fuchsia::feedback::CrashReporter* CrashReporter() { return crash_reporter_server_.get(); }
stubs::RebootMethodsWatcherRegisterBase* RebootWatcherRegisterServer() {
return reboot_watcher_register_server_.get();
}
private:
timekeeper::AsyncTestClock clock_;
cobalt::Logger cobalt_;
IdentityRedactor redactor_{inspect::BoolProperty()};
std::unique_ptr<stubs::RebootMethodsWatcherRegisterBase> reboot_watcher_register_server_;
std::unique_ptr<stubs::CrashReporterBase> crash_reporter_server_;
};
TEST_F(LastRebootTest, FirstInstance) {
const zx::duration oom_crash_reporting_delay = zx::sec(90);
const RebootLog reboot_log(RebootReason::kOOM, "reboot log", zx::sec(1), std::nullopt);
SetUpCrashReporterServer(
std::make_unique<stubs::CrashReporter>(stubs::CrashReporter::Expectations{
.crash_signature = ToCrashSignature(reboot_log.RebootReason()),
.reboot_log = reboot_log.RebootLogStr(),
.uptime = reboot_log.Uptime(),
.is_fatal = IsFatal(reboot_log.RebootReason()),
}));
LastReboot last_reboot(dispatcher(), services(), Cobalt(), Redactor(), CrashReporter(),
LastReboot::Options{
.is_first_instance = true,
.reboot_log = reboot_log,
.graceful_reboot_reason_write_path = "n/a",
.oom_crash_reporting_delay = oom_crash_reporting_delay,
});
RunLoopFor(oom_crash_reporting_delay);
EXPECT_TRUE(RebootWatcherRegisterServer()->IsBound());
EXPECT_THAT(
ReceivedCobaltEvents(),
UnorderedElementsAreArray({
cobalt::Event(cobalt::LastRebootReason::kSystemOutOfMemory, zx::sec(1).to_usecs()),
}));
}
TEST_F(LastRebootTest, IsNotFirstInstance) {
const zx::duration oom_crash_reporting_delay = zx::sec(90);
const RebootLog reboot_log(RebootReason::kOOM, "reboot log", zx::sec(1), std::nullopt);
SetUpCrashReporterServer(std::make_unique<stubs::CrashReporterNoFileExpected>());
LastReboot last_reboot(dispatcher(), services(), Cobalt(), Redactor(), CrashReporter(),
LastReboot::Options{
.is_first_instance = false,
.reboot_log = reboot_log,
.graceful_reboot_reason_write_path = "n/a",
.oom_crash_reporting_delay = oom_crash_reporting_delay,
});
RunLoopFor(oom_crash_reporting_delay);
EXPECT_TRUE(RebootWatcherRegisterServer()->IsBound());
EXPECT_THAT(ReceivedCobaltEvents(), IsEmpty());
}
TEST_F(LastRebootTest, ReportsOnReboot) {
const zx::duration oom_crash_reporting_delay = zx::sec(90);
const RebootLog reboot_log(RebootReason::kOOM, "reboot log", zx::sec(1), std::nullopt);
LastReboot last_reboot(dispatcher(), services(), Cobalt(), Redactor(), CrashReporter(),
LastReboot::Options{
.is_first_instance = false,
.reboot_log = reboot_log,
.graceful_reboot_reason_write_path = "n/a",
.oom_crash_reporting_delay = oom_crash_reporting_delay,
});
bool error_handler_called = false;
::fidl::InterfaceRequestHandler<fuchsia::feedback::LastRebootInfoProvider> handler(
[&](::fidl::InterfaceRequest<fuchsia::feedback::LastRebootInfoProvider> request) {
last_reboot.Handle(std::move(request), [&](zx_status_t) { error_handler_called = true; });
});
AddHandler(std::move(handler));
fuchsia::feedback::LastRebootInfoProviderPtr last_reboot_info_ptr;
services()->Connect(last_reboot_info_ptr.NewRequest(dispatcher()));
bool called = false;
last_reboot_info_ptr->Get([&](::fuchsia::feedback::LastReboot) { called = true; });
RunLoopUntilIdle();
EXPECT_TRUE(called);
last_reboot_info_ptr.Unbind();
RunLoopUntilIdle();
EXPECT_TRUE(error_handler_called);
}
} // namespace
} // namespace forensics::feedback