Home | History | Annotate | Download | only in tests
      1 // 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 #define DEBUG false
     15 #include "Log.h"
     16 
     17 #include "FdBuffer.h"
     18 #include "incidentd_util.h"
     19 
     20 #include <fcntl.h>
     21 #include <signal.h>
     22 #include <string.h>
     23 
     24 #include <android-base/file.h>
     25 #include <gtest/gtest.h>
     26 
     27 using namespace android;
     28 using namespace android::base;
     29 using namespace android::os::incidentd;
     30 using ::testing::Test;
     31 
     32 const int READ_TIMEOUT = 5 * 1000;
     33 const int BUFFER_SIZE = 16 * 1024;
     34 const int QUICK_TIMEOUT_MS = 100;
     35 const std::string HEAD = "[OK]";
     36 
     37 class FdBufferTest : public Test {
     38 public:
     39     virtual void SetUp() override {
     40         ASSERT_NE(tf.fd, -1);
     41         ASSERT_NE(p2cPipe.init(), -1);
     42         ASSERT_NE(c2pPipe.init(), -1);
     43     }
     44 
     45     void AssertBufferReadSuccessful(size_t expected) {
     46         EXPECT_EQ(buffer.size(), expected);
     47         EXPECT_FALSE(buffer.timedOut());
     48         EXPECT_FALSE(buffer.truncated());
     49     }
     50 
     51     void AssertBufferContent(const char* expected) {
     52         int i = 0;
     53         sp<ProtoReader> reader = buffer.data()->read();
     54         while (reader->hasNext()) {
     55             ASSERT_EQ(reader->next(), expected[i++]);
     56         }
     57         EXPECT_EQ(expected[i], '\0');
     58     }
     59 
     60     bool DoDataStream(const unique_fd& rFd, const unique_fd& wFd) {
     61         char buf[BUFFER_SIZE];
     62         ssize_t nRead;
     63         while ((nRead = read(rFd.get(), buf, BUFFER_SIZE)) > 0) {
     64             ssize_t nWritten = 0;
     65             while (nWritten < nRead) {
     66                 ssize_t amt = write(wFd.get(), buf + nWritten, nRead - nWritten);
     67                 if (amt < 0) {
     68                     return false;
     69                 }
     70                 nWritten += amt;
     71             }
     72         }
     73         return nRead == 0;
     74     }
     75 
     76 protected:
     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 
     86 TEST_F(FdBufferTest, ReadAndWrite) {
     87     std::string testdata = "FdBuffer test string";
     88     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
     89     ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
     90     AssertBufferReadSuccessful(testdata.size());
     91     AssertBufferContent(testdata.c_str());
     92 }
     93 
     94 TEST_F(FdBufferTest, IterateEmpty) {
     95     sp<ProtoReader> reader = buffer.data()->read();
     96     EXPECT_FALSE(reader->hasNext());
     97 }
     98 
     99 TEST_F(FdBufferTest, ReadAndIterate) {
    100     std::string testdata = "FdBuffer test string";
    101     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
    102     ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
    103 
    104     int i = 0;
    105     sp<ProtoReader> reader = buffer.data()->read();
    106 
    107     while (reader->hasNext()) {
    108         EXPECT_EQ(reader->next(), (uint8_t)testdata[i++]);
    109     }
    110 }
    111 
    112 TEST_F(FdBufferTest, Move) {
    113     std::string testdata = "FdBuffer test string";
    114     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
    115     ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
    116 
    117     sp<ProtoReader> reader = buffer.data()->read();
    118     reader->move(buffer.size());
    119 
    120     EXPECT_EQ(reader->bytesRead(), testdata.size());
    121     EXPECT_FALSE(reader->hasNext());
    122 }
    123 
    124 TEST_F(FdBufferTest, ReadTimeout) {
    125     int pid = fork();
    126     ASSERT_TRUE(pid != -1);
    127 
    128     if (pid == 0) {
    129         c2pPipe.readFd().reset();
    130         while (true) {
    131             write(c2pPipe.writeFd(), "poo", 3);
    132             sleep(1);
    133         }
    134         _exit(EXIT_FAILURE);
    135     } else {
    136         c2pPipe.writeFd().reset();
    137 
    138         status_t status = buffer.read(c2pPipe.readFd().get(), QUICK_TIMEOUT_MS);
    139         ASSERT_EQ(NO_ERROR, status);
    140         EXPECT_TRUE(buffer.timedOut());
    141 
    142         kill(pid, SIGKILL);  // reap the child process
    143     }
    144 }
    145 
    146 TEST_F(FdBufferTest, ReadInStreamAndWrite) {
    147     std::string testdata = "simply test read in stream";
    148     std::string expected = HEAD + testdata;
    149     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
    150 
    151     int pid = fork();
    152     ASSERT_TRUE(pid != -1);
    153 
    154     if (pid == 0) {
    155         p2cPipe.writeFd().reset();
    156         c2pPipe.readFd().reset();
    157         ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
    158         ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
    159         p2cPipe.readFd().reset();
    160         c2pPipe.writeFd().reset();
    161         // Must exit here otherwise the child process will continue executing the test binary.
    162         _exit(EXIT_SUCCESS);
    163     } else {
    164         p2cPipe.readFd().reset();
    165         c2pPipe.writeFd().reset();
    166 
    167         ASSERT_EQ(NO_ERROR,
    168                   buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
    169                                                    std::move(c2pPipe.readFd()), READ_TIMEOUT));
    170         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
    171         AssertBufferContent(expected.c_str());
    172         wait(&pid);
    173     }
    174 }
    175 
    176 TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
    177     std::string testdata = "child process flushes only after all data are read.";
    178     std::string expected = HEAD + testdata;
    179     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
    180 
    181     int pid = fork();
    182     ASSERT_TRUE(pid != -1);
    183 
    184     if (pid == 0) {
    185         p2cPipe.writeFd().reset();
    186         c2pPipe.readFd().reset();
    187         std::string data;
    188         // wait for read finishes then write.
    189         ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
    190         data = HEAD + data;
    191         ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
    192         p2cPipe.readFd().reset();
    193         c2pPipe.writeFd().reset();
    194         // Must exit here otherwise the child process will continue executing the test binary.
    195         _exit(EXIT_SUCCESS);
    196     } else {
    197         p2cPipe.readFd().reset();
    198         c2pPipe.writeFd().reset();
    199 
    200         ASSERT_EQ(NO_ERROR,
    201                   buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
    202                                                    std::move(c2pPipe.readFd()), READ_TIMEOUT));
    203         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
    204         AssertBufferContent(expected.c_str());
    205         wait(&pid);
    206     }
    207 }
    208 
    209 TEST_F(FdBufferTest, ReadInStreamEmpty) {
    210     ASSERT_TRUE(WriteStringToFile("", tf.path));
    211 
    212     int pid = fork();
    213     ASSERT_TRUE(pid != -1);
    214 
    215     if (pid == 0) {
    216         p2cPipe.writeFd().reset();
    217         c2pPipe.readFd().reset();
    218         ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
    219         p2cPipe.readFd().reset();
    220         c2pPipe.writeFd().reset();
    221         _exit(EXIT_SUCCESS);
    222     } else {
    223         p2cPipe.readFd().reset();
    224         c2pPipe.writeFd().reset();
    225 
    226         ASSERT_EQ(NO_ERROR,
    227                   buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
    228                                                    std::move(c2pPipe.readFd()), READ_TIMEOUT));
    229         AssertBufferReadSuccessful(0);
    230         AssertBufferContent("");
    231         wait(&pid);
    232     }
    233 }
    234 
    235 TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithMove) {
    236     const std::string testFile = kTestDataPath + "morethan96MB.txt";
    237     size_t ninetySixMB = (size_t)96 * 1024 * 1024;
    238     unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
    239     ASSERT_NE(fd.get(), -1);
    240     int pid = fork();
    241     ASSERT_TRUE(pid != -1);
    242 
    243     if (pid == 0) {
    244         p2cPipe.writeFd().reset();
    245         c2pPipe.readFd().reset();
    246         ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
    247         p2cPipe.readFd().reset();
    248         c2pPipe.writeFd().reset();
    249         _exit(EXIT_SUCCESS);
    250     } else {
    251         p2cPipe.readFd().reset();
    252         c2pPipe.writeFd().reset();
    253 
    254         ASSERT_EQ(NO_ERROR,
    255                   buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
    256                                                    std::move(c2pPipe.readFd()), READ_TIMEOUT));
    257         EXPECT_EQ(buffer.size(), ninetySixMB);
    258         EXPECT_FALSE(buffer.timedOut());
    259         EXPECT_TRUE(buffer.truncated());
    260         wait(&pid);
    261         sp<ProtoReader> reader = buffer.data()->read();
    262         reader->move(ninetySixMB);
    263 
    264         EXPECT_EQ(reader->bytesRead(), ninetySixMB);
    265         EXPECT_FALSE(reader->hasNext());
    266     }
    267 }
    268 
    269 TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithNext) {
    270     const std::string testFile = kTestDataPath + "morethan96MB.txt";
    271     size_t ninetySixMB = (size_t)96 * 1024 * 1024;
    272     unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
    273     ASSERT_NE(fd.get(), -1);
    274     int pid = fork();
    275     ASSERT_TRUE(pid != -1);
    276 
    277     if (pid == 0) {
    278         p2cPipe.writeFd().reset();
    279         c2pPipe.readFd().reset();
    280         ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
    281         p2cPipe.readFd().reset();
    282         c2pPipe.writeFd().reset();
    283         _exit(EXIT_SUCCESS);
    284     } else {
    285         p2cPipe.readFd().reset();
    286         c2pPipe.writeFd().reset();
    287 
    288         ASSERT_EQ(NO_ERROR,
    289                   buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
    290                                                    std::move(c2pPipe.readFd()), READ_TIMEOUT));
    291         EXPECT_EQ(buffer.size(), ninetySixMB);
    292         EXPECT_FALSE(buffer.timedOut());
    293         EXPECT_TRUE(buffer.truncated());
    294         wait(&pid);
    295         sp<ProtoReader> reader = buffer.data()->read();
    296 
    297         while (reader->hasNext()) {
    298             char c = 'A' + (reader->bytesRead() % 64 / 8);
    299             ASSERT_TRUE(reader->next() == c);
    300         }
    301     }
    302 }
    303 
    304 TEST_F(FdBufferTest, ReadInStreamTimeOut) {
    305     std::string testdata = "timeout test";
    306     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
    307 
    308     int pid = fork();
    309     ASSERT_TRUE(pid != -1);
    310 
    311     if (pid == 0) {
    312         p2cPipe.writeFd().reset();
    313         c2pPipe.readFd().reset();
    314         while (true) {
    315             sleep(1);
    316         }
    317         _exit(EXIT_FAILURE);
    318     } else {
    319         p2cPipe.readFd().reset();
    320         c2pPipe.writeFd().reset();
    321 
    322         ASSERT_EQ(NO_ERROR,
    323                   buffer.readProcessedDataInStream(tf.fd, std::move(p2cPipe.writeFd()),
    324                                                    std::move(c2pPipe.readFd()), QUICK_TIMEOUT_MS));
    325         EXPECT_TRUE(buffer.timedOut());
    326         kill(pid, SIGKILL);  // reap the child process
    327     }
    328 }
    329