1// Copyright (c) 2011 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// This test is POSIX only.
6
7#include "ipc/file_descriptor_set_posix.h"
8
9#include <unistd.h>
10#include <fcntl.h>
11
12#include "base/basictypes.h"
13#include "base/posix/eintr_wrapper.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace {
17
18// Get a safe file descriptor for test purposes.
19int GetSafeFd() {
20  return open("/dev/null", O_RDONLY);
21}
22
23// Returns true if fd was already closed.  Closes fd if not closed.
24bool VerifyClosed(int fd) {
25  const int duped = dup(fd);
26  if (duped != -1) {
27    EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
28    EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
29    return false;
30  }
31  return true;
32}
33
34// The FileDescriptorSet will try and close some of the descriptor numbers
35// which we given it. This is the base descriptor value. It's great enough such
36// that no real descriptor will accidently be closed.
37static const int kFDBase = 50000;
38
39TEST(FileDescriptorSet, BasicAdd) {
40  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
41
42  ASSERT_EQ(set->size(), 0u);
43  ASSERT_TRUE(set->empty());
44  ASSERT_TRUE(set->AddToBorrow(kFDBase));
45  ASSERT_EQ(set->size(), 1u);
46  ASSERT_TRUE(!set->empty());
47
48  // Empties the set and stops a warning about deleting a set with unconsumed
49  // descriptors
50  set->CommitAll();
51}
52
53TEST(FileDescriptorSet, BasicAddAndClose) {
54  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
55
56  ASSERT_EQ(set->size(), 0u);
57  ASSERT_TRUE(set->empty());
58  const int fd = GetSafeFd();
59  ASSERT_TRUE(set->AddToOwn(base::ScopedFD(fd)));
60  ASSERT_EQ(set->size(), 1u);
61  ASSERT_TRUE(!set->empty());
62
63  set->CommitAll();
64
65  ASSERT_TRUE(VerifyClosed(fd));
66}
67TEST(FileDescriptorSet, MaxSize) {
68  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
69
70  for (size_t i = 0; i < FileDescriptorSet::kMaxDescriptorsPerMessage; ++i)
71    ASSERT_TRUE(set->AddToBorrow(kFDBase + 1 + i));
72
73  ASSERT_TRUE(!set->AddToBorrow(kFDBase));
74
75  set->CommitAll();
76}
77
78TEST(FileDescriptorSet, SetDescriptors) {
79  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
80
81  ASSERT_TRUE(set->empty());
82  set->AddDescriptorsToOwn(NULL, 0);
83  ASSERT_TRUE(set->empty());
84
85  const int fd = GetSafeFd();
86  static const int fds[] = {fd};
87  set->AddDescriptorsToOwn(fds, 1);
88  ASSERT_TRUE(!set->empty());
89  ASSERT_EQ(set->size(), 1u);
90
91  set->CommitAll();
92
93  ASSERT_TRUE(VerifyClosed(fd));
94}
95
96TEST(FileDescriptorSet, PeekDescriptors) {
97  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
98
99  set->PeekDescriptors(NULL);
100  ASSERT_TRUE(set->AddToBorrow(kFDBase));
101
102  int fds[1];
103  fds[0] = 0;
104  set->PeekDescriptors(fds);
105  ASSERT_EQ(fds[0], kFDBase);
106  set->CommitAll();
107  ASSERT_TRUE(set->empty());
108}
109
110TEST(FileDescriptorSet, WalkInOrder) {
111  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
112
113  // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
114  // used to retrieve borrowed descriptors. That never happens in production.
115  ASSERT_TRUE(set->AddToBorrow(kFDBase));
116  ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
117  ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
118
119  ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
120  ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
121  ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
122
123  set->CommitAll();
124}
125
126TEST(FileDescriptorSet, WalkWrongOrder) {
127  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
128
129  // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
130  // used to retrieve borrowed descriptors. That never happens in production.
131  ASSERT_TRUE(set->AddToBorrow(kFDBase));
132  ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
133  ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
134
135  ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
136  ASSERT_EQ(set->TakeDescriptorAt(2), -1);
137
138  set->CommitAll();
139}
140
141TEST(FileDescriptorSet, WalkCycle) {
142  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
143
144  // TODO(morrita): This test is wrong. TakeDescriptorAt() shouldn't be
145  // used to retrieve borrowed descriptors. That never happens in production.
146  ASSERT_TRUE(set->AddToBorrow(kFDBase));
147  ASSERT_TRUE(set->AddToBorrow(kFDBase + 1));
148  ASSERT_TRUE(set->AddToBorrow(kFDBase + 2));
149
150  ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
151  ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
152  ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
153  ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
154  ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
155  ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
156  ASSERT_EQ(set->TakeDescriptorAt(0), kFDBase);
157  ASSERT_EQ(set->TakeDescriptorAt(1), kFDBase + 1);
158  ASSERT_EQ(set->TakeDescriptorAt(2), kFDBase + 2);
159
160  set->CommitAll();
161}
162
163TEST(FileDescriptorSet, DontClose) {
164  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
165
166  const int fd = GetSafeFd();
167  ASSERT_TRUE(set->AddToBorrow(fd));
168  set->CommitAll();
169
170  ASSERT_FALSE(VerifyClosed(fd));
171}
172
173TEST(FileDescriptorSet, DoClose) {
174  scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
175
176  const int fd = GetSafeFd();
177  ASSERT_TRUE(set->AddToOwn(base::ScopedFD(fd)));
178  set->CommitAll();
179
180  ASSERT_TRUE(VerifyClosed(fd));
181}
182
183}  // namespace
184