Use UintToString() for unsigned values.
[chromium-blink-merge.git] / base / trace_event / memory_dump_manager_unittest.cc
blobaf3287ddfdeb9146efbf9ef2b9ea21b3c53f86db
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/strings/stringprintf.h"
12 #include "base/test/test_io_thread.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/thread.h"
15 #include "base/trace_event/memory_dump_provider.h"
16 #include "base/trace_event/process_memory_dump.h"
17 #include "base/trace_event/trace_config_memory_test_util.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using testing::_;
22 using testing::AnyNumber;
23 using testing::AtMost;
24 using testing::Between;
25 using testing::Invoke;
26 using testing::Return;
28 namespace base {
29 namespace trace_event {
31 // GTest matchers for MemoryDumpRequestArgs arguments.
32 MATCHER(IsDetailedDump, "") {
33 return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
36 MATCHER(IsLightDump, "") {
37 return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
40 // Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
41 // requests locally to the MemoryDumpManager instead of performing IPC dances.
42 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
43 public:
44 MemoryDumpManagerDelegateForTesting() {
45 ON_CALL(*this, RequestGlobalMemoryDump(_, _))
46 .WillByDefault(Invoke(
47 this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
50 MOCK_METHOD2(RequestGlobalMemoryDump,
51 void(const MemoryDumpRequestArgs& args,
52 const MemoryDumpCallback& callback));
54 uint64 GetTracingProcessId() const override {
55 NOTREACHED();
56 return MemoryDumpManager::kInvalidTracingProcessId;
60 class MockMemoryDumpProvider : public MemoryDumpProvider {
61 public:
62 MOCK_METHOD2(OnMemoryDump,
63 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
66 class MemoryDumpManagerTest : public testing::Test {
67 public:
68 void SetUp() override {
69 last_callback_success_ = false;
70 message_loop_.reset(new MessageLoop());
71 mdm_.reset(new MemoryDumpManager());
72 MemoryDumpManager::SetInstanceForTesting(mdm_.get());
73 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
74 delegate_.reset(new MemoryDumpManagerDelegateForTesting);
77 void TearDown() override {
78 MemoryDumpManager::SetInstanceForTesting(nullptr);
79 mdm_.reset();
80 delegate_.reset();
81 message_loop_.reset();
82 TraceLog::DeleteForTesting();
85 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
86 Closure closure,
87 uint64 dump_guid,
88 bool success) {
89 last_callback_success_ = success;
90 task_runner->PostTask(FROM_HERE, closure);
93 protected:
94 void InitializeMemoryDumpManager(bool is_coordinator) {
95 mdm_->Initialize(delegate_.get(), is_coordinator);
98 void EnableTracingWithLegacyCategories(const char* category) {
99 TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
100 TraceLog::RECORDING_MODE);
103 void EnableTracingWithTraceConfig(const std::string& trace_config) {
104 TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
105 TraceLog::RECORDING_MODE);
108 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
110 bool IsPeriodicDumpingEnabled() const {
111 return mdm_->periodic_dump_timer_.IsRunning();
114 int GetMaxConsecutiveFailuresCount() const {
115 return MemoryDumpManager::kMaxConsecutiveFailuresCount;
118 scoped_ptr<MemoryDumpManager> mdm_;
119 scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
120 bool last_callback_success_;
122 private:
123 scoped_ptr<MessageLoop> message_loop_;
125 // We want our singleton torn down after each test.
126 ShadowingAtExitManager at_exit_manager_;
129 // Basic sanity checks. Registers a memory dump provider and checks that it is
130 // called, but only when memory-infra is enabled.
131 TEST_F(MemoryDumpManagerTest, SingleDumper) {
132 InitializeMemoryDumpManager(false /* is_coordinator */);
133 MockMemoryDumpProvider mdp;
134 mdm_->RegisterDumpProvider(&mdp);
136 // Check that the dumper is not called if the memory category is not enabled.
137 EnableTracingWithLegacyCategories("foobar-but-not-memory");
138 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
139 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
140 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
141 MemoryDumpLevelOfDetail::DETAILED);
142 DisableTracing();
144 // Now repeat enabling the memory category and check that the dumper is
145 // invoked this time.
146 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
147 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
148 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
149 for (int i = 0; i < 3; ++i)
150 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
151 MemoryDumpLevelOfDetail::DETAILED);
152 DisableTracing();
154 mdm_->UnregisterDumpProvider(&mdp);
156 // Finally check the unregister logic: the delegate will be invoked but not
157 // the dump provider, as it has been unregistered.
158 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
159 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
160 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
161 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
162 MemoryDumpLevelOfDetail::DETAILED);
163 TraceLog::GetInstance()->SetDisabled();
166 // Checks that requesting dumps with high level of detail actually propagates
167 // the level of the detail properly to OnMemoryDump() call on dump providers.
168 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
169 InitializeMemoryDumpManager(false /* is_coordinator */);
170 MockMemoryDumpProvider mdp;
172 mdm_->RegisterDumpProvider(&mdp);
173 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
174 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
175 EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
176 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
177 MemoryDumpLevelOfDetail::DETAILED);
178 DisableTracing();
179 mdm_->UnregisterDumpProvider(&mdp);
181 // Check that requesting dumps with low level of detail actually propagates to
182 // OnMemoryDump() call on dump providers.
183 mdm_->RegisterDumpProvider(&mdp);
184 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
185 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
186 EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
187 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
188 MemoryDumpLevelOfDetail::LIGHT);
189 DisableTracing();
190 mdm_->UnregisterDumpProvider(&mdp);
193 // Checks that the SharedSessionState object is acqually shared over time.
194 TEST_F(MemoryDumpManagerTest, SharedSessionState) {
195 InitializeMemoryDumpManager(false /* is_coordinator */);
196 MockMemoryDumpProvider mdp1;
197 MockMemoryDumpProvider mdp2;
198 mdm_->RegisterDumpProvider(&mdp1);
199 mdm_->RegisterDumpProvider(&mdp2);
201 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
202 const MemoryDumpSessionState* session_state = mdm_->session_state().get();
203 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
204 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
205 .Times(2)
206 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
207 ProcessMemoryDump* pmd) -> bool {
208 EXPECT_EQ(session_state, pmd->session_state().get());
209 return true;
210 }));
211 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
212 .Times(2)
213 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
214 ProcessMemoryDump* pmd) -> bool {
215 EXPECT_EQ(session_state, pmd->session_state().get());
216 return true;
217 }));
219 for (int i = 0; i < 2; ++i)
220 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
221 MemoryDumpLevelOfDetail::DETAILED);
223 DisableTracing();
226 // Checks that the (Un)RegisterDumpProvider logic behaves sanely.
227 TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
228 InitializeMemoryDumpManager(false /* is_coordinator */);
229 MockMemoryDumpProvider mdp1;
230 MockMemoryDumpProvider mdp2;
232 // Enable only mdp1.
233 mdm_->RegisterDumpProvider(&mdp1);
234 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
235 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
236 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
237 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
238 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
239 MemoryDumpLevelOfDetail::DETAILED);
240 DisableTracing();
242 // Invert: enable mdp1 and disable mdp2.
243 mdm_->UnregisterDumpProvider(&mdp1);
244 mdm_->RegisterDumpProvider(&mdp2);
245 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
246 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
247 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
248 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
249 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
250 MemoryDumpLevelOfDetail::DETAILED);
251 DisableTracing();
253 // Enable both mdp1 and mdp2.
254 mdm_->RegisterDumpProvider(&mdp1);
255 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
256 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
257 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
258 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
259 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
260 MemoryDumpLevelOfDetail::DETAILED);
261 DisableTracing();
264 // Checks that the dump provider invocations depend only on the current
265 // registration state and not on previous registrations and dumps.
266 TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
267 InitializeMemoryDumpManager(false /* is_coordinator */);
268 MockMemoryDumpProvider mdp;
270 mdm_->RegisterDumpProvider(&mdp);
273 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
274 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
275 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
276 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
277 MemoryDumpLevelOfDetail::DETAILED);
278 DisableTracing();
281 mdm_->UnregisterDumpProvider(&mdp);
284 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
285 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
286 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
287 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
288 MemoryDumpLevelOfDetail::DETAILED);
289 DisableTracing();
292 mdm_->RegisterDumpProvider(&mdp);
293 mdm_->UnregisterDumpProvider(&mdp);
296 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
297 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
298 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
299 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
300 MemoryDumpLevelOfDetail::DETAILED);
301 DisableTracing();
304 mdm_->RegisterDumpProvider(&mdp);
305 mdm_->UnregisterDumpProvider(&mdp);
306 mdm_->RegisterDumpProvider(&mdp);
309 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
310 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
311 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
312 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
313 MemoryDumpLevelOfDetail::DETAILED);
314 DisableTracing();
318 // Checks that the MemoryDumpManager respects the thread affinity when a
319 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8
320 // threads and registering a MemoryDumpProvider on each of them. At each
321 // iteration, one thread is removed, to check the live unregistration logic.
322 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
323 InitializeMemoryDumpManager(false /* is_coordinator */);
324 const uint32 kNumInitialThreads = 8;
326 ScopedVector<Thread> threads;
327 ScopedVector<MockMemoryDumpProvider> mdps;
329 // Create the threads and setup the expectations. Given that at each iteration
330 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
331 // invoked a number of times equal to its index.
332 for (uint32 i = kNumInitialThreads; i > 0; --i) {
333 Thread* thread = new Thread("test thread");
334 threads.push_back(thread);
335 threads.back()->Start();
336 scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
337 MockMemoryDumpProvider* mdp = new MockMemoryDumpProvider();
338 mdps.push_back(mdp);
339 mdm_->RegisterDumpProvider(mdp, task_runner);
340 EXPECT_CALL(*mdp, OnMemoryDump(_, _))
341 .Times(i)
342 .WillRepeatedly(Invoke(
343 [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
344 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
345 return true;
346 }));
349 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
351 while (!threads.empty()) {
352 last_callback_success_ = false;
354 RunLoop run_loop;
355 MemoryDumpCallback callback =
356 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
357 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
358 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
359 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
360 MemoryDumpLevelOfDetail::DETAILED, callback);
361 // This nested message loop (|run_loop|) will quit if and only if the
362 // |callback| passed to RequestGlobalDump() is invoked.
363 run_loop.Run();
365 EXPECT_TRUE(last_callback_success_);
367 // Unregister a MDP and destroy one thread at each iteration to check the
368 // live unregistration logic. The unregistration needs to happen on the same
369 // thread the MDP belongs to.
371 RunLoop run_loop;
372 Closure unregistration =
373 Bind(&MemoryDumpManager::UnregisterDumpProvider,
374 Unretained(mdm_.get()), Unretained(mdps.back()));
375 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
376 run_loop.QuitClosure());
377 run_loop.Run();
379 mdps.pop_back();
380 threads.back()->Stop();
381 threads.pop_back();
384 DisableTracing();
387 // Checks that providers get disabled after 3 consecutive failures, but not
388 // otherwise (e.g., if interleaved).
389 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
390 InitializeMemoryDumpManager(false /* is_coordinator */);
391 MockMemoryDumpProvider mdp1;
392 MockMemoryDumpProvider mdp2;
394 mdm_->RegisterDumpProvider(&mdp1);
395 mdm_->RegisterDumpProvider(&mdp2);
396 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
398 const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
399 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
401 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
402 .Times(GetMaxConsecutiveFailuresCount())
403 .WillRepeatedly(Return(false));
405 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
406 .WillOnce(Return(false))
407 .WillOnce(Return(true))
408 .WillOnce(Return(false))
409 .WillOnce(Return(false))
410 .WillOnce(Return(true))
411 .WillOnce(Return(false));
413 for (int i = 0; i < kNumDumps; i++) {
414 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
415 MemoryDumpLevelOfDetail::DETAILED);
418 DisableTracing();
421 // Sneakily registers an extra memory dump provider while an existing one is
422 // dumping and expect it to take part in the already active tracing session.
423 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
424 InitializeMemoryDumpManager(false /* is_coordinator */);
425 MockMemoryDumpProvider mdp1;
426 MockMemoryDumpProvider mdp2;
428 mdm_->RegisterDumpProvider(&mdp1);
429 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
431 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
433 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
434 .Times(4)
435 .WillOnce(Return(true))
436 .WillOnce(
437 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
438 MemoryDumpManager::GetInstance()->RegisterDumpProvider(&mdp2);
439 return true;
441 .WillRepeatedly(Return(true));
443 // Depending on the insertion order (before or after mdp1), mdp2 might be
444 // called also immediately after it gets registered.
445 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
446 .Times(Between(2, 3))
447 .WillRepeatedly(Return(true));
449 for (int i = 0; i < 4; i++) {
450 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
451 MemoryDumpLevelOfDetail::DETAILED);
454 DisableTracing();
457 // Like RegisterDumperWhileDumping, but unregister the dump provider instead.
458 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
459 InitializeMemoryDumpManager(false /* is_coordinator */);
460 MockMemoryDumpProvider mdp1;
461 MockMemoryDumpProvider mdp2;
463 mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
464 mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
465 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
467 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
469 EXPECT_CALL(mdp1, OnMemoryDump(_, _))
470 .Times(4)
471 .WillOnce(Return(true))
472 .WillOnce(
473 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
474 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
475 return true;
477 .WillRepeatedly(Return(true));
479 // Depending on the insertion order (before or after mdp1), mdp2 might have
480 // been already called when UnregisterDumpProvider happens.
481 EXPECT_CALL(mdp2, OnMemoryDump(_, _))
482 .Times(Between(1, 2))
483 .WillRepeatedly(Return(true));
485 for (int i = 0; i < 4; i++) {
486 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
487 MemoryDumpLevelOfDetail::DETAILED);
490 DisableTracing();
493 // Checks that the dump does not abort when unregistering a provider while
494 // dumping from a different thread than the dumping thread.
495 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
496 InitializeMemoryDumpManager(false /* is_coordinator */);
497 ScopedVector<TestIOThread> threads;
498 ScopedVector<MockMemoryDumpProvider> mdps;
500 for (int i = 0; i < 2; i++) {
501 threads.push_back(new TestIOThread(TestIOThread::kAutoStart));
502 mdps.push_back(new MockMemoryDumpProvider());
503 mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner());
506 int on_memory_dump_call_count = 0;
507 RunLoop run_loop;
509 // When OnMemoryDump is called on either of the dump providers, it will
510 // unregister the other one.
511 for (MockMemoryDumpProvider* mdp : mdps) {
512 int other_idx = (mdps.front() == mdp);
513 TestIOThread* other_thread = threads[other_idx];
514 MockMemoryDumpProvider* other_mdp = mdps[other_idx];
515 auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
516 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
517 other_thread->PostTaskAndWait(
518 FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
519 base::Unretained(&*mdm_), other_mdp));
520 on_memory_dump_call_count++;
521 return true;
524 // OnMemoryDump is called once for the provider that dumps first, and zero
525 // times for the other provider.
526 EXPECT_CALL(*mdp, OnMemoryDump(_, _))
527 .Times(AtMost(1))
528 .WillOnce(Invoke(on_dump));
531 last_callback_success_ = false;
532 MemoryDumpCallback callback =
533 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
534 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
536 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
538 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
539 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
540 MemoryDumpLevelOfDetail::DETAILED, callback);
542 run_loop.Run();
544 ASSERT_EQ(1, on_memory_dump_call_count);
545 ASSERT_EQ(true, last_callback_success_);
547 DisableTracing();
550 // Checks that a NACK callback is invoked if RequestGlobalDump() is called when
551 // tracing is not enabled.
552 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
553 InitializeMemoryDumpManager(false /* is_coordinator */);
554 MockMemoryDumpProvider mdp1;
555 mdm_->RegisterDumpProvider(&mdp1);
557 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
558 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
560 last_callback_success_ = true;
562 RunLoop run_loop;
563 MemoryDumpCallback callback =
564 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
565 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
566 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
567 MemoryDumpLevelOfDetail::DETAILED, callback);
568 run_loop.Run();
570 EXPECT_FALSE(last_callback_success_);
573 // Checks that is the MemoryDumpManager is initialized after tracing already
574 // began, it will still late-join the party (real use case: startup tracing).
575 TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
576 MockMemoryDumpProvider mdp;
577 mdm_->RegisterDumpProvider(&mdp);
578 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
580 // First check that a RequestGlobalDump() issued before the MemoryDumpManager
581 // initialization gets NACK-ed cleanly.
583 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
584 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
585 RunLoop run_loop;
586 MemoryDumpCallback callback =
587 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
588 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
589 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
590 MemoryDumpLevelOfDetail::DETAILED, callback);
591 run_loop.Run();
592 EXPECT_FALSE(last_callback_success_);
595 // Now late-initialize the MemoryDumpManager and check that the
596 // RequestGlobalDump completes successfully.
598 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
599 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
600 InitializeMemoryDumpManager(false /* is_coordinator */);
601 RunLoop run_loop;
602 MemoryDumpCallback callback =
603 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
604 MessageLoop::current()->task_runner(), run_loop.QuitClosure());
605 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
606 MemoryDumpLevelOfDetail::DETAILED, callback);
607 run_loop.Run();
608 EXPECT_TRUE(last_callback_success_);
610 DisableTracing();
613 // This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
614 // expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
615 // dumps in memory-infra, handling gracefully the transition between the legacy
616 // and the new-style (JSON-based) TraceConfig.
617 TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
618 InitializeMemoryDumpManager(false /* is_coordinator */);
619 MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
621 // Don't trigger the default behavior of the mock delegate in this test,
622 // which would short-circuit the dump request to the actual
623 // CreateProcessDump().
624 // We don't want to create any dump in this test, only check whether the dumps
625 // are requested or not.
626 ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
628 // Enabling memory-infra in a non-coordinator process should not trigger any
629 // periodic dumps.
630 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
631 EXPECT_FALSE(IsPeriodicDumpingEnabled());
632 DisableTracing();
634 // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
635 // process with a fully defined trigger config should NOT enable any periodic
636 // dumps.
637 EnableTracingWithTraceConfig(
638 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
639 EXPECT_FALSE(IsPeriodicDumpingEnabled());
640 DisableTracing();
643 TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
644 InitializeMemoryDumpManager(true /* is_coordinator */);
645 MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
646 ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
648 // Enabling memory-infra with the legacy TraceConfig (category filter) in
649 // a coordinator process should enable periodic dumps.
650 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
651 EXPECT_TRUE(IsPeriodicDumpingEnabled());
652 DisableTracing();
654 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
655 // process without specifying any "memory_dump_config" section should enable
656 // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
657 // is: ticking memory-infra should dump periodically with the default config.
658 EnableTracingWithTraceConfig(
659 TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
660 EXPECT_TRUE(IsPeriodicDumpingEnabled());
661 DisableTracing();
663 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
664 // process with an empty "memory_dump_config" should NOT enable periodic
665 // dumps. This is the way telemetry is supposed to use memory-infra with
666 // only explicitly triggered dumps.
667 EnableTracingWithTraceConfig(
668 TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
669 EXPECT_FALSE(IsPeriodicDumpingEnabled());
670 DisableTracing();
672 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
673 // process with a fully defined trigger config should cause periodic dumps to
674 // be performed in the correct order.
675 RunLoop run_loop;
676 auto quit_closure = run_loop.QuitClosure();
678 const int kHeavyDumpRate = 5;
679 const int kLightDumpPeriodMs = 1;
680 const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
681 // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
682 testing::InSequence sequence;
683 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
684 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
685 .Times(kHeavyDumpRate - 1);
686 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
687 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
688 .Times(kHeavyDumpRate - 2);
689 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
690 .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
691 const MemoryDumpCallback& callback) {
692 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
693 }));
695 // Swallow all the final spurious calls until tracing gets disabled.
696 EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
698 EnableTracingWithTraceConfig(
699 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
700 kLightDumpPeriodMs, kHeavyDumpPeriodMs));
701 run_loop.Run();
702 DisableTracing();
705 } // namespace trace_event
706 } // namespace base