blob: 521f8f205cfa7768812575e1d449ab209dca0660 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory_instrumentation {
class CoordinatorImplTest : public testing::Test {
public:
CoordinatorImplTest() {}
void SetUp() override {
dump_response_args_ = {0U, false};
coordinator_.reset(new CoordinatorImpl(false));
}
void TearDown() override { coordinator_.reset(); }
void RegisterProcessLocalDumpManager(
mojom::ProcessLocalDumpManagerPtr process_manager) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager,
base::Unretained(coordinator_.get()),
base::Passed(&process_manager)));
}
void RequestGlobalMemoryDump(base::trace_event::MemoryDumpRequestArgs args,
base::Closure closure) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&CoordinatorImpl::RequestGlobalMemoryDump,
base::Unretained(coordinator_.get()), args,
base::Bind(&CoordinatorImplTest::OnGlobalMemoryDumpResponse,
base::Unretained(this), closure)));
}
void OnGlobalMemoryDumpResponse(base::Closure closure,
uint64_t dump_guid,
bool success) {
dump_response_args_ = {dump_guid, success};
closure.Run();
}
protected:
struct DumpResponseArgs {
uint64_t dump_guid;
bool success;
};
DumpResponseArgs dump_response_args_;
private:
std::unique_ptr<CoordinatorImpl> coordinator_;
base::MessageLoop message_loop_;
};
class MockDumpManager : public mojom::ProcessLocalDumpManager {
public:
MockDumpManager(CoordinatorImplTest* test_coordinator, int expected_calls)
: binding_(this), expected_calls_(expected_calls) {
// Register to the coordinator.
mojom::ProcessLocalDumpManagerPtr process_manager;
binding_.Bind(mojo::MakeRequest(&process_manager));
test_coordinator->RegisterProcessLocalDumpManager(
std::move(process_manager));
}
~MockDumpManager() override { EXPECT_EQ(0, expected_calls_); }
void RequestProcessMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const RequestProcessMemoryDumpCallback& callback) override {
expected_calls_--;
base::trace_event::MemoryDumpCallbackResult result;
callback.Run(args.dump_guid, true, result);
}
private:
mojo::Binding<mojom::ProcessLocalDumpManager> binding_;
int expected_calls_;
};
TEST_F(CoordinatorImplTest, NoProcessLocalManagers) {
base::RunLoop run_loop;
base::trace_event::MemoryDumpRequestArgs args = {
1234, base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
RequestGlobalMemoryDump(args, run_loop.QuitClosure());
run_loop.Run();
EXPECT_EQ(1234U, dump_response_args_.dump_guid);
EXPECT_TRUE(dump_response_args_.success);
}
TEST_F(CoordinatorImplTest, SeveralProcessLocalManagers) {
base::RunLoop run_loop;
MockDumpManager dump_manager_1(this, 1);
MockDumpManager dump_manager_2(this, 1);
base::trace_event::MemoryDumpRequestArgs args = {
2345, base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
RequestGlobalMemoryDump(args, run_loop.QuitClosure());
run_loop.Run();
EXPECT_EQ(2345U, dump_response_args_.dump_guid);
EXPECT_TRUE(dump_response_args_.success);
}
TEST_F(CoordinatorImplTest, FaultyProcessLocalManager) {
base::RunLoop run_loop;
MockDumpManager dump_manager_1(this, 1);
std::unique_ptr<MockDumpManager> dump_manager_2(new MockDumpManager(this, 0));
base::trace_event::MemoryDumpRequestArgs args = {
3456, base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
RequestGlobalMemoryDump(args, run_loop.QuitClosure());
// One of the process-local managers dies after a global dump is requested and
// before it receives the corresponding process dump request. The coordinator
// should detect that one of its clients is disconnected and claim the global
// dump attempt has failed.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind([](std::unique_ptr<MockDumpManager> dm) {},
base::Passed(&dump_manager_2)));
run_loop.Run();
EXPECT_EQ(3456U, dump_response_args_.dump_guid);
EXPECT_FALSE(dump_response_args_.success);
}
} // namespace memory_instrumentation