// Copyright 2015 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 "base/trace_event/memory_dump_manager.h"

#include "base/bind_helpers.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using testing::_;
using testing::Between;
using testing::Invoke;
using testing::Return;

namespace base {
namespace trace_event {

// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
// instead of performing IPC dances.
class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
 public:
  void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
                               const MemoryDumpCallback& callback) override {
    CreateProcessDump(args, callback);
  }

  bool IsCoordinatorProcess() const override { return false; }
};

class MemoryDumpManagerTest : public testing::Test {
 public:
  void SetUp() override {
    message_loop_.reset(new MessageLoop());
    mdm_.reset(new MemoryDumpManager());
    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
    ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
    MemoryDumpManager::GetInstance()->Initialize();
    MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
  }

  void TearDown() override {
    MemoryDumpManager::SetInstanceForTesting(nullptr);
    mdm_.reset();
    message_loop_.reset();
    TraceLog::DeleteForTesting();
  }

  void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
                           Closure closure,
                           uint64 dump_guid,
                           bool success) {
    task_runner->PostTask(FROM_HERE, closure);
  }

 protected:
  const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;

  void EnableTracing(const char* category) {
    TraceLog::GetInstance()->SetEnabled(
        TraceConfig(category, ""), TraceLog::RECORDING_MODE);
  }

  void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }

  scoped_ptr<MemoryDumpManager> mdm_;

 private:
  scoped_ptr<MessageLoop> message_loop_;
  MemoryDumpManagerDelegateForTesting delegate_;

  // We want our singleton torn down after each test.
  ShadowingAtExitManager at_exit_manager_;
};

class MockDumpProvider : public MemoryDumpProvider {
 public:
  MockDumpProvider()
      : dump_provider_to_register_or_unregister(nullptr),
        last_session_state_(nullptr) {}

  // Ctor used by the RespectTaskRunnerAffinity test.
  explicit MockDumpProvider(
      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
      : last_session_state_(nullptr), task_runner_(task_runner) {}

  virtual ~MockDumpProvider() {}

  MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));

  // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
  bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
    EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
    return true;
  }

  // OnMemoryDump() override for the SharedSessionState test.
  bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
    MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
    if (last_session_state_)
      EXPECT_EQ(last_session_state_, cur_session_state);
    last_session_state_ = cur_session_state;
    return true;
  }

  // OnMemoryDump() override for the RegisterDumperWhileDumping test.
  bool OnMemoryDump_RegisterExtraDumpProvider(ProcessMemoryDump* pmd) {
    MemoryDumpManager::GetInstance()->RegisterDumpProvider(
        dump_provider_to_register_or_unregister);
    return true;
  }

  // OnMemoryDump() override for the UnegisterDumperWhileDumping test.
  bool OnMemoryDump_UnregisterDumpProvider(ProcessMemoryDump* pmd) {
    MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
        dump_provider_to_register_or_unregister);
    return true;
  }

  // Used by OnMemoryDump_(Un)RegisterExtraDumpProvider.
  MemoryDumpProvider* dump_provider_to_register_or_unregister;

 private:
  MemoryDumpSessionState* last_session_state_;
  scoped_refptr<SingleThreadTaskRunner> task_runner_;
};

TEST_F(MemoryDumpManagerTest, SingleDumper) {
  MockDumpProvider mdp;
  mdm_->RegisterDumpProvider(&mdp);

  // Check that the dumper is not called if the memory category is not enabled.
  EnableTracing("foo-and-bar-but-not-memory");
  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  DisableTracing();

  // Now repeat enabling the memory category and check that the dumper is
  // invoked this time.
  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
  for (int i = 0; i < 3; ++i)
    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  DisableTracing();

  mdm_->UnregisterDumpProvider(&mdp);

  // Finally check the unregister logic (no calls to the mdp after unregister).
  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  TraceLog::GetInstance()->SetDisabled();
}

TEST_F(MemoryDumpManagerTest, SharedSessionState) {
  MockDumpProvider mdp1;
  MockDumpProvider mdp2;
  mdm_->RegisterDumpProvider(&mdp1);
  mdm_->RegisterDumpProvider(&mdp2);

  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp1, OnMemoryDump(_))
      .Times(2)
      .WillRepeatedly(
          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
  EXPECT_CALL(mdp2, OnMemoryDump(_))
      .Times(2)
      .WillRepeatedly(
          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));

  for (int i = 0; i < 2; ++i)
    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);

  DisableTracing();
}

TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
  MockDumpProvider mdp1;
  MockDumpProvider mdp2;

  // Enable only mdp1.
  mdm_->RegisterDumpProvider(&mdp1);
  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  DisableTracing();

  // Invert: enable mdp1 and disable mdp2.
  mdm_->UnregisterDumpProvider(&mdp1);
  mdm_->RegisterDumpProvider(&mdp2);
  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  DisableTracing();

  // Enable both mdp1 and mdp2.
  mdm_->RegisterDumpProvider(&mdp1);
  EnableTracing(kTraceCategory);
  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  DisableTracing();
}

