summaryrefslogtreecommitdiffstats
path: root/chrome/browser/process_info_snapshot_mac_unittest.cc
blob: c30a883ec7d45b34a12590e19c95d16b89c5e5e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright (c) 2012 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 "chrome/browser/process_info_snapshot.h"

#include <sys/types.h>  // For |uid_t| (and |pid_t|).
#include <unistd.h>  // For |getpid()|, |getuid()|, etc.

#include <vector>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"

typedef testing::Test ProcessInfoSnapshotMacTest;

TEST_F(ProcessInfoSnapshotMacTest, FindPidOneTest) {
  // Sample process with PID 1, which should exist and presumably belong to
  // root.
  std::vector<base::ProcessId> pid_list;
  pid_list.push_back(1);
  ProcessInfoSnapshot snapshot;
  ASSERT_TRUE(snapshot.Sample(pid_list));

  ProcessInfoSnapshot::ProcInfoEntry proc_info;
  ASSERT_TRUE(snapshot.GetProcInfo(1, &proc_info));
  EXPECT_EQ(1, static_cast<int64>(proc_info.pid));
  EXPECT_EQ(0, static_cast<int64>(proc_info.ppid));
  EXPECT_EQ(0, static_cast<int64>(proc_info.uid));
  EXPECT_EQ(0, static_cast<int64>(proc_info.euid));
  EXPECT_GE(proc_info.rss, 0u);
  EXPECT_GT(proc_info.vsize, 0u);

  // Try out the |Get...OfPID()|, but don't examine the results, since they
  // depend on how we map |ProcInfoEntry| to |...KBytes|.
  base::CommittedKBytes usage;
  EXPECT_TRUE(snapshot.GetCommittedKBytesOfPID(1, &usage));
  base::WorkingSetKBytes ws_usage;
  EXPECT_TRUE(snapshot.GetWorkingSetKBytesOfPID(1, &ws_usage));

  // Make sure it hasn't picked up some other PID (say, 2).
  EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));

  // Make sure PID 2 still isn't there (in case I mess up my use of std::map).
  EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));

  // Test |Reset()|.
  snapshot.Reset();
  EXPECT_FALSE(snapshot.GetProcInfo(1, &proc_info));
}

TEST_F(ProcessInfoSnapshotMacTest, FindPidSelfTest) {
  // Sample this process and its parent.
  base::ProcessId pid = static_cast<base::ProcessId>(getpid());
  base::ProcessId ppid = static_cast<base::ProcessId>(getppid());
  uid_t uid = getuid();
  uid_t euid = geteuid();
  EXPECT_NE(static_cast<int64>(ppid), 0);

  std::vector<base::ProcessId> pid_list;
  pid_list.push_back(pid);
  pid_list.push_back(ppid);
  ProcessInfoSnapshot snapshot;
  ASSERT_TRUE(snapshot.Sample(pid_list));

  // Find our process.
  ProcessInfoSnapshot::ProcInfoEntry proc_info;
  ASSERT_TRUE(snapshot.GetProcInfo(pid, &proc_info));
  EXPECT_EQ(pid, proc_info.pid);
  EXPECT_EQ(ppid, proc_info.ppid);
  EXPECT_EQ(uid, proc_info.uid);
  EXPECT_EQ(euid, proc_info.euid);
  EXPECT_GE(proc_info.rss, 100u);     // Sanity check: we're running, so we
                                      // should occupy at least 100 kilobytes.
  EXPECT_GE(proc_info.vsize, 1024u);  // Sanity check: our |vsize| is presumably
                                      // at least a megabyte.
  EXPECT_GE(proc_info.rshrd, 1024u);  // Shared memory should also > 1 MB.
  EXPECT_GE(proc_info.rprvt, 1024u);  // Same with private memory.

  // Find our parent.
  ASSERT_TRUE(snapshot.GetProcInfo(ppid, &proc_info));
  EXPECT_EQ(ppid, proc_info.pid);
  EXPECT_NE(static_cast<int64>(proc_info.ppid), 0);
  EXPECT_EQ(uid, proc_info.uid);    // This (and the following) should be true
  EXPECT_EQ(euid, proc_info.euid);  // under reasonable circumstances.
  // Can't say anything definite about its |rss|.
  EXPECT_GT(proc_info.vsize, 0u);   // Its |vsize| should be nonzero though.
}

// To verify that ProcessInfoSnapshot is getting the actual uid and effective
// uid, this test runs top. top should have a uid of the caller and effective
// uid of 0 (root).
TEST_F(ProcessInfoSnapshotMacTest, EffectiveVsRealUserIDTest) {
  // Create a pipe to be able to read top's output.
  int fds[2];
  PCHECK(pipe(fds) == 0);
  base::FileHandleMappingVector fds_to_remap;
  fds_to_remap.push_back(std::make_pair(fds[1], 1));

  // Hook up top's stderr to the test process' stderr.
  fds_to_remap.push_back(std::make_pair(fileno(stderr), 2));

  std::vector<std::string> argv;
  argv.push_back("/usr/bin/top");
  argv.push_back("-l");
  argv.push_back("0");

  base::ProcessHandle process_handle;
  base::LaunchOptions options;
  options.fds_to_remap = &fds_to_remap;
  ASSERT_TRUE(base::LaunchProcess(argv, options, &process_handle));
  PCHECK(HANDLE_EINTR(close(fds[1])) == 0);

  // Wait until there's some output form top. This is an easy way to tell that
  // the exec() call is done and top is actually running.
  char buf[1];
  PCHECK(HANDLE_EINTR(read(fds[0], buf, 1)) == 1);

  std::vector<base::ProcessId> pid_list;
  pid_list.push_back(process_handle);
  ProcessInfoSnapshot snapshot;
  ASSERT_TRUE(snapshot.Sample(pid_list));

  ProcessInfoSnapshot::ProcInfoEntry proc_info;
  ASSERT_TRUE(snapshot.GetProcInfo(process_handle, &proc_info));
  // Effective user ID should be 0 (root).
  EXPECT_EQ(proc_info.euid, 0u);
  // Real user ID should match the calling process's user id.
  EXPECT_EQ(proc_info.uid, geteuid());

  ASSERT_TRUE(base::KillProcess(process_handle, 0, true));
  PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
}