Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / base / trace_event / memory_dump_manager_unittest.cc
blob4d0372fd3243286fca9fbca439a89108970be143
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/trace_event/memory_dump_manager.h"
7 #include "base/bind_helpers.h"
8 #include "base/memory/scoped_vector.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/test/test_io_thread.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread.h"
14 #include "base/trace_event/memory_dump_provider.h"
15 #include "base/trace_event/process_memory_dump.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using testing::_;
20 using testing::AtMost;
21 using testing::Between;
22 using testing::Invoke;
23 using testing::Return;
25 namespace base {
26 namespace trace_event {
27 namespace {
28 MemoryDumpArgs high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH};
29 MemoryDumpArgs low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW};
32 // Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
33 // instead of performing IPC dances.
34 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
35 public:
36 void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
37 const MemoryDumpCallback& callback) override {
38 CreateProcessDump(args, callback);
41 bool IsCoordinatorProcess() const override { return false; }
42 uint64 GetTracingProcessId() const override {
43 return MemoryDumpManager::kInvalidTracingProcessId;
47 class MemoryDumpManagerTest : public testing::Test {
48 public:
49 void SetUp() override {
50 last_callback_success_ = false;
51 message_loop_.reset(new MessageLoop());
52 mdm_.reset(new MemoryDumpManager());
53 MemoryDumpManager::SetInstanceForTesting(mdm_.get());
54 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
55 MemoryDumpManager::GetInstance()->Initialize();
56 MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
59 void TearDown() override {
60 MemoryDumpManager::SetInstanceForTesting(nullptr);
61 mdm_.reset();
62 message_loop_.reset();
63 TraceLog::DeleteForTesting();
66 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
67 Closure closure,
68 uint64 dump_guid,
69 bool success) {
70 last_callback_success_ = success;
71 task_runner->PostTask(FROM_HERE, closure);
74 protected:
75 void EnableTracing(const char* category) {
76 TraceLog::GetInstance()->SetEnabled(
77 TraceConfig(category, ""), TraceLog::RECORDING_MODE);
80 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
82 scoped_ptr<MemoryDumpManager> mdm_;
83 bool last_callback_success_;
85 private:
86 scoped_ptr<MessageLoop> message_loop_;
87 MemoryDumpManagerDelegateForTesting delegate_;
89 // We want our singleton torn down after each test.
90 ShadowingAtExitManager at_exit_manager_;
93 class MockDumpProvider : public MemoryDumpProvider {
94 public:
95 MockDumpProvider()
96 : dump_provider_to_register_or_unregister(nullptr),
97 last_session_state_(nullptr),
98 level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {}
100 // Ctor used by the RespectTaskRunnerAffinity test.
101 explicit MockDumpProvider(
102 const scoped_refptr<SingleThreadTaskRunner>& task_runner)
103 : last_session_state_(nullptr),
104 task_runner_(task_runner),
105 level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {}
107 // Ctor used by CheckMemoryDumpArgs test.
108 explicit MockDumpProvider(const MemoryDumpArgs::LevelOfDetail level_of_detail)
109 : last_session_state_(nullptr), level_of_detail_(level_of_detail) {}
111 virtual ~MockDumpProvider() {}
113 MOCK_METHOD2(OnMemoryDump,
114 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
116 // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
117 bool OnMemoryDump_CheckTaskRunner(const MemoryDumpArgs& args,
118 ProcessMemoryDump* pmd) {
119 EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
120 return true;
123 // OnMemoryDump() override for the SharedSessionState test.
124 bool OnMemoryDump_CheckSessionState(const MemoryDumpArgs& args,
125 ProcessMemoryDump* pmd) {
126 MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
127 if (last_session_state_)
128 EXPECT_EQ(last_session_state_, cur_session_state);
129 last_session_state_ = cur_session_state;
130 return true;
133 // OnMemoryDump() override for the RegisterDumperWhileDumping test.
134 bool OnMemoryDump_RegisterExtraDumpProvider(const MemoryDumpArgs& args,
135 ProcessMemoryDump* pmd) {
136 MemoryDumpManager::GetInstance()->RegisterDumpProvider(
137 dump_provider_to_register_or_unregister);
138 return true;
141 // OnMemoryDump() override for the UnegisterDumperWhileDumping test.
142 bool OnMemoryDump_UnregisterDumpProvider(const MemoryDumpArgs& args,
143 ProcessMemoryDump* pmd) {
144 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
145 dump_provider_to_register_or_unregister);
146 return true;
149 // OnMemoryDump() override for the CheckMemoryDumpArgs test.
150 bool OnMemoryDump_CheckMemoryDumpArgs(const MemoryDumpArgs& args,
151 ProcessMemoryDump* pmd) {
152 EXPECT_EQ(level_of_detail_, args.level_of_detail);
153 return true;
156 // Used by OnMemoryDump_(Un)RegisterExtraDumpProvider.
157 MemoryDumpProvider* dump_provider_to_register_or_unregister;
159 private:
160 MemoryDumpSessionState* last_session_state_;
161 scoped_refptr<SingleThreadTaskRunner> task_runner_;
162 const MemoryDumpArgs::LevelOfDetail level_of_detail_;
165 TEST_F(MemoryDumpManagerTest, SingleDumper) {
166 MockDumpProvider mdp;
167 mdm_->RegisterDumpProvider(&mdp);
169 // Check that the dumper is not called if the memory category is not enabled.
170 EnableTracing("foo-and-bar-but-not-memory");
171 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
172 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
173 high_detail_args);
174 DisableTracing();
176 // Now repeat enabling the memory category and check that the dumper is
177 // invoked this time.
178 EnableTracing(MemoryDumpManager::kTraceCategory);
179 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
180 for (int i = 0; i < 3; ++i)
181 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
182 high_detail_args);
183 DisableTracing();
185 mdm_->UnregisterDumpProvider(&mdp);
187 // Finally check the unregister logic (no calls to the mdp after unregister).
188 EnableTracing(MemoryDumpManager::kTraceCategory);
189 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
190 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
191 high_detail_args);
192 TraceLog::GetInstance()->SetDisabled();
195 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
196 // Check that requesting dumps with high level of detail actually propagates
197 // to OnMemoryDump() call on dump providers.
198 MockDumpProvider mdp_high_detail(MemoryDumpArgs::LevelOfDetail::HIGH);
199 mdm_->RegisterDumpProvider(&mdp_high_detail);
201 EnableTracing(MemoryDumpManager::kTraceCategory);
202 EXPECT_CALL(mdp_high_detail, OnMemoryDump(_, _))
203 .Times(1)
204 .WillRepeatedly(
205 Invoke(&mdp_high_detail,
206 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
207 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
208 high_detail_args);
209 DisableTracing();
210 mdm_->UnregisterDumpProvider(&mdp_high_detail);
212 // Check that requesting dumps with low level of detail actually propagates to
213 // OnMemoryDump() call on dump providers.
214 MockDumpProvider mdp_low_detail(MemoryDumpArgs::LevelOfDetail::LOW);
215 mdm_->RegisterDumpProvider(&mdp_low_detail);
217 EnableTracing(MemoryDumpManager::kTraceCategory);
218 EXPECT_CALL(mdp_low_detail, OnMemoryDump(_, _))
219 .Times(1)
220 .WillRepeatedly(
221 Invoke(&mdp_low_detail,
222 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs));
223 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
224 low_detail_args);
225 DisableTracing();
226 mdm_->UnregisterDumpProvider(&mdp_low_detail);
229 TEST_F(MemoryDumpManagerTest, SharedSessionState) {
230 MockDumpProvider mdp1;
231 MockDumpProvider mdp2;
232 mdm_->RegisterDumpProvider(&mdp1);
233 mdm_->RegisterDumpProvider(&mdp2);
235 EnableTracing(MemoryDumpManager::kTraceCategory);
236 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
237 .Times(2)
238 .WillRepeatedly(
239 Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
240 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
241 .Times(2)
242 .WillRepeatedly(
243 Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
245 for (int i = 0; i < 2; ++i)
246 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
247 high_detail_args);
249 DisableTracing();
252 TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
253 MockDumpProvider mdp1;
254 MockDumpProvider mdp2;
256 // Enable only mdp1.
257 mdm_->RegisterDumpProvider(&mdp1);
258 EnableTracing(MemoryDumpManager::kTraceCategory);
259 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
260 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
261 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
262 high_detail_args);
263 DisableTracing();
265 // Invert: enable mdp1 and disable mdp2.
266 mdm_->UnregisterDumpProvider(&mdp1);
267 mdm_->RegisterDumpProvider(&mdp2);
268 EnableTracing(MemoryDumpManager::kTraceCategory);
269 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
270 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
271 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
272 high_detail_args);
273 DisableTracing();
275 // Enable both mdp1 and mdp2.
276 mdm_->RegisterDumpProvider(&mdp1);
277 EnableTracing(MemoryDumpManager::kTraceCategory);
278 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
279 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
280 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
281 high_detail_args);
282 DisableTracing();
285 // Verify that whether OnMemoryDump is called depends only on the current
286 // registration state and not on previous registrations and dumps.
287 TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
288 MockDumpProvider mdp;
290 mdm_->RegisterDumpProvider(&mdp);
293 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
294 EnableTracing(MemoryDumpManager::kTraceCategory);
295 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
296 high_detail_args);
297 DisableTracing();
300 mdm_->UnregisterDumpProvider(&mdp);
303 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
304 EnableTracing(MemoryDumpManager::kTraceCategory);
305 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
306 high_detail_args);
307 DisableTracing();
310 mdm_->RegisterDumpProvider(&mdp);
311 mdm_->UnregisterDumpProvider(&mdp);
314 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
315 EnableTracing(MemoryDumpManager::kTraceCategory);
316 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
317 high_detail_args);
318 DisableTracing();
321 mdm_->RegisterDumpProvider(&mdp);
322 mdm_->UnregisterDumpProvider(&mdp);
323 mdm_->RegisterDumpProvider(&mdp);
326 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
327 EnableTracing(MemoryDumpManager::kTraceCategory);
328 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
329 high_detail_args);
330 DisableTracing();
334 // Checks that the MemoryDumpManager respects the thread affinity when a
335 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8
336 // threads and registering a MemoryDumpProvider on each of them. At each
337 // iteration, one thread is removed, to check the live unregistration logic.
338 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
339 const uint32 kNumInitialThreads = 8;
341 ScopedVector<Thread> threads;
342 ScopedVector<MockDumpProvider> mdps;
344 // Create the threads and setup the expectations. Given that at each iteration
345 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
346 // invoked a number of times equal to its index.
347 for (uint32 i = kNumInitialThreads; i > 0; --i) {
348 threads.push_back(new Thread("test thread"));
349 threads.back()->Start();
350 mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
351 MockDumpProvider* mdp = mdps.back();
352 mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
353 EXPECT_CALL(*mdp, OnMemoryDump(_, _))
354 .Times(i)
355 .WillRepeatedly(
356 Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
359 EnableTracing(MemoryDumpManager::kTraceCategory);
361 while (!threads.empty()) {
362 last_callback_success_ = false;
364 RunLoop run_loop;
365 MemoryDumpCallback callback =
366 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
367 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
368 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
369 high_detail_args, callback);
370 // This nested message loop (|run_loop|) will be quit if and only if
371 // the RequestGlobalDump callback is invoked.
372 run_loop.Run();
374 EXPECT_TRUE(last_callback_success_);
376 // Unregister a MDP and destroy one thread at each iteration to check the
377 // live unregistration logic. The unregistration needs to happen on the same
378 // thread the MDP belongs to.
380 RunLoop run_loop;
381 Closure unregistration =
382 Bind(&MemoryDumpManager::UnregisterDumpProvider,
383 Unretained(mdm_.get()), Unretained(mdps.back()));
384 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
385 run_loop.QuitClosure());
386 run_loop.Run();
388 mdps.pop_back();
389 threads.back()->Stop();
390 threads.pop_back();
393 DisableTracing();
396 // Enable both dump providers, make sure that mdp gets disabled after 3 failures
397 // and not disabled after 1.
398 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
399 MockDumpProvider mdp1;
400 MockDumpProvider mdp2;
402 mdm_->RegisterDumpProvider(&mdp1);
403 mdm_->RegisterDumpProvider(&mdp2);
404 EnableTracing(MemoryDumpManager::kTraceCategory);
406 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
407 .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount)
408 .WillRepeatedly(Return(false));
410 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
411 .Times(1 + MemoryDumpManager::kMaxConsecutiveFailuresCount)
412 .WillOnce(Return(false))
413 .WillRepeatedly(Return(true));
414 for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount;
415 i++) {
416 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
417 high_detail_args);
420 DisableTracing();
423 // Sneakily register an extra memory dump provider while an existing one is
424 // dumping and expect it to take part in the already active tracing session.
425 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
426 MockDumpProvider mdp1;
427 MockDumpProvider mdp2;
429 mdp1.dump_provider_to_register_or_unregister = &mdp2;
430 mdm_->RegisterDumpProvider(&mdp1);
431 EnableTracing(MemoryDumpManager::kTraceCategory);
433 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
434 .Times(4)
435 .WillOnce(Return(true))
436 .WillOnce(Invoke(
437 &mdp1, &MockDumpProvider::OnMemoryDump_RegisterExtraDumpProvider))
438 .WillRepeatedly(Return(true));
440 // Depending on the insertion order (before or after mdp1), mdp2 might be
441 // called also immediately after it gets registered.
442 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
443 .Times(Between(2, 3))
444 .WillRepeatedly(Return(true));
446 for (int i = 0; i < 4; i++) {
447 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
448 high_detail_args);
451 DisableTracing();
454 // Like the above, but suddenly unregister the dump provider.
455 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
456 MockDumpProvider mdp1;
457 MockDumpProvider mdp2;
459 mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
460 mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
461 mdp1.dump_provider_to_register_or_unregister = &mdp2;
462 EnableTracing(MemoryDumpManager::kTraceCategory);
464 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
465 .Times(4)
466 .WillOnce(Return(true))
467 .WillOnce(
468 Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_UnregisterDumpProvider))
469 .WillRepeatedly(Return(true));
471 // Depending on the insertion order (before or after mdp1), mdp2 might have
472 // been already called when OnMemoryDump_UnregisterDumpProvider happens.
473 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
474 .Times(Between(1, 2))
475 .WillRepeatedly(Return(true));
477 for (int i = 0; i < 4; i++) {
478 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
479 high_detail_args);
482 DisableTracing();
485 // Verify that the dump does not abort when unregistering a provider while
486 // dumping from a different thread than the dumping thread.
487 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
488 ScopedVector<TestIOThread> threads;
489 ScopedVector<MockDumpProvider> mdps;
491 for (int i = 0; i < 2; i++) {
492 threads.push_back(new TestIOThread(TestIOThread::kAutoStart));
493 mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
494 mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner());
497 int on_memory_dump_call_count = 0;
498 RunLoop run_loop;
500 // When OnMemoryDump is called on either of the dump providers, it will
501 // unregister the other one.
502 for (MockDumpProvider* mdp : mdps) {
503 int other_idx = (mdps.front() == mdp);
504 TestIOThread* other_thread = threads[other_idx];
505 MockDumpProvider* other_mdp = mdps[other_idx];
506 auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
507 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
508 other_thread->PostTaskAndWait(
509 FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
510 base::Unretained(&*mdm_), other_mdp));
511 on_memory_dump_call_count++;
512 return true;
515 // OnMemoryDump is called once for the provider that dumps first, and zero
516 // times for the other provider.
517 EXPECT_CALL(*mdp, OnMemoryDump(_, _))
518 .Times(AtMost(1))
519 .WillOnce(Invoke(on_dump));
522 last_callback_success_ = false;
523 MemoryDumpCallback callback =
524 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
525 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
527 EnableTracing(MemoryDumpManager::kTraceCategory);
528 MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED,
529 high_detail_args};
530 mdm_->CreateProcessDump(request_args, callback);
532 run_loop.Run();
534 ASSERT_EQ(1, on_memory_dump_call_count);
535 ASSERT_EQ(true, last_callback_success_);
537 DisableTracing();
540 // Ensures that a NACK callback is invoked if RequestGlobalDump is called when
541 // tracing is not enabled.
542 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
543 MockDumpProvider mdp1;
545 mdm_->RegisterDumpProvider(&mdp1);
546 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
548 last_callback_success_ = true;
550 RunLoop run_loop;
551 MemoryDumpCallback callback =
552 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
553 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
554 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
555 high_detail_args, callback);
556 run_loop.Run();
558 EXPECT_FALSE(last_callback_success_);
561 } // namespace trace_event
562 } // namespace base