// Checks that the MemoryDumpManager respects the thread affinity when a
// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
// threads and registering a MemoryDumpProvider on each of them. At each
// iteration, one thread is removed, to check the live unregistration logic.
TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
  const uint32 kNumInitialThreads = 8;

  ScopedVector<Thread> threads;
  ScopedVector<MockDumpProvider> mdps;

  // Create the threads and setup the expectations. Given that at each iteration
  // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
  // invoked a number of times equal to its index.
  for (uint32 i = kNumInitialThreads; i > 0; --i) {
    threads.push_back(new Thread("test thread"));
    threads.back()->Start();
    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
    MockDumpProvider* mdp = mdps.back();
    mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
    EXPECT_CALL(*mdp, OnMemoryDump(_))
        .Times(i)
        .WillRepeatedly(
            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
  }

  EnableTracing(kTraceCategory);

  while (!threads.empty()) {
    {
      RunLoop run_loop;
      MemoryDumpCallback callback =
          Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
               MessageLoop::current()->task_runner(), run_loop.QuitClosure());
      mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
      // This nested message loop (|run_loop|) will be quit if and only if
      // the RequestGlobalDump callback is invoked.
      run_loop.Run();
    }

    // Unregister a MDP and destroy one thread at each iteration to check the
    // live unregistration logic. The unregistration needs to happen on the same
    // thread the MDP belongs to.
    {
      RunLoop run_loop;
      Closure unregistration =
          Bind(&MemoryDumpManager::UnregisterDumpProvider,
               Unretained(mdm_.get()), Unretained(mdps.back()));
      threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
                                                      run_loop.QuitClosure());
      run_loop.Run();
    }
    mdps.pop_back();
    threads.back()->Stop();
    threads.pop_back();
  }

  DisableTracing();
}

// Enable both dump providers, make sure that mdp gets disabled after 3 failures
// and not disabled after 1.
TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
  MockDumpProvider mdp1;
  MockDumpProvider mdp2;

  mdm_->RegisterDumpProvider(&mdp1);
  mdm_->RegisterDumpProvider(&mdp2);
  EnableTracing(kTraceCategory);

  EXPECT_CALL(mdp1, OnMemoryDump(_))
      .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount)
      .WillRepeatedly(Return(false));

  EXPECT_CALL(mdp2, OnMemoryDump(_))
      .Times(1 + MemoryDumpManager::kMaxConsecutiveFailuresCount)
      .WillOnce(Return(false))
      .WillRepeatedly(Return(true));
  for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount;
       i++) {
    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  }

  DisableTracing();
}

// Sneakily register an extra memory dump provider while an existing one is
// dumping and expect it to take part in the already active tracing session.
TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
  MockDumpProvider mdp1;
  MockDumpProvider mdp2;

  mdp1.dump_provider_to_register_or_unregister = &mdp2;
  mdm_->RegisterDumpProvider(&mdp1);
  EnableTracing(kTraceCategory);

  EXPECT_CALL(mdp1, OnMemoryDump(_))
      .Times(4)
      .WillOnce(Return(true))
      .WillOnce(Invoke(
          &mdp1, &MockDumpProvider::OnMemoryDump_RegisterExtraDumpProvider))
      .WillRepeatedly(Return(true));

  // Depending on the insertion order (before or after mdp1), mdp2 might be
  // called also immediately after it gets registered.
  EXPECT_CALL(mdp2, OnMemoryDump(_))
      .Times(Between(2, 3))
      .WillRepeatedly(Return(true));

  for (int i = 0; i < 4; i++) {
    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  }

  DisableTracing();
}

// Like the above, but suddenly unregister the dump provider.
TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
  MockDumpProvider mdp1;
  MockDumpProvider mdp2;

  mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
  mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
  mdp1.dump_provider_to_register_or_unregister = &mdp2;
  EnableTracing(kTraceCategory);

  EXPECT_CALL(mdp1, OnMemoryDump(_))
      .Times(4)
      .WillOnce(Return(true))
      .WillOnce(Invoke(&mdp1,
                       &MockDumpProvider::OnMemoryDump_UnregisterDumpProvider))
      .WillRepeatedly(Return(true));

  // Depending on the insertion order (before or after mdp1), mdp2 might have
  // been already called when OnMemoryDump_UnregisterDumpProvider happens.
  EXPECT_CALL(mdp2, OnMemoryDump(_))
      .Times(Between(1, 2))
      .WillRepeatedly(Return(true));

  for (int i = 0; i < 4; i++) {
    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
  }

  DisableTracing();
}

}  // namespace trace_event
}  // namespace base
