summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjbudorick <jbudorick@chromium.org>2014-11-10 15:14:15 -0800
committerCommit bot <commit-bot@chromium.org>2014-11-10 23:14:42 +0000
commit42287bc6d09d1a402e866f751be7b8441c0de6a1 (patch)
treea96bc90008ea5f7948391f1a7cb9b995c3986e07
parentfeeff71519070dddf09693c273bb4cd89c6168dc (diff)
downloadchromium_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}
-rw-r--r--testing/android/java/AndroidManifest.xml4
-rw-r--r--testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java17
-rw-r--r--testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java196
-rw-r--r--testing/android/native_test_launcher.cc15
-rw-r--r--testing/android/native_test_util.cc8
-rw-r--r--testing/android/native_test_util.h2
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);