Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <gmock/gmock.h>
     18 #include <gtest/gtest.h>
     19 
     20 #include <fcntl.h>
     21 #include <libgen.h>
     22 
     23 #include <android-base/file.h>
     24 #include <cutils/properties.h>
     25 #include <ziparchive/zip_archive.h>
     26 
     27 #include "dumpstate.h"
     28 
     29 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
     30 
     31 namespace android {
     32 namespace os {
     33 namespace dumpstate {
     34 
     35 using ::testing::Test;
     36 using ::std::literals::chrono_literals::operator""s;
     37 
     38 struct SectionInfo {
     39     std::string name;
     40     status_t status;
     41     int32_t size_bytes;
     42     int32_t duration_ms;
     43 };
     44 
     45 /**
     46  * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
     47  * section details generated by dumpstate are added to a vector to be used by Tests later.
     48  */
     49 class DumpstateListener : public IDumpstateListener {
     50   public:
     51     int outFd_, max_progress_;
     52     std::shared_ptr<std::vector<SectionInfo>> sections_;
     53     DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
     54         : outFd_(fd), max_progress_(5000), sections_(sections) {
     55     }
     56     binder::Status onProgressUpdated(int32_t progress) override {
     57         dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
     58         return binder::Status::ok();
     59     }
     60     binder::Status onMaxProgressUpdated(int32_t max_progress) override {
     61         max_progress_ = max_progress;
     62         return binder::Status::ok();
     63     }
     64     binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
     65                                      int32_t duration_ms) override {
     66         sections_->push_back({name, status, size_bytes, duration_ms});
     67         return binder::Status::ok();
     68     }
     69     IBinder* onAsBinder() override {
     70         return nullptr;
     71     }
     72 };
     73 
     74 /**
     75  * Generates bug report and provide access to the bug report file and other info for other tests.
     76  * Since bug report generation is slow, the bugreport is only generated once.
     77  */
     78 class ZippedBugreportGenerationTest : public Test {
     79   public:
     80     static std::shared_ptr<std::vector<SectionInfo>> sections;
     81     static Dumpstate& ds;
     82     static std::chrono::milliseconds duration;
     83     static void SetUpTestCase() {
     84         property_set("dumpstate.options", "bugreportplus");
     85         // clang-format off
     86         char* argv[] = {
     87             (char*)"dumpstate",
     88             (char*)"-d",
     89             (char*)"-z",
     90             (char*)"-B",
     91             (char*)"-o",
     92             (char*)dirname(android::base::GetExecutablePath().c_str())
     93         };
     94         // clang-format on
     95         sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
     96         ds.listener_ = listener;
     97         ds.listener_name_ = "Smokey";
     98         ds.report_section_ = true;
     99         auto start = std::chrono::steady_clock::now();
    100         run_main(ARRAY_SIZE(argv), argv);
    101         auto end = std::chrono::steady_clock::now();
    102         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    103     }
    104 
    105     static const char* getZipFilePath() {
    106         return ds.GetPath(".zip").c_str();
    107     }
    108 };
    109 std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
    110     std::make_shared<std::vector<SectionInfo>>();
    111 Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance();
    112 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
    113 
    114 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
    115     EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
    116 }
    117 
    118 TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
    119     struct stat st;
    120     EXPECT_EQ(stat(getZipFilePath(), &st), 0);
    121     EXPECT_GE(st.st_size, 3000000 /* 3MB */);
    122     EXPECT_LE(st.st_size, 30000000 /* 30MB */);
    123 }
    124 
    125 TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
    126     EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
    127                              << duration.count() << " s.";
    128     EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
    129                               << duration.count() << " s.";
    130 }
    131 
    132 /**
    133  * Run tests on contents of zipped bug report.
    134  */
    135 class ZippedBugReportContentsTest : public Test {
    136   public:
    137     ZipArchiveHandle handle;
    138     void SetUp() {
    139         ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
    140     }
    141     void TearDown() {
    142         CloseArchive(handle);
    143     }
    144 
    145     void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
    146         ZipEntry entry;
    147         EXPECT_EQ(FindEntry(handle, ZipString(filename), &entry), 0);
    148         EXPECT_GT(entry.uncompressed_length, minsize);
    149         EXPECT_LT(entry.uncompressed_length, maxsize);
    150     }
    151 };
    152 
    153 TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
    154     ZipEntry mainEntryLoc;
    155     // contains main entry name file
    156     EXPECT_EQ(FindEntry(handle, ZipString("main_entry.txt"), &mainEntryLoc), 0);
    157 
    158     char* buf = new char[mainEntryLoc.uncompressed_length];
    159     ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length);
    160     delete[] buf;
    161 
    162     // contains main entry file
    163     FileExists(buf, 1000000U, 50000000U);
    164 }
    165 
    166 TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
    167     ZipEntry entry;
    168     // contains main entry name file
    169     EXPECT_EQ(FindEntry(handle, ZipString("version.txt"), &entry), 0);
    170 
    171     char* buf = new char[entry.uncompressed_length + 1];
    172     ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
    173     buf[entry.uncompressed_length] = 0;
    174     EXPECT_STREQ(buf, ZippedBugreportGenerationTest::ds.version_.c_str());
    175     delete[] buf;
    176 }
    177 
    178 TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
    179     FileExists("dumpstate_board.bin", 1000000U, 80000000U);
    180     FileExists("dumpstate_board.txt", 100000U, 1000000U);
    181 }
    182 
    183 // Spot check on some files pulled from the file system
    184 TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
    185     // FS/proc/*/mountinfo size > 0
    186     FileExists("FS/proc/1/mountinfo", 0U, 100000U);
    187 
    188     // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
    189     FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
    190 }
    191 
    192 /**
    193  * Runs tests on section data generated by dumpstate and captured by DumpstateListener.
    194  */
    195 class BugreportSectionTest : public Test {
    196   public:
    197     int numMatches(const std::string& substring) {
    198         int matches = 0;
    199         for (auto const& section : *ZippedBugreportGenerationTest::sections) {
    200             if (section.name.find(substring) != std::string::npos) {
    201                 matches++;
    202             }
    203         }
    204         return matches;
    205     }
    206     void SectionExists(const std::string& sectionName, int minsize) {
    207         for (auto const& section : *ZippedBugreportGenerationTest::sections) {
    208             if (sectionName == section.name) {
    209                 EXPECT_GE(section.size_bytes, minsize);
    210                 return;
    211             }
    212         }
    213         FAIL() << sectionName << " not found.";
    214     }
    215 };
    216 
    217 // Test all sections are generated without timeouts or errors
    218 TEST_F(BugreportSectionTest, GeneratedWithoutErrors) {
    219     for (auto const& section : *ZippedBugreportGenerationTest::sections) {
    220         EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status;
    221     }
    222 }
    223 
    224 TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
    225     int numSections = numMatches("DUMPSYS CRITICAL");
    226     EXPECT_GE(numSections, 3);
    227 }
    228 
    229 TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
    230     int numSections = numMatches("DUMPSYS HIGH");
    231     EXPECT_GE(numSections, 2);
    232 }
    233 
    234 TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
    235     int allSections = numMatches("DUMPSYS");
    236     int criticalSections = numMatches("DUMPSYS CRITICAL");
    237     int highSections = numMatches("DUMPSYS HIGH");
    238     int normalSections = allSections - criticalSections - highSections;
    239 
    240     EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
    241                                   << "High:" << highSections << "Normal:" << normalSections << ")";
    242 }
    243 
    244 TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) {
    245     int numSections = numMatches("proto/");
    246     EXPECT_GE(numSections, 1);
    247 }
    248 
    249 // Test if some critical sections are being generated.
    250 TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
    251     SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000);
    252 }
    253 
    254 TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
    255     SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000);
    256     SectionExists("DUMPSYS - activity", /* bytes= */ 10000);
    257 }
    258 
    259 TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
    260     SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000);
    261 }
    262 
    263 TEST_F(BugreportSectionTest, WindowSectionGenerated) {
    264     SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000);
    265 }
    266 
    267 TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
    268     SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000);
    269     SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000);
    270 }
    271 
    272 TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
    273     SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000);
    274 }
    275 
    276 TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
    277     SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000);
    278 }
    279 
    280 TEST_F(BugreportSectionTest, WifiSectionGenerated) {
    281     SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
    282 }
    283 
    284 }  // namespace dumpstate
    285 }  // namespace os
    286 }  // namespace android
    287