blob: 3fd2ed82a26e31ae0184d62b50758ad261ded05a [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;
Yi Jinc23fad22017-09-15 17:24:59 -070052 EncodedBuffer::iterator it = buffer.data();
53 while (it.hasNext()) {
54 ASSERT_EQ(it.next(), expected[i++]);
Yi Jin99c248f2017-08-25 18:11:58 -070055 }
Yi Jinc23fad22017-09-15 17:24:59 -070056 EXPECT_EQ(expected[i], '\0');
Yi Jin0a3406f2017-06-22 19:23:11 -070057 }
58
59 bool DoDataStream(int rFd, int wFd) {
60 char buf[BUFFER_SIZE];
61 ssize_t nRead;
62 while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) {
63 ssize_t nWritten = 0;
64 while (nWritten < nRead) {
65 ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten);
66 if (amt < 0) {
67 return false;
68 }
69 nWritten += amt;
70 }
71 }
72 return nRead == 0;
73 }
74
75protected:
76 FdBuffer buffer;
77 TemporaryFile tf;
78 Fpipe p2cPipe;
79 Fpipe c2pPipe;
80
81 const std::string kTestPath = GetExecutableDirectory();
82 const std::string kTestDataPath = kTestPath + "/testdata/";
83};
84
85TEST_F(FdBufferTest, ReadAndWrite) {
86 std::string testdata = "FdBuffer test string";
Wei Wang254102d2017-11-09 21:45:29 -080087 ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
Yi Jin0a3406f2017-06-22 19:23:11 -070088 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
89 AssertBufferReadSuccessful(testdata.size());
90 AssertBufferContent(testdata.c_str());
91}
92
Yi Jin0ed9b682017-08-18 14:51:20 -070093TEST_F(FdBufferTest, IterateEmpty) {
Yi Jinc23fad22017-09-15 17:24:59 -070094 EncodedBuffer::iterator it = buffer.data();
95 EXPECT_FALSE(it.hasNext());
Yi Jin99c248f2017-08-25 18:11:58 -070096}
97
Yi Jin0ed9b682017-08-18 14:51:20 -070098TEST_F(FdBufferTest, ReadAndIterate) {
99 std::string testdata = "FdBuffer test string";
Wei Wang254102d2017-11-09 21:45:29 -0800100 ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
Yi Jin0ed9b682017-08-18 14:51:20 -0700101 ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
102
103 int i=0;
Yi Jinc23fad22017-09-15 17:24:59 -0700104 EncodedBuffer::iterator it = buffer.data();
105 while (it.hasNext()) {
106 EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
Yi Jin0ed9b682017-08-18 14:51:20 -0700107 }
108
Yi Jinc23fad22017-09-15 17:24:59 -0700109 it.rp()->rewind();
110 it.rp()->move(buffer.size());
Yi Jin0ed9b682017-08-18 14:51:20 -0700111 EXPECT_EQ(it.bytesRead(), testdata.size());
Yi Jinc23fad22017-09-15 17:24:59 -0700112 EXPECT_FALSE(it.hasNext());
Yi Jin0ed9b682017-08-18 14:51:20 -0700113}
114
Yi Jin0a3406f2017-06-22 19:23:11 -0700115TEST_F(FdBufferTest, ReadTimeout) {
116 int pid = fork();
117 ASSERT_TRUE(pid != -1);
118
119 if (pid == 0) {
120 close(c2pPipe.readFd());
121 while(true) {
122 write(c2pPipe.writeFd(), "poo", 3);
123 sleep(1);
124 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700125 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700126 } else {
127 close(c2pPipe.writeFd());
128
Yi Jinb44f7d42017-07-21 12:12:59 -0700129 status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700130 ASSERT_EQ(NO_ERROR, status);
131 EXPECT_TRUE(buffer.timedOut());
132
133 kill(pid, SIGKILL); // reap the child process
134 }
135}
136
137TEST_F(FdBufferTest, ReadInStreamAndWrite) {
138 std::string testdata = "simply test read in stream";
139 std::string expected = HEAD + testdata;
Wei Wang254102d2017-11-09 21:45:29 -0800140 ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
Yi Jin0a3406f2017-06-22 19:23:11 -0700141
142 int pid = fork();
143 ASSERT_TRUE(pid != -1);
144
145 if (pid == 0) {
146 close(p2cPipe.writeFd());
147 close(c2pPipe.readFd());
148 ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
149 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
150 close(p2cPipe.readFd());
151 close(c2pPipe.writeFd());
152 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700153 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700154 } else {
155 close(p2cPipe.readFd());
156 close(c2pPipe.writeFd());
157
158 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
159 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
160 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
161 AssertBufferContent(expected.c_str());
162 wait(&pid);
163 }
164}
165
166TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
167 std::string testdata = "child process flushes only after all data are read.";
168 std::string expected = HEAD + testdata;
Wei Wang254102d2017-11-09 21:45:29 -0800169 ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
Yi Jin0a3406f2017-06-22 19:23:11 -0700170
171 int pid = fork();
172 ASSERT_TRUE(pid != -1);
173
174 if (pid == 0) {
175 close(p2cPipe.writeFd());
176 close(c2pPipe.readFd());
177 std::string data;
178 // wait for read finishes then write.
179 ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
180 data = HEAD + data;
181 ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
182 close(p2cPipe.readFd());
183 close(c2pPipe.writeFd());
184 // Must exit here otherwise the child process will continue executing the test binary.
Yi Jinb44f7d42017-07-21 12:12:59 -0700185 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700186 } else {
187 close(p2cPipe.readFd());
188 close(c2pPipe.writeFd());
189
190 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
191 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
192 AssertBufferReadSuccessful(HEAD.size() + testdata.size());
193 AssertBufferContent(expected.c_str());
194 wait(&pid);
195 }
196}
197
198TEST_F(FdBufferTest, ReadInStreamEmpty) {
Wei Wang254102d2017-11-09 21:45:29 -0800199 ASSERT_TRUE(WriteStringToFile("", tf.path));
Yi Jin0a3406f2017-06-22 19:23:11 -0700200
201 int pid = fork();
202 ASSERT_TRUE(pid != -1);
203
204 if (pid == 0) {
205 close(p2cPipe.writeFd());
206 close(c2pPipe.readFd());
207 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
208 close(p2cPipe.readFd());
209 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700210 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700211 } else {
212 close(p2cPipe.readFd());
213 close(c2pPipe.writeFd());
214
215 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
216 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
217 AssertBufferReadSuccessful(0);
218 AssertBufferContent("");
219 wait(&pid);
220 }
221}
222
223TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
224 const std::string testFile = kTestDataPath + "morethan4MB.txt";
Yi Jin0ed9b682017-08-18 14:51:20 -0700225 size_t fourMB = (size_t) 4 * 1024 * 1024;
Yi Jin99c248f2017-08-25 18:11:58 -0700226 int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
Yi Jin0a3406f2017-06-22 19:23:11 -0700227 ASSERT_NE(fd, -1);
228 int pid = fork();
229 ASSERT_TRUE(pid != -1);
230
231 if (pid == 0) {
232 close(p2cPipe.writeFd());
233 close(c2pPipe.readFd());
234 ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
235 close(p2cPipe.readFd());
236 close(c2pPipe.writeFd());
Yi Jinb44f7d42017-07-21 12:12:59 -0700237 _exit(EXIT_SUCCESS);
Yi Jin0a3406f2017-06-22 19:23:11 -0700238 } else {
239 close(p2cPipe.readFd());
240 close(c2pPipe.writeFd());
241
242 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
243 p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
Yi Jin0ed9b682017-08-18 14:51:20 -0700244 EXPECT_EQ(buffer.size(), fourMB);
Yi Jin0a3406f2017-06-22 19:23:11 -0700245 EXPECT_FALSE(buffer.timedOut());
246 EXPECT_TRUE(buffer.truncated());
247 wait(&pid);
Yi Jinc23fad22017-09-15 17:24:59 -0700248 EncodedBuffer::iterator it = buffer.data();
249 it.rp()->move(fourMB);
Yi Jin0ed9b682017-08-18 14:51:20 -0700250 EXPECT_EQ(it.bytesRead(), fourMB);
Yi Jinc23fad22017-09-15 17:24:59 -0700251 EXPECT_FALSE(it.hasNext());
252
253 it.rp()->rewind();
254 while (it.hasNext()) {
Yi Jin0ed9b682017-08-18 14:51:20 -0700255 char c = 'A' + (it.bytesRead() % 64 / 8);
Yi Jinc23fad22017-09-15 17:24:59 -0700256 ASSERT_TRUE(it.next() == c);
Yi Jin0ed9b682017-08-18 14:51:20 -0700257 }
Yi Jin0a3406f2017-06-22 19:23:11 -0700258 }
259}
260
261TEST_F(FdBufferTest, ReadInStreamTimeOut) {
262 std::string testdata = "timeout test";
Wei Wang254102d2017-11-09 21:45:29 -0800263 ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
Yi Jin0a3406f2017-06-22 19:23:11 -0700264
265 int pid = fork();
266 ASSERT_TRUE(pid != -1);
267
268 if (pid == 0) {
269 close(p2cPipe.writeFd());
270 close(c2pPipe.readFd());
271 while (true) {
272 sleep(1);
273 }
Yi Jinb44f7d42017-07-21 12:12:59 -0700274 _exit(EXIT_FAILURE);
Yi Jin0a3406f2017-06-22 19:23:11 -0700275 } else {
276 close(p2cPipe.readFd());
277 close(c2pPipe.writeFd());
278
279 ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
Yi Jinb44f7d42017-07-21 12:12:59 -0700280 p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
Yi Jin0a3406f2017-06-22 19:23:11 -0700281 EXPECT_TRUE(buffer.timedOut());
282 kill(pid, SIGKILL); // reap the child process
283 }
284}