Add tests for reporter class

Test: Add test for Reporter class
Change-Id: Ic1d87a26dd4b8271bab7b03374c7a1d4d7b87f92
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 7c6789e..c4b54bb 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -153,7 +153,6 @@
             break;
         }
         reporter->batch.add(request);
-        reporter->args.merge(request->args);
     }
 
     // Take the report, which might take a while. More requests might queue
@@ -235,7 +234,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                 "Only system uid can call systemRunning");
     }
-    
+
     // When system_server is up and running, schedule the dropbox task to run.
     mHandler->scheduleSendBacklogToDropbox();
 
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 2a4f89e..ea73bcd 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -35,7 +35,7 @@
 /**
  * The directory where the incident reports are stored.
  */
-static const String8 INCIDENT_DIRECTORY("/data/misc/incidents");
+static const char* INCIDENT_DIRECTORY = "/data/misc/incidents/";
 
 // ================================================================================
 static status_t write_all(int fd, uint8_t const* buf, size_t size)
@@ -68,6 +68,7 @@
 // ================================================================================
 ReportRequestSet::ReportRequestSet()
     :mRequests(),
+     mSections(),
      mWritableCount(0),
      mMainFd(-1)
 {
@@ -77,10 +78,12 @@
 {
 }
 
+// TODO: dedup on exact same args and fd, report the status back to listener!
 void
 ReportRequestSet::add(const sp<ReportRequest>& request)
 {
     mRequests.push_back(request);
+    mSections.merge(request->args);
     mWritableCount++;
 }
 
@@ -122,11 +125,16 @@
     return mWritableCount > 0 ? NO_ERROR : err;
 }
 
+bool
+ReportRequestSet::containsSection(int id) {
+    return mSections.containsSection(id);
+}
 
 // ================================================================================
-Reporter::Reporter()
-    :args(),
-     batch()
+Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
+
+Reporter::Reporter(const char* directory)
+    :batch()
 {
     char buf[100];
 
@@ -134,10 +142,15 @@
     mMaxSize = 100 * 1024 * 1024;
     mMaxCount = 100;
 
+    // string ends up with '/' is a directory
+    String8 dir = String8(directory);
+    if (directory[dir.size() - 1] != '/') dir += "/";
+    mIncidentDirectory = dir.string();
+
     // There can't be two at the same time because it's on one thread.
     mStartTime = time(NULL);
-    strftime(buf, sizeof(buf), "/incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
-    mFilename = INCIDENT_DIRECTORY + buf;
+    strftime(buf, sizeof(buf), "incident-%Y%m%d-%H%M%S", localtime(&mStartTime));
+    mFilename = mIncidentDirectory + buf;
 }
 
 Reporter::~Reporter()
@@ -161,7 +174,7 @@
     }
     if (needMainFd) {
         // Create the directory
-        err = create_directory(INCIDENT_DIRECTORY);
+        if (!isTest) err = create_directory(mIncidentDirectory);
         if (err != NO_ERROR) {
             goto done;
         }
@@ -169,7 +182,7 @@
         // If there are too many files in the directory (for whatever reason),
         // delete the oldest ones until it's under the limit. Doing this first
         // does mean that we can go over, so the max size is not a hard limit.
-        clean_directory(INCIDENT_DIRECTORY, mMaxSize, mMaxCount);
+        if (!isTest) clean_directory(mIncidentDirectory, mMaxSize, mMaxCount);
 
         // Open the file.
         err = create_file(&mainFd);
@@ -214,7 +227,7 @@
         const int id = (*section)->id;
         ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
 
-        if (this->args.containsSection(id)) {
+        if (this->batch.containsSection(id)) {
             // Notify listener of starting
             for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
                 if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
@@ -270,7 +283,7 @@
         // If the status was ok, delete the file. If not, leave it around until the next
         // boot or the next checkin. If the directory gets too big older files will
         // be rotated out.
-        unlink(mFilename.c_str());
+        if(!isTest) unlink(mFilename.c_str());
     }
 
     return REPORT_FINISHED;
@@ -284,7 +297,7 @@
 {
     const char* filename = mFilename.c_str();
 
-    *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0660);
+    *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
     if (*fd < 0) {
         ALOGE("Couldn't open incident file: %s (%s)", filename, strerror(errno));
         return -errno;
@@ -303,20 +316,24 @@
     return NO_ERROR;
 }
 
-// ================================================================================
 Reporter::run_report_status_t
 Reporter::upload_backlog()
 {
     DIR* dir;
     struct dirent* entry;
     struct stat st;
+    status_t err;
 
-    if ((dir = opendir(INCIDENT_DIRECTORY.string())) == NULL) {
-        ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY.string());
+    if ((err = create_directory(INCIDENT_DIRECTORY)) != NO_ERROR) {
+        ALOGE("directory doesn't exist: %s", strerror(-err));
+        return REPORT_FINISHED;
+    }
+
+    if ((dir = opendir(INCIDENT_DIRECTORY)) == NULL) {
+        ALOGE("Couldn't open incident directory: %s", INCIDENT_DIRECTORY);
         return REPORT_NEEDS_DROPBOX;
     }
 
-    String8 dirbase(INCIDENT_DIRECTORY + "/");
     sp<DropBoxManager> dropbox = new DropBoxManager();
 
     // Enumerate, count and add up size
@@ -324,7 +341,7 @@
         if (entry->d_name[0] == '.') {
             continue;
         }
-        String8 filename = dirbase + entry->d_name;
+        String8 filename = String8(INCIDENT_DIRECTORY) + entry->d_name;
         if (stat(filename.string(), &st) != 0) {
             ALOGE("Unable to stat file %s", filename.string());
             continue;
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 5b86561..509611c 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -62,8 +62,10 @@
     iterator begin() { return mRequests.begin(); }
     iterator end() { return mRequests.end(); }
 
+    bool containsSection(int id);
 private:
     vector<sp<ReportRequest>> mRequests;
+    IncidentReportArgs mSections;
     int mWritableCount;
     int mMainFd;
 };
@@ -77,10 +79,10 @@
         REPORT_NEEDS_DROPBOX = 1
     };
 
-    IncidentReportArgs args;
     ReportRequestSet batch;
 
     Reporter();
+    Reporter(const char* directory);
     virtual ~Reporter();
 
     // Run the report as described in the batch and args parameters.
@@ -89,12 +91,16 @@
     static run_report_status_t upload_backlog();
 
 private:
+    String8 mIncidentDirectory;
+
     string mFilename;
     off_t mMaxSize;
     size_t mMaxCount;
     time_t mStartTime;
 
     status_t create_file(int* fd);
+
+    bool isTest = true; // default to true for testing
 };
 
 
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 8ef6817..e3f2b36 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -424,7 +424,7 @@
     status_t cmdStatus = waitForChild(cmdPid);
     status_t ihStatus  = waitForChild(ihPid);
     if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
-        ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incidnet helper: %s",
+        ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident helper: %s",
             this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
         return cmdStatus != NO_ERROR ? cmdStatus : ihStatus;
     }
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index f60b8ac..110902c 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -129,7 +129,8 @@
         return;
     }
 
-    String8 dirbase(String8(directory) + "/");
+    String8 dirbase(directory);
+    if (directory[dirbase.size() - 1] != '/') dirbase += "/";
 
     off_t totalSize = 0;
     size_t totalCount = 0;