diff options
Diffstat (limited to 'base/debug/activity_tracker_unittest.cc')
-rw-r--r-- | base/debug/activity_tracker_unittest.cc | 184 |
1 files changed, 173 insertions, 11 deletions
diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc index aced4fb36a..116c13d623 100644 --- a/base/debug/activity_tracker_unittest.cc +++ b/base/debug/activity_tracker_unittest.cc @@ -84,45 +84,73 @@ class ActivityTrackerTest : public testing::Test { return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); } + void HandleProcessExit(int64_t id, + int64_t stamp, + int code, + GlobalActivityTracker::ProcessPhase phase, + std::string&& command, + ActivityUserData::Snapshot&& data) { + exit_id = id; + exit_stamp = stamp; + exit_code = code; + exit_phase = phase; + exit_command = std::move(command); + exit_data = std::move(data); + } + static void DoNothing() {} + + int64_t exit_id = 0; + int64_t exit_stamp; + int exit_code; + GlobalActivityTracker::ProcessPhase exit_phase; + std::string exit_command; + ActivityUserData::Snapshot exit_data; }; TEST_F(ActivityTrackerTest, UserDataTest) { char buffer[256]; memset(buffer, 0, sizeof(buffer)); ActivityUserData data(buffer, sizeof(buffer)); - const size_t space = sizeof(buffer) - 8; + size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader); ASSERT_EQ(space, data.available_); data.SetInt("foo", 1); - ASSERT_EQ(space - 24, data.available_); + space -= 24; + ASSERT_EQ(space, data.available_); data.SetUint("b", 1U); // Small names fit beside header in a word. - ASSERT_EQ(space - 24 - 16, data.available_); + space -= 16; + ASSERT_EQ(space, data.available_); data.Set("c", buffer, 10); - ASSERT_EQ(space - 24 - 16 - 24, data.available_); + space -= 24; + ASSERT_EQ(space, data.available_); data.SetString("dear john", "it's been fun"); - ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); + space -= 32; + ASSERT_EQ(space, data.available_); data.Set("c", buffer, 20); - ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); + ASSERT_EQ(space, data.available_); data.SetString("dear john", "but we're done together"); - ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); + ASSERT_EQ(space, data.available_); data.SetString("dear john", "bye"); - ASSERT_EQ(space - 24 - 16 - 24 - 32, data.available_); + ASSERT_EQ(space, data.available_); data.SetChar("d", 'x'); - ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8, data.available_); + space -= 8; + ASSERT_EQ(space, data.available_); data.SetBool("ee", true); - ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16, data.available_); + space -= 16; + ASSERT_EQ(space, data.available_); data.SetString("f", ""); - ASSERT_EQ(space - 24 - 16 - 24 - 32 - 8 - 16 - 8, data.available_); + space -= 8; + ASSERT_EQ(space, data.available_); } TEST_F(ActivityTrackerTest, PushPopTest) { @@ -222,6 +250,28 @@ TEST_F(ActivityTrackerTest, ScopedTaskTest) { ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed()); } +TEST_F(ActivityTrackerTest, ExceptionTest) { + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker* global = GlobalActivityTracker::Get(); + + ThreadActivityTracker* tracker = + GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); + ThreadActivityTracker::Snapshot snapshot; + ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); + + ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); + ASSERT_EQ(0U, snapshot.last_exception.activity_type); + + char origin; + global->RecordException(&origin, 42); + + ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); + EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type); + EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin), + snapshot.last_exception.origin_address); + EXPECT_EQ(42U, snapshot.last_exception.data.exception.code); +} + TEST_F(ActivityTrackerTest, CreateWithFileTest) { const char temp_name[] = "CreateWithFileTest"; ScopedTempDir temp_dir; @@ -250,6 +300,16 @@ TEST_F(ActivityTrackerTest, CreateWithFileTest) { // GlobalActivityTracker tests below. +TEST_F(ActivityTrackerTest, BasicTest) { + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker* global = GlobalActivityTracker::Get(); + + // Ensure the data repositories have backing store, indicated by non-zero ID. + EXPECT_NE(0U, global->process_data().id()); + EXPECT_NE(0U, global->global_data().id()); + EXPECT_NE(global->process_data().id(), global->global_data().id()); +} + class SimpleActivityThread : public SimpleThread { public: SimpleActivityThread(const std::string& name, @@ -336,5 +396,107 @@ TEST_F(ActivityTrackerTest, ThreadDeathTest) { EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); } +TEST_F(ActivityTrackerTest, ProcessDeathTest) { + // This doesn't actually create and destroy a process. Instead, it uses for- + // testing interfaces to simulate data created by other processes. + const ProcessId other_process_id = GetCurrentProcId() + 1; + + GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); + GlobalActivityTracker* global = GlobalActivityTracker::Get(); + ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); + + // Get callbacks for process exit. + global->SetProcessExitCallback( + Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this))); + + // Pretend than another process has started. + global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar")); + + // Do some activities. + PendingTask task(FROM_HERE, base::Bind(&DoNothing)); + ScopedTaskRunActivity activity(task); + ActivityUserData& user_data = activity.user_data(); + ASSERT_NE(0U, user_data.id()); + + // Get the memory-allocator references to that data. + PersistentMemoryAllocator::Reference proc_data_ref = + global->allocator()->GetAsReference( + global->process_data().GetBaseAddress(), + GlobalActivityTracker::kTypeIdProcessDataRecord); + ASSERT_TRUE(proc_data_ref); + PersistentMemoryAllocator::Reference tracker_ref = + global->allocator()->GetAsReference( + thread->GetBaseAddress(), + GlobalActivityTracker::kTypeIdActivityTracker); + ASSERT_TRUE(tracker_ref); + PersistentMemoryAllocator::Reference user_data_ref = + global->allocator()->GetAsReference( + user_data.GetBaseAddress(), + GlobalActivityTracker::kTypeIdUserDataRecord); + ASSERT_TRUE(user_data_ref); + + // Make a copy of the thread-tracker state so it can be restored later. + const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); + std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); + memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); + + // Change the objects to appear to be owned by another process. + ProcessId owning_id; + int64_t stamp; + ASSERT_TRUE(ActivityUserData::GetOwningProcessId( + global->process_data().GetBaseAddress(), &owning_id, &stamp)); + EXPECT_NE(other_process_id, owning_id); + ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( + thread->GetBaseAddress(), &owning_id, &stamp)); + EXPECT_NE(other_process_id, owning_id); + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), + &owning_id, &stamp)); + EXPECT_NE(other_process_id, owning_id); + global->process_data().SetOwningProcessIdForTesting(other_process_id, stamp); + thread->SetOwningProcessIdForTesting(other_process_id, stamp); + user_data.SetOwningProcessIdForTesting(other_process_id, stamp); + ASSERT_TRUE(ActivityUserData::GetOwningProcessId( + global->process_data().GetBaseAddress(), &owning_id, &stamp)); + EXPECT_EQ(other_process_id, owning_id); + ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( + thread->GetBaseAddress(), &owning_id, &stamp)); + EXPECT_EQ(other_process_id, owning_id); + ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), + &owning_id, &stamp)); + EXPECT_EQ(other_process_id, owning_id); + + // Check that process exit will perform callback and free the allocations. + ASSERT_EQ(0, exit_id); + ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, + global->allocator()->GetType(proc_data_ref)); + ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, + global->allocator()->GetType(tracker_ref)); + ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, + global->allocator()->GetType(user_data_ref)); + global->RecordProcessExit(other_process_id, 0); + EXPECT_EQ(other_process_id, exit_id); + EXPECT_EQ("foo --bar", exit_command); + EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, + global->allocator()->GetType(proc_data_ref)); + EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, + global->allocator()->GetType(tracker_ref)); + EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, + global->allocator()->GetType(user_data_ref)); + + // Restore memory contents and types so things don't crash when doing real + // process clean-up. + memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), + tracker_size); + global->allocator()->ChangeType( + proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, + GlobalActivityTracker::kTypeIdUserDataRecordFree, false); + global->allocator()->ChangeType( + tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, + GlobalActivityTracker::kTypeIdActivityTrackerFree, false); + global->allocator()->ChangeType( + user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, + GlobalActivityTracker::kTypeIdUserDataRecordFree, false); +} + } // namespace debug } // namespace base |