From 06078a2767fc196d8d89d0c469815796c51a6ffe Mon Sep 17 00:00:00 2001 From: "nileshagrawal@chromium.org" Date: Sat, 9 Feb 2013 02:45:32 +0000 Subject: [PATCH] Android: Refactor native test setup in a util class. This is also needed by content_browsertests. Also redirecting stdout,stderr for content_browsertests to a fifo file to be read by the test runner scripts. BUG=138275 TBR=jam@chromium.org Review URL: https://chromiumcodereview.appspot.com/12213035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@181587 0039d316-1c4b-4281-b951-d872f2087c98 --- content/content_tests.gypi | 1 + .../content_browser_tests_android.cc | 69 ++++-------- testing/android/native_test.gyp | 12 +++ testing/android/native_test_launcher.cc | 102 +++--------------- testing/android/native_test_util.cc | 90 ++++++++++++++++ testing/android/native_test_util.h | 41 +++++++ 6 files changed, 179 insertions(+), 136 deletions(-) create mode 100644 testing/android/native_test_util.cc create mode 100644 testing/android/native_test_util.h diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 932bba6e5992ea..0f4434b367e008 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -843,6 +843,7 @@ 'dependencies': [ 'content_shell_jni_headers', 'content_shell_lib', + '../testing/android/native_test.gyp:native_test_util', ], }], ['OS=="mac"', { diff --git a/content/shell/android/browsertests_apk/content_browser_tests_android.cc b/content/shell/android/browsertests_apk/content_browser_tests_android.cc index e2313ba8ae2a34..48b73e9fc2e971 100644 --- a/content/shell/android/browsertests_apk/content_browser_tests_android.cc +++ b/content/shell/android/browsertests_apk/content_browser_tests_android.cc @@ -22,60 +22,23 @@ #include "content/public/app/android_library_loader_hooks.h" #include "content/shell/android/shell_jni_registrar.h" #include "jni/ContentBrowserTestsActivity_jni.h" +#include "testing/android/native_test_util.h" + +using testing::native_test_util::ArgsToArgv; +using testing::native_test_util::CreateFIFO; +using testing::native_test_util::ParseArgsFromCommandLineFile; +using testing::native_test_util::RedirectStream; +using testing::native_test_util::ScopedMainEntryLogger; // The main function of the program to be wrapped as an apk. extern int main(int argc, char** argv); namespace { -void ParseArgsFromString(const std::string& command_line, - std::vector* args) { - base::StringTokenizer tokenizer(command_line, kWhitespaceASCII); - tokenizer.set_quote_chars("\""); - while (tokenizer.GetNext()) { - std::string token; - RemoveChars(tokenizer.token(), "\"", &token); - args->push_back(token); - } -} - -void ParseArgsFromCommandLineFile(std::vector* args) { - // The test runner script writes the command line file in - // "/data/local/tmp". - static const char kCommandLineFilePath[] = - "/data/local/tmp/content-browser-tests-command-line"; - base::FilePath command_line(kCommandLineFilePath); - std::string command_line_string; - if (file_util::ReadFileToString(command_line, &command_line_string)) { - ParseArgsFromString(command_line_string, args); - } -} - -int ArgsToArgv(const std::vector& args, - std::vector* argv) { - // We need to pass in a non-const char**. - int argc = args.size(); - - argv->resize(argc + 1); - for (int i = 0; i < argc; ++i) - (*argv)[i] = const_cast(args[i].c_str()); - (*argv)[argc] = NULL; // argv must be NULL terminated. - - return argc; -} - -class ScopedMainEntryLogger { - public: - ScopedMainEntryLogger() { - printf(">>ScopedMainEntryLogger\n"); - } - - ~ScopedMainEntryLogger() { - printf("< args; - ParseArgsFromCommandLineFile(&args); + ParseArgsFromCommandLineFile(kCommandLineFilePath, &args); - // We need to pass in a non-const char**. std::vector argv; int argc = ArgsToArgv(args, &argv); @@ -105,6 +67,13 @@ static void RunTests(JNIEnv* env, CommandLine::ForCurrentProcess()->AppendArguments( CommandLine(argc, &argv[0]), false); + // Create fifo and redirect stdout and stderr to it. + FilePath files_dir(base::android::ConvertJavaStringToUTF8(env, jfiles_dir)); + FilePath fifo_path(files_dir.Append(FilePath("test.fifo"))); + CreateFIFO(fifo_path.value().c_str()); + RedirectStream(stdout, fifo_path.value().c_str(), "w"); + dup2(STDOUT_FILENO, STDERR_FILENO); + ScopedMainEntryLogger scoped_main_entry_logger; main(argc, &argv[0]); } diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp index 06f72793f509bd..ebf0b42413ce2e 100644 --- a/testing/android/native_test.gyp +++ b/testing/android/native_test.gyp @@ -69,6 +69,7 @@ '../../base/base.gyp:test_support_base', '../gtest.gyp:gtest', 'native_test_jni_headers', + 'native_test_util', ], }, { @@ -89,6 +90,17 @@ ], }, }, + { + 'target_name': 'native_test_util', + 'type': 'static_library', + 'sources': [ + 'native_test_util.cc', + 'native_test_util.h', + ], + 'dependencies': [ + '../../base/base.gyp:base', + ], + }, ], }] ], diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc index e3cf59eeca7958..68bb5d100eb98b 100644 --- a/testing/android/native_test_launcher.cc +++ b/testing/android/native_test_launcher.cc @@ -11,27 +11,27 @@ #include #include -#include -#include #include "base/android/base_jni_registrar.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" -#include "base/android/locale_utils.h" -#include "base/android/path_utils.h" #include "base/android/scoped_java_ref.h" #include "base/at_exit.h" #include "base/base_switches.h" #include "base/command_line.h" #include "base/file_path.h" -#include "base/file_util.h" #include "base/logging.h" -#include "base/string_util.h" #include "base/stringprintf.h" -#include "base/strings/string_tokenizer.h" #include "gtest/gtest.h" +#include "testing/android/native_test_util.h" #include "testing/jni/ChromeNativeTestActivity_jni.h" +using testing::native_test_util::ArgsToArgv; +using testing::native_test_util::CreateFIFO; +using testing::native_test_util::ParseArgsFromCommandLineFile; +using testing::native_test_util::RedirectStream; +using testing::native_test_util::ScopedMainEntryLogger; + // The main function of the program to be wrapped as a test apk. extern int main(int argc, char** argv); @@ -42,16 +42,14 @@ namespace { const char kSeparateStderrFifo[] = "separate-stderr-fifo"; const char kCreateStdinFifo[] = "create-stdin-fifo"; +// The test runner script writes the command line file in +// "/data/local/tmp". +static const char kCommandLineFilePath[] = + "/data/local/tmp/chrome-native-tests-command-line"; + const char kLogTag[] = "chromium"; const char kCrashedMarker[] = "[ CRASHED ]\n"; -void AndroidLogError(const char* format, ...) { - va_list args; - va_start(args, format); - __android_log_vprint(ANDROID_LOG_ERROR, kLogTag, format, args); - va_end(args); -} - // The list of signals which are considered to be crashes. const int kExceptionSignals[] = { SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1 @@ -80,73 +78,6 @@ void InstallHandlers() { } } -void ParseArgsFromString(const std::string& command_line, - std::vector* args) { - base::StringTokenizer tokenizer(command_line, kWhitespaceASCII); - tokenizer.set_quote_chars("\""); - while (tokenizer.GetNext()) { - std::string token; - RemoveChars(tokenizer.token(), "\"", &token); - args->push_back(token); - } -} - -void ParseArgsFromCommandLineFile(std::vector* args) { - // The test runner script writes the command line file in - // "/data/local/tmp". - static const char kCommandLineFilePath[] = - "/data/local/tmp/chrome-native-tests-command-line"; - FilePath command_line(kCommandLineFilePath); - std::string command_line_string; - if (file_util::ReadFileToString(command_line, &command_line_string)) { - ParseArgsFromString(command_line_string, args); - } -} - -int ArgsToArgv(const std::vector& args, - std::vector* argv) { - // We need to pass in a non-const char**. - int argc = args.size(); - - argv->resize(argc + 1); - for (int i = 0; i < argc; ++i) - (*argv)[i] = const_cast(args[i].c_str()); - (*argv)[argc] = NULL; // argv must be NULL terminated. - - return argc; -} - -void CreateFIFO(const char* fifo_path) { - unlink(fifo_path); - // Default permissions for mkfifo is ignored, chmod is required. - if (mkfifo(fifo_path, 0666) || chmod(fifo_path, 0666)) { - AndroidLogError("Failed to create fifo %s: %s\n", - fifo_path, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -void Redirect(FILE* stream, const char* path, const char* mode) { - if (!freopen(path, mode, stream)) { - AndroidLogError("Failed to redirect stream to file: %s: %s\n", - path, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -class ScopedMainEntryLogger { - public: - ScopedMainEntryLogger() { - printf(">>ScopedMainEntryLogger\n"); - } - - ~ScopedMainEntryLogger() { - printf("< args; - ParseArgsFromCommandLineFile(&args); + ParseArgsFromCommandLineFile(kCommandLineFilePath, &args); - // We need to pass in a non-const char**. std::vector argv; int argc = ArgsToArgv(args, &argv); @@ -202,11 +132,11 @@ static void RunTests(JNIEnv* env, } // Only redirect the streams after all fifos have been created. - Redirect(stdout, fifo_path.value().c_str(), "w"); + RedirectStream(stdout, fifo_path.value().c_str(), "w"); if (!stdin_fifo_path.empty()) - Redirect(stdin, stdin_fifo_path.value().c_str(), "r"); + RedirectStream(stdin, stdin_fifo_path.value().c_str(), "r"); if (!stderr_fifo_path.empty()) - Redirect(stderr, stderr_fifo_path.value().c_str(), "w"); + RedirectStream(stderr, stderr_fifo_path.value().c_str(), "w"); else dup2(STDOUT_FILENO, STDERR_FILENO); diff --git a/testing/android/native_test_util.cc b/testing/android/native_test_util.cc new file mode 100644 index 00000000000000..08f901b6418354 --- /dev/null +++ b/testing/android/native_test_util.cc @@ -0,0 +1,90 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/android/native_test_util.h" + +#include +#include +#include +#include +#include +#include + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/string_util.h" +#include "base/strings/string_tokenizer.h" + +namespace { + +const char kLogTag[] = "chromium"; + +void AndroidLogError(const char* format, ...) { + va_list args; + va_start(args, format); + __android_log_vprint(ANDROID_LOG_ERROR, kLogTag, format, args); + va_end(args); +} + +void ParseArgsFromString(const std::string& command_line, + std::vector* args) { + base::StringTokenizer tokenizer(command_line, kWhitespaceASCII); + tokenizer.set_quote_chars("\""); + while (tokenizer.GetNext()) { + std::string token; + RemoveChars(tokenizer.token(), "\"", &token); + args->push_back(token); + } +} + +} // namespace + +namespace testing { +namespace native_test_util { + +void CreateFIFO(const char* fifo_path) { + unlink(fifo_path); + // Default permissions for mkfifo is ignored, chmod is required. + if (mkfifo(fifo_path, 0666) || chmod(fifo_path, 0666)) { + AndroidLogError("Failed to create fifo %s: %s\n", + fifo_path, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +void RedirectStream( + FILE* stream, const char* path, const char* mode) { + if (!freopen(path, mode, stream)) { + AndroidLogError("Failed to redirect stream to file: %s: %s\n", + path, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +void ParseArgsFromCommandLineFile( + const char* path, std::vector* args) { + base::FilePath command_line(path); + std::string command_line_string; + if (file_util::ReadFileToString(command_line, &command_line_string)) { + ParseArgsFromString(command_line_string, args); + } +} + +int ArgsToArgv(const std::vector& args, + std::vector* argv) { + // We need to pass in a non-const char**. + int argc = args.size(); + + argv->resize(argc + 1); + for (int i = 0; i < argc; ++i) { + (*argv)[i] = const_cast(args[i].c_str()); + } + (*argv)[argc] = NULL; // argv must be NULL terminated. + + return argc; +} + +} // namespace native_test_util +} // namespace testing diff --git a/testing/android/native_test_util.h b/testing/android/native_test_util.h new file mode 100644 index 00000000000000..4e40222fdec7db --- /dev/null +++ b/testing/android/native_test_util.h @@ -0,0 +1,41 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TESTING_ANDROID_NATIVE_TEST_UTIL_ +#define TESTING_ANDROID_NATIVE_TEST_UTIL_ + +#include +#include +#include + +// Helper methods for setting up environment for running gtest tests +// inside an APK. +namespace testing { +namespace native_test_util { + +class ScopedMainEntryLogger { + public: + ScopedMainEntryLogger() { + printf(">>ScopedMainEntryLogger\n"); + } + + ~ScopedMainEntryLogger() { + printf("<* args); +int ArgsToArgv(const std::vector& args, std::vector* argv); + +} // namespace native_test_util +} // namespace testing + +#endif // TESTING_ANDROID_NATIVE_TEST_UTIL_