blob: d1436b2cc36f89de15a8bfa92b2fa349f1711ef1 [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"
Yi Jin99c248f2017-08-25 18:11:58 -070018#include "io_util.h"
Yi Jin0a3406f2017-06-22 19:23:11 -070019
20#include <android-base/file.h>
21#include <android-base/test_utils.h>
Yi Jin99c248f2017-08-25 18:11:58 -070022#include <fcntl.h>
Yi Jin0a3406f2017-06-22 19:23:11 -070023#include <gtest/gtest.h>
24#include <signal.h>
25#include <string.h>
26
27const int READ_TIMEOUT = 5 * 1000;
28const int BUFFER_SIZE = 16 * 1024;
Yi Jinb44f7d42017-07-21 12:12:59 -070029const int QUICK_TIMEOUT_MS = 100;
Yi Jin0a3406f2017-06-22 19:23:11 -070030const std::string HEAD = "[OK]";
31
32using namespace android;
33using namespace android::base;
Yi Jin0a3406f2017-06-22 19:23:11 -070034using ::testing::Test;
Yi Jin0a3406f2017-06-22 19:23:11 -070035
36class FdBufferTest : public Test {
37public:
38 virtual void SetUp() override {
39 ASSERT_NE(tf.fd, -1);
40 ASSERT_NE(p2cPipe.init(), -1);
41 ASSERT_NE(c2pPipe.init(), -1);
42 }
43
44 void AssertBufferReadSuccessful(size_t expected) {
45 EXPECT_EQ(buffer.size(), expected);
46 EXPECT_FALSE(buffer.timedOut());
47 EXPECT_FALSE(buffer.truncated());
48 }
49
50 void AssertBufferContent(const char* expected) {
Yi Jin99c248f2017-08-25 18:11:58 -070051 int i=0;
52 FdBuffer::iterator it = buffer.begin();
53 while (expected[i] != '\0') {
54 ASSERT_EQ(*it, expected[i++]);
55 it++;
56 }
57 ASSERT_EQ(it, buffer.end());
Yi Jin0a3406f2017-06-22 19:23:11 -070058 }
59
60 bool DoDataStream(int rFd, int wFd) {
61 char buf[BUFFER_SIZE];
62 ssize_t nRead;
63 while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) {
64 ssize_t nWritten = 0;
65 while (nWritten < nRead) {
66 ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten);
67 if (amt < 0) {
68 return false;
69 }
70 nWritten += amt;
71 }
72 }
73 return nRead == 0;
74 }
75
76protected:
77 FdBuffer buffer;
78 TemporaryFile tf;
79 Fpipe p2cPipe;
80 Fpipe c2pPipe;
81
82 const std::string kTestPath = GetExecutableDirectory();
83 const std::string kTestDataPath = kTestPath + "/testdata/";
84};
85
86TEST_F(FdBufferTest, ReadAndWrite) {
87 std::string testdata = "FdBuffer test string";
88 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
89 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
90 AssertBufferReadSuccessful(testdata.size());
91 AssertBufferContent(testdata.c_str());
92}
93
Yi Jin0ed9b682017-08-18 14:51:20 -070094TEST_F(FdBufferTest, IterateEmpty) {
95 FdBuffer::iterator it = buffer.begin();
96 EXPECT_EQ(it, buffer.end());
97 it += 1;
98 EXPECT_TRUE(it.outOfBound());
99}
100
Yi Jin99c248f2017-08-25 18:11:58 -0700101TEST_F(FdBufferTest, IteratorSnapshot) {
102 FdBuffer::iterator it = buffer.begin();
103 it += 4;
104 FdBuffer::iterator snapshot = it.snapshot();
105 it += 5;
106 EXPECT_TRUE(snapshot != it);
107 EXPECT_EQ(it - snapshot, 5);
108 EXPECT_EQ(snapshot - it, -5);
109}
110
Yi Jin0ed9b682017-08-18 14:51:20 -0700111TEST_F(FdBufferTest, ReadAndIterate) {
112 std::string testdata = "FdBuffer test string";
113 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
114 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
115
116 int i=0;
117 for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); ++it) {
118 EXPECT_EQ(*it, (uint8_t)testdata[i++]);
119 }
120
121 FdBuffer::iterator it = buffer.begin();
122 it += buffer.size();
123 EXPECT_EQ(it, buffer.end());
124 EXPECT_EQ(it.bytesRead(), testdata.size());
125 EXPECT_FALSE(it.outOfBound());
126}
127
Yi Jin0a3406f2017-06-22 19:23:11 -0700128TEST_F(FdBufferTest, ReadTimeout) {
129 int pid = fork();
130 ASSERT_TRUE(pid != -1);
131
132 if (pid == 0) {
133 close(c2pPipe.readFd());
134 while(true) {
135 write(c2pPipe.writeFd(), "poo", 3);
136 sleep(1);
137 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700138 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700139 } else {
140 close(c2pPipe.writeFd());
141
Yi Jinb44f7d42017-07-21 12:12:59 -0700142 status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700143 ASSERT_EQ(NO_ERROR, status);
144 EXPECT_TRUE(buffer.timedOut());
145
146 kill(pid, SIGKILL); // reap the child process
147 }
148}
149
150TEST_F(FdBufferTest, ReadInStreamAndWrite) {
151 std::string testdata = "simply test read in stream";
152 std::string expected = HEAD + testdata;
153 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
154
155 int pid = fork();
156 ASSERT_TRUE(pid != -1);
157
158 if (pid == 0) {
159 close(p2cPipe.writeFd());
160 close(c2pPipe.readFd());
161 ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
162 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
163 close(p2cPipe.readFd());
164 close(c2pPipe.writeFd());
165 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700166 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700167 } else {
168 close(p2cPipe.readFd());
169 close(c2pPipe.writeFd());
170
171 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
172 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
173 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
174 AssertBufferContent(expected.c_str());
175 wait(&pid);
176 }
177}
178
179TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
180 std::string testdata = "child process flushes only after all data are read.";
181 std::string expected = HEAD + testdata;
182 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
183
184 int pid = fork();
185 ASSERT_TRUE(pid != -1);
186
187 if (pid == 0) {
188 close(p2cPipe.writeFd());
189 close(c2pPipe.readFd());
190 std::string data;
191 // wait for read finishes then write.
192 ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
193 data = HEAD + data;
194 ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
195 close(p2cPipe.readFd());
196 close(c2pPipe.writeFd());
197 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700198 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700199 } else {
200 close(p2cPipe.readFd());
201 close(c2pPipe.writeFd());
202
203 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
204 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
205 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
206 AssertBufferContent(expected.c_str());
207 wait(&pid);
208 }
209}
210
211TEST_F(FdBufferTest, ReadInStreamEmpty) {
212 ASSERT_TRUE(WriteStringToFile("", tf.path, false));
213
214 int pid = fork();
215 ASSERT_TRUE(pid != -1);
216
217 if (pid == 0) {
218 close(p2cPipe.writeFd());
219 close(c2pPipe.readFd());
220 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
221 close(p2cPipe.readFd());
222 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700223 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700224 } else {
225 close(p2cPipe.readFd());
226 close(c2pPipe.writeFd());
227
228 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
229 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
230 AssertBufferReadSuccessful(0);
231 AssertBufferContent("");
232 wait(&pid);
233 }
234}
235
236TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
237 const std::string testFile = kTestDataPath + "morethan4MB.txt";
Yi Jin0ed9b682017-08-18 14:51:20 -0700238 size_t fourMB = (size_t) 4 * 1024 * 1024;
Yi Jin99c248f2017-08-25 18:11:58 -0700239 int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
Yi Jin0a3406f2017-06-22 19:23:11 -0700240 ASSERT_NE(fd, -1);
241 int pid = fork();
242 ASSERT_TRUE(pid != -1);
243
244 if (pid == 0) {
245 close(p2cPipe.writeFd());
246 close(c2pPipe.readFd());
247 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
248 close(p2cPipe.readFd());
249 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700250 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700251 } else {
252 close(p2cPipe.readFd());
253 close(c2pPipe.writeFd());
254
255 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
256 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
Yi Jin0ed9b682017-08-18 14:51:20 -0700257 EXPECT_EQ(buffer.size(), fourMB);
Yi Jin0a3406f2017-06-22 19:23:11 -0700258 EXPECT_FALSE(buffer.timedOut());
259 EXPECT_TRUE(buffer.truncated());
260 wait(&pid);
Yi Jin0ed9b682017-08-18 14:51:20 -0700261 FdBuffer::iterator it = buffer.begin();
262 it += fourMB;
263 EXPECT_EQ(it.bytesRead(), fourMB);
264 EXPECT_EQ(it, buffer.end());
265 for (FdBuffer::iterator it = buffer.begin(); it != buffer.end(); it++) {
266 char c = 'A' + (it.bytesRead() % 64 / 8);
267 ASSERT_TRUE(*it == c);
268 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700269 }
270}
271
272TEST_F(FdBufferTest, ReadInStreamTimeOut) {
273 std::string testdata = "timeout test";
274 ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
275
276 int pid = fork();
277 ASSERT_TRUE(pid != -1);
278
279 if (pid == 0) {
280 close(p2cPipe.writeFd());
281 close(c2pPipe.readFd());
282 while (true) {
283 sleep(1);
284 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700285 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700286 } else {
287 close(p2cPipe.readFd());
288 close(c2pPipe.writeFd());
289
290 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
Yi Jinb44f7d42017-07-21 12:12:59 -0700291 p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
Yi Jin0a3406f2017-06-22 19:23:11 -0700292 EXPECT_TRUE(buffer.timedOut());
293 kill(pid, SIGKILL); // reap the child process
294 }
295}