Merge "Perfprofd: Fix tests"
diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc
index 8b49f89..cc0d32f 100644
--- a/perfprofd/tests/perfprofd_test.cc
+++ b/perfprofd/tests/perfprofd_test.cc
@@ -14,18 +14,24 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
 #include <algorithm>
 #include <cctype>
-#include <string>
+#include <memory>
 #include <regex>
+#include <string>
+
+#include <fcntl.h>
 #include <stdio.h>
+#include <libgen.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
 
+#include <android-base/file.h>
+#include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
 
 #include "config.h"
 #include "configreader.h"
@@ -39,18 +45,7 @@
 //
 // Set to argv[0] on startup
 //
-static const char *executable_path;
-
-//
-// test_dir is the directory containing the test executable and
-// any files associated with the test (will be created by the harness).
-//
-// dest_dir is a subdirectory of test_dir that we'll create on the fly
-// at the start of each testpoint (into which new files can be written),
-// then delete at end of testpoint.
-//
-static std::string test_dir;
-static std::string dest_dir;
+static std::string gExecutableRealpath;
 
 // Path to perf executable on device
 #define PERFPATH "/system/bin/perf"
@@ -58,59 +53,49 @@
 // Temporary config file that we will emit for the daemon to read
 #define CONFIGFILE "perfprofd.conf"
 
-static std::string encoded_file_path(int seq)
-{
-  return android::base::StringPrintf("%s/perf.data.encoded.%d",
-                                     dest_dir.c_str(), seq);
-}
-
 class PerfProfdTest : public testing::Test {
  protected:
   virtual void SetUp() {
     mock_perfprofdutils_init();
-    create_dest_dir();
-    yesclean();
+    create_dirs();
   }
 
   virtual void TearDown() {
     mock_perfprofdutils_finish();
+
+    // TODO: proper management of test files. For now, use old system() code.
+    for (const auto dir : { &dest_dir, &conf_dir }) {
+      std::string cmd("rm -rf ");
+      cmd += *dir;
+      int ret = system(cmd.c_str());
+      CHECK_EQ(0, ret);
+    }
   }
 
-  void noclean() {
-    clean_ = false;
-  }
-  void yesclean() {
-    clean_ = true;
-  }
+ protected:
+  // test_dir is the directory containing the test executable and
+  // any files associated with the test (will be created by the harness).
+  std::string test_dir;
+
+  // dest_dir is a temporary directory that we're using as the destination directory.
+  // It is backed by temp_dir1.
+  std::string dest_dir;
+
+  // conf_dir is a temporary directory that we're using as the configuration directory.
+  // It is backed by temp_dir2.
+  std::string conf_dir;
 
  private:
-  bool clean_;
-
-  void create_dest_dir() {
-    setup_dirs();
-    ASSERT_FALSE(dest_dir == "");
-    if (clean_) {
-      std::string cmd("rm -rf ");
-      cmd += dest_dir;
-      system(cmd.c_str());
-    }
-    std::string cmd("mkdir -p ");
-    cmd += dest_dir;
-    system(cmd.c_str());
+  void create_dirs() {
+    temp_dir1.reset(new TemporaryDir());
+    temp_dir2.reset(new TemporaryDir());
+    dest_dir = temp_dir1->path;
+    conf_dir = temp_dir2->path;
+    test_dir = android::base::Dirname(gExecutableRealpath);
   }
 
-  void setup_dirs()
-  {
-    if (test_dir == "") {
-      ASSERT_TRUE(executable_path != nullptr);
-      std::string s(executable_path);
-      auto found = s.find_last_of('/');
-      test_dir = s.substr(0,found);
-      dest_dir = test_dir;
-      dest_dir += "/tmp";
-    }
-  }
-
+  std::unique_ptr<TemporaryDir> temp_dir1;
+  std::unique_ptr<TemporaryDir> temp_dir2;
 };
 
 static bool bothWhiteSpace(char lhs, char rhs)
@@ -175,10 +160,10 @@
 ///
 class PerfProfdRunner {
  public:
-  PerfProfdRunner()
-      : config_path_(test_dir)
+  explicit PerfProfdRunner(const std::string& config_dir)
+      : config_dir_(config_dir)
   {
-    config_path_ += "/" CONFIGFILE;
+    config_path_ = config_dir + "/" CONFIGFILE;
   }
 
   ~PerfProfdRunner()
@@ -194,21 +179,21 @@
 
   void remove_semaphore_file()
   {
-    std::string semaphore(test_dir);
+    std::string semaphore(config_dir_);
     semaphore += "/" SEMAPHORE_FILENAME;
     unlink(semaphore.c_str());
   }
 
   void create_semaphore_file()
   {
-    std::string semaphore(test_dir);
+    std::string semaphore(config_dir_);
     semaphore += "/" SEMAPHORE_FILENAME;
     close(open(semaphore.c_str(), O_WRONLY|O_CREAT, 0600));
   }
 
   void write_processed_file(int start_seq, int end_seq)
   {
-    std::string processed = test_dir + "/" PROCESSED_FILENAME;
+    std::string processed = config_dir_ + "/" PROCESSED_FILENAME;
     FILE *fp = fopen(processed.c_str(), "w");
     for (int i = start_seq; i < end_seq; i++) {
       fprintf(fp, "%d\n", i);
@@ -218,7 +203,7 @@
 
   void remove_processed_file()
   {
-    std::string processed = test_dir + "/" PROCESSED_FILENAME;
+    std::string processed = config_dir_ + "/" PROCESSED_FILENAME;
     unlink(processed.c_str());
   }
 
@@ -262,6 +247,7 @@
   }
 
  private:
+  std::string config_dir_;
   std::string config_path_;
   std::string config_text_;
 
@@ -277,17 +263,24 @@
 
 //......................................................................
 
-static void readEncodedProfile(const char *testpoint,
+static std::string encoded_file_path(const std::string& dest_dir,
+                                     int seq) {
+  return android::base::StringPrintf("%s/perf.data.encoded.%d",
+                                     dest_dir.c_str(), seq);
+}
+
+static void readEncodedProfile(const std::string& dest_dir,
+                               const char *testpoint,
                                wireless_android_play_playlog::AndroidPerfProfile &encodedProfile)
 {
   struct stat statb;
-  int perf_data_stat_result = stat(encoded_file_path(0).c_str(), &statb);
+  int perf_data_stat_result = stat(encoded_file_path(dest_dir, 0).c_str(), &statb);
   ASSERT_NE(-1, perf_data_stat_result);
 
   // read
   std::string encoded;
   encoded.resize(statb.st_size);
-  FILE *ifp = fopen(encoded_file_path(0).c_str(), "r");
+  FILE *ifp = fopen(encoded_file_path(dest_dir, 0).c_str(), "r");
   ASSERT_NE(nullptr, ifp);
   size_t items_read = fread((void*) encoded.data(), statb.st_size, 1, ifp);
   ASSERT_EQ(1, items_read);
@@ -374,7 +367,7 @@
   // may not be there. This test insures that the daemon does the
   // right thing in this case.
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
   runner.addToConfig("trace_config_read=0");
   runner.addToConfig("config_directory=/does/not/exist");
@@ -410,9 +403,9 @@
   // passes, then it creates a semaphore file for the daemon to pick
   // up on.
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
@@ -445,10 +438,10 @@
   // checks to make sure that if 'simpleperf' is not present we bail out
   // from collecting profiles.
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
   runner.addToConfig("trace_config_read=1");
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
@@ -483,9 +476,9 @@
   // crash. This test makes sure that we detect such a case and log
   // the error.
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
@@ -518,7 +511,7 @@
   //
   // Gracefully handly malformed items in the config file
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
   runner.addToConfig("main_loop_iterations=1");
   runner.addToConfig("collection_interval=100");
@@ -587,12 +580,13 @@
 
   // Kick off encoder and check return code
   PROFILE_RESULT result =
-      encode_to_proto(input_perf_data, encoded_file_path(0).c_str(), config, 0);
+      encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0);
   EXPECT_EQ(OK_PROFILE_COLLECTION, result);
 
   // Read and decode the resulting perf.data.encoded file
   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
-  readEncodedProfile("BasicRunWithCannedPerf",
+  readEncodedProfile(dest_dir,
+                     "BasicRunWithCannedPerf",
                      encodedProfile);
 
   // Expect 45 programs
@@ -661,12 +655,13 @@
 
   // Kick off encoder and check return code
   PROFILE_RESULT result =
-      encode_to_proto(input_perf_data, encoded_file_path(0).c_str(), config, 0);
+      encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0);
   EXPECT_EQ(OK_PROFILE_COLLECTION, result);
 
   // Read and decode the resulting perf.data.encoded file
   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
-  readEncodedProfile("BasicRunWithCannedPerf",
+  readEncodedProfile(dest_dir,
+                     "BasicRunWithCannedPerf",
                      encodedProfile);
 
 
@@ -726,11 +721,11 @@
   // Basic test to exercise the main loop of the daemon. It includes
   // a live 'perf' run
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   runner.addToConfig("main_loop_iterations=1");
   runner.addToConfig("use_fixed_seed=12345678");
@@ -749,16 +744,17 @@
 
   // Read and decode the resulting perf.data.encoded file
   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
-  readEncodedProfile("BasicRunWithLivePerf", encodedProfile);
+  readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile);
 
   // Examine what we get back. Since it's a live profile, we can't
   // really do much in terms of verifying the contents.
   EXPECT_LT(0, encodedProfile.programs_size());
 
   // Verify log contents
-  const std::string expected = RAW_RESULT(
-      I: starting Android Wide Profiling daemon
-      I: config file path set to $NATIVE_TESTS/perfprofd_test/perfprofd.conf
+  const std::string expected = std::string(
+      "I: starting Android Wide Profiling daemon ") +
+      "I: config file path set to " + conf_dir + "/perfprofd.conf " +
+      RAW_RESULT(
       I: random seed set to 12345678
       I: sleep 674 seconds
       I: initiating profile collection
@@ -778,11 +774,11 @@
   // Basic test to exercise the main loop of the daemon. It includes
   // a live 'perf' run
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   runner.addToConfig("only_debug_build=0");
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   runner.addToConfig("main_loop_iterations=3");
   runner.addToConfig("use_fixed_seed=12345678");
@@ -801,21 +797,22 @@
 
   // Read and decode the resulting perf.data.encoded file
   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
-  readEncodedProfile("BasicRunWithLivePerf", encodedProfile);
+  readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile);
 
   // Examine what we get back. Since it's a live profile, we can't
   // really do much in terms of verifying the contents.
   EXPECT_LT(0, encodedProfile.programs_size());
 
   // Examine that encoded.1 file is removed while encoded.{0|2} exists.
-  EXPECT_EQ(0, access(encoded_file_path(0).c_str(), F_OK));
-  EXPECT_NE(0, access(encoded_file_path(1).c_str(), F_OK));
-  EXPECT_EQ(0, access(encoded_file_path(2).c_str(), F_OK));
+  EXPECT_EQ(0, access(encoded_file_path(dest_dir, 0).c_str(), F_OK));
+  EXPECT_NE(0, access(encoded_file_path(dest_dir, 1).c_str(), F_OK));
+  EXPECT_EQ(0, access(encoded_file_path(dest_dir, 2).c_str(), F_OK));
 
   // Verify log contents
-  const std::string expected = RAW_RESULT(
-      I: starting Android Wide Profiling daemon
-      I: config file path set to $NATIVE_TESTS/perfprofd_test/perfprofd.conf
+  const std::string expected = std::string(
+      "I: starting Android Wide Profiling daemon ") +
+      "I: config file path set to " + conf_dir + "/perfprofd.conf " +
+      RAW_RESULT(
       I: random seed set to 12345678
       I: sleep 674 seconds
       I: initiating profile collection
@@ -845,10 +842,10 @@
   // Collect a callchain profile, so as to exercise the code in
   // perf_data post-processing that digests callchains.
   //
-  PerfProfdRunner runner;
+  PerfProfdRunner runner(conf_dir);
   std::string ddparam("destination_directory="); ddparam += dest_dir;
   runner.addToConfig(ddparam);
-  std::string cfparam("config_directory="); cfparam += test_dir;
+  std::string cfparam("config_directory="); cfparam += conf_dir;
   runner.addToConfig(cfparam);
   runner.addToConfig("main_loop_iterations=1");
   runner.addToConfig("use_fixed_seed=12345678");
@@ -868,16 +865,17 @@
 
   // Read and decode the resulting perf.data.encoded file
   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
-  readEncodedProfile("CallChainRunWithLivePerf", encodedProfile);
+  readEncodedProfile(dest_dir, "CallChainRunWithLivePerf", encodedProfile);
 
   // Examine what we get back. Since it's a live profile, we can't
   // really do much in terms of verifying the contents.
   EXPECT_LT(0, encodedProfile.programs_size());
 
   // Verify log contents
-  const std::string expected = RAW_RESULT(
-      I: starting Android Wide Profiling daemon
-      I: config file path set to $NATIVE_TESTS/perfprofd_test/perfprofd.conf
+  const std::string expected = std::string(
+      "I: starting Android Wide Profiling daemon ") +
+      "I: config file path set to " + conf_dir + "/perfprofd.conf " +
+      RAW_RESULT(
       I: random seed set to 12345678
       I: sleep 674 seconds
       I: initiating profile collection
@@ -892,7 +890,11 @@
 }
 
 int main(int argc, char **argv) {
-  executable_path = argv[0];
+  // Always log to cerr, so that device failures are visible.
+  android::base::SetLogger(android::base::StderrLogger);
+
+  CHECK(android::base::Realpath(argv[0], &gExecutableRealpath));
+
   // switch to / before starting testing (perfprofd
   // should be location-independent)
   chdir("/");