Refactored

This commit is contained in:
butomo1989 2017-03-21 13:33:46 +01:00
parent 26b99bd32b
commit f4e16a3cf2
10 changed files with 76 additions and 176 deletions

View file

@ -46,8 +46,8 @@ ENV PATH="${PATH}:${JAVA_HOME}/bin"
#===================== #=====================
RUN apt-get install wget unzip libqt5webkit5 -y RUN apt-get install wget unzip libqt5webkit5 -y
RUN wget https://dl.google.com/android/repository/tools_r25.2.3-linux.zip RUN wget https://dl.google.com/android/repository/tools_r25.2.3-linux.zip && \
RUN unzip tools_r25.2.3-linux.zip && rm tools_r25.2.3-linux.zip unzip tools_r25.2.3-linux.zip && rm tools_r25.2.3-linux.zip
ENV ANDROID_HOME="/root" ENV ANDROID_HOME="/root"
ENV PATH="${PATH}:${ANDROID_HOME}/tools" ENV PATH="${PATH}:${ANDROID_HOME}/tools"
@ -55,9 +55,8 @@ ENV PATH="${PATH}:${ANDROID_HOME}/tools"
# Install Platform-tools, Build-tools # Install Platform-tools, Build-tools
# To see list of available packages: android list sdk # To see list of available packages: android list sdk
#===================================================== #=====================================================
RUN echo y | android update sdk --no-ui --filter 2,3 RUN echo y | android update sdk --no-ui --filter platform-tools,build-tools-25.0.2
ENV PATH="${PATH}:${ANDROID_HOME}/platform-tools" ENV PATH="${PATH}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/build-tools"
ENV PATH="${PATH}:${ANDROID_HOME}/build-tools"
RUN mv ${ANDROID_HOME}/tools/emulator ${ANDROID_HOME}/tools/emulator.backup RUN mv ${ANDROID_HOME}/tools/emulator ${ANDROID_HOME}/tools/emulator.backup
#==================================== #====================================

View file

@ -1,6 +1,7 @@
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')

View file

@ -1,44 +1,37 @@
import logging import logging
import os import os
import re
import subprocess import subprocess
logging.basicConfig() from src import ANDROID_PATH
logger = logging.getLogger('android') logger = logging.getLogger('android')
# not using enum because need to install pip that will make docker image size bigger EMULATOR = 'emulator'
TYPE_ARMEABI = 'armeabi' TYPE_ARMEABI = 'armeabi'
TYPE_X86 = 'x86' TYPE_X86 = 'x86'
TYPE_X86_64 = 'x86_64' TYPE_X86_64 = 'x86_64'
API_LEVEL_ANDROID_5 = 21 API_LEVELS = {
'2.1': 7,
'2.2': 8,
def get_available_sdk_packages(): '2.3.1': 9,
""" '2.3.3': 1,
Get list of available sdk packages. '3.0': 11,
'3.1': 12,
:return: List of available packages. '3.2': 13,
:rtype: bytearray '4.0': 14,
""" '4.0.3': 15,
logger.info('List of Android SDK: ') '4.1.2': 16,
output_str = subprocess.check_output('android list sdk'.split()) '4.2.2': 17,
logger.info(output_str) '4.3.1': 18,
return [output.strip() for output in output_str.split('\n')] if output_str else None '4.4.2': 19,
'4.4W.2': 20,
'5.0.1': 21,
def get_item_position(keyword, items): '5.1.1': 22,
""" '6.0': 23,
Get position of item in array by given keyword. '7.0': 24,
'7.1.1': 25
:return: item position }
:rtype: int
"""
pos = 0
for p, v in enumerate(items):
if keyword in v:
pos = p # Get the last item that match with keyword
return pos
def get_api_level(android_version): def get_api_level(android_version):
@ -47,38 +40,25 @@ def get_api_level(android_version):
:param android_version: android version :param android_version: android version
:type android_version: str :type android_version: str
:return: api version :return: api level
:rtype: str :rtype: int
""" """
api_version = None api_level = None
try: try:
packages = get_available_sdk_packages() 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)
if packages: return api_level
item_pos = get_item_position(android_version, packages)
logger.info('Package in position: {pos}'.format(pos=item_pos))
item = packages[item_pos]
logger.info('Item: {item}'.format(item=item))
item_info = item.split('-')
api_version = re.search('%s(.*)%s' % ('API', ','), item_info[1]).group(1).strip()
logger.info('API level: {api}'.format(api=api_version))
else:
raise RuntimeError('List of packages is empty!')
except IndexError as i_err:
logger.error(i_err)
return api_version
def install_package(android_path, emulator_file, api_level, sys_img): def install_package(emulator_file, api_level, sys_img):
""" """
Install sdk package. Install sdk package.
:param android_path: location where android SDK is installed
:type android_path: str
:param emulator_file: emulator file that need to be link :param emulator_file: emulator file that need to be link
:type emulator_file: str :type emulator_file: str
:param api_level: api level :param api_level: api level
@ -87,8 +67,8 @@ def install_package(android_path, emulator_file, api_level, sys_img):
:type sys_img: str :type sys_img: str
""" """
# Link emulator shortcut # Link emulator shortcut
emu_file = os.path.join(android_path, 'tools', emulator_file) emu_file = os.path.join(ANDROID_PATH, 'tools', emulator_file)
emu_target = os.path.join(android_path, 'tools', 'emulator') emu_target = os.path.join(ANDROID_PATH, 'tools', 'emulator')
os.symlink(emu_file, emu_target) os.symlink(emu_file, emu_target)
# Install package based on given android version # Install package based on given android version
@ -96,16 +76,13 @@ def install_package(android_path, emulator_file, api_level, sys_img):
api=api_level, sys_img=sys_img) api=api_level, sys_img=sys_img)
logger.info('SDK package installation command: {install}'.format(install=cmd)) logger.info('SDK package installation command: {install}'.format(install=cmd))
titel = 'SDK package installation process' titel = 'SDK package installation process'
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format( subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
titel=titel, cmd=cmd), shell=True)
def create_avd(android_path, device, avd_name, api_level): def create_avd(device, avd_name, api_level):
""" """
Create android virtual device. Create android virtual device.
:param android_path: location where android SDK is installed
:type android_path: str
:param device: name of device :param device: name of device
:type device: str :type device: str
:param avd_name: desire name :param avd_name: desire name
@ -115,13 +92,13 @@ def create_avd(android_path, device, avd_name, api_level):
""" """
# Create android emulator # Create android emulator
cmd = 'echo no | android create avd -f -n {name} -t android-{api}'.format(name=avd_name, api=api_level) cmd = 'echo no | android create avd -f -n {name} -t android-{api}'.format(name=avd_name, api=api_level)
if device != 'emulator': if device != EMULATOR:
# Link emulator skins # Link emulator skins
from src import ROOT from src import ROOT
skin_rsc_path = os.path.join(ROOT, 'devices', 'skins') skin_rsc_path = os.path.join(ROOT, 'devices', 'skins')
logger.info('Skin ressource path: {rsc}'.format(rsc=skin_rsc_path)) 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') 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)) logger.info('Skin destination path: {dst}'.format(dst=skin_dst_path))
for s in os.listdir(skin_rsc_path): for s in os.listdir(skin_rsc_path):
@ -146,5 +123,4 @@ def create_avd(android_path, device, avd_name, api_level):
logger.info('AVD creation command: {cmd}'.format(cmd=cmd)) logger.info('AVD creation command: {cmd}'.format(cmd=cmd))
titel = 'AVD creation process' titel = 'AVD creation process'
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format( subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
titel=titel, cmd=cmd), shell=True)

View file

@ -6,14 +6,14 @@ import subprocess
logger = logging.getLogger('appium') logger = logging.getLogger('appium')
def run(connect_to_grid, emulator_name, android_version): def run(connect_to_grid, avd_name, android_version):
""" """
Run appium server. Run appium server.
:param connect_to_grid: option to connect with selenium grid :param connect_to_grid: option to connect with selenium grid
:type connect_to_grid: bool :type connect_to_grid: bool
:param emulator_name: name of emulator :param avd_name: name of device
:type emulator_name: str :type avd_name: str
:param android_version: android version :param android_version: android version
:type android_version: str :type android_version: str
""" """
@ -25,14 +25,13 @@ def run(connect_to_grid, emulator_name, android_version):
appium_port = int(os.getenv('APPIUM_PORT', 4723)) appium_port = int(os.getenv('APPIUM_PORT', 4723))
selenium_host = os.getenv('SELENIUM_HOST', '172.17.0.1') selenium_host = os.getenv('SELENIUM_HOST', '172.17.0.1')
selenium_port = int(os.getenv('SELENIUM_PORT', 4444)) selenium_port = int(os.getenv('SELENIUM_PORT', 4444))
create_node_config(CONFIG_FILE, emulator_name, android_version, create_node_config(CONFIG_FILE, avd_name, android_version, appium_host, appium_port,
appium_host, appium_port, selenium_host, selenium_port) selenium_host, selenium_port)
cmd += ' --nodeconfig {file}'.format(file=CONFIG_FILE) cmd += ' --nodeconfig {file}'.format(file=CONFIG_FILE)
except ValueError as v_err: except ValueError as v_err:
logger.error(v_err) logger.error(v_err)
titel = 'avd name: {name}'.format(name=emulator_name) titel = 'avd name: {name}'.format(name=avd_name)
subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format( subprocess.check_call('xterm -T "{titel}" -n "{titel}" -e \"{cmd}\"'.format(titel=titel, cmd=cmd), shell=True)
titel=titel, cmd=cmd), shell=True)
def create_node_config(config_file, emulator_name, android_version, appium_host, appium_port, def create_node_config(config_file, emulator_name, android_version, appium_host, appium_port,

View file

@ -11,25 +11,20 @@ def start():
Installation of needed sdk package, creation of android emulator and execution of appium server. Installation of needed sdk package, creation of android emulator and execution of appium server.
""" """
# Android SDK path
android_path = os.getenv('ANDROID_HOME', '/root')
logger.info('Android path: {path}'.format(path=android_path))
# Emulator informations
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))
# Device name # Device name
device = os.getenv('DEVICE', 'Nexus 5') device = os.getenv('DEVICE', 'Nexus 5')
# Android version # Android version
android_version = os.getenv('ANDROID_VERSION', '4.2.2') android_version = os.getenv('ANDROID_VERSION', '5.0')
logger.info('Android version: {version}'.format(version=android_version)) 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 # Selenium grid connection
connect_to_grid = str_to_bool(str(os.getenv('CONNECT_TO_GRID', False))) 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)) logger.info('Connect to selenium grid? {input}'.format(input=connect_to_grid))
@ -38,21 +33,21 @@ def start():
api_level = android.get_api_level(android_version) api_level = android.get_api_level(android_version)
# Bug: cannot use skin for system image x86 with android version < 5.0 # Bug: cannot use skin for system image x86 with android version < 5.0
if emu_type == android.TYPE_X86: if emu_type == android.TYPE_X86:
if int(api_level) < android.API_LEVEL_ANDROID_5: if int(api_level) < android.get_api_level('5.0'):
sys_img = android.TYPE_X86 sys_img = android.TYPE_X86
device = 'emulator' device = android.EMULATOR
else: else:
sys_img = android.TYPE_X86_64 sys_img = android.TYPE_X86_64
else: else:
sys_img = '{type}-v7a'.format(type=android.TYPE_ARMEABI) sys_img = '{type}-v7a'.format(type=android.TYPE_ARMEABI)
logger.info('System image: {sys_img}'.format(sys_img=sys_img)) logger.info('System image: {sys_img}'.format(sys_img=sys_img))
android.install_package(android_path, emu_file, api_level, sys_img) android.install_package(emu_file, api_level, sys_img)
# Create android virtual device # Create android virtual device
logger.info('Device: {device}'.format(device=device)) logger.info('Device: {device}'.format(device=device))
avd_name = '{device}_{version}'.format(device=device.replace(' ', '_').lower(), version=android_version) avd_name = '{device}_{version}'.format(device=device.replace(' ', '_').lower(), version=android_version)
logger.info('AVD name: {avd}'.format(avd=avd_name)) logger.info('AVD name: {avd}'.format(avd=avd_name))
android.create_avd(android_path, device, avd_name, api_level) android.create_avd(device, avd_name, api_level)
# Run appium server # Run appium server
appium.run(connect_to_grid, avd_name, android_version) appium.run(connect_to_grid, avd_name, android_version)

View file

@ -1,33 +1,20 @@
"""Unit test for android.py.""" """Unit test for android.py."""
from unittest import TestCase from unittest import TestCase
import mock
from src import android from src import android
@mock.patch('src.android.get_available_sdk_packages')
class TestApiLevel(TestCase): class TestApiLevel(TestCase):
"""Unit test class to test method get_api_level.""" """Unit test class to test method get_api_level."""
def setUp(self): def setUp(self):
self.android_version = '4.2.2' self.android_version = '4.2.2'
def test_get_api_level(self, mocked_packages): def test_get_api_level(self):
mocked_packages.return_value = ['9- SDK Platform Android 4.4.2, API 19, revision 4', api_level = android.get_api_level('4.2')
'10- SDK Platform Android 4.3.1, API 18, revision 3', self.assertEqual(api_level, 19)
'11- SDK Platform Android 4.2.2, API 17, revision 3']
api_level = android.get_api_level(self.android_version)
self.assertEqual(api_level, '17')
def test_empty_packages(self, mocked_packages): def test_wrong_type(self):
mocked_packages.return_value = None api_level = android.get_api_level(4)
with self.assertRaises(RuntimeError): self.assertRaises(TypeError)
android.get_api_level(self.android_version) self.assertEqual(api_level, None)
def test_index_error(self, mocked_packages):
mocked_packages.return_value = ['9 SDK Platform Android 4.4.2, API 19, revision 4',
'10 SDK Platform Android 4.3.1, API 18, revision 3',
'11 SDK Platform Android 4.2.2, API 17, revision 3']
android.get_api_level(self.android_version)
self.assertRaises(IndexError)

View file

@ -1,28 +0,0 @@
"""Unit test for android.py."""
from unittest import TestCase
import mock
from src import android
class TestAvailablePackages(TestCase):
"""Unit test class to test method get_available_sdk_packages."""
@mock.patch('subprocess.check_output')
def test_valid_output(self, mocked_output):
mocked_output.return_value = 'package 1 \n package 2'
output = android.get_available_sdk_packages()
self.assertEqual(['package 1', 'package 2'], output)
@mock.patch('subprocess.check_output')
def test_without_line_break(self, mocked_output):
mocked_output.return_value = 'package 1, package 2'
output = android.get_available_sdk_packages()
self.assertEqual(['package 1, package 2'], output)
@mock.patch('subprocess.check_output')
def test_empty_string(self, mocked_output):
mocked_output.return_value = None
output = android.get_available_sdk_packages()
self.assertEqual(None, output)

View file

@ -12,7 +12,6 @@ class TestAvd(TestCase):
"""Unit test class to test method create_avd.""" """Unit test class to test method create_avd."""
def setUp(self): def setUp(self):
self.android_path = '/root'
self.avd_name = 'test_avd' self.avd_name = 'test_avd'
self.api_level = 21 self.api_level = 21
@ -22,7 +21,7 @@ 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(self.android_path, 'Nexus 5', self.avd_name, self.api_level) android.create_avd('Nexus 5', self.avd_name, self.api_level)
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)
@ -33,7 +32,7 @@ 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(self.android_path, 'Samsung Galaxy S6', self.avd_name, self.api_level) android.create_avd('Samsung Galaxy S6', self.avd_name, self.api_level)
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)
@ -44,5 +43,5 @@ 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(self.android_path, 'emulator', self.avd_name, self.api_level) android.create_avd('emulator', self.avd_name, self.api_level)
self.assertFalse(mocked_list_dir.called) self.assertFalse(mocked_list_dir.called)

View file

@ -10,7 +10,6 @@ class TestInstallPackage(TestCase):
"""Unit test class to test method install_package.""" """Unit test class to test method install_package."""
def setUp(self): def setUp(self):
self.android_path = '/root'
self.emulator_file = 'emulator64-arm' self.emulator_file = 'emulator64-arm'
self.api_level = 21 self.api_level = 21
self.sys_img = 'armeabi-v7a' self.sys_img = 'armeabi-v7a'
@ -20,6 +19,6 @@ class TestInstallPackage(TestCase):
def test_package_installation(self, mocked_sys_link, mocked_suprocess): def test_package_installation(self, mocked_sys_link, mocked_suprocess):
self.assertFalse(mocked_sys_link.called) self.assertFalse(mocked_sys_link.called)
self.assertFalse(mocked_suprocess.called) self.assertFalse(mocked_suprocess.called)
android.install_package(self.android_path, self.emulator_file, self.api_level, self.sys_img) android.install_package(self.emulator_file, self.api_level, self.sys_img)
self.assertTrue(mocked_sys_link.called) self.assertTrue(mocked_sys_link.called)
self.assertTrue(mocked_suprocess.called) self.assertTrue(mocked_suprocess.called)

View file

@ -1,27 +0,0 @@
"""Unit test for android.py."""
from unittest import TestCase
from src import android
class TestItemPosition(TestCase):
"""Unit test class to test method get_item_position."""
def setUp(self):
self.items = ['android 4.1', 'android 4.2.2', 'android 4.3', 'android 4.4', 'android 4.4.2']
def test_valid_params(self):
keyword = '4.2'
output = android.get_item_position(keyword, self.items)
self.assertEqual(4, output)
def test_invalid_keyword(self):
keyword = 'fake'
output = android.get_item_position(keyword, self.items)
self.assertEqual(0, output)
def test_empty_array(self):
items = []
keyword = '4.2'
output = android.get_item_position(keyword, items)
self.assertEqual(0, output)