blob: 403a2abf670ae7d8fa70306ba0a5f76c3efe56df [file] [log] [blame]
Yi Jin0a3406f2017-06-22 19:23:11 -07001// Copyright (C) 2017 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#define LOG_TAG "incidentd"
16
17#include "FdBuffer.h"
18
19#include <android-base/file.h>
20#include <android-base/test_utils.h>
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23#include <signal.h>
24#include <string.h>
25
26const int READ_TIMEOUT = 5 * 1000;
27const int BUFFER_SIZE = 16 * 1024;
Yi Jinb44f7d42017-07-21 12:12:59 -070028const int QUICK_TIMEOUT_MS = 100;
Yi Jin0a3406f2017-06-22 19:23:11 -070029const std::string HEAD = "[OK]";
30
31using namespace android;
32using namespace android::base;
33using ::testing::StrEq;
34using ::testing::Test;
35using ::testing::internal::CaptureStdout;
36using ::testing::internal::GetCapturedStdout;
37
38class FdBufferTest : public Test {
39public:
40 virtual void SetUp() override {
41 ASSERT_NE(tf.fd, -1);
42 ASSERT_NE(p2cPipe.init(), -1);
43 ASSERT_NE(c2pPipe.init(), -1);
44 }
45
46 void AssertBufferReadSuccessful(size_t expected) {
47 EXPECT_EQ(buffer.size(), expected);
48 EXPECT_FALSE(buffer.timedOut());
49 EXPECT_FALSE(buffer.truncated());
50 }
51
52 void AssertBufferContent(const char* expected) {
53 ReportRequestSet requests;
54 requests.setMainFd(STDOUT_FILENO);
55
56 CaptureStdout();
57 ASSERT_EQ(NO_ERROR, buffer.write(&requests));
58 EXPECT_THAT(GetCapturedStdout(), StrEq(expected));
59 }
60
61 bool DoDataStream(int rFd, int wFd) {
62 char buf[BUFFER_SIZE];
63 ssize_t nRead;
64 while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) {
65 ssize_t nWritten = 0;
66 while (nWritten < nRead) {
67 ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten);
68 if (amt < 0) {
69 return false;
70 }
71 nWritten += amt;
72 }
73 }
74 return nRead == 0;
75 }
76
77protected:
78 FdBuffer buffer;
79 TemporaryFile tf;
80 Fpipe p2cPipe;
81 Fpipe c2pPipe;
82
83 const std::string kTestPath = GetExecutableDirectory();
84 const std::string kTestDataPath = kTestPath + "/testdata/";
85};
86
87TEST_F(FdBufferTest, ReadAndWrite) {
88 std::string testdata = "FdBuffer test string";
89 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
90 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
91 AssertBufferReadSuccessful(testdata.size());
92 AssertBufferContent(testdata.c_str());
93}
94
Yi Jin0ed9b682017-08-18 14:51:20 -070095TEST_F(FdBufferTest, IterateEmpty) {
96 FdBuffer::iterator it = buffer.begin();
97 EXPECT_EQ(it, buffer.end());
98 it += 1;
99 EXPECT_TRUE(it.outOfBound());
100}
101
102TEST_F(FdBufferTest, ReadAndIterate) {
103 std::string testdata = "FdBuffer test string";
104 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
105 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
106
107 int i=0;
108 for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); ++it) {
109 EXPECT_EQ(*it, (uint8_t)testdata[i++]);
110 }
111
112 FdBuffer::iterator it = buffer.begin();
113 it += buffer.size();
114 EXPECT_EQ(it, buffer.end());
115 EXPECT_EQ(it.bytesRead(), testdata.size());
116 EXPECT_FALSE(it.outOfBound());
117}
118
Yi Jin0a3406f2017-06-22 19:23:11 -0700119TEST_F(FdBufferTest, ReadTimeout) {
120 int pid = fork();
121 ASSERT_TRUE(pid != -1);
122
123 if (pid == 0) {
124 close(c2pPipe.readFd());
125 while(true) {
126 write(c2pPipe.writeFd(), "poo", 3);
127 sleep(1);
128 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700129 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700130 } else {
131 close(c2pPipe.writeFd());
132
Yi Jinb44f7d42017-07-21 12:12:59 -0700133 status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700134 ASSERT_EQ(NO_ERROR, status);
135 EXPECT_TRUE(buffer.timedOut());
136
137 kill(pid, SIGKILL); // reap the child process
138 }
139}
140
141TEST_F(FdBufferTest, ReadInStreamAndWrite) {
142 std::string testdata = "simply test read in stream";
143 std::string expected = HEAD + testdata;
144 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
145
146 int pid = fork();
147 ASSERT_TRUE(pid != -1);
148
149 if (pid == 0) {
150 close(p2cPipe.writeFd());
151 close(c2pPipe.readFd());
152 ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
153 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
154 close(p2cPipe.readFd());
155 close(c2pPipe.writeFd());
156 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700157 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700158 } else {
159 close(p2cPipe.readFd());
160 close(c2pPipe.writeFd());
161
162 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
163 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
164 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
165 AssertBufferContent(expected.c_str());
166 wait(&pid);
167 }
168}
169
170TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
171 std::string testdata = "child process flushes only after all data are read.";
172 std::string expected = HEAD + testdata;
173 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
174
175 int pid = fork();
176 ASSERT_TRUE(pid != -1);
177
178 if (pid == 0) {
179 close(p2cPipe.writeFd());
180 close(c2pPipe.readFd());
181 std::string data;
182 // wait for read finishes then write.
183 ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
184 data = HEAD + data;
185 ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
186 close(p2cPipe.readFd());
187 close(c2pPipe.writeFd());
188 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700189 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700190 } else {
191 close(p2cPipe.readFd());
192 close(c2pPipe.writeFd());
193
194 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
195 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
196 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
197 AssertBufferContent(expected.c_str());
198 wait(&pid);
199 }
200}
201
202TEST_F(FdBufferTest, ReadInStreamEmpty) {
203 ASSERT_TRUE(WriteStringToFile("", tf.path, false));
204
205 int pid = fork();
206 ASSERT_TRUE(pid != -1);
207
208 if (pid == 0) {
209 close(p2cPipe.writeFd());
210 close(c2pPipe.readFd());
211 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
212 close(p2cPipe.readFd());
213 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700214 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700215 } else {
216 close(p2cPipe.readFd());
217 close(c2pPipe.writeFd());
218
219 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
220 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
221 AssertBufferReadSuccessful(0);
222 AssertBufferContent("");
223 wait(&pid);
224 }
225}
226
227TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
228 const std::string testFile = kTestDataPath + "morethan4MB.txt";
Yi Jin0ed9b682017-08-18 14:51:20 -0700229 size_t fourMB = (size_t) 4 * 1024 * 1024;
George Burgess IV4e4a34b2017-07-31 11:09:10 -0700230 int fd = open(testFile.c_str(), O_RDONLY);
Yi Jin0a3406f2017-06-22 19:23:11 -0700231 ASSERT_NE(fd, -1);
232 int pid = fork();
233 ASSERT_TRUE(pid != -1);
234
235 if (pid == 0) {
236 close(p2cPipe.writeFd());
237 close(c2pPipe.readFd());
238 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
239 close(p2cPipe.readFd());
240 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700241 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700242 } else {
243 close(p2cPipe.readFd());
244 close(c2pPipe.writeFd());
245
246 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
247 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
Yi Jin0ed9b682017-08-18 14:51:20 -0700248 EXPECT_EQ(buffer.size(), fourMB);
Yi Jin0a3406f2017-06-22 19:23:11 -0700249 EXPECT_FALSE(buffer.timedOut());
250 EXPECT_TRUE(buffer.truncated());
251 wait(&pid);
Yi Jin0ed9b682017-08-18 14:51:20 -0700252 FdBuffer::iterator it = buffer.begin();
253 it += fourMB;
254 EXPECT_EQ(it.bytesRead(), fourMB);
255 EXPECT_EQ(it, buffer.end());
256 for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); it++) {
257 char c = 'A' + (it.bytesRead() % 64 / 8);
258 ASSERT_TRUE(*it == c);
259 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700260 }
261}
262
263TEST_F(FdBufferTest, ReadInStreamTimeOut) {
264 std::string testdata = "timeout test";
265 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
266
267 int pid = fork();
268 ASSERT_TRUE(pid != -1);
269
270 if (pid == 0) {
271 close(p2cPipe.writeFd());
272 close(c2pPipe.readFd());
273 while (true) {
274 sleep(1);
275 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700276 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700277 } else {
278 close(p2cPipe.readFd());
279 close(c2pPipe.writeFd());
280
281 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
Yi Jinb44f7d42017-07-21 12:12:59 -0700282 p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
Yi Jin0a3406f2017-06-22 19:23:11 -0700283 EXPECT_TRUE(buffer.timedOut());
284 kill(pid, SIGKILL); // reap the child process
285 }
286}