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 "Section.h"
     18 
     19 #include <android-base/file.h>
     20 #include <android-base/test_utils.h>
     21 #include <android/os/IncidentReportArgs.h>
     22 #include <android/util/protobuf.h>
     23 #include <frameworks/base/core/proto/android/os/incident.pb.h>
     24 #include <frameworks/base/core/proto/android/os/header.pb.h>
     25 #include <gmock/gmock.h>
     26 #include <gtest/gtest.h>
     27 #include <string.h>
     28 
     29 using namespace android;
     30 using namespace android::base;
     31 using namespace android::binder;
     32 using namespace android::os;
     33 using namespace android::os::incidentd;
     34 using namespace android::util;
     35 using ::testing::StrEq;
     36 using ::testing::Test;
     37 using ::testing::internal::CaptureStdout;
     38 using ::testing::internal::GetCapturedStdout;
     39 
     40 const int TIMEOUT_PARSER = -1;
     41 const int NOOP_PARSER = 0;
     42 const int REVERSE_PARSER = 1;
     43 
     44 const int QUICK_TIMEOUT_MS = 100;
     45 
     46 const std::string VARINT_FIELD_1 = "\x08\x96\x01";  // 150
     47 const std::string STRING_FIELD_2 = "\x12\vandroidwins";
     48 const std::string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff";  // -1
     49 
     50 // NOTICE: this test requires /system/bin/incident_helper is installed.
     51 class SectionTest : public Test {
     52 public:
     53     virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
     54 
     55     void printDebugString(std::string s) {
     56         fprintf(stderr, "size: %zu\n", s.length());
     57         for (size_t i = 0; i < s.length(); i++) {
     58             char c = s[i];
     59             fprintf(stderr, "\\x%x", c);
     60         }
     61         fprintf(stderr, "\n");
     62     }
     63 
     64 protected:
     65     TemporaryFile tf;
     66 
     67     const std::string kTestPath = GetExecutableDirectory();
     68     const std::string kTestDataPath = kTestPath + "/testdata/";
     69 };
     70 
     71 class SimpleListener : public IIncidentReportStatusListener {
     72 public:
     73     SimpleListener(){};
     74     virtual ~SimpleListener(){};
     75 
     76     virtual Status onReportStarted() { return Status::ok(); };
     77     virtual Status onReportSectionStatus(int /*section*/, int /*status*/)
     78             { return Status::ok(); };
     79     virtual Status onReportFinished() { return Status::ok(); };
     80     virtual Status onReportFailed() { return Status::ok(); };
     81 
     82 protected:
     83     virtual IBinder* onAsBinder() override { return nullptr; };
     84 };
     85 
     86 /*
     87 TEST_F(SectionTest, MetadataSection) {
     88     MetadataSection ms;
     89 
     90     vector<sp<ReportRequest>> requests;
     91     ReportRequestSet requestSet(requests);
     92     requestSet.setMainFd(STDOUT_FILENO);
     93 
     94     requestSet.setMainPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL);
     95     requestSet.editSectionStats(1)->set_success(true);
     96 
     97     CaptureStdout();
     98     ASSERT_EQ(NO_ERROR, ms.Execute(&requestSet));
     99 
    100     string out = GetCapturedStdout();
    101     IncidentProto expectedIncident;
    102     expectedIncident.ParseFromArray(out.data(), out.size());
    103     ASSERT_TRUE(expectedIncident.has_metadata());
    104     const IncidentMetadata& expectedMetadata = expectedIncident.metadata();
    105     ASSERT_EQ(IncidentMetadata::LOCAL, expectedMetadata.dest());
    106     ASSERT_EQ(1, expectedMetadata.sections_size());
    107     ASSERT_EQ(1, expectedMetadata.sections(0).id());
    108     ASSERT_TRUE(expectedMetadata.sections(0).has_success());
    109     ASSERT_TRUE(expectedMetadata.sections(0).success());
    110 }
    111 
    112 TEST_F(SectionTest, FileSection) {
    113     FileSection fs(REVERSE_PARSER, tf.path);
    114 
    115     ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path));
    116 
    117     vector<sp<ReportRequest>> requests;
    118     ReportRequestSet requestSet(requests);
    119     requestSet.setMainFd(STDOUT_FILENO);
    120 
    121     CaptureStdout();
    122     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    123     // The input string is reversed in incident helper
    124     // The length is 11, in 128Varint it is "0000 1011" -> \v
    125     EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\vatadtsetmai"));
    126 }
    127 
    128 TEST_F(SectionTest, FileSectionNotExist) {
    129     vector<sp<ReportRequest>> requests;
    130     ReportRequestSet requestSet(requests);
    131 
    132     FileSection fs1(NOOP_PARSER, "notexist", QUICK_TIMEOUT_MS);
    133     ASSERT_EQ(NO_ERROR, fs1.Execute(&requestSet));
    134 
    135     FileSection fs2(NOOP_PARSER, "notexist", QUICK_TIMEOUT_MS);
    136     ASSERT_EQ(NO_ERROR, fs2.Execute(&requestSet));
    137 }
    138 
    139 TEST_F(SectionTest, FileSectionTimeout) {
    140     vector<sp<ReportRequest>> requests;
    141     ReportRequestSet requestSet(requests);
    142 
    143     FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS);
    144     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    145     ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out());
    146 }
    147 
    148 TEST_F(SectionTest, GZipSection) {
    149     const std::string testFile = kTestDataPath + "kmsg.txt";
    150     const std::string testGzFile = testFile + ".gz";
    151     GZipSection gs(NOOP_PARSER, "/tmp/nonexist", testFile.c_str(), NULL);
    152 
    153     vector<sp<ReportRequest>> requests;
    154     ReportRequestSet requestSet(requests);
    155     requestSet.setMainFd(tf.fd);
    156     requestSet.setMainPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL);
    157 
    158     ASSERT_EQ(NO_ERROR, gs.Execute(&requestSet));
    159     std::string expected, gzFile, actual;
    160     ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile));
    161     ASSERT_TRUE(ReadFileToString(tf.path, &actual));
    162     // generates the expected protobuf result.
    163     size_t fileLen = testFile.size();
    164     size_t totalLen = 1 + get_varint_size(fileLen) + fileLen + 3 + gzFile.size();
    165     uint8_t header[20];
    166     header[0] = '\x2';  // header 0 << 3 + 2
    167     uint8_t* ptr = write_raw_varint(header + 1, totalLen);
    168     *ptr = '\n';  // header 1 << 3 + 2
    169     ptr = write_raw_varint(++ptr, fileLen);
    170     expected.assign((const char*)header, ptr - header);
    171     expected += testFile + "\x12\x9F\x6" + gzFile;
    172     EXPECT_THAT(actual, StrEq(expected));
    173 }
    174 
    175 TEST_F(SectionTest, GZipSectionNoFileFound) {
    176     GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL);
    177     vector<sp<ReportRequest>> requests;
    178     ReportRequestSet requestSet(requests);
    179     requestSet.setMainFd(STDOUT_FILENO);
    180     ASSERT_EQ(NO_ERROR, gs.Execute(&requestSet));
    181 }
    182 
    183 TEST_F(SectionTest, CommandSectionConstructor) {
    184     CommandSection cs1(1, "echo", "\"this is a test\"", "ooo", NULL);
    185     CommandSection cs2(2, "single_command", NULL);
    186     CommandSection cs3(1, 3123, "echo", "\"this is a test\"", "ooo", NULL);
    187     CommandSection cs4(2, 43214, "single_command", NULL);
    188 
    189     EXPECT_THAT(cs1.name.string(), StrEq("cmd echo \"this is a test\" ooo"));
    190     EXPECT_THAT(cs2.name.string(), StrEq("cmd single_command"));
    191     EXPECT_EQ(3123, cs3.timeoutMs);
    192     EXPECT_EQ(43214, cs4.timeoutMs);
    193     EXPECT_THAT(cs3.name.string(), StrEq("cmd echo \"this is a test\" ooo"));
    194     EXPECT_THAT(cs4.name.string(), StrEq("cmd single_command"));
    195 }
    196 
    197 TEST_F(SectionTest, CommandSectionEcho) {
    198     CommandSection cs(REVERSE_PARSER, "/system/bin/echo", "about", NULL);
    199     vector<sp<ReportRequest>> requests;
    200     ReportRequestSet requestSet(requests);
    201     requestSet.setMainFd(STDOUT_FILENO);
    202     CaptureStdout();
    203     ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet));
    204     EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\x06\ntuoba"));
    205 }
    206 
    207 TEST_F(SectionTest, CommandSectionCommandTimeout) {
    208     CommandSection cs(NOOP_PARSER, QUICK_TIMEOUT_MS, "/system/bin/yes", NULL);
    209     vector<sp<ReportRequest>> requests;
    210     ReportRequestSet requestSet(requests);
    211     ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet));
    212     ASSERT_TRUE(requestSet.getSectionStats(NOOP_PARSER)->timed_out());
    213 }
    214 
    215 TEST_F(SectionTest, CommandSectionIncidentHelperTimeout) {
    216     CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "/system/bin/echo", "about", NULL);
    217     vector<sp<ReportRequest>> requests;
    218     ReportRequestSet requestSet(requests);
    219     requestSet.setMainFd(STDOUT_FILENO);
    220     ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet));
    221     ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out());
    222 }
    223 
    224 TEST_F(SectionTest, CommandSectionBadCommand) {
    225     CommandSection cs(NOOP_PARSER, "echoo", "about", NULL);
    226     vector<sp<ReportRequest>> requests;
    227     ReportRequestSet requestSet(requests);
    228     ASSERT_EQ(NAME_NOT_FOUND, cs.Execute(&requestSet));
    229 }
    230 
    231 TEST_F(SectionTest, CommandSectionBadCommandAndTimeout) {
    232     CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "nonexistcommand", "-opt", NULL);
    233     // timeout will return first
    234     vector<sp<ReportRequest>> requests;
    235     ReportRequestSet requestSet(requests);
    236     ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet));
    237     ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out());
    238 }
    239 
    240 TEST_F(SectionTest, LogSectionBinary) {
    241     LogSection ls(1, LOG_ID_EVENTS);
    242     vector<sp<ReportRequest>> requests;
    243     ReportRequestSet requestSet(requests);
    244     requestSet.setMainFd(STDOUT_FILENO);
    245     CaptureStdout();
    246     ASSERT_EQ(NO_ERROR, ls.Execute(&requestSet));
    247     std::string results = GetCapturedStdout();
    248     EXPECT_FALSE(results.empty());
    249 }
    250 
    251 TEST_F(SectionTest, LogSectionSystem) {
    252     LogSection ls(1, LOG_ID_SYSTEM);
    253     vector<sp<ReportRequest>> requests;
    254     ReportRequestSet requestSet(requests);
    255     requestSet.setMainFd(STDOUT_FILENO);
    256     CaptureStdout();
    257     ASSERT_EQ(NO_ERROR, ls.Execute(&requestSet));
    258     std::string results = GetCapturedStdout();
    259     EXPECT_FALSE(results.empty());
    260 }
    261 
    262 TEST_F(SectionTest, TestFilterPiiTaggedFields) {
    263     FileSection fs(NOOP_PARSER, tf.path);
    264 
    265     ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
    266 
    267     vector<sp<ReportRequest>> requests;
    268     ReportRequestSet requestSet(requests);
    269     requestSet.setMainFd(STDOUT_FILENO);
    270 
    271     CaptureStdout();
    272     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    273     EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2));
    274 }
    275 
    276 TEST_F(SectionTest, TestBadFdRequest) {
    277     FileSection fs(NOOP_PARSER, tf.path);
    278     ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
    279 
    280     IncidentReportArgs args;
    281     args.setAll(true);
    282     args.setPrivacyPolicy(0);
    283     sp<ReportRequest> badFdRequest = new ReportRequest(args, new SimpleListener(), 1234567);
    284 
    285     vector<sp<ReportRequest>> requests;
    286     requests.push_back(badFdRequest);
    287     ReportRequestSet requestSet(requests);
    288     requestSet.setMainFd(STDOUT_FILENO);
    289 
    290     CaptureStdout();
    291     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    292     EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2));
    293     EXPECT_EQ(badFdRequest->err, -EBADF);
    294 }
    295 
    296 TEST_F(SectionTest, TestBadRequests) {
    297     FileSection fs(NOOP_PARSER, tf.path);
    298     ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
    299 
    300     IncidentReportArgs args;
    301     args.setAll(true);
    302     args.setPrivacyPolicy(0);
    303 
    304     vector<sp<ReportRequest>> requests;
    305     requests.push_back(new ReportRequest(args, new SimpleListener(), -1));
    306     ReportRequestSet requestSet(requests);
    307 
    308     EXPECT_EQ(fs.Execute(&requestSet), -EBADF);
    309 }
    310 
    311 TEST_F(SectionTest, TestMultipleRequests) {
    312     TemporaryFile output1, output2, output3;
    313     FileSection fs(NOOP_PARSER, tf.path);
    314 
    315     ASSERT_TRUE(output1.fd != -1);
    316     ASSERT_TRUE(output2.fd != -1);
    317     ASSERT_TRUE(output3.fd != -1);
    318     ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
    319 
    320     IncidentReportArgs args1, args2, args3;
    321     args1.setAll(true);
    322     args1.setPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL);
    323     args2.setAll(true);
    324     args2.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT);
    325     sp<SimpleListener> l = new SimpleListener();
    326 
    327     vector<sp<ReportRequest>> requests;
    328     requests.push_back(new ReportRequest(args1, l, output1.fd));
    329     requests.push_back(new ReportRequest(args2, l, output2.fd));
    330     requests.push_back(new ReportRequest(args3, l, output3.fd));
    331     ReportRequestSet requestSet(requests);
    332     requestSet.setMainFd(STDOUT_FILENO);
    333 
    334     CaptureStdout();
    335     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    336     EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2));
    337 
    338     std::string content, expect;
    339     expect = VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3;
    340     char c = (char)expect.size();
    341     EXPECT_TRUE(ReadFileToString(output1.path, &content));
    342     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
    343 
    344     expect = STRING_FIELD_2 + FIX64_FIELD_3;
    345     c = (char)expect.size();
    346     EXPECT_TRUE(ReadFileToString(output2.path, &content));
    347     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
    348 
    349     // because args3 doesn't set section, so it should receive nothing
    350     EXPECT_TRUE(ReadFileToString(output3.path, &content));
    351     EXPECT_THAT(content, StrEq(""));
    352 }
    353 
    354 TEST_F(SectionTest, TestMultipleRequestsBySpec) {
    355     TemporaryFile output1, output2, output3;
    356     FileSection fs(NOOP_PARSER, tf.path);
    357 
    358     ASSERT_TRUE(output1.fd != -1);
    359     ASSERT_TRUE(output2.fd != -1);
    360     ASSERT_TRUE(output3.fd != -1);
    361 
    362     ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
    363 
    364     IncidentReportArgs args1, args2, args3;
    365     args1.setAll(true);
    366     args1.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT);
    367     args2.setAll(true);
    368     args2.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT);
    369     args3.setAll(true);
    370     sp<SimpleListener> l = new SimpleListener();
    371 
    372     vector<sp<ReportRequest>> requests;
    373     requests.push_back(new ReportRequest(args1, l, output1.fd));
    374     requests.push_back(new ReportRequest(args2, l, output2.fd));
    375     requests.push_back(new ReportRequest(args3, l, output3.fd));
    376     ReportRequestSet requestSet(requests);
    377     requestSet.setMainFd(STDOUT_FILENO);
    378 
    379     CaptureStdout();
    380     ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet));
    381     EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2));
    382 
    383     std::string content, expect;
    384     expect = STRING_FIELD_2 + FIX64_FIELD_3;
    385     char c = (char)expect.size();
    386 
    387     // output1 and output2 are the same
    388     EXPECT_TRUE(ReadFileToString(output1.path, &content));
    389     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
    390     EXPECT_TRUE(ReadFileToString(output2.path, &content));
    391     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
    392 
    393     // output3 has only auto field
    394     c = (char)STRING_FIELD_2.size();
    395     EXPECT_TRUE(ReadFileToString(output3.path, &content));
    396     EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
    397 }
    398 */
    399