diff options
author | jbudorick <jbudorick@chromium.org> | 2014-11-10 15:14:15 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-10 23:14:42 +0000 |
commit | 42287bc6d09d1a402e866f751be7b8441c0de6a1 (patch) | |
tree | a96bc90008ea5f7948391f1a7cb9b995c3986e07 | |
parent | feeff71519070dddf09693c273bb4cd89c6168dc (diff) | |
download | chromium_src-42287bc6d09d1a402e866f751be7b8441c0de6a1.zip chromium_src-42287bc6d09d1a402e866f751be7b8441c0de6a1.tar.gz chromium_src-42287bc6d09d1a402e866f751be7b8441c0de6a1.tar.bz2 |
[Android] Add Instrumentation wrapper for gtest APKs.
BUG=428942
Review URL: https://codereview.chromium.org/691103002
Cr-Commit-Position: refs/heads/master@{#303530}
6 files changed, 233 insertions, 9 deletions
diff --git a/testing/android/java/AndroidManifest.xml b/testing/android/java/AndroidManifest.xml index c704cc4..a561f0c 100644 --- a/testing/android/java/AndroidManifest.xml +++ b/testing/android/java/AndroidManifest.xml @@ -24,6 +24,10 @@ found in the LICENSE file. </activity> </application> + <instrumentation android:name="org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner" + android:targetPackage="org.chromium.native_test" + android:label="Instrumentation entry point for org.chromium.native_test"/> + <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> diff --git a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java index f5d381a..42befe5 100644 --- a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java +++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java @@ -22,6 +22,11 @@ import org.chromium.base.library_loader.NativeLibraries; * the native activity class loader. */ public class ChromeNativeTestActivity extends Activity { + public static final String EXTRA_COMMAND_LINE_FILE = + "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile"; + public static final String EXTRA_COMMAND_LINE_FLAGS = + "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags"; + private static final String TAG = "ChromeNativeTestActivity"; private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread"; // We post a delayed task to run tests so that we do not block onCreate(). @@ -66,8 +71,15 @@ public class ChromeNativeTestActivity extends Activity { } private void runTests() { + String commandLineFlags = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FLAGS); + if (commandLineFlags == null) commandLineFlags = ""; + + String commandLineFilePath = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FILE); + if (commandLineFilePath == null) commandLineFilePath = ""; + // This directory is used by build/android/pylib/test_package_apk.py. - nativeRunTests(getFilesDir().getAbsolutePath(), getApplicationContext()); + nativeRunTests(commandLineFlags, commandLineFilePath, getFilesDir().getAbsolutePath(), + getApplicationContext()); } // Signal a failure of the native test loader to python scripts @@ -85,5 +97,6 @@ public class ChromeNativeTestActivity extends Activity { } } - private native void nativeRunTests(String filesDir, Context appContext); + private native void nativeRunTests(String commandLineFlags, String commandLineFilePath, + String filesDir, Context appContext); } diff --git a/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java new file mode 100644 index 0000000..5e8d8e5 --- /dev/null +++ b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java @@ -0,0 +1,196 @@ +// Copyright 2014 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. + +package org.chromium.native_test; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An Instrumentation that runs tests based on ChromeNativeTestActivity. + */ +public class ChromiumNativeTestInstrumentationTestRunner extends Instrumentation { + + private static final String TAG = "ChromiumNativeTestInstrumentationTestRunner"; + private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]*) .*"); + + private static interface ResultsBundleGenerator { + public Bundle generate(Map<String, TestResult> rawResults); + } + + private String mCommandLineFile; + private String mCommandLineFlags; + private Bundle mLogBundle; + private ResultsBundleGenerator mBundleGenerator; + + @Override + public void onCreate(Bundle arguments) { + mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE); + mCommandLineFlags = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS); + mLogBundle = new Bundle(); + mBundleGenerator = new RobotiumBundleGenerator(); + start(); + } + + @Override + public void onStart() { + super.onStart(); + Bundle results = runTests(); + finish(Activity.RESULT_OK, results); + } + + /** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results. + */ + private Bundle runTests() { + Log.i(TAG, "Creating activity."); + Activity activityUnderTest = startNativeTestActivity(); + + Log.i(TAG, "Getting results from FIFO."); + Map<String, TestResult> results = parseResultsFromFifo(activityUnderTest); + + Log.i(TAG, "Finishing activity."); + activityUnderTest.finish(); + + Log.i(TAG, "Parsing results and generating output."); + return mBundleGenerator.generate(results); + } + + /** Starts the ChromeNativeTestActivty. + */ + private Activity startNativeTestActivity() { + Intent i = new Intent(Intent.ACTION_MAIN); + i.setComponent(new ComponentName( + "org.chromium.native_test", + "org.chromium.native_test.ChromeNativeTestActivity")); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (mCommandLineFile != null) { + Log.i(TAG, "Passing command line file extra: " + mCommandLineFile); + i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile); + } + if (mCommandLineFlags != null) { + Log.i(TAG, "Passing command line flag extra: " + mCommandLineFlags); + i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags); + } + return startActivitySync(i); + } + + private static enum TestResult { + PASSED, FAILED, ERROR, UNKNOWN + } + + /** + * Generates a map between test names and test results from the instrumented Activity's FIFO. + */ + private Map<String, TestResult> parseResultsFromFifo(Activity activityUnderTest) { + Map<String, TestResult> results = new HashMap<String, TestResult>(); + + File fifo = null; + BufferedReader r = null; + + try { + // Wait for the test to create the FIFO. + fifo = new File(getTargetContext().getFilesDir().getAbsolutePath(), "test.fifo"); + while (!fifo.exists()) { + Thread.sleep(1000); + } + + r = new BufferedReader( + new InputStreamReader(new BufferedInputStream(new FileInputStream(fifo)))); + + StringBuilder resultsStr = new StringBuilder(); + for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger"); + l = r.readLine()) { + Matcher m = RE_TEST_OUTPUT.matcher(l); + if (m.matches()) { + if (m.group(1).equals("RUN")) { + results.put(m.group(2), TestResult.UNKNOWN); + } else if (m.group(1).equals("FAILED")) { + results.put(m.group(2), TestResult.FAILED); + } else if (m.group(1).equals("OK")) { + results.put(m.group(2), TestResult.PASSED); + } + } + resultsStr.append(l); + resultsStr.append("\n"); + } + mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, resultsStr.toString()); + sendStatus(0, mLogBundle); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted while waiting for FIFO file creation: " + e.toString()); + } catch (FileNotFoundException e) { + Log.e(TAG, "Couldn't find FIFO file: " + e.toString()); + } catch (IOException e) { + Log.e(TAG, "Error handling FIFO file: " + e.toString()); + } finally { + if (r != null) { + try { + r.close(); + } catch (IOException e) { + Log.e(TAG, "Error while closing FIFO reader."); + } + } + if (fifo != null) { + if (!fifo.delete()) { + Log.e(TAG, "Unable to delete " + fifo.getAbsolutePath()); + } + } + } + return results; + } + + /** + * Creates a results bundle that emulates the one created by Robotium. + */ + private static class RobotiumBundleGenerator implements ResultsBundleGenerator { + public Bundle generate(Map<String, TestResult> rawResults) { + Bundle resultsBundle = new Bundle(); + + int testsPassed = 0; + int testsFailed = 0; + + for (Map.Entry<String, TestResult> entry : rawResults.entrySet()) { + switch (entry.getValue()) { + case PASSED: + ++testsPassed; + break; + case FAILED: + ++testsFailed; + break; + default: + Log.w(TAG, "Unhandled: " + entry.getKey() + ", " + + entry.getValue().toString()); + break; + } + } + + StringBuilder resultBuilder = new StringBuilder(); + resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)"); + if (testsFailed > 0) { + resultBuilder.append( + "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size()) + + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0"); + } + resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, + resultBuilder.toString()); + return resultsBundle; + } + } + +} diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc index 63e389a..b7c9d28 100644 --- a/testing/android/native_test_launcher.cc +++ b/testing/android/native_test_launcher.cc @@ -30,6 +30,7 @@ using testing::native_test_util::ArgsToArgv; using testing::native_test_util::ParseArgsFromCommandLineFile; +using testing::native_test_util::ParseArgsFromString; using testing::native_test_util::ScopedMainEntryLogger; // The main function of the program to be wrapped as a test apk. @@ -117,6 +118,8 @@ void EnsureRedirectStream(FILE* stream, static void RunTests(JNIEnv* env, jobject obj, + jstring jcommand_line_flags, + jstring jcommand_line_file_path, jstring jfiles_dir, jobject app_context) { base::AtExitManager exit_manager; @@ -132,7 +135,17 @@ static void RunTests(JNIEnv* env, base::android::RegisterJni(env); std::vector<std::string> args; - ParseArgsFromCommandLineFile(kCommandLineFilePath, &args); + + const std::string command_line_file_path( + base::android::ConvertJavaStringToUTF8(env, jcommand_line_file_path)); + if (command_line_file_path.empty()) + ParseArgsFromCommandLineFile(kCommandLineFilePath, &args); + else + ParseArgsFromCommandLineFile(command_line_file_path.c_str(), &args); + + const std::string command_line_flags( + base::android::ConvertJavaStringToUTF8(env, jcommand_line_flags)); + ParseArgsFromString(command_line_flags, &args); std::vector<char*> argv; int argc = ArgsToArgv(args, &argv); diff --git a/testing/android/native_test_util.cc b/testing/android/native_test_util.cc index 98f32c7..885f297 100644 --- a/testing/android/native_test_util.cc +++ b/testing/android/native_test_util.cc @@ -9,7 +9,8 @@ #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" -namespace { +namespace testing { +namespace native_test_util { void ParseArgsFromString(const std::string& command_line, std::vector<std::string>* args) { @@ -22,11 +23,6 @@ void ParseArgsFromString(const std::string& command_line, } } -} // namespace - -namespace testing { -namespace native_test_util { - void ParseArgsFromCommandLineFile( const char* path, std::vector<std::string>* args) { base::FilePath command_line(path); diff --git a/testing/android/native_test_util.h b/testing/android/native_test_util.h index a756739..ef17e52 100644 --- a/testing/android/native_test_util.h +++ b/testing/android/native_test_util.h @@ -27,6 +27,8 @@ class ScopedMainEntryLogger { } }; +void ParseArgsFromString( + const std::string& command_line, std::vector<std::string>* args); void ParseArgsFromCommandLineFile( const char* path, std::vector<std::string>* args); int ArgsToArgv(const std::vector<std::string>& args, std::vector<char*>* argv); |