Enable preinstallation android packages
This commit is contained in:
parent
ef3ead7067
commit
4fdf66f89f
|
@ -1,10 +1,15 @@
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
|
|
||||||
install: "pip install -r requirements.txt"
|
install: "pip install -r requirements.txt"
|
||||||
script: nosetests
|
|
||||||
|
script: bash release.sh test 5.0 x86
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
39
Dockerfile
39
Dockerfile
|
@ -78,21 +78,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
RUN git clone https://github.com/kanaka/noVNC.git \
|
RUN git clone https://github.com/kanaka/noVNC.git \
|
||||||
&& cd noVNC/utils && git clone https://github.com/kanaka/websockify websockify
|
&& cd noVNC/utils && git clone https://github.com/kanaka/websockify websockify
|
||||||
|
|
||||||
#======================================
|
#=====================
|
||||||
# Install Android SDK and its packages
|
# Install Android SDK
|
||||||
#======================================
|
#=====================
|
||||||
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/jre
|
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/jre
|
||||||
ENV PATH ${PATH}:${JAVA_HOME}/bin
|
ENV PATH ${PATH}:${JAVA_HOME}/bin
|
||||||
|
|
||||||
ENV SDK_VERSION=25.2.3 \
|
ENV SDK_VERSION=25.2.3 \
|
||||||
BUILD_TOOL=25.0.2 \
|
|
||||||
ANDROID_HOME=/root
|
ANDROID_HOME=/root
|
||||||
RUN wget -O android.zip https://dl.google.com/android/repository/tools_r${SDK_VERSION}-linux.zip \
|
RUN wget -O android.zip https://dl.google.com/android/repository/tools_r${SDK_VERSION}-linux.zip \
|
||||||
&& unzip android.zip && rm android.zip
|
&& unzip android.zip && rm android.zip
|
||||||
ENV PATH ${PATH}:${ANDROID_HOME}/tools
|
ENV PATH ${PATH}:${ANDROID_HOME}/tools
|
||||||
RUN echo y | android update sdk --no-ui -a --filter platform-tools,build-tools-${BUILD_TOOL}
|
RUN echo y | android update sdk --no-ui -a --filter platform-tools
|
||||||
ENV PATH ${PATH}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/build-tools
|
ENV PATH ${PATH}:${ANDROID_HOME}/platform-tools
|
||||||
RUN mv ${ANDROID_HOME}/tools/emulator ${ANDROID_HOME}/tools/emulator.backup
|
|
||||||
|
|
||||||
#====================================
|
#====================================
|
||||||
# Install latest nodejs, npm, appium
|
# Install latest nodejs, npm, appium
|
||||||
|
@ -102,6 +100,26 @@ RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - \
|
||||||
ENV APPIUM_VERSION 1.6.3
|
ENV APPIUM_VERSION 1.6.3
|
||||||
RUN npm install -g appium@$APPIUM_VERSION && npm cache clean
|
RUN npm install -g appium@$APPIUM_VERSION && npm cache clean
|
||||||
|
|
||||||
|
#======================
|
||||||
|
# Install SDK packages
|
||||||
|
#======================
|
||||||
|
ARG ANDROID_VERSION=5.0.1
|
||||||
|
ARG BUILD_TOOL=21.1.2
|
||||||
|
ARG API_LEVEL=21
|
||||||
|
ARG PROCESSOR=x86
|
||||||
|
ARG SYS_IMG=x86_64
|
||||||
|
ENV ANDROID_VERSION=$ANDROID_VERSION \
|
||||||
|
BUILD_TOOL=$BUILD_TOOL \
|
||||||
|
API_LEVEL=$API_LEVEL \
|
||||||
|
PROCESSOR=$PROCESSOR \
|
||||||
|
SYS_IMG=$SYS_IMG
|
||||||
|
RUN echo y | android update sdk --no-ui -a --filter build-tools-${BUILD_TOOL}
|
||||||
|
ENV PATH ${PATH}:${ANDROID_HOME}/build-tools
|
||||||
|
|
||||||
|
RUN rm ${ANDROID_HOME}/tools/emulator \
|
||||||
|
&& ln -s ${ANDROID_HOME}/tools/emulator64-${PROCESSOR} ${ANDROID_HOME}/tools/emulator
|
||||||
|
RUN echo y | android update sdk --no-ui -a -t android-${API_LEVEL},sys-img-${SYS_IMG}-android-${API_LEVEL}
|
||||||
|
|
||||||
#================================================
|
#================================================
|
||||||
# noVNC Default Configurations
|
# noVNC Default Configurations
|
||||||
# These Configurations can be changed through -e
|
# These Configurations can be changed through -e
|
||||||
|
@ -127,11 +145,6 @@ RUN ln -s noVNC/vnc_auto.html noVNC/index.html
|
||||||
#===============
|
#===============
|
||||||
EXPOSE 4723 6080
|
EXPOSE 4723 6080
|
||||||
|
|
||||||
#==================
|
|
||||||
# Add Browser APKs
|
|
||||||
#==================
|
|
||||||
COPY browser_apk /root/browser_apk
|
|
||||||
|
|
||||||
#======================
|
#======================
|
||||||
# Add Emulator Devices
|
# Add Emulator Devices
|
||||||
#======================
|
#======================
|
||||||
|
@ -140,6 +153,6 @@ COPY devices /root/devices
|
||||||
#===================
|
#===================
|
||||||
# Run docker-appium
|
# Run docker-appium
|
||||||
#===================
|
#===================
|
||||||
COPY supervisord.conf /root/
|
|
||||||
COPY src /root/src
|
COPY src /root/src
|
||||||
|
COPY supervisord.conf /root/
|
||||||
CMD /usr/bin/supervisord --configuration supervisord.conf
|
CMD /usr/bin/supervisord --configuration supervisord.conf
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
Browser apps are downloaded from http://www.apkmirror.com
|
|
|
@ -1,29 +0,0 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from appium import webdriver
|
|
||||||
|
|
||||||
|
|
||||||
class MSiteChromeAndroidUITests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
desired_caps = {
|
|
||||||
'platformName': 'Android',
|
|
||||||
'deviceName': 'Android Emulator',
|
|
||||||
# For emulator type armeabi, please use browser apk :
|
|
||||||
# /root/browser_apk/chrome_55.0.2883.91-288309100_min_android4.1_armeabi-v7a.apk
|
|
||||||
'app': '/root/browser_apk/chrome_55.0.2883.91_min_android4.1_x86.apk',
|
|
||||||
'appPackage': 'com.android.chrome',
|
|
||||||
'appActivity': 'com.google.android.apps.chrome.Main',
|
|
||||||
'avd': 'nexus_5_5.0'
|
|
||||||
}
|
|
||||||
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
|
|
||||||
|
|
||||||
def test_open_url(self):
|
|
||||||
self.driver.get('http://targeturl.com')
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.driver.quit()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(MSiteChromeAndroidUITests)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
|
@ -1,29 +0,0 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from appium import webdriver
|
|
||||||
|
|
||||||
|
|
||||||
class MSiteFirefoxAndroidUITests(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
desired_caps = {
|
|
||||||
'platformName': 'Android',
|
|
||||||
'deviceName': 'Android Emulator',
|
|
||||||
# For emulator type armeabi, please use browser apk :
|
|
||||||
# /root/browser_apk/firefox_51.0-2015466281_min_android4.0.3_armeabi-v7a.apk
|
|
||||||
'app': '/root/browser_apk/firefox_51.0-2015466284_min_android4.0.3_x86.apk',
|
|
||||||
'appPackage': 'org.mozilla.firefox',
|
|
||||||
'appActivity': 'org.mozilla.gecko.LauncherActivity',
|
|
||||||
'avd': 'nexus_5_5.0'
|
|
||||||
}
|
|
||||||
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
|
|
||||||
|
|
||||||
def test_open_url(self):
|
|
||||||
self.driver.get('http://targeturl.com')
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.driver.quit()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(MSiteFirefoxAndroidUITests)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
126
release.sh
Normal file
126
release.sh
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Bash version should >= 4 to be able to run this script.
|
||||||
|
|
||||||
|
IMAGE="butomo1989/docker-android"
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
read -p "Environment (test|build|push|all) : " TASK
|
||||||
|
else
|
||||||
|
TASK=$1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
read -p "Android version: " GIVEN_VERSION
|
||||||
|
else
|
||||||
|
GIVEN_VERSION=$2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$3" ]; then
|
||||||
|
read -p "Processor type (x86|arm): " PROCESSOR
|
||||||
|
else
|
||||||
|
PROCESSOR=$3
|
||||||
|
fi
|
||||||
|
|
||||||
|
function build_tool() {
|
||||||
|
declare -A build_tools=(
|
||||||
|
[5.0.1]=21.1.2
|
||||||
|
[5.1.1]=22.0.1
|
||||||
|
[6.0]=23.0.3
|
||||||
|
[7.0]=24.0.3
|
||||||
|
[7.1.1]=25.0.2
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO: Need to be sorted
|
||||||
|
for key in "${!build_tools[@]}"; do
|
||||||
|
if [[ $key == *"$GIVEN_VERSION"* ]]; then
|
||||||
|
version=$key
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If version cannot be found in the list
|
||||||
|
if [ -z "$version" ]; then
|
||||||
|
echo "Version is not found in the list or not supported! Support only version 5.0.1, 5.1.1, 6.0, 7.0, 7.1.1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Android version: $version"
|
||||||
|
build_tools=${build_tools[$version]}
|
||||||
|
echo "Build tool: $build_tools"
|
||||||
|
}
|
||||||
|
|
||||||
|
function api_level() {
|
||||||
|
declare -A levels=(
|
||||||
|
[5.0.1]=21
|
||||||
|
[5.1.1]=22
|
||||||
|
[6.0]=23
|
||||||
|
[7.0]=24
|
||||||
|
[7.1.1]=25
|
||||||
|
)
|
||||||
|
|
||||||
|
level=${levels[$version]}
|
||||||
|
echo "Api level: $level"
|
||||||
|
}
|
||||||
|
|
||||||
|
function system_image() {
|
||||||
|
case $PROCESSOR in
|
||||||
|
x86)
|
||||||
|
sys_img=x86_64
|
||||||
|
;;
|
||||||
|
arm)
|
||||||
|
sys_img=armeabi-v7a
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid processor! Valid options: x86, arm"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "Processor: $PROCESSOR"
|
||||||
|
echo "System Image: $sys_img"
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
build_tool
|
||||||
|
api_level
|
||||||
|
system_image
|
||||||
|
}
|
||||||
|
|
||||||
|
init
|
||||||
|
IMAGE_NAME="$IMAGE-$PROCESSOR-$version"
|
||||||
|
echo "Image tag: $TAG"
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
(export ANDROID_HOME=/root && export ANDROID_VERSION=$version && export API_LEVEL=$level \
|
||||||
|
&& export PROCESSOR=$PROCESSOR && export SYS_IMG=$sys_img && nosetests -v)
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
# Remove pyc files
|
||||||
|
find . -name "*.pyc" -exec rm -f {} \;
|
||||||
|
|
||||||
|
docker build -t $IMAGE_NAME --build-arg ANDROID_VERSION=$version --build-arg BUILD_TOOL=$$build_tools \
|
||||||
|
--build-arg API_LEVEL=$level --build-arg PROCESSOR=$PROCESSOR --build-arg SYS_IMG=$sys_img .
|
||||||
|
}
|
||||||
|
|
||||||
|
function push() {
|
||||||
|
docker push $IMAGE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
case $TASK in
|
||||||
|
test)
|
||||||
|
test
|
||||||
|
;;
|
||||||
|
build)
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
push)
|
||||||
|
push
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
test
|
||||||
|
build
|
||||||
|
push
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid environment! Valid options: test, build, push, all"
|
||||||
|
;;
|
||||||
|
esac
|
|
@ -1,4 +1,3 @@
|
||||||
autopep8==1.2.4
|
|
||||||
coverage==4.2
|
coverage==4.2
|
||||||
mock==2.0.0
|
mock==2.0.0
|
||||||
nose==1.3.7
|
nose==1.3.7
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
ROOT = '/root'
|
ROOT = '/root'
|
||||||
ANDROID_PATH = os.getenv('ANDROID_HOME', '/root')
|
|
||||||
WORKDIR = os.path.dirname(__file__)
|
WORKDIR = os.path.dirname(__file__)
|
||||||
CONFIG_FILE = os.path.join(WORKDIR, 'nodeconfig.json')
|
CONFIG_FILE = os.path.join(WORKDIR, 'nodeconfig.json')
|
||||||
LOGGING_FILE = os.path.join(WORKDIR, 'logging.conf')
|
LOGGING_FILE = os.path.join(WORKDIR, 'logging.conf')
|
||||||
|
|
126
src/android.py
126
src/android.py
|
@ -1,126 +0,0 @@
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from src import ANDROID_PATH
|
|
||||||
|
|
||||||
logger = logging.getLogger('android')
|
|
||||||
|
|
||||||
EMULATOR = 'emulator'
|
|
||||||
TYPE_ARMEABI = 'armeabi'
|
|
||||||
TYPE_X86 = 'x86'
|
|
||||||
TYPE_X86_64 = 'x86_64'
|
|
||||||
|
|
||||||
API_LEVELS = {
|
|
||||||
'2.1': 7,
|
|
||||||
'2.2': 8,
|
|
||||||
'2.3.1': 9,
|
|
||||||
'2.3.3': 1,
|
|
||||||
'3.0': 11,
|
|
||||||
'3.1': 12,
|
|
||||||
'3.2': 13,
|
|
||||||
'4.0': 14,
|
|
||||||
'4.0.3': 15,
|
|
||||||
'4.1.2': 16,
|
|
||||||
'4.2.2': 17,
|
|
||||||
'4.3.1': 18,
|
|
||||||
'4.4.2': 19,
|
|
||||||
'4.4W.2': 20,
|
|
||||||
'5.0.1': 21,
|
|
||||||
'5.1.1': 22,
|
|
||||||
'6.0': 23,
|
|
||||||
'7.0': 24,
|
|
||||||
'7.1.1': 25
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_level(android_version):
|
|
||||||
"""
|
|
||||||
Get api level of android version.
|
|
||||||
|
|
||||||
:param android_version: android version
|
|
||||||
:type android_version: str
|
|
||||||
:return: api level
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
api_level = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
for key in sorted(API_LEVELS):
|
|
||||||
if android_version in key:
|
|
||||||
api_level = API_LEVELS.get(key)
|
|
||||||
except TypeError as t_err:
|
|
||||||
logger.error(t_err)
|
|
||||||
|
|
||||||
return api_level
|
|
||||||
|
|
||||||
|
|
||||||
def install_package(emulator_file, api_level, sys_img):
|
|
||||||
"""
|
|
||||||
Install sdk package.
|
|
||||||
|
|
||||||
:param emulator_file: emulator file that need to be link
|
|
||||||
:type emulator_file: str
|
|
||||||
:param api_level: api level
|
|
||||||
:type api_level: str
|
|
||||||
:param sys_img: system image of emulator
|
|
||||||
:type sys_img: str
|
|
||||||
"""
|
|
||||||
# Link emulator shortcut
|
|
||||||
emu_file = os.path.join(ANDROID_PATH, 'tools', emulator_file)
|
|
||||||
emu_target = os.path.join(ANDROID_PATH, 'tools', 'emulator')
|
|
||||||
os.symlink(emu_file, emu_target)
|
|
||||||
|
|
||||||
# Install package based on given android version
|
|
||||||
cmd = 'echo y | android update sdk --no-ui -a -t android-{api},sys-img-{sys_img}-android-{api}'.format(
|
|
||||||
api=api_level, sys_img=sys_img)
|
|
||||||
logger.info('SDK package installation command: {install}'.format(install=cmd))
|
|
||||||
titel = 'SDK package installation process'
|
|
||||||
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
|
|
||||||
|
|
||||||
|
|
||||||
def create_avd(device, avd_name, api_level):
|
|
||||||
"""
|
|
||||||
Create android virtual device.
|
|
||||||
|
|
||||||
:param device: name of device
|
|
||||||
:type device: str
|
|
||||||
:param avd_name: desire name
|
|
||||||
:type avd_name: str
|
|
||||||
:param api_level: api level
|
|
||||||
:type api_level: str
|
|
||||||
"""
|
|
||||||
# Create android emulator
|
|
||||||
cmd = 'echo no | android create avd -f -n {name} -t android-{api}'.format(name=avd_name, api=api_level)
|
|
||||||
if device != EMULATOR:
|
|
||||||
# Link emulator skins
|
|
||||||
from src import ROOT
|
|
||||||
skin_rsc_path = os.path.join(ROOT, 'devices', 'skins')
|
|
||||||
logger.info('Skin ressource path: {rsc}'.format(rsc=skin_rsc_path))
|
|
||||||
|
|
||||||
skin_dst_path = os.path.join(ANDROID_PATH, 'platforms', 'android-{api}'.format(api=api_level), 'skins')
|
|
||||||
logger.info('Skin destination path: {dst}'.format(dst=skin_dst_path))
|
|
||||||
|
|
||||||
for s in os.listdir(skin_rsc_path):
|
|
||||||
os.symlink(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s))
|
|
||||||
|
|
||||||
# Hardware and its skin
|
|
||||||
device_name_bash = device.replace(' ', '\ ')
|
|
||||||
skin_name = device.replace(' ', '_').lower()
|
|
||||||
logger.info('device name in bash: {db}, skin name: {skin}'.format(db=device_name_bash, skin=skin_name))
|
|
||||||
|
|
||||||
# For custom hardware profile
|
|
||||||
profile_dst_path = os.path.join(ROOT, '.android', 'devices.xml')
|
|
||||||
if 'samsung' in device.lower():
|
|
||||||
# profile file name = skin name
|
|
||||||
profile_src_path = os.path.join(ROOT, 'devices', 'profiles', '{profile}.xml'.format(profile=skin_name))
|
|
||||||
logger.info('Hardware profile resource path: {rsc}'.format(rsc=profile_src_path))
|
|
||||||
logger.info('Hardware profile destination path: {dst}'.format(dst=profile_dst_path))
|
|
||||||
os.symlink(profile_src_path, profile_dst_path)
|
|
||||||
|
|
||||||
# append command
|
|
||||||
cmd += ' -d {device} -s {skin}'.format(device=device_name_bash, skin=skin_name)
|
|
||||||
|
|
||||||
logger.info('AVD creation command: {cmd}'.format(cmd=cmd))
|
|
||||||
titel = 'AVD creation process'
|
|
||||||
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
|
|
182
src/app.py
Normal file
182
src/app.py
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from src import CONFIG_FILE, ROOT
|
||||||
|
from src import log
|
||||||
|
|
||||||
|
log.init()
|
||||||
|
logger = logging.getLogger('app')
|
||||||
|
|
||||||
|
|
||||||
|
def get_or_raise(env):
|
||||||
|
"""
|
||||||
|
Check if needed environment variables are given.
|
||||||
|
|
||||||
|
:param env: key
|
||||||
|
:type env: str
|
||||||
|
:return: value
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
env_value = os.getenv(env)
|
||||||
|
if not env_value:
|
||||||
|
raise RuntimeError('The environment variable {0:s} is missing.'
|
||||||
|
'Please check docker image or Dockerfile!'.format(env))
|
||||||
|
return env_value
|
||||||
|
|
||||||
|
|
||||||
|
def str_to_bool(str):
|
||||||
|
"""
|
||||||
|
Convert string to boolean.
|
||||||
|
|
||||||
|
:param str: given string
|
||||||
|
:type str: str
|
||||||
|
:return: converted string
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return str.lower() in ('yes', 'true', 't', '1')
|
||||||
|
except AttributeError as err:
|
||||||
|
logger.error(err)
|
||||||
|
|
||||||
|
|
||||||
|
ANDROID_HOME = get_or_raise('ANDROID_HOME')
|
||||||
|
ANDROID_VERSION = get_or_raise('ANDROID_VERSION')
|
||||||
|
API_LEVEL = get_or_raise('API_LEVEL')
|
||||||
|
PROCESSOR = get_or_raise('PROCESSOR')
|
||||||
|
SYS_IMG = get_or_raise('SYS_IMG')
|
||||||
|
|
||||||
|
logger.info('Android version: {version} \n'
|
||||||
|
'API level: {level} \n'
|
||||||
|
'Processor: {processor} \n'
|
||||||
|
'System image: {img}'.format(version=ANDROID_VERSION, level=API_LEVEL, processor=PROCESSOR,
|
||||||
|
img=SYS_IMG))
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_avd(device, avd_name):
|
||||||
|
"""
|
||||||
|
Create and run android virtual device.
|
||||||
|
|
||||||
|
:param device: Device name
|
||||||
|
:type device: str
|
||||||
|
:param avd_name: Name of android virtual device / emulator
|
||||||
|
:type avd_name: str
|
||||||
|
"""
|
||||||
|
cmd = 'echo no | android create avd -f -n {name} -t android-{api} -b {sys_img}'.format(
|
||||||
|
name=avd_name, api=API_LEVEL, sys_img=SYS_IMG)
|
||||||
|
|
||||||
|
# Link emulator skins
|
||||||
|
skin_rsc_path = os.path.join(ROOT, 'devices', 'skins')
|
||||||
|
logger.info('Skin ressource path: {rsc}'.format(rsc=skin_rsc_path))
|
||||||
|
skin_dst_path = os.path.join(ANDROID_HOME, 'platforms', 'android-{api}'.format(api=API_LEVEL), 'skins')
|
||||||
|
logger.info('Skin destination path: {dst}'.format(dst=skin_dst_path))
|
||||||
|
for s in os.listdir(skin_rsc_path):
|
||||||
|
os.symlink(os.path.join(skin_rsc_path, s), os.path.join(skin_dst_path, s))
|
||||||
|
|
||||||
|
# Hardware and its skin
|
||||||
|
device_name_bash = device.replace(' ', '\ ')
|
||||||
|
skin_name = device.replace(' ', '_').lower()
|
||||||
|
logger.info('Device name in bash: {db}, Skin name: {skin}'.format(db=device_name_bash, skin=skin_name))
|
||||||
|
|
||||||
|
# For custom hardware profile
|
||||||
|
profile_dst_path = os.path.join(ROOT, '.android', 'devices.xml')
|
||||||
|
if 'samsung' in device.lower():
|
||||||
|
# profile file name = skin name
|
||||||
|
profile_src_path = os.path.join(ROOT, 'devices', 'profiles', '{profile}.xml'.format(profile=skin_name))
|
||||||
|
logger.info('Hardware profile resource path: {rsc}'.format(rsc=profile_src_path))
|
||||||
|
logger.info('Hardware profile destination path: {dst}'.format(dst=profile_dst_path))
|
||||||
|
os.symlink(profile_src_path, profile_dst_path)
|
||||||
|
|
||||||
|
# Append command
|
||||||
|
cmd += ' -d {device} -s {skin}'.format(device=device_name_bash, skin=skin_name)
|
||||||
|
logger.info('AVD creation command: {cmd}'.format(cmd=cmd))
|
||||||
|
titel = 'AVD creation process'
|
||||||
|
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
|
||||||
|
|
||||||
|
|
||||||
|
def appium_run(avd_name):
|
||||||
|
"""
|
||||||
|
Run appium server.
|
||||||
|
|
||||||
|
:param avd_name: Name of android virtual device / emulator
|
||||||
|
:type avd_name: str
|
||||||
|
"""
|
||||||
|
cmd = 'appium'
|
||||||
|
|
||||||
|
grid_connect = str_to_bool(str(os.getenv('CONNECT_TO_GRID', False)))
|
||||||
|
logger.info('Connect to selenium grid? {connect}'.format(connect=grid_connect))
|
||||||
|
if grid_connect:
|
||||||
|
try:
|
||||||
|
appium_host = os.getenv('APPIUM_HOST', '127.0.0.1')
|
||||||
|
appium_port = int(os.getenv('APPIUM_PORT', 4723))
|
||||||
|
selenium_host = os.getenv('SELENIUM_HOST', '172.17.0.1')
|
||||||
|
selenium_port = int(os.getenv('SELENIUM_PORT', 4444))
|
||||||
|
create_node_config(avd_name, appium_host, appium_port, selenium_host, selenium_port)
|
||||||
|
cmd += ' --nodeconfig {file}'.format(file=CONFIG_FILE)
|
||||||
|
except ValueError as v_err:
|
||||||
|
logger.error(v_err)
|
||||||
|
titel = 'Appium Server'
|
||||||
|
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
|
||||||
|
|
||||||
|
|
||||||
|
def create_node_config(avd_name, appium_host, appium_port, selenium_host, selenium_port):
|
||||||
|
"""
|
||||||
|
Create custom node config file in json format to be able to connect with selenium server.
|
||||||
|
|
||||||
|
:param avd_name: Name of android virtual device / emulator
|
||||||
|
:type avd_name: str
|
||||||
|
:param appium_host: Host where appium server is running
|
||||||
|
:type appium_host: str
|
||||||
|
:param appium_port: Port number where where appium server is running
|
||||||
|
:type appium_port: int
|
||||||
|
:param selenium_host: Host where selenium server is running
|
||||||
|
:type selenium_host: str
|
||||||
|
:param selenium_port: Port number where selenium server is running
|
||||||
|
:type selenium_port: int
|
||||||
|
|
||||||
|
"""
|
||||||
|
config = {
|
||||||
|
'capabilities': [
|
||||||
|
{
|
||||||
|
'platform': 'Android',
|
||||||
|
'platformName': 'Android',
|
||||||
|
'version': ANDROID_VERSION,
|
||||||
|
'browserName': avd_name,
|
||||||
|
'maxInstances': 1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'configuration': {
|
||||||
|
'cleanUpCycle': 2000,
|
||||||
|
'timeout': 30000,
|
||||||
|
'proxy': 'org.openqa.grid.selenium.proxy.DefaultRemoteProxy',
|
||||||
|
'url': 'http://{host}:{port}/wd/hub'.format(host=appium_host, port=appium_port),
|
||||||
|
'host': appium_host,
|
||||||
|
'port': appium_port,
|
||||||
|
'maxSession': 6,
|
||||||
|
'register': True,
|
||||||
|
'registerCycle': 5000,
|
||||||
|
'hubHost': selenium_host,
|
||||||
|
'hubPort': selenium_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info('Appium node config: {config}'.format(config=config))
|
||||||
|
with open(CONFIG_FILE, 'w') as cf:
|
||||||
|
cf.write(json.dumps(config))
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""Run app."""
|
||||||
|
device = os.getenv('DEVICE', 'Nexus 5')
|
||||||
|
logger.info('Device: {device}'.format(device=device))
|
||||||
|
|
||||||
|
avd_name = '{device}_{version}'.format(device=device.replace(' ', '_').lower(), version=ANDROID_VERSION)
|
||||||
|
logger.info('AVD name: {avd}'.format(avd=avd_name))
|
||||||
|
|
||||||
|
prepare_avd(device, avd_name)
|
||||||
|
appium = str_to_bool(str(os.getenv('APPIUM', True)))
|
||||||
|
if appium:
|
||||||
|
appium_run(avd_name)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run()
|
|
@ -1,84 +0,0 @@
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
logger = logging.getLogger('appium')
|
|
||||||
|
|
||||||
|
|
||||||
def run(connect_to_grid, avd_name, android_version):
|
|
||||||
"""
|
|
||||||
Run appium server.
|
|
||||||
|
|
||||||
:param connect_to_grid: option to connect with selenium grid
|
|
||||||
:type connect_to_grid: bool
|
|
||||||
:param avd_name: name of device
|
|
||||||
:type avd_name: str
|
|
||||||
:param android_version: android version
|
|
||||||
:type android_version: str
|
|
||||||
"""
|
|
||||||
cmd = 'appium'
|
|
||||||
if connect_to_grid:
|
|
||||||
from src import CONFIG_FILE
|
|
||||||
try:
|
|
||||||
appium_host = os.getenv('APPIUM_HOST', '127.0.0.1')
|
|
||||||
appium_port = int(os.getenv('APPIUM_PORT', 4723))
|
|
||||||
selenium_host = os.getenv('SELENIUM_HOST', '172.17.0.1')
|
|
||||||
selenium_port = int(os.getenv('SELENIUM_PORT', 4444))
|
|
||||||
create_node_config(CONFIG_FILE, avd_name, android_version, appium_host, appium_port,
|
|
||||||
selenium_host, selenium_port)
|
|
||||||
cmd += ' --nodeconfig {file}'.format(file=CONFIG_FILE)
|
|
||||||
except ValueError as v_err:
|
|
||||||
logger.error(v_err)
|
|
||||||
titel = 'avd name: {name}'.format(name=avd_name)
|
|
||||||
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
|
|
||||||
|
|
||||||
|
|
||||||
def create_node_config(config_file, emulator_name, android_version, appium_host, appium_port,
|
|
||||||
selenium_host, selenium_port):
|
|
||||||
"""
|
|
||||||
Create custom node config file in json format to be able to connect with selenium server.
|
|
||||||
|
|
||||||
:param config_file: config file
|
|
||||||
:type config_file: str
|
|
||||||
:param emulator_name: emulator name
|
|
||||||
:type emulator_name: str
|
|
||||||
:param android_version: android version of android emulator
|
|
||||||
:type android_version: str
|
|
||||||
:param appium_host: host where appium server is running
|
|
||||||
:type appium_host: str
|
|
||||||
:param appium_port: port number where where appium server is running
|
|
||||||
:type appium_port: int
|
|
||||||
:param selenium_host: host where selenium server is running
|
|
||||||
:type selenium_host: str
|
|
||||||
:param selenium_port: port number where selenium server is running
|
|
||||||
:type selenium_port: int
|
|
||||||
|
|
||||||
"""
|
|
||||||
config = {
|
|
||||||
'capabilities': [
|
|
||||||
{
|
|
||||||
'platform': 'Android',
|
|
||||||
'platformName': 'Android',
|
|
||||||
'version': android_version,
|
|
||||||
'browserName': emulator_name,
|
|
||||||
'maxInstances': 1,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'configuration': {
|
|
||||||
'cleanUpCycle': 2000,
|
|
||||||
'timeout': 30000,
|
|
||||||
'proxy': 'org.openqa.grid.selenium.proxy.DefaultRemoteProxy',
|
|
||||||
'url': 'http://{host}:{port}/wd/hub'.format(host=appium_host, port=appium_port),
|
|
||||||
'host': appium_host,
|
|
||||||
'port': appium_port,
|
|
||||||
'maxSession': 6,
|
|
||||||
'register': True,
|
|
||||||
'registerCycle': 5000,
|
|
||||||
'hubHost': selenium_host,
|
|
||||||
'hubPort': selenium_port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info('appium node config: {config}'.format(config=config))
|
|
||||||
with open(config_file, 'w') as cf:
|
|
||||||
cf.write(json.dumps(config))
|
|
|
@ -1,5 +1,5 @@
|
||||||
[loggers]
|
[loggers]
|
||||||
keys=root, android, appium, service
|
keys=root, app
|
||||||
|
|
||||||
[handlers]
|
[handlers]
|
||||||
keys=console
|
keys=console
|
||||||
|
@ -11,23 +11,11 @@ keys=formatter
|
||||||
level=INFO
|
level=INFO
|
||||||
handlers=console
|
handlers=console
|
||||||
|
|
||||||
[logger_android]
|
[logger_app]
|
||||||
level=INFO
|
level=INFO
|
||||||
handlers=console
|
handlers=console
|
||||||
propagate=0
|
propagate=0
|
||||||
qualname=android
|
qualname=app
|
||||||
|
|
||||||
[logger_appium]
|
|
||||||
level=INFO
|
|
||||||
handlers=console
|
|
||||||
propagate=0
|
|
||||||
qualname=appium
|
|
||||||
|
|
||||||
[logger_service]
|
|
||||||
level=INFO
|
|
||||||
handlers=console
|
|
||||||
propagate=0
|
|
||||||
qualname=service
|
|
||||||
|
|
||||||
[handler_console]
|
[handler_console]
|
||||||
class=StreamHandler
|
class=StreamHandler
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
|
|
||||||
from src import android, appium, log
|
|
||||||
|
|
||||||
logger = logging.getLogger('service')
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
"""
|
|
||||||
Installation of needed sdk package, creation of android emulator and execution of appium server.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Device name
|
|
||||||
device = os.getenv('DEVICE', 'Nexus 5')
|
|
||||||
|
|
||||||
# Android version
|
|
||||||
android_version = os.getenv('ANDROID_VERSION', '5.0')
|
|
||||||
logger.info('Android version: {version}'.format(version=android_version))
|
|
||||||
|
|
||||||
# Emulator type
|
|
||||||
emu_type = os.getenv('EMULATOR_TYPE', android.TYPE_ARMEABI).lower()
|
|
||||||
emu_type = android.TYPE_ARMEABI if emu_type not in [android.TYPE_ARMEABI, android.TYPE_X86] else emu_type
|
|
||||||
logger.info('Emulator type: {type}'.format(type=emu_type))
|
|
||||||
emu_file = 'emulator64-x86' if emu_type == android.TYPE_X86 else 'emulator64-arm'
|
|
||||||
logger.info('Emulator file: {file}'.format(file=emu_file))
|
|
||||||
|
|
||||||
# Selenium grid connection
|
|
||||||
connect_to_grid = str_to_bool(str(os.getenv('CONNECT_TO_GRID', False)))
|
|
||||||
logger.info('Connect to selenium grid? {input}'.format(input=connect_to_grid))
|
|
||||||
|
|
||||||
# Install android sdk package
|
|
||||||
api_level = android.get_api_level(android_version)
|
|
||||||
# Bug: cannot use skin for system image x86 with android version < 5.0
|
|
||||||
if emu_type == android.TYPE_X86:
|
|
||||||
if int(api_level) < android.get_api_level('5.0'):
|
|
||||||
sys_img = android.TYPE_X86
|
|
||||||
device = android.EMULATOR
|
|
||||||
else:
|
|
||||||
sys_img = android.TYPE_X86_64
|
|
||||||
else:
|
|
||||||
sys_img = '{type}-v7a'.format(type=android.TYPE_ARMEABI)
|
|
||||||
logger.info('System image: {sys_img}'.format(sys_img=sys_img))
|
|
||||||
android.install_package(emu_file, api_level, sys_img)
|
|
||||||
|
|
||||||
# Create android virtual device
|
|
||||||
logger.info('Device: {device}'.format(device=device))
|
|
||||||
avd_name = '{device}_{version}'.format(device=device.replace(' ', '_').lower(), version=android_version)
|
|
||||||
logger.info('AVD name: {avd}'.format(avd=avd_name))
|
|
||||||
android.create_avd(device, avd_name, api_level)
|
|
||||||
|
|
||||||
# Run appium server
|
|
||||||
appium.run(connect_to_grid, avd_name, android_version)
|
|
||||||
|
|
||||||
|
|
||||||
def str_to_bool(str):
|
|
||||||
"""
|
|
||||||
Convert string to boolean.
|
|
||||||
|
|
||||||
:param str: given string
|
|
||||||
:type str: str
|
|
||||||
:return: converted string
|
|
||||||
:rtype: bool
|
|
||||||
"""
|
|
||||||
return str.lower() in ('yes', 'true', 't', '1')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
log.init()
|
|
||||||
start()
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""Unit test to test app."""
|
||||||
|
import os
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from src import app
|
||||||
|
|
||||||
|
|
||||||
|
class TestApp(TestCase):
|
||||||
|
"""Unit test class to test other methods in the app."""
|
||||||
|
|
||||||
|
def test_valid_env(self):
|
||||||
|
key = 'ENV_1'
|
||||||
|
os.environ[key] = 'test'
|
||||||
|
app.get_or_raise(key)
|
||||||
|
del os.environ[key]
|
||||||
|
|
||||||
|
def test_invalid_env(self):
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
app.get_or_raise('ENV_2')
|
||||||
|
|
||||||
|
def test_valid_bool(self):
|
||||||
|
self.assertEqual(app.str_to_bool('True'), True)
|
||||||
|
self.assertEqual(app.str_to_bool('t'), True)
|
||||||
|
self.assertEqual(app.str_to_bool('1'), True)
|
||||||
|
self.assertEqual(app.str_to_bool('YES'), True)
|
||||||
|
|
||||||
|
def test_invalid_bool(self):
|
||||||
|
self.assertEqual(app.str_to_bool(''), False)
|
||||||
|
self.assertEqual(app.str_to_bool('test'), False)
|
||||||
|
|
||||||
|
def test_invalid_format(self):
|
||||||
|
self.assertEqual(app.str_to_bool(True), None)
|
||||||
|
|
||||||
|
@mock.patch('src.app.prepare_avd')
|
||||||
|
def test_run_with_appium(self, mocked_avd):
|
||||||
|
with mock.patch('src.app.appium_run') as mocked_appium:
|
||||||
|
app.run()
|
||||||
|
self.assertTrue(mocked_avd.called)
|
||||||
|
self.assertTrue(mocked_appium.called)
|
||||||
|
|
||||||
|
@mock.patch('src.app.prepare_avd')
|
||||||
|
def test_run_withhout_appium(self, mocked_avd):
|
||||||
|
with mock.patch('src.app.appium_run') as mocked_appium:
|
||||||
|
os.environ['APPIUM'] = str(False)
|
||||||
|
app.run()
|
||||||
|
self.assertTrue(mocked_avd.called)
|
||||||
|
self.assertFalse(mocked_appium.called)
|
|
@ -1,20 +0,0 @@
|
||||||
"""Unit test for android.py."""
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from src import android
|
|
||||||
|
|
||||||
|
|
||||||
class TestApiLevel(TestCase):
|
|
||||||
"""Unit test class to test method get_api_level."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.android_version = '4.2.2'
|
|
||||||
|
|
||||||
def test_get_api_level(self):
|
|
||||||
api_level = android.get_api_level('4.2')
|
|
||||||
self.assertEqual(api_level, 19)
|
|
||||||
|
|
||||||
def test_wrong_type(self):
|
|
||||||
api_level = android.get_api_level(4)
|
|
||||||
self.assertRaises(TypeError)
|
|
||||||
self.assertEqual(api_level, None)
|
|
|
@ -1,24 +0,0 @@
|
||||||
"""Unit test for android.py."""
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from src import android
|
|
||||||
|
|
||||||
|
|
||||||
class TestInstallPackage(TestCase):
|
|
||||||
"""Unit test class to test method install_package."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.emulator_file = 'emulator64-arm'
|
|
||||||
self.api_level = 21
|
|
||||||
self.sys_img = 'armeabi-v7a'
|
|
||||||
|
|
||||||
@mock.patch('os.symlink')
|
|
||||||
@mock.patch('subprocess.check_call')
|
|
||||||
def test_package_installation(self, mocked_sys_link, mocked_suprocess):
|
|
||||||
self.assertFalse(mocked_sys_link.called)
|
|
||||||
self.assertFalse(mocked_suprocess.called)
|
|
||||||
android.install_package(self.emulator_file, self.api_level, self.sys_img)
|
|
||||||
self.assertTrue(mocked_sys_link.called)
|
|
||||||
self.assertTrue(mocked_suprocess.called)
|
|
|
@ -1,16 +0,0 @@
|
||||||
"""Unit test for appium.py."""
|
|
||||||
import os
|
|
||||||
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from src import CONFIG_FILE, appium
|
|
||||||
|
|
||||||
|
|
||||||
class TestAppiumConfig(TestCase):
|
|
||||||
"""Unit test class to test method create_node_config."""
|
|
||||||
|
|
||||||
def test_config_creation(self):
|
|
||||||
self.assertFalse(os.path.exists(CONFIG_FILE))
|
|
||||||
appium.create_node_config(CONFIG_FILE, 'emulator_name', '4.2.2', '127.0.0.1', 4723, '127.0.0.1', 4444)
|
|
||||||
self.assertTrue(os.path.exists(CONFIG_FILE))
|
|
||||||
os.remove(CONFIG_FILE)
|
|
|
@ -1,46 +0,0 @@
|
||||||
"""Unit test for appium.py."""
|
|
||||||
import os
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from src import appium
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('subprocess.check_call')
|
|
||||||
class TestAppiumConfig(TestCase):
|
|
||||||
"""Unit test class to test method run."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.emulator_name = 'test'
|
|
||||||
self.android_version = '4.2.2'
|
|
||||||
|
|
||||||
def test_without_selenium_grid(self, mocked_subprocess):
|
|
||||||
with mock.patch('src.appium.create_node_config') as mocked_config:
|
|
||||||
self.assertFalse(mocked_config.called)
|
|
||||||
self.assertFalse(mocked_subprocess.called)
|
|
||||||
appium.run(False, self.emulator_name, self.android_version)
|
|
||||||
self.assertFalse(mocked_config.called)
|
|
||||||
self.assertTrue(mocked_subprocess.called)
|
|
||||||
|
|
||||||
def test_with_selenium_grid(self, mocked_subprocess):
|
|
||||||
with mock.patch('src.appium.create_node_config') as mocked_config:
|
|
||||||
self.assertFalse(mocked_config.called)
|
|
||||||
self.assertFalse(mocked_subprocess.called)
|
|
||||||
appium.run(True, self.emulator_name, self.android_version)
|
|
||||||
self.assertTrue(mocked_config.called)
|
|
||||||
self.assertTrue(mocked_subprocess.called)
|
|
||||||
|
|
||||||
def test_invalid_integer(self, mocked_subprocess):
|
|
||||||
os.environ['APPIUM_PORT'] = 'test'
|
|
||||||
with mock.patch('src.appium.create_node_config') as mocked_config:
|
|
||||||
self.assertFalse(mocked_config.called)
|
|
||||||
self.assertFalse(mocked_subprocess.called)
|
|
||||||
appium.run(True, self.emulator_name, self.android_version)
|
|
||||||
self.assertFalse(mocked_config.called)
|
|
||||||
self.assertTrue(mocked_subprocess.called)
|
|
||||||
self.assertRaises(ValueError)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
if os.getenv('APPIUM_PORT'):
|
|
||||||
del os.environ['APPIUM_PORT']
|
|
54
src/tests/test_appium.py
Normal file
54
src/tests/test_appium.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
"""Unit test to test appium service."""
|
||||||
|
import os
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from src import app
|
||||||
|
|
||||||
|
|
||||||
|
class TestAppium(TestCase):
|
||||||
|
"""Unit test class to test appium methods."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
os.environ['CONNECT_TO_GRID'] = str(True)
|
||||||
|
self.avd_name = 'test_avd'
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call')
|
||||||
|
def test_without_selenium_grid(self, mocked_subprocess):
|
||||||
|
os.environ['CONNECT_TO_GRID'] = str(False)
|
||||||
|
self.assertFalse(mocked_subprocess.called)
|
||||||
|
app.appium_run(self.avd_name)
|
||||||
|
self.assertTrue(mocked_subprocess.called)
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call')
|
||||||
|
def test_with_selenium_grid(self, mocked_subprocess):
|
||||||
|
with mock.patch('src.app.create_node_config') as mocked_config:
|
||||||
|
self.assertFalse(mocked_config.called)
|
||||||
|
self.assertFalse(mocked_subprocess.called)
|
||||||
|
app.appium_run(self.avd_name)
|
||||||
|
self.assertTrue(mocked_config.called)
|
||||||
|
self.assertTrue(mocked_subprocess.called)
|
||||||
|
|
||||||
|
@mock.patch('subprocess.check_call')
|
||||||
|
def test_invalid_integer(self, mocked_subprocess):
|
||||||
|
os.environ['APPIUM_PORT'] = 'test'
|
||||||
|
with mock.patch('src.app.create_node_config') as mocked_config:
|
||||||
|
self.assertFalse(mocked_config.called)
|
||||||
|
self.assertFalse(mocked_subprocess.called)
|
||||||
|
app.appium_run(self.avd_name)
|
||||||
|
self.assertFalse(mocked_config.called)
|
||||||
|
self.assertTrue(mocked_subprocess.called)
|
||||||
|
self.assertRaises(ValueError)
|
||||||
|
|
||||||
|
def test_config_creation(self):
|
||||||
|
from src import CONFIG_FILE
|
||||||
|
self.assertFalse(os.path.exists(CONFIG_FILE))
|
||||||
|
app.create_node_config('test', '127.0.0.1', 4723, '127.0.0.1', 4444)
|
||||||
|
self.assertTrue(os.path.exists(CONFIG_FILE))
|
||||||
|
os.remove(CONFIG_FILE)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
del os.environ['CONNECT_TO_GRID']
|
||||||
|
if os.getenv('APPIUM_PORT'):
|
||||||
|
del os.environ['APPIUM_PORT']
|
|
@ -1,9 +1,10 @@
|
||||||
"""Unit test for android.py."""
|
"""Unit test for android virtual device creation.py."""
|
||||||
|
import os
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from src import android
|
from src import app
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('subprocess.check_call')
|
@mock.patch('subprocess.check_call')
|
||||||
|
@ -13,15 +14,14 @@ class TestAvd(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.avd_name = 'test_avd'
|
self.avd_name = 'test_avd'
|
||||||
self.api_level = 21
|
|
||||||
|
|
||||||
def test_nexus_avd(self, mocked_suprocess, mocked_sys_link):
|
def test_nexus_avd_as_default(self, mocked_suprocess, mocked_sys_link):
|
||||||
with mock.patch('os.listdir') as mocked_list_dir:
|
with mock.patch('os.listdir') as mocked_list_dir:
|
||||||
mocked_list_dir.return_value = ['file1', 'file2']
|
mocked_list_dir.return_value = ['file1', 'file2']
|
||||||
self.assertFalse(mocked_list_dir.called)
|
self.assertFalse(mocked_list_dir.called)
|
||||||
self.assertFalse(mocked_sys_link.called)
|
self.assertFalse(mocked_sys_link.called)
|
||||||
self.assertFalse(mocked_suprocess.called)
|
self.assertFalse(mocked_suprocess.called)
|
||||||
android.create_avd('Nexus 5', self.avd_name, self.api_level)
|
app.prepare_avd('Nexus 5', self.avd_name)
|
||||||
self.assertTrue(mocked_list_dir.called)
|
self.assertTrue(mocked_list_dir.called)
|
||||||
self.assertTrue(mocked_sys_link.called)
|
self.assertTrue(mocked_sys_link.called)
|
||||||
self.assertTrue(mocked_suprocess.called)
|
self.assertTrue(mocked_suprocess.called)
|
||||||
|
@ -32,16 +32,11 @@ class TestAvd(TestCase):
|
||||||
self.assertFalse(mocked_list_dir.called)
|
self.assertFalse(mocked_list_dir.called)
|
||||||
self.assertFalse(mocked_sys_link.called)
|
self.assertFalse(mocked_sys_link.called)
|
||||||
self.assertFalse(mocked_suprocess.called)
|
self.assertFalse(mocked_suprocess.called)
|
||||||
android.create_avd('Samsung Galaxy S6', self.avd_name, self.api_level)
|
app.prepare_avd('Samsung Galaxy S6', self.avd_name)
|
||||||
self.assertTrue(mocked_list_dir.called)
|
self.assertTrue(mocked_list_dir.called)
|
||||||
self.assertTrue(mocked_sys_link.called)
|
self.assertTrue(mocked_sys_link.called)
|
||||||
self.assertTrue(mocked_suprocess.called)
|
self.assertTrue(mocked_suprocess.called)
|
||||||
|
|
||||||
def test_default_avd(self, mocked_suprocess, mocked_sys_link):
|
def tearDown(self):
|
||||||
with mock.patch('os.listdir') as mocked_list_dir:
|
if os.getenv('DEVICE'):
|
||||||
mocked_list_dir.return_value = ['file1', 'file2']
|
del os.environ['DEVICE']
|
||||||
self.assertFalse(mocked_list_dir.called)
|
|
||||||
self.assertFalse(mocked_sys_link.called)
|
|
||||||
self.assertFalse(mocked_suprocess.called)
|
|
||||||
android.create_avd('emulator', self.avd_name, self.api_level)
|
|
||||||
self.assertFalse(mocked_list_dir.called)
|
|
|
@ -5,26 +5,26 @@ childlogdir=%(ENV_LOG_PATH)s
|
||||||
|
|
||||||
[program:xvfb]
|
[program:xvfb]
|
||||||
command=/usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s
|
command=/usr/bin/Xvfb %(ENV_DISPLAY)s -screen %(ENV_SCREEN)s %(ENV_SCREEN_WIDTH)sx%(ENV_SCREEN_HEIGHT)sx%(ENV_SCREEN_DEPTH)s
|
||||||
stdout_logfile=%(ENV_LOG_PATH)s/xvfb.stdout.log
|
stdout_logfile=%(ENV_LOG_PATH)s/xvfb.log
|
||||||
stderr_logfile=%(ENV_LOG_PATH)s/xvfb.stderr.log
|
redirect_stderr=true
|
||||||
|
|
||||||
[program:openbox]
|
[program:openbox]
|
||||||
command=/usr/bin/openbox-session
|
command=/usr/bin/openbox-session
|
||||||
stdout_logfile=%(ENV_LOG_PATH)s/openbox.stdout.log
|
stdout_logfile=%(ENV_LOG_PATH)s/openbox.log
|
||||||
stderr_logfile=%(ENV_LOG_PATH)s/openbox.stderr.log
|
redirect_stderr=true
|
||||||
|
|
||||||
[program:x11vnc]
|
[program:x11vnc]
|
||||||
command=/usr/bin/x11vnc -display %(ENV_DISPLAY)s -nopw -ncache 10 -forever
|
command=/usr/bin/x11vnc -display %(ENV_DISPLAY)s -nopw -ncache 10 -forever
|
||||||
stdout_logfile=%(ENV_LOG_PATH)s/x11vnc.stdout.log
|
stdout_logfile=%(ENV_LOG_PATH)s/x11vnc.log
|
||||||
stderr_logfile=%(ENV_LOG_PATH)s/x11vnc.stderr.log
|
redirect_stderr=true
|
||||||
|
|
||||||
[program:novnc]
|
[program:novnc]
|
||||||
command=./noVNC/utils/launch.sh --vnc localhost:%(ENV_LOCAL_PORT)s --listen %(ENV_TARGET_PORT)s
|
command=./noVNC/utils/launch.sh --vnc localhost:%(ENV_LOCAL_PORT)s --listen %(ENV_TARGET_PORT)s
|
||||||
stdout_logfile=%(ENV_LOG_PATH)s/novnc.stdout.log
|
stdout_logfile=%(ENV_LOG_PATH)s/novnc.log
|
||||||
stderr_logfile=%(ENV_LOG_PATH)s/novnc.stderr.log
|
redirect_stderr=true
|
||||||
|
|
||||||
[program:docker-appium]
|
[program:docker-appium]
|
||||||
command=python -m src.service
|
command=python -m src.app
|
||||||
autorestart=false
|
autorestart=false
|
||||||
stdout_logfile=%(ENV_LOG_PATH)s/docker-appium.stdout.log
|
stdout_logfile=%(ENV_LOG_PATH)s/docker-appium.log
|
||||||
stderr_logfile=%(ENV_LOG_PATH)s/docker-appium.stderr.log
|
redirect_stderr=true
|
||||||
|
|
Loading…
Reference in a new issue