summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shalamov <alexander.shalamov@mapbox.com>2018-10-18 17:30:19 +0300
committerAlexander Shalamov <alexander.shalamov@mapbox.com>2019-01-10 18:49:44 +0200
commitdf63be71ce10a67bb7a3edfc7684b83822cd1f4c (patch)
treebafe817fe9e95f6df115b0707fd2c78d22daaee0
parent0a398bd6fd9254dcc16e5b9d46814bf439fa7955 (diff)
downloadqtlocation-mapboxgl-df63be71ce10a67bb7a3edfc7684b83822cd1f4c.tar.gz
[android] Implement android test runner for core unit tests
-rw-r--r--Makefile22
-rw-r--r--platform/android/config.cmake18
-rw-r--r--platform/android/src/test/Main.java15
-rw-r--r--platform/android/src/test/main.jni.cpp76
-rw-r--r--platform/android/src/test/runtime.cpp73
-rw-r--r--platform/android/src/test/runtime.hpp9
-rw-r--r--platform/android/src/test/test_runner.cpp10
-rw-r--r--platform/android/src/test/version-script8
8 files changed, 118 insertions, 113 deletions
diff --git a/Makefile b/Makefile
index e9a0e4e351..434ce6e0dc 100644
--- a/Makefile
+++ b/Makefile
@@ -500,7 +500,7 @@ MBGL_ANDROID_ABIS += x86-64;x86_64
MBGL_ANDROID_LOCAL_WORK_DIR = /data/local/tmp/core-tests
MBGL_ANDROID_LIBDIR = lib$(if $(filter arm-v8 x86-64,$1),64)
MBGL_ANDROID_DALVIKVM = dalvikvm$(if $(filter arm-v8 x86-64,$1),64,32)
-MBGL_ANDROID_APK_SUFFIX = $(if $(filter Release,$(BUILDTYPE)),release-unsigned,debug)
+MBGL_ANDROID_APK_SUFFIX = $(if $(filter Release,$(BUILDTYPE)),release,debug)
MBGL_ANDROID_CORE_TEST_DIR = platform/android/MapboxGLAndroidSDK/.externalNativeBuild/cmake/$(buildtype)/$2/core-tests
MBGL_ANDROID_STL ?= c++_static
MBGL_ANDROID_GRADLE = ./gradlew --parallel --max-workers=$(JOBS) -Pmapbox.buildtype=$(buildtype) -Pmapbox.stl=$(MBGL_ANDROID_STL)
@@ -542,27 +542,21 @@ android-$1: platform/android/gradle/configuration.gradle
android-core-test-$1: android-test-lib-$1
# Compile main sources and extract the classes (using the test app to get all transitive dependencies in one place)
mkdir -p $(MBGL_ANDROID_CORE_TEST_DIR)
- unzip -o platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-$(MBGL_ANDROID_APK_SUFFIX).apk classes.dex -d $(MBGL_ANDROID_CORE_TEST_DIR)
-
- # Compile Test runner
- find platform/android/src/test -name "*.java" > $(MBGL_ANDROID_CORE_TEST_DIR)/java-sources.txt
- javac -sourcepath platform/android/src/test -d $(MBGL_ANDROID_CORE_TEST_DIR) -source 1.7 -target 1.7 @$(MBGL_ANDROID_CORE_TEST_DIR)/java-sources.txt
-
- # Combine and dex
- cd $(MBGL_ANDROID_CORE_TEST_DIR) && $(ANDROID_HOME)/build-tools/25.0.0/dx --dex --output=test.jar *.class classes.dex
+ unzip -o platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/$(buildtype)/MapboxGLAndroidSDKTestApp-$(MBGL_ANDROID_APK_SUFFIX).apk classes.dex -d $(MBGL_ANDROID_CORE_TEST_DIR)
run-android-core-test-$1-%: android-core-test-$1
# Ensure clean state on the device
- adb shell "rm -Rf $(MBGL_ANDROID_LOCAL_WORK_DIR) && mkdir -p $(MBGL_ANDROID_LOCAL_WORK_DIR)/test"
+ adb shell "rm -Rf $(MBGL_ANDROID_LOCAL_WORK_DIR) && mkdir -p $(MBGL_ANDROID_LOCAL_WORK_DIR)/test && mkdir -p $(MBGL_ANDROID_LOCAL_WORK_DIR)/mapbox-gl-js/src/style-spec/reference"
# Push all needed files to the device
- adb push $(MBGL_ANDROID_CORE_TEST_DIR)/test.jar $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
+ adb push $(MBGL_ANDROID_CORE_TEST_DIR)/classes.dex $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
+ adb push platform/android/MapboxGLAndroidSDK/build/intermediates/intermediate-jars/$(buildtype)/jni/$2/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
adb push test/fixtures $(MBGL_ANDROID_LOCAL_WORK_DIR)/test > /dev/null 2>&1
- adb push platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/$2/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
- adb push platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/$2/libmbgl-test.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
+ adb push mapbox-gl-js/src/style-spec/reference/v8.json $(MBGL_ANDROID_LOCAL_WORK_DIR)/mapbox-gl-js/src/style-spec/reference > /dev/null 2>&1
+ adb push platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/$(buildtype)/obj/$2/mbgl-test $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
# Kick off the tests
- adb shell "export LD_LIBRARY_PATH=/system/$(MBGL_ANDROID_LIBDIR):$(MBGL_ANDROID_LOCAL_WORK_DIR) && cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && $(MBGL_ANDROID_DALVIKVM) -cp $(MBGL_ANDROID_LOCAL_WORK_DIR)/test.jar Main --gtest_filter=$$*"
+ adb shell "export LD_LIBRARY_PATH=$(MBGL_ANDROID_LOCAL_WORK_DIR) && cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && chmod +x mbgl-test && ./mbgl-test --class_path=$(MBGL_ANDROID_LOCAL_WORK_DIR)/classes.dex --gtest_filter=$$*"
# Gather the results and unpack them
adb shell "cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && tar -cvzf results.tgz test/fixtures/* > /dev/null 2>&1"
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index 4a2361a7db..d78a6ce94b 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -85,23 +85,25 @@ target_link_libraries(mapbox-gl
PRIVATE mbgl-filesource
)
-## Test library ##
-
-set(MBGL_TEST_TARGET_TYPE "library")
+## Test executable ##
macro(mbgl_platform_test)
target_sources(mbgl-test
- PRIVATE platform/default/src/mbgl/test/main.cpp
-
- # Main test entry point
- platform/android/src/test/main.jni.cpp
+ PRIVATE platform/android/src/test/test_runner.cpp
+ PRIVATE platform/android/src/test/runtime.cpp
)
target_include_directories(mbgl-test
PRIVATE platform/android/include
)
+ set_target_properties(mbgl-test
+ PROPERTIES
+ LINK_FLAGS
+ "-fPIE -pie \
+ -Wl,--export-dynamic \
+ -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/src/test/version-script")
+
target_link_libraries(mbgl-test
- PRIVATE mbgl-core
PRIVATE mbgl-filesource
)
endmacro()
diff --git a/platform/android/src/test/Main.java b/platform/android/src/test/Main.java
deleted file mode 100644
index b0f3aeb7b9..0000000000
--- a/platform/android/src/test/Main.java
+++ /dev/null
@@ -1,15 +0,0 @@
-
-public class Main {
- public native void runAllTests(String[] args);
-
- public static void main(String[] args) throws Exception {
- // Load the tests
- System.loadLibrary("mbgl-test");
-
- // Run the tests
- new Main().runAllTests(args);
-
- // Exit explicitly otherwise dalvikvm won't quit
- System.exit(0);
- }
-}
diff --git a/platform/android/src/test/main.jni.cpp b/platform/android/src/test/main.jni.cpp
deleted file mode 100644
index 1cd0d26d2c..0000000000
--- a/platform/android/src/test/main.jni.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "../jni.hpp"
-
-#include <jni/jni.hpp>
-
-#include <mbgl/util/logging.hpp>
-#include <mbgl/test.hpp>
-
-#include <vector>
-
-namespace {
-
-// Main class (entry point for tests from dalvikvm)
-struct Main {
- static constexpr auto Name() {
- return "Main";
- }
-
- /**
- * JNI Bound to Main#runAllTests()
- */
- static void runAllTests(jni::JNIEnv& env, const jni::Object<Main>&, const jni::Array<jni::String>& args) {
- mbgl::Log::Warning(mbgl::Event::JNI, "Starting tests");
-
- // We need to create a copy of the argv data since Java-internals are stored in UTF-16.
- std::vector<std::string> data;
- // Add a fake first argument to align indices. Google Test expects the first argument to
- // start at index 1; index 0 is the name of the executable.
- data.push_back("main.jar");
- const int argc = args.Length(env);
- for (auto i = 0; i < argc; i++) {
- data.emplace_back(jni::Make<std::string>(env, args.Get(env, i)));
- }
-
- // Create an array of char pointers that point back to the data array.
- std::vector<const char*> argv;
- for (const auto& arg : data) {
- argv.push_back(arg.data());
- }
- mbgl::runTests(argv.size(), const_cast<char**>(argv.data()));
- }
-};
-
-} // namespace
-
-// We're declaring the function, which is libandroid_runtime.so.
-// It is defined in AndroidRuntime.cpp:
-// https://github.com/android/platform_frameworks_base/blob/master/core/jni/AndroidRuntime.cpp
-// Once this symbol goes away, we'll have to revisit.
-// This method loads and registers all of the Android-native frameworks so that we can use
-// android.util.Log, android.graphics.Bitmap and so on.
-// Setting the weak attribute tells the linker that this symbol is loaded at runtime and avoids
-// a missing symbol error.
-namespace android {
-struct AndroidRuntime {
- static int startReg(JNIEnv* env) __attribute__((weak));
-};
-} // namespace android
-
-// Main entry point
-extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
- // Load Android-native jni bindings
- jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
- android::AndroidRuntime::startReg(&env);
-
- // Load the main library jni bindings
- mbgl::Log::Info(mbgl::Event::JNI, "Registering main JNI Methods");
- mbgl::android::registerNatives(vm);
-
- // Load the test library jni bindings
- mbgl::Log::Info(mbgl::Event::JNI, "Registering test JNI Methods");
-
- jni::RegisterNatives(env, *jni::Class<Main>::Find(env),
- jni::MakeNativeMethod<decltype(Main::runAllTests), &Main::runAllTests>("runAllTests"));
-
- return JNI_VERSION_1_6;
-}
diff --git a/platform/android/src/test/runtime.cpp b/platform/android/src/test/runtime.cpp
new file mode 100644
index 0000000000..9cf79c501c
--- /dev/null
+++ b/platform/android/src/test/runtime.cpp
@@ -0,0 +1,73 @@
+#include "runtime.hpp"
+#include "../jni.hpp"
+
+#include <cassert>
+#include <dlfcn.h>
+#include <jni.h>
+#include <signal.h>
+#include <string>
+
+// Required for art / libsigchain
+extern "C" JNIEXPORT void EnsureFrontOfChain(int, struct sigaction*) { }
+extern "C" JNIEXPORT void AddSpecialSignalHandlerFn(int, void*) { }
+extern "C" JNIEXPORT void RemoveSpecialSignalHandlerFn(int, bool (*) (int, siginfo_t*, void*)) { }
+
+namespace {
+const std::string kClassPathCommand{"--class_path="};
+const std::string kClassPath{"-Djava.class.path="};
+const std::string kDefaultDex{"/data/local/tmp/core-tests/classes.dex"};
+} // namespace
+
+namespace mbgl {
+namespace android {
+
+bool initRuntime(int argc, char *argv[]) {
+ void* vmHandle = dlopen("libart.so", RTLD_NOW);
+ assert(vmHandle != nullptr);
+
+ using CreateJavaVMFn = jint (*)(JavaVM** vm, JNIEnv** env, void* vmArgs);
+ CreateJavaVMFn createJavaVMFn = reinterpret_cast<CreateJavaVMFn>(dlsym(vmHandle, "JNI_CreateJavaVM"));
+ assert(createJavaVMFn != nullptr);
+
+ std::string classPath = kClassPath + kDefaultDex;
+ for (int i = 0; i < argc; ++i) {
+ const std::string arg{argv[i]};
+ if (arg.compare(0, kClassPathCommand.length(), kClassPathCommand) == 0) {
+ classPath = kClassPath + arg.substr(kClassPathCommand.length());
+ break;
+ }
+ }
+
+ JavaVMOption options[1];
+ options[0].optionString = classPath.c_str();
+
+ JavaVMInitArgs args;
+ args.version = JNI_VERSION_1_6;
+ args.nOptions = 1;
+ args.options = options;
+ args.ignoreUnrecognized = JNI_FALSE;
+
+ JavaVM* vm;
+ JNIEnv* env;
+
+ if (createJavaVMFn(&vm, &env, &args) != JNI_OK) {
+ return false;
+ }
+
+ void* runtimeHandle = dlopen("libandroid_runtime.so", RTLD_NOW);
+ assert(runtimeHandle != nullptr);
+
+ using RegisterNativesFn = jint (*)(JNIEnv* env);
+ RegisterNativesFn registerNativesFn = reinterpret_cast<RegisterNativesFn>(dlsym(runtimeHandle, "registerFrameworkNatives"));
+ assert(registerNativesFn != nullptr);
+
+ if (registerNativesFn(env) != JNI_OK) {
+ return false;
+ }
+
+ mbgl::android::registerNatives(vm);
+ return true;
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/test/runtime.hpp b/platform/android/src/test/runtime.hpp
new file mode 100644
index 0000000000..c5e69d61c0
--- /dev/null
+++ b/platform/android/src/test/runtime.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace mbgl {
+namespace android {
+
+bool initRuntime(int argc, char *argv[]);
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/test/test_runner.cpp b/platform/android/src/test/test_runner.cpp
new file mode 100644
index 0000000000..008e3c5748
--- /dev/null
+++ b/platform/android/src/test/test_runner.cpp
@@ -0,0 +1,10 @@
+#include "runtime.hpp"
+#include <mbgl/test.hpp>
+
+int main(int argc, char *argv[]) {
+ if (!mbgl::android::initRuntime(argc, argv)) {
+ return 1;
+ }
+
+ mbgl::runTests(argc, argv);
+}
diff --git a/platform/android/src/test/version-script b/platform/android/src/test/version-script
new file mode 100644
index 0000000000..ebc2c17018
--- /dev/null
+++ b/platform/android/src/test/version-script
@@ -0,0 +1,8 @@
+{
+global:
+ EnsureFrontOfChain;
+ AddSpecialSignalHandlerFn;
+ RemoveSpecialSignalHandlerFn;
+local:
+ *;
+};