diff options
author | Timofey <t.danshin@corp.mail.ru> | 2015-04-21 07:55:01 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:46:13 +0300 |
commit | 73e590bc94f438c116b74095eb98bd70e70f042d (patch) | |
tree | 49ea0552cbe7be78350934108def6555e860dc01 /android/UnitTests | |
parent | 27b72ffbf3134d0279802019f8b5dc8ca5fb99cb (diff) |
Merge remote-tracking branch 'origin/run_android_tests' into squashed_android_tests
Diffstat (limited to 'android/UnitTests')
-rw-r--r-- | android/UnitTests/jni/AndroidBeginning.mk | 1 | ||||
-rwxr-xr-x | android/UnitTests/native_build.sh | 14 | ||||
-rwxr-xr-x | android/UnitTests/runtests.py | 210 |
3 files changed, 224 insertions, 1 deletions
diff --git a/android/UnitTests/jni/AndroidBeginning.mk b/android/UnitTests/jni/AndroidBeginning.mk index 3cad168ef1..15d49363f5 100644 --- a/android/UnitTests/jni/AndroidBeginning.mk +++ b/android/UnitTests/jni/AndroidBeginning.mk @@ -35,6 +35,7 @@ LOCAL_CPP_FEATURES += exceptions rtti LOCAL_C_INCLUDES := $(ROOT_PATH_FROM_JNI)/ LOCAL_C_INCLUDES += $(ROOT_PATH)/ +LOCAL_C_INCLUDES += $(ROOT_PATH)/3party/boost/ ifneq ($(NDK_DEBUG),1) ifeq ($(PRODUCTION),1) diff --git a/android/UnitTests/native_build.sh b/android/UnitTests/native_build.sh index 5bfcf130d0..b731624374 100755 --- a/android/UnitTests/native_build.sh +++ b/android/UnitTests/native_build.sh @@ -5,6 +5,18 @@ MY_PATH="`( cd \"$MY_PATH\" && pwd )`" # absolutized and normalized source "$MY_PATH/tests_list.sh" + +NDK_PATH="" +for line in $(< ../local.properties) +do + case $line in + ndk*) NDK_PATH=`echo $line| cut -d'=' -f 2` ;; + *) ;; + esac +done + + + declare -r NDK_ABI=armeabi-v7a-hard declare -r PROP_DEBUG_NDK_FLAGS="-j8 V=1 NDK_DEBUG=1 DEBUG=1 APP_ABI=$NDK_ABI" @@ -22,7 +34,7 @@ NdkBuild() { NDK_PARAMS="--directory=$2 ${PROP_RELEASE_NDK_FLAGS}" fi echo "ndk-build $NDK_PARAMS" - ndk-build $NDK_PARAMS + $NDK_PATH/ndk-build $NDK_PARAMS } if [ $# != 1 ]; then diff --git a/android/UnitTests/runtests.py b/android/UnitTests/runtests.py new file mode 100755 index 0000000000..8c059713f8 --- /dev/null +++ b/android/UnitTests/runtests.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python + +""" +This script is for running the Android tests on android devices from the build +server. It may take as a parameter the build number (e.g. the build number from +Jenkins). The build number may also be a string. + +The script removes all the apps whose ids contain "mapswithme", and cleans up +the device logs before running the tests, so make sure you don't have important +logs on devices before you connect them to the server. After the test, the +device logs are filtered and saved as <build number>_<device_id>.log in the +current directory. +""" + + +from __future__ import print_function +import re +import subprocess +import time +import sys +import threading +import os +from os import listdir +from os.path import isfile, join + + +# this list is for removing possible MapsWithMe data folders, not used yet, but will be in the future +# mapswithme_paths=["storage/sdcard0/MapsWithMe", "mnt/sdcard/MapsWithMe", +# "/mnt/shell/emulated/0/MapsWithMe", "/mnt/sdcard/MapsWithMe"] + + +ACTIVITY_NAME = "com.mapswithme.maps.unittests.debug/com.mapswithme.maps.unittests.AllTestsActivity" + +APP_ID = "com.mapswithme.maps.unittests.debug" + +APK_LOCATION = "build/outputs/apk/UnitTests-debug.apk" + +MAX_TEST_RUN_TIME = 3600 # seconds + +TEST_WAIT_PAUSE = 2 # seconds + +SERIAL_PATTERN = re.compile("^[\da-f]{4,}") + +build_number = "0" + + +def exec_shell(command): + # print "> " + command + s = subprocess.check_output(command.split()) + return s.split('\r\n') + + +def adb(command, serial=None, shell=False): + + shell_cmd = list(['adb']) + if serial is not None: + shell_cmd += ['-s', serial] + if shell: + shell_cmd += ['shell'] + shell_cmd += [command] + + return exec_shell(' '.join(shell_cmd).replace(" ", " ")) + + +def uninstall(serial, package): + adb("pm uninstall -k {}".format(package), serial=serial, shell=True) + + +def install(serial, path): + command = " -s {serial} install {path}".format(serial=serial, path=path) + adb(command) + + +def connected_devices(): + adb_devices = adb("devices") + filter_fn = lambda device : SERIAL_PATTERN.match(device) + map_fn = lambda d : d.split("\t")[0] + + return [ id for id in process_output(adb_devices, map_fn, filter_fn)] + + +def process_output(output, fn, filter_fn): + """ + adb returns an array of strings, at least one of them contains several lines of output. + To all probability, only the 0th string in the array contains any meaningful output, + but there is some chance that others might as well, so to be on the safe side, we + process all of them. + """ + for full_string in output: + lines = full_string.split("\n") + + for line in lines: + if not filter_fn(line): + continue + + yield fn(line) + + +def packages(serial): + packs = adb("pm list packages | grep mapswithme", serial=serial, shell=True) + + filter_fn = lambda x : x.startswith("package:") + ret_fn = lambda x : x.split(":")[1] + + return process_output(packs, ret_fn, filter_fn) + + +def app_is_running(serial): + # if the app is not running, we get just an empty line, otherwise we get + # the app info line + the empty line. This lets us assume that the app is not running. + command = "ps | grep {}".format(APP_ID) + result = adb(command, serial=serial, shell=True) + return len(result) > 1 + + +def run_app(serial): + command = "am start -n {}".format(ACTIVITY_NAME) + adb(command, serial=serial, shell=True) + + +def save_log(serial): + command = "logcat -d | grep MapsMeTest" + device_log = adb(command, serial=serial) + lines = process_output(device_log, lambda x: x, lambda x: True) + write_lines_to_file(lines, serial) + + +def write_lines_to_file(lines, serial): + with open("{build_number}_{serial}.log".format(build_number=build_number, serial=serial), "w") as log_file: + for line in lines: + log_file.write(line + "\n") + + + +def clear_log(serial): + command = "-s {serial} logcat -c".format(serial=serial) + adb(command) + + +def device_run_loop(serial): + start = time.time() + + clear_log(serial) + run_app(serial) + + elapsed_time = 0 + + while elapsed_time < MAX_TEST_RUN_TIME: + if not app_is_running(serial): + break + + time.sleep(TEST_WAIT_PAUSE) + elapsed_time += TEST_WAIT_PAUSE + + if elapsed_time >= MAX_TEST_RUN_TIME: + print("The tests on {serial} took too long".format(serial=serial)) + + save_log(serial) + + end = time.time() + print("Ran tests on {serial} in {duration} sec.".format(serial=serial, duration=(end - start))) + + +def clean_device(serial): + start = time.time() + for pack in packages(serial): + uninstall(serial, pack) + + install(serial, APK_LOCATION) + end = time.time() + print("Cleaned up {serial} in {duration} sec.".format(serial=serial, duration=(end - start))) + + +def process_devices(device_ids, fn): + run_loop_threads = [] + + for serial in device_ids: + thread = threading.Thread(target=fn, args=(serial,)) + run_loop_threads.append(thread) + thread.start() + + for thread in run_loop_threads: + thread.join() + + +def main(): + logs = [ f for f in listdir(".") if f.endswith(".log") and isfile(join(".",f)) ] + + for log in logs: + os.remove(log) + + if len(sys.argv) > 1: + global build_number + build_number = sys.argv[1] + + device_ids = connected_devices() + print("Running on devices:") + for device_id in device_ids: + print(device_id) + + print("\nCleaning up devices and installing test apk...") + process_devices(device_ids, clean_device) + print("\nRunning the test suites...") + process_devices(device_ids, device_run_loop) + + print("\nTests finished running on all devices") + + +if __name__ == "__main__": + main() |