chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc

// Copyright 2018 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/heap_profiling/in_process/heap_profiler_controller.h"

#include <atomic>
#include <iomanip>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/allocator/dispatcher/notification_data.h"
#include "base/allocator/dispatcher/subsystem.h"
#include "base/auto_reset.h"
#include "base/barrier_closure.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/enum_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/metrics_hashes.h"
#include "base/notreached.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/profiler/process_type.h"
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/multiprocess_test.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/heap_profiling/in_process/browser_process_snapshot_controller.h"
#include "components/heap_profiling/in_process/child_process_snapshot_controller.h"
#include "components/heap_profiling/in_process/heap_profiler_parameters.h"
#include "components/heap_profiling/in_process/mojom/snapshot_controller.mojom.h"
#include "components/heap_profiling/in_process/mojom/test_connector.mojom.h"
#include "components/heap_profiling/in_process/switches.h"
#include "components/metrics/call_stacks/call_stack_profile_builder.h"
#include "components/metrics/public/mojom/call_stack_profile_collector.mojom.h"
#include "components/version_info/channel.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
#include "third_party/metrics_proto/call_stack_profile.pb.h"
#include "third_party/metrics_proto/execution_context.pb.h"
#include "third_party/metrics_proto/sampled_profile.pb.h"

namespace metrics {

// Test printer for SampledProfile. This needs to be in the metrics namespace so
// GTest can find it.
void PrintTo(const SampledProfile& profile, std::ostream* os) {}

}  // namespace metrics

namespace heap_profiling {

namespace {

#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
#define ENABLE_MULTIPROCESS_TESTS
#else
#define ENABLE_MULTIPROCESS_TESTS
#endif

FeatureRef;
FeatureRefAndParams;
ProcessType;
using ProcessTypeSet =
    base::EnumSet<ProcessType, ProcessType::kUnknown, ProcessType::kMax>;
ProfileCollectorCallback;
AllocationNotificationData;
AllocationSubsystem;
FreeNotificationData;
ScopedMuteHookedSamplesForTesting;
ScopedSuppressRandomnessForTesting;

_;
AllOf;
Conditional;
ElementsAre;
Ge;
IsEmpty;
Lt;
Optional;
Property;
ResultOf;
UnorderedElementsAreArray;

constexpr size_t kSamplingRate =;
constexpr size_t kAllocationSize =;

// A fake CallStackProfileCollector that deserializes profiles it receives from
// a fake child process, and passes them to the same callback that receives
// profiles from the fake browser process.
class TestCallStackProfileCollector final
    : public metrics::mojom::CallStackProfileCollector {};

// A scoped holder for callbacks to pass to
// HeapProfilerControllerTest::StartHeapProfiling(), and a BarrierClosure that
// will quit a run loop. The ScopedCallbacks object must stay in scope until the
// run loop finishes.
class ScopedCallbacks {};

class ProfilerSetUpMixin {};

#if ENABLE_MULTIPROCESS_TESTS

constexpr char kTestChildTypeSwitch[] =;
constexpr char kTestNumAllocationsSwitch[] =;

// Runs the heap profiler in a multiprocess test child. This is used instead of
// HeapProfilerControllerTest::CreateHeapProfiler() in tests that create real
// child processes. (Most tests run only in the test main process and pretend
// that it's the Chrome browser process or a Chrome child process.)
class MultiprocessTestChild final : public mojom::TestConnector,
                                    public ProfilerSetUpMixin {};

// Manages a set of multiprocess test children and mojo connections to them.
// Created in test cases in the parent process.
class MultiprocessTestParent {};

#endif  // ENABLE_MULTIPROCESS_TESTS

class MockSnapshotController : public mojom::SnapshotController {};

// Configurations of the HeapProfiler* features to test.
// The default parameters collect samples from stable and nonstable channels in
// the browser process only.
struct FeatureTestParams {};

// Converts the test params to field trial parameters for the
// HeapProfilerReporting feature.
base::FieldTrialParams FeatureTestParams::ToFieldTrialParams() const {}

std::vector<FeatureRefAndParams> FeatureTestParams::GetEnabledFeatures() const {}

std::vector<FeatureRef> FeatureTestParams::GetDisabledFeatures() const {}

// Formats the test params for error messages.
std::ostream& operator<<(std::ostream& os, const FeatureTestParams& params) {}

class HeapProfilerControllerTest
    : public ::testing::TestWithParam<FeatureTestParams>,
      public ProfilerSetUpMixin {};

// Basic tests only use the default feature params.
INSTANTIATE_TEST_SUITE_P();

// Sampling profiler is not capable of unwinding stack on Android under tests.
#if !BUILDFLAG(IS_ANDROID)
TEST_P(HeapProfilerControllerTest, ProfileCollectionsScheduler) {}
#endif

TEST_P(HeapProfilerControllerTest, UnhandledProcess) {}

TEST_P(HeapProfilerControllerTest, EmptyProfile) {}

// Test the feature on various channels in the browser process.
constexpr FeatureTestParams kChannelConfigs[] =;

HeapProfilerControllerChannelTest;

INSTANTIATE_TEST_SUITE_P();

TEST_P(HeapProfilerControllerChannelTest, StableChannel) {}

TEST_P(HeapProfilerControllerChannelTest, CanaryChannel) {}

TEST_P(HeapProfilerControllerChannelTest, UnknownChannel) {}

// Test the feature in various processes on the stable channel.
constexpr FeatureTestParams kProcessConfigs[] =;

HeapProfilerControllerProcessTest;

INSTANTIATE_TEST_SUITE_P();

TEST_P(HeapProfilerControllerProcessTest, BrowserProcess) {}

TEST_P(HeapProfilerControllerProcessTest, ChildProcess) {}

#if ENABLE_MULTIPROCESS_TESTS

// Returns a lambda that can be called from a GMock matcher. It will return the
// value of a MetadataItem named `name` in a given CallStackProfile, or nullopt
// if there's no metadata with that name.
auto GetProfileMetadataFunc(std::string_view name) {}

// End-to-end test of the HeapProfilerCentralControl feature with multiple child
// processes.
constexpr FeatureTestParams kMultipleChildConfigs[] =;

HeapProfilerControllerMultipleChildTest;

INSTANTIATE_TEST_SUITE_P();

MULTIPROCESS_TEST_MAIN(HeapProfilerControllerChildMain) {}

TEST_P(HeapProfilerControllerMultipleChildTest, EndToEnd) {}

#endif  // ENABLE_MULTIPROCESS_TESTS

}  // namespace

}  // namespace heap_profiling