Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a5e0096
Showing
18 changed files
with
419 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.idea/* | ||
.DS_Store | ||
*.pyc | ||
|
||
# Coverage | ||
.coverage | ||
coverage.xml | ||
xunit.xml | ||
coverage/* |
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,10 @@ | ||
language: python | ||
python: | ||
- "2.7" | ||
install: "pip install -r requirements.txt" | ||
script: nosetests | ||
branches: | ||
only: | ||
- master | ||
after_success: | ||
- bash <(curl -s https://codecov.io/bash) |
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,53 @@ | ||
FROM ubuntu:16.04 | ||
|
||
#======================= | ||
# General Configuration | ||
#======================= | ||
RUN apt-get update && apt-get upgrade -y | ||
RUN apt-get install wget -y | ||
|
||
#============== | ||
# Install Java | ||
#============== | ||
RUN apt-get install openjdk-8-jdk -y | ||
ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/jre" | ||
ENV PATH="${PATH}:${JAVA_HOME}/bin" | ||
|
||
#===================== | ||
# Install Android SDK | ||
#===================== | ||
RUN wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz | ||
RUN tar -xvzf android-sdk_r24.4.1-linux.tgz | ||
ENV ANDROID_HOME="/android-sdk-linux" | ||
ENV PATH="${PATH}:${ANDROID_HOME}/tools" | ||
|
||
#===================================================== | ||
# Install Platform-tools, Build-tools | ||
# To see list of available packages: android list sdk | ||
#===================================================== | ||
RUN echo y | android update sdk --no-ui --filter 2,3 | ||
ENV PATH="${PATH}:${ANDROID_HOME}/platform-tools" | ||
ENV PATH="${PATH}:${ANDROID_HOME}/build-tools" | ||
|
||
#================================================== | ||
# Fix issue regarding 64bit while running emulator | ||
#================================================== | ||
RUN dpkg --add-architecture i386 | ||
RUN apt-get update | ||
RUN apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 -y | ||
ENV ANDROID_EMULATOR_FORCE_32BIT=true | ||
RUN adb start-server | ||
|
||
#============================================ | ||
# Install nodejs, npm, appium, appium-doctor | ||
#============================================ | ||
RUN apt-get install npm nodejs-legacy -y | ||
ENV APPIUM_VERSION 1.6.3 | ||
RUN npm install -g appium@$APPIUM_VERSION | ||
|
||
#=================== | ||
# Run docker-appium | ||
#=================== | ||
COPY service /service | ||
WORKDIR /service | ||
CMD python start.py |
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,13 @@ | ||
Copyright 2016 budi utomo | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. |
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 @@ | ||
Budi Utomo <budi.ut.1989@gmail.com> |
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,45 @@ | ||
Docker-Android-Appium | ||
===================== | ||
|
||
Android emulator and Appium server in docker solution. | ||
|
||
Requirements | ||
------------ | ||
|
||
Docker is installed in your system. | ||
|
||
Quick Start | ||
----------- | ||
|
||
1. Run docker-appium with command: | ||
|
||
```bash | ||
docker run -d -p 4723:4723 -v <apk_path_that_will_be_tested>:/target_apk -e ANDROID_VERSION=<target_android_version> --name appium-container butomo1989/docker-appium | ||
``` | ||
|
||
***Note: There is an example apk in folder example.*** | ||
|
||
An Example: | ||
|
||
```bash | ||
docker run -d -p 4723:4723 -v $PWD/example/sample_apk:/target_apk -e ANDROID_VERSION=4.2.2 --name appium-container docker-android-appium | ||
``` | ||
|
||
2. See the docker logs with command: | ||
|
||
```bash | ||
docker logs appium-container -f | ||
``` | ||
|
||
3. Wait until you see this following example messages in logs that showing that appium server is ready to use: | ||
|
||
```bash | ||
INFO:android_appium:Android emulator is created | ||
INFO:android_appium:android emulator name: emulator_4.2.2 | ||
[Appium] Welcome to Appium v1.6.3 | ||
[Appium] Appium REST http interface listener started on 0.0.0.0:4723 | ||
``` | ||
|
||
4. Run your UI tests by using docker-appium. | ||
|
||
***Note: There is an example UITests in folder example.*** |
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,14 @@ | ||
Docker-Android-Appium Sample | ||
---------------------------- | ||
|
||
Example UI test to use docker-appium. | ||
|
||
Requirements | ||
============ | ||
1. docker-appium | ||
2. python | ||
|
||
Quick Start | ||
=========== | ||
1. pip install -r requirements | ||
2. python android_simple.py |
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,34 @@ | ||
import unittest | ||
|
||
from appium import webdriver | ||
|
||
|
||
class SimpleAndroidUITests(unittest.TestCase): | ||
|
||
def setUp(self): | ||
desired_caps = { | ||
'platformName': 'Android', | ||
'deviceName': 'Android Emulator', | ||
'platformVersion': '4.2', | ||
'app': '/target_apk/sample_apk_debug.apk', | ||
'avd': 'emulator_4.2.2' | ||
} | ||
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) | ||
|
||
def tearDown(self): | ||
self.driver.quit() | ||
|
||
def test_calculation(self): | ||
text_fields = self.driver.find_elements_by_class_name('android.widget.EditText') | ||
text_fields[0].send_keys(4) | ||
text_fields[1].send_keys(6) | ||
|
||
btn_calculate = self.driver.find_element_by_class_name('android.widget.Button') | ||
btn_calculate.click() | ||
|
||
self.assertEqual('10', text_fields[2].text) | ||
|
||
|
||
if __name__ == '__main__': | ||
suite = unittest.TestLoader().loadTestsFromTestCase(SimpleAndroidUITests) | ||
unittest.TextTestRunner(verbosity=2).run(suite) |
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 @@ | ||
Appium-Python-Client==0.23 |
Binary file not shown.
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,4 @@ | ||
autopep8==1.2.4 | ||
coverage==4.2 | ||
mock==2.0.0 | ||
nose==1.3.7 |
Empty file.
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,110 @@ | ||
import logging | ||
import os | ||
import re | ||
import subprocess | ||
|
||
logging.basicConfig() | ||
logger = logging.getLogger('android_appium') | ||
|
||
|
||
def run(): | ||
""" | ||
Run Android emulator and Appium server. | ||
""" | ||
android_version = os.getenv('ANDROID_VERSION', '4.2.2') | ||
create_android_emulator(android_version) | ||
|
||
emulator_name = 'emulator_{version}'.format(version=android_version) | ||
|
||
logger.info('android emulator name: {name} '.format(name=emulator_name)) | ||
# TODO: check android emulator is ready to use | ||
cmd_run = 'emulator -avd {name} -no-audio -no-window & appium'.format(name=emulator_name) | ||
subprocess.check_call(cmd_run, shell=True) | ||
|
||
|
||
def get_available_sdk_packages(): | ||
""" | ||
Get list of available sdk packages. | ||
:return: List of available packages. | ||
:rtype: bytearray | ||
""" | ||
logger.info('List of Android SDK: ') | ||
cmd = ['android', 'list', 'sdk'] | ||
|
||
output_str = subprocess.check_output(cmd) | ||
logger.info(output_str) | ||
|
||
return [output.strip() for output in output_str.split('\n')] if output_str else None | ||
|
||
|
||
def get_item_position(keyword, items): | ||
""" | ||
Get position of item in array by given keyword. | ||
:return: Item position. | ||
:rtype: int | ||
""" | ||
pos = 0 | ||
for p, v in enumerate(items): | ||
if keyword in v: | ||
pos = p | ||
break # Get the first item that match with keyword | ||
return pos | ||
|
||
|
||
def create_android_emulator(android_version): | ||
""" | ||
Create android emulator based on given android version. | ||
It include installation of sdk package and its armeabi v7a. | ||
To see list of available targets: android list targets | ||
To see list to avd: android list avd | ||
:param android_version: android version | ||
:type android_version: str | ||
""" | ||
try: | ||
packages = get_available_sdk_packages() | ||
|
||
if packages: | ||
item_pos = get_item_position(android_version, packages) | ||
logger.info('item position: {pos}'.format(pos=item_pos)) | ||
item = packages[item_pos] | ||
|
||
item_info = item.split('-') | ||
package_number = item_info[0] | ||
api_version = re.search('%s(.*)%s' % ('API', ','), item_info[1]).group(1).strip() | ||
logger.info( | ||
'Package number: {number}, API version: {version}'.format(number=package_number, version=api_version)) | ||
|
||
# Install SDK package | ||
logger.info('Installing SDK package...') | ||
cmd_sdk = 'echo y | android update sdk --no-ui --filter {number}'.format(number=package_number) | ||
subprocess.check_call(cmd_sdk, shell=True) | ||
logger.info('Installation completed') | ||
|
||
# Install armeabi v7a | ||
logger.info('Installing its armeabi...') | ||
cmd_arm = 'echo y | android update sdk --no-ui -a --filter sys-img-armeabi-v7a-android-{api}'.format( | ||
api=api_version) | ||
subprocess.check_call(cmd_arm, shell=True) | ||
logger.info('Installation completed') | ||
|
||
# Create android emulator | ||
logger.info('Creating android emulator...') | ||
cmd_emu = 'echo no | android create avd -f -n emulator_{version} -t android-{api} --abi armeabi-v7a'.format( | ||
version=android_version, api=api_version) | ||
subprocess.check_call(cmd_emu, shell=True) | ||
logger.info('Android emulator is created') | ||
else: | ||
raise RuntimeError('Packages is empty!') | ||
|
||
except IndexError as i_err: | ||
logger.error(i_err) | ||
|
||
|
||
if __name__ == '__main__': | ||
logger.setLevel(logging.INFO) | ||
run() |
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,19 @@ | ||
"""Unit test for start.py.""" | ||
from unittest import TestCase | ||
|
||
import mock | ||
|
||
from service import start | ||
|
||
|
||
class TestService(TestCase): | ||
"""Unit test class to test method run.""" | ||
|
||
@mock.patch('service.start.create_android_emulator') | ||
@mock.patch('subprocess.check_call') | ||
def test_service(self, mocked_creation, mocked_subprocess): | ||
self.assertFalse(mocked_creation.called) | ||
self.assertFalse(mocked_subprocess.called) | ||
start.run() | ||
self.assertTrue(mocked_creation.called) | ||
self.assertTrue(mocked_subprocess.called) |
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,34 @@ | ||
"""Unit test for start.py.""" | ||
from unittest import TestCase | ||
|
||
import mock | ||
|
||
from service import start | ||
|
||
|
||
@mock.patch('service.start.get_available_sdk_packages') | ||
class TestRunService(TestCase): | ||
"""Unit test class to test method create_android_emulator.""" | ||
|
||
def test_create_emulator(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'] | ||
with mock.patch('subprocess.check_call') as mocked_subprocess: | ||
self.assertFalse(mocked_subprocess.called) | ||
android_version = '4.2.2' | ||
start.create_android_emulator(android_version) | ||
self.assertTrue(mocked_subprocess.called) | ||
|
||
def test_empty_packages(self, mocked_packages): | ||
mocked_packages.return_value = None | ||
with self.assertRaises(RuntimeError): | ||
start.create_android_emulator('4.2.2') | ||
|
||
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_version = '4.2.2' | ||
start.create_android_emulator(android_version) | ||
self.assertRaises(IndexError) |
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,28 @@ | ||
"""Unit test for start.py.""" | ||
from unittest import TestCase | ||
|
||
import mock | ||
|
||
from service import start | ||
|
||
|
||
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 = start.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 = start.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 = start.get_available_sdk_packages() | ||
self.assertEqual(None, output) |
Oops, something went wrong.