forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
apk-based test runner work. Not enabled yet. This CL is a combination…
… of upstreaming, ndk/ant-ification, and other tweaks. BUG=None TEST= Review URL: http://codereview.chromium.org/9834037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128679 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
jrg@chromium.org
committed
Mar 24, 2012
1 parent
27cc5a0
commit 9713fa8
Showing
16 changed files
with
489 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="org.chromium.native_test" | ||
android:versionCode="1" | ||
android:versionName="1.0"> | ||
|
||
<!-- This is the platform API where NativeActivity was introduced. --> | ||
<uses-sdk android:minSdkVersion="14" /> | ||
|
||
<application android:label="ChromeNativeTest"> | ||
<activity android:name=".ChromeNativeTestActivity" | ||
android:label="ChromeNativeTest" | ||
android:configChanges="orientation|keyboardHidden"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
|
||
<uses-permission android:name="android.permission.INTERNET"/> | ||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | ||
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||
<uses-permission android:name="android.permission.VIBRATE"/> | ||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/> | ||
<uses-permission android:name="android.permission.USE_CREDENTIALS"/> | ||
<uses-permission android:name="android.permission.READ_CONTACTS"/> | ||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> | ||
<uses-permission android:name="android.permission.READ_LOGS"/> | ||
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/> | ||
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/> | ||
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"/> | ||
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" /> | ||
<uses-permission android:name="android.permission.READ_SYNC_STATS"/> | ||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> | ||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/> | ||
<uses-permission android:name="android.permission.RECORD_AUDIO"/> | ||
<uses-permission android:name="android.permission.WAKE_LOCK"/> | ||
|
||
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
jrg@chromium.org | ||
bulach@chromium.org |
47 changes: 47 additions & 0 deletions
47
base/test/android/java/org/chromium/ChromeNativeTestActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright (c) 2012 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.os.Bundle; | ||
import android.util.Log; | ||
|
||
// Android's NativeActivity is mostly useful for pure-native code. | ||
// Our tests need to go up to our own java classes, which is not possible using | ||
// the native activity class loader. | ||
// We start a background thread in here to run the tests and avoid an ANR. | ||
// TODO(bulach): watch out for tests that implicitly assume they run on the main | ||
// thread. | ||
public class ChromeNativeTestActivity extends Activity { | ||
private final String TAG = "ChromeNativeTestActivity"; | ||
private final String LIBRARY = "native_tests"; | ||
|
||
@Override | ||
public void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
try { | ||
loadLibrary(); | ||
new Thread() { | ||
@Override | ||
public void run() { | ||
Log.d(TAG, ">>nativeRunTests"); | ||
nativeRunTests(getFilesDir().getAbsolutePath()); | ||
Log.d(TAG, "<<nativeRunTests"); | ||
} | ||
}.start(); | ||
} catch (UnsatisfiedLinkError e) { | ||
Log.e(TAG, "Unable to load libnative_tests.so: " + e); | ||
throw e; | ||
} | ||
} | ||
|
||
private void loadLibrary() throws UnsatisfiedLinkError { | ||
Log.i(TAG, "loading: " + LIBRARY); | ||
System.loadLibrary(LIBRARY); | ||
Log.i(TAG, "loaded: " + LIBRARY); | ||
} | ||
|
||
private native void nativeRunTests(String filesDir); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright (c) 2012 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. | ||
|
||
{ | ||
'conditions': [ | ||
['OS=="android"', { | ||
'targets': [ | ||
{ | ||
'target_name': 'native_test_apk', | ||
'message': 'building native test package', | ||
'type': 'none', | ||
'actions': [ | ||
{ | ||
'action_name': 'native_test_apk', | ||
'inputs': [ | ||
'<(DEPTH)/base/test/android/native_test_apk.xml', | ||
'<!@(find test/android/java -name "*.java")', | ||
'native_test_launcher.cc' | ||
], | ||
'outputs': [ | ||
# Awkwardly, we build a Debug APK even when gyp is in | ||
# Release mode. I don't think it matters (e.g. we're | ||
# probably happy to not codesign) but naming should be | ||
# fixed. | ||
'<(PRODUCT_DIR)/ChromeNativeTests-debug.apk', | ||
], | ||
'action': [ | ||
'ant', | ||
'-DPRODUCT_DIR=<(PRODUCT_DIR)', | ||
'-buildfile', | ||
'<(DEPTH)/base/test/android/native_test_apk.xml', | ||
] | ||
} | ||
], | ||
}, | ||
], | ||
}] | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project name="ChromeNativeTests" default="debug" basedir="."> | ||
|
||
<description> | ||
Building native test runner ChromeNativeTests.apk | ||
</description> | ||
|
||
<property environment="env"/> | ||
<property name="sdk.dir" location="${env.ANDROID_SDK_ROOT}"/> | ||
<property name="source.dir" location="java"/> | ||
<property name="target" value="android-14"/> | ||
|
||
<!-- We expect PRODUCT_DIR to be set like the gyp var | ||
(e.g. $ROOT/out/Debug) --> | ||
<!-- TODO(jrg): ideally we need this to run before -build-setup, where | ||
directories are made based on this variable. --> | ||
<target name="-pre-build"> | ||
<if> | ||
<condition> | ||
<isset property="PRODUCT_DIR" /> | ||
</condition> | ||
<else> | ||
<fail message="PRODUCT_DIR env var not set?" /> | ||
</else> | ||
</if> | ||
</target> | ||
|
||
<property name="out.dir" location="${PRODUCT_DIR}"/> | ||
|
||
<!-- TODO(jrg): should I make these directories specific to the apk? --> | ||
<property name="resource.absolute.dir" value="${out.dir}/res"/> | ||
<property name="gen.absolute.dir" value="${out.dir}/gen"/> | ||
<property name="jar.libs.dir" value="${out.dir}/java/libs"/> | ||
|
||
<import file="${sdk.dir}/tools/ant/build.xml" /> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// Copyright (c) 2012 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 <stdio.h> | ||
|
||
#include "base/android/jni_android.h" | ||
#include "base/android/jni_string.h" | ||
#include "base/android/path_utils.h" | ||
#include "base/at_exit.h" | ||
#include "base/command_line.h" | ||
#include "base/file_path.h" | ||
#include "base/file_util.h" | ||
#include "base/logging.h" | ||
#include "base/stringprintf.h" | ||
#include "base/string_tokenizer.h" | ||
#include "base/string_util.h" | ||
#include "base/test/test_suite.h" | ||
#include "jni/chrome_native_test_activity_jni.h" | ||
#include "gtest/gtest.h" | ||
|
||
// GTest's main function. | ||
extern int main(int argc, char** argv); | ||
|
||
namespace { | ||
|
||
void ParseArgsFromString(const std::string& command_line, | ||
std::vector<std::string>* args) { | ||
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(const FilePath& internal_data_path, | ||
std::vector<std::string>* args) { | ||
static const char kCommandLineFile[] = "chrome-native-tests-command-line"; | ||
FilePath command_line(internal_data_path.Append(FilePath(kCommandLineFile))); | ||
std::string command_line_string; | ||
if (file_util::ReadFileToString(command_line, &command_line_string)) { | ||
ParseArgsFromString(command_line_string, args); | ||
} | ||
} | ||
|
||
void ArgsToArgv(const std::vector<std::string>& args, | ||
std::vector<char*>* argv) { | ||
// We need to pass in a non-const char**. | ||
int argc = args.size(); | ||
argv->resize(argc); | ||
for (int i = 0; i < argc; ++i) | ||
(*argv)[i] = const_cast<char*>(args[i].c_str()); | ||
} | ||
|
||
// As we are the native side of an Android app, we don't have any 'console', so | ||
// gtest's standard output goes nowhere. | ||
// Instead, we inject an "EventListener" in gtest and then we print the results | ||
// using LOG, which goes to adb logcat. | ||
class AndroidLogPrinter : public ::testing::EmptyTestEventListener { | ||
public: | ||
void Init(int* argc, char** argv); | ||
|
||
// EmptyTestEventListener | ||
virtual void OnTestProgramStart( | ||
const ::testing::UnitTest& unit_test) OVERRIDE; | ||
virtual void OnTestStart(const ::testing::TestInfo& test_info) OVERRIDE; | ||
virtual void OnTestPartResult( | ||
const ::testing::TestPartResult& test_part_result) OVERRIDE; | ||
virtual void OnTestEnd(const ::testing::TestInfo& test_info) OVERRIDE; | ||
virtual void OnTestProgramEnd(const ::testing::UnitTest& unit_test) OVERRIDE; | ||
}; | ||
|
||
void AndroidLogPrinter::Init(int* argc, char** argv) { | ||
// InitGoogleTest must be called befure we add ourselves as a listener. | ||
::testing::InitGoogleTest(argc, argv); | ||
::testing::TestEventListeners& listeners = | ||
::testing::UnitTest::GetInstance()->listeners(); | ||
// Adds a listener to the end. Google Test takes the ownership. | ||
listeners.Append(this); | ||
} | ||
|
||
void AndroidLogPrinter::OnTestProgramStart( | ||
const ::testing::UnitTest& unit_test) { | ||
std::string msg = StringPrintf("[ START ] %d", | ||
unit_test.test_to_run_count()); | ||
LOG(ERROR) << msg; | ||
} | ||
|
||
void AndroidLogPrinter::OnTestStart(const ::testing::TestInfo& test_info) { | ||
std::string msg = StringPrintf("[ RUN ] %s.%s", | ||
test_info.test_case_name(), test_info.name()); | ||
LOG(ERROR) << msg; | ||
} | ||
|
||
void AndroidLogPrinter::OnTestPartResult( | ||
const ::testing::TestPartResult& test_part_result) { | ||
std::string msg = StringPrintf( | ||
"%s in %s:%d\n%s\n", | ||
test_part_result.failed() ? "*** Failure" : "Success", | ||
test_part_result.file_name(), | ||
test_part_result.line_number(), | ||
test_part_result.summary()); | ||
LOG(ERROR) << msg; | ||
} | ||
|
||
void AndroidLogPrinter::OnTestEnd(const ::testing::TestInfo& test_info) { | ||
std::string msg = StringPrintf("%s %s.%s", | ||
test_info.result()->Failed() ? "[ FAILED ]" : "[ OK ]", | ||
test_info.test_case_name(), test_info.name()); | ||
LOG(ERROR) << msg; | ||
} | ||
|
||
void AndroidLogPrinter::OnTestProgramEnd( | ||
const ::testing::UnitTest& unit_test) { | ||
std::string msg = StringPrintf("[ END ] %d", | ||
unit_test.successful_test_count()); | ||
LOG(ERROR) << msg; | ||
} | ||
|
||
void LibraryLoadedOnMainThread(JNIEnv* env) { | ||
static const char* const kInitialArgv[] = { "ChromeTestActivity" }; | ||
|
||
{ | ||
// We need a test suite to be created before we do any tracing or | ||
// logging: it creates a global at_exit_manager and initializes | ||
// internal gtest data structures based on the command line. | ||
// It needs to be scoped as it also resets the CommandLine. | ||
std::vector<std::string> args; | ||
FilePath path("/data/user/0/org.chromium.native_tests/files/"); | ||
ParseArgsFromCommandLineFile(path, &args); | ||
std::vector<char*> argv; | ||
ArgsToArgv(args, &argv); | ||
base::TestSuite test_suite(argv.size(), &argv[0]); | ||
} | ||
|
||
CommandLine::Init(arraysize(kInitialArgv), kInitialArgv); | ||
|
||
logging::InitLogging(NULL, | ||
logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, | ||
logging::DONT_LOCK_LOG_FILE, | ||
logging::DELETE_OLD_LOG_FILE, | ||
logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); | ||
// To view log output with IDs and timestamps use "adb logcat -v threadtime". | ||
logging::SetLogItems(false, // Process ID | ||
false, // Thread ID | ||
false, // Timestamp | ||
false); // Tick count | ||
VLOG(0) << "Chromium logging enabled: level = " << logging::GetMinLogLevel() | ||
<< ", default verbosity = " << logging::GetVlogVerbosity(); | ||
base::android::RegisterPathUtils(env); | ||
} | ||
|
||
} // namespace | ||
|
||
// This method is called on a separate java thread so that we won't trigger | ||
// an ANR. | ||
static void RunTests(JNIEnv* env, jobject obj, jstring jfiles_dir) { | ||
FilePath files_dir(base::android::ConvertJavaStringToUTF8(env, jfiles_dir)); | ||
// A few options, such "--gtest_list_tests", will just use printf directly | ||
// and won't use the "AndroidLogPrinter". Redirect stdout to a known file. | ||
FilePath stdout_path(files_dir.Append(FilePath("stdout.txt"))); | ||
freopen(stdout_path.value().c_str(), "w", stdout); | ||
|
||
std::vector<std::string> args; | ||
ParseArgsFromCommandLineFile(files_dir, &args); | ||
|
||
// We need to pass in a non-const char**. | ||
std::vector<char*> argv; | ||
ArgsToArgv(args, &argv); | ||
|
||
int argc = argv.size(); | ||
// This object is owned by gtest. | ||
AndroidLogPrinter* log = new AndroidLogPrinter(); | ||
log->Init(&argc, &argv[0]); | ||
|
||
main(argc, &argv[0]); | ||
} | ||
|
||
// This is called by the VM when the shared library is first loaded. | ||
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { | ||
base::android::InitVM(vm); | ||
JNIEnv* env = base::android::AttachCurrentThread(); | ||
if (!RegisterNativesImpl(env)) { | ||
return -1; | ||
} | ||
LibraryLoadedOnMainThread(env); | ||
return JNI_VERSION_1_4; | ||
} |
Oops, something went wrong.