1// Copyright 2014 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.
4
5#include "tools/cygprofile/cygprofile.h"
6
7#include <vector>
8
9#include <sys/time.h>
10
11#include "base/bind.h"
12#include "base/callback.h"
13#include "base/logging.h"
14#include "base/synchronization/waitable_event.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace cygprofile {
18namespace {
19
20void FlushEntries(std::vector<LogEntry>* destination,
21                  std::vector<LogEntry>* entries) {
22  CHECK_EQ(0U, destination->size());
23  // Move the provided |entries| vector to the provided |destination| so that
24  // the unit test that triggered the flush can check it.
25  destination->swap(*entries);
26}
27
28// Flush callback that should not be invoked.
29void CheckFlushDoesNotHappen(std::vector<LogEntry>* entries) {
30  NOTREACHED();
31}
32
33uint64_t GetUsecSecTimeFromTimeSpec(struct timespec timespec) {
34  return timespec.tv_sec * 1000 * 1000 + timespec.tv_nsec / 1000;
35}
36
37TEST(CygprofileTest, ThreadLogBasic) {
38  ThreadLog thread_log(base::Bind(&CheckFlushDoesNotHappen));
39
40  thread_log.AddEntry(reinterpret_cast<void*>(0x2));
41  thread_log.AddEntry(reinterpret_cast<void*>(0x1));
42
43  std::vector<LogEntry> entries;
44  thread_log.TakeEntries(&entries);
45
46  ASSERT_EQ(2U, entries.size());
47  // The entries should appear in their insertion order.
48  const LogEntry& first_entry = entries[0];
49  ASSERT_EQ(reinterpret_cast<int>(first_entry.address), 2);
50  ASSERT_EQ(getpid(), first_entry.pid);
51  ASSERT_LT(0, first_entry.tid);
52
53  const LogEntry& second_entry = entries[1];
54  ASSERT_EQ(1, reinterpret_cast<int>(second_entry.address));
55  ASSERT_EQ(first_entry.pid, second_entry.pid);
56  ASSERT_EQ(first_entry.tid, second_entry.tid);
57
58  ASSERT_GE(GetUsecSecTimeFromTimeSpec(second_entry.time),
59            GetUsecSecTimeFromTimeSpec(first_entry.time));
60}
61
62TEST(CygprofileTest, ManagerBasic) {
63  base::WaitableEvent wait_event(true, false);
64  base::WaitableEvent notify_event(true, false);
65
66  ThreadLogsManager manager(
67      base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_event)),
68      base::Bind(&base::WaitableEvent::Signal,
69                 base::Unretained(&notify_event)));
70
71  std::vector<LogEntry> entries;
72  scoped_ptr<ThreadLog> thread_log(
73      new ThreadLog(base::Bind(&FlushEntries, base::Unretained(&entries))));
74
75  thread_log->AddEntry(reinterpret_cast<void*>(0x2));
76  thread_log->AddEntry(reinterpret_cast<void*>(0x3));
77
78  // This should make the manager spawn its internal flush thread which will
79  // wait for a notification before it starts doing some work.
80  manager.AddLog(thread_log.Pass());
81
82  EXPECT_EQ(0U, entries.size());
83  // This will wake up the internal thread.
84  wait_event.Signal();
85  // Now it's our turn to wait until it performed the flush.
86  notify_event.Wait();
87
88  // The flush should have moved the data to the local vector of entries.
89  EXPECT_EQ(2U, entries.size());
90  ASSERT_EQ(2, reinterpret_cast<int>(entries[0].address));
91  ASSERT_EQ(3, reinterpret_cast<int>(entries[1].address));
92}
93
94}  // namespace
95}  // namespace cygprofile
96
97// Custom runner implementation since base's one requires JNI on Android.
98int main(int argc, char** argv) {
99  testing::InitGoogleTest(&argc, argv);
100  return RUN_ALL_TESTS();
101}
102