chromium/components/allocation_recorder/testing/crash_verification.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/allocation_recorder/testing/crash_verification.h"

#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <set>
#include <vector>

#include "base/debug/debugging_buildflags.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/ranges/algorithm.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/allocation_recorder/internal/internal.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/crashpad/crashpad/client/crash_report_database.h"
#include "third_party/crashpad/crashpad/snapshot/minidump/minidump_stream.h"
#include "third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h"
#include "third_party/crashpad/crashpad/util/misc/uuid.h"

#if BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)
#include "components/allocation_recorder/crash_handler/memory_operation_report.pb.h"
#endif

AssertionFailure;
AssertionResult;
AssertionSuccess;

namespace crashpad {
void PrintTo(const CrashReportDatabase::OperationStatus status,
             std::ostream* os) {}
}  // namespace crashpad

namespace {

class CrashpadIntegration {};

void CrashpadIntegration::SetUp(const base::FilePath& crashpad_database_path) {}

void CrashpadIntegration::ShutDown() {}

void CrashpadIntegration::CrashDatabaseHasReport() {}

void CrashpadIntegration::ReportHasProcessSnapshot() {}

std::vector<const crashpad::MinidumpStream*>
CrashpadIntegration::GetAllocationRecorderStreams() {}

void CrashpadIntegration::TryReadCreatedReport() {}

void CrashpadIntegration::CheckHasNoAllocationRecorderStream() {}

#if BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)
void CrashpadIntegration::GetAllocationRecorderStream(
    const crashpad::MinidumpStream*& allocation_recorder_stream) {
  const auto allocation_recorder_streams = GetAllocationRecorderStreams();

  ASSERT_EQ(std::size(allocation_recorder_streams), 1ul)
      << "Didn't find expected number of allocation recorder streams.";
  ASSERT_NE(allocation_recorder_streams.front(), nullptr)
      << "The only allocation recorder stream is nullptr.";

  allocation_recorder_stream = allocation_recorder_streams.front();
}

void CrashpadIntegration::GetPayload(allocation_recorder::Payload& payload) {
  ASSERT_NO_FATAL_FAILURE(CrashDatabaseHasReport());
  ASSERT_NO_FATAL_FAILURE(ReportHasProcessSnapshot());

  const crashpad::MinidumpStream* allocation_recorder_stream;
  ASSERT_NO_FATAL_FAILURE(
      GetAllocationRecorderStream(allocation_recorder_stream));
  const std::vector<uint8_t>& data = allocation_recorder_stream->data();

  ASSERT_TRUE(payload.ParseFromArray(std::data(data), std::size(data)))
      << "Failed to parse recorder information "
         "from recorder stream.";
}
#endif
}  // namespace

namespace allocation_recorder::testing {

void VerifyCrashCreatesCrashpadReportWithoutAllocationRecorderStream(
    const base::FilePath& crashpad_database_path,
    base::OnceClosure crash_function) {}

#if BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)
void VerifyCrashCreatesCrashpadReportWithAllocationRecorderStream(
    const base::FilePath& crashpad_database_path,
    base::OnceClosure crash_function,
    base::OnceCallback<void(const allocation_recorder::Payload& payload)>
        payload_verification) {
  ASSERT_TRUE(crash_function);

  CrashpadIntegration crashpad_integration;

  ASSERT_NO_FATAL_FAILURE(crashpad_integration.SetUp(crashpad_database_path));

  ASSERT_NO_FATAL_FAILURE(std::move(crash_function).Run());

  allocation_recorder::Payload payload;
  ASSERT_NO_FATAL_FAILURE(crashpad_integration.GetPayload(payload));

  if (payload_verification) {
    ASSERT_NO_FATAL_FAILURE(std::move(payload_verification).Run(payload));
  }

  ASSERT_NO_FATAL_FAILURE(crashpad_integration.ShutDown());
}

void VerifyPayload(const bool expect_report_with_content,
                   const allocation_recorder::Payload& payload) {
  ASSERT_TRUE(payload.has_operation_report());
  const auto& operation_report = payload.operation_report();

  ASSERT_TRUE(operation_report.has_statistics());
  const auto& statistics = operation_report.statistics();

  if (expect_report_with_content) {
    EXPECT_GT(operation_report.memory_operations_size(), 0);
    EXPECT_GT(statistics.total_number_of_operations(), 0ul);
  } else {
    EXPECT_EQ(operation_report.memory_operations_size(), 0);
    EXPECT_EQ(statistics.total_number_of_operations(), 0ul);
  }

#if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
  EXPECT_TRUE(statistics.has_total_number_of_collisions());
#endif
}
#endif

}  // namespace allocation_recorder::testing