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