mirror of
https://github.com/budtmo/docker-android.git
synced 2026-07-31 04:07:25 +00:00
Compare commits
29
Commits
v2.18.0-p0
...
v3.0.2-p1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a89d4679be | ||
|
|
9290e90e3c | ||
|
|
136b49fab8 | ||
|
|
c5651e78f9 | ||
|
|
76ae526591 | ||
|
|
46805d6a81 | ||
|
|
6302de6bc4 | ||
|
|
1e1c60fc89 | ||
|
|
2a12e66077 | ||
|
|
f2a418d712 | ||
|
|
44dcc5b166 | ||
|
|
2e88c06124 | ||
|
|
6b34c74a25 | ||
|
|
1fc2c74d8c | ||
|
|
ffbafe87e8 | ||
|
|
62fa6a05c8 | ||
|
|
77542f5b45 | ||
|
|
39df955c26 | ||
|
|
8da596a8f1 | ||
|
|
7f55b248fd | ||
|
|
c434ae7770 | ||
|
|
ff9f9268e3 | ||
|
|
27e95cd197 | ||
|
|
1f1224599e | ||
|
|
846cd2ed09 | ||
|
|
b5fbe9777e | ||
|
|
21ffb20ca6 | ||
|
|
c0368d3d71 | ||
|
|
6e5ed8386a |
@@ -13,29 +13,17 @@ jobs:
|
||||
python-version: ["3.8"]
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
cd cli
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
|
||||
- name: Run test
|
||||
run: |
|
||||
cd cli && nosetests -v
|
||||
- name: Run unit-test
|
||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||
|
||||
release_base:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: run_test
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Get release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
@@ -54,11 +42,20 @@ jobs:
|
||||
android: ["9.0", "10.0", "11.0", "12.0", "13.0", "14.0"]
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up extension
|
||||
run: |
|
||||
echo "${{ secrets.extension }}" > extension.sh
|
||||
chmod 700 extension.sh
|
||||
shell: bash
|
||||
|
||||
- name: Build and push emulator image ${{ matrix.android }} (${RELEASE_VERSION})
|
||||
run: |
|
||||
docker login -u=${{secrets.DOCKER_USERNAME}} -p=${{secrets.DOCKER_PASSWORD}}
|
||||
@@ -70,11 +67,20 @@ jobs:
|
||||
needs: release_base
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Get release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up extension
|
||||
run: |
|
||||
echo "${{ secrets.extension }}" > extension.sh
|
||||
chmod 700 extension.sh
|
||||
shell: bash
|
||||
|
||||
- name: Build and push genymotion image (${RELEASE_VERSION})
|
||||
run: |
|
||||
docker login -u=${{secrets.DOCKER_USERNAME}} -p=${{secrets.DOCKER_PASSWORD}}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Run Test on Demand
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up extension
|
||||
run: |
|
||||
echo "${{ secrets.extension }}" > extension.sh
|
||||
chmod 700 extension.sh
|
||||
shell: bash
|
||||
|
||||
- name: Build base image
|
||||
run: script -e -c "./app.sh build base test"
|
||||
|
||||
- name: Build sample image
|
||||
run: script -e -c "./app.sh build emulator test 11.0"
|
||||
|
||||
- name: Run unit-test
|
||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||
|
||||
- name: Publish test result
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
@@ -4,21 +4,31 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.actor == 'budtmo'
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up extension
|
||||
run: |
|
||||
echo "${{ secrets.extension }}" > extension.sh
|
||||
chmod 700 extension.sh
|
||||
shell: bash
|
||||
|
||||
- name: Build base image
|
||||
run: script -e -c "./app.sh build base test"
|
||||
|
||||
- name: Build emulator image and run unit-test
|
||||
- name: Build sample image
|
||||
run: script -e -c "./app.sh build emulator test 11.0"
|
||||
|
||||
- name: Run unit-test
|
||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||
|
||||
- name: Publish test result
|
||||
|
||||
+1
-1
@@ -17,4 +17,4 @@ tmp/
|
||||
|
||||
# Dev-files
|
||||
n*.txt
|
||||
test-*.sh
|
||||
e*.sh
|
||||
|
||||
@@ -96,7 +96,7 @@ Credit goes to [Guillaume - The Parallel Interface blog](https://www.paralint.co
|
||||
sudo usermod -a -G kvm ${USER}
|
||||
```
|
||||
|
||||
2. Add necessary flags to `/etc/wsl2.conf` to their respective sections.
|
||||
2. Add necessary flags to `/etc/wsl.conf` to their respective sections.
|
||||
```
|
||||
[boot]
|
||||
command = /bin/bash -c 'chown -v root:kvm /dev/kvm && chmod 660 /dev/kvm'
|
||||
@@ -163,7 +163,7 @@ The differences between normal version and pro version are:
|
||||
|user-behavior-analytics|Yes|No|-|
|
||||
|proxy|No|Yes|Set up company proxy on Android emulator on fly|
|
||||
|language|No|Yes|Set up language on Android emulator on fly|
|
||||
|Newer Android version|No|Yes|Support other newer Android version e.g. Android 15, etc|
|
||||
|Newer Android version|No|Yes|Support other newer Android version e.g. Android 15, Android 16, etc|
|
||||
|root-privileged|No|Yes|Able to run command with security privileged|
|
||||
|headless-mode|No|Yes|Save resources by using headless mode|
|
||||
|Selenium 4.x integration|No|Yes|Running Appium UI-Tests againt one (Selenium Hub) endpoint for Android- and iOS emulator(s) / device(s)|
|
||||
|
||||
@@ -81,9 +81,15 @@ echo "${IMAGE_NAME_SPECIFIC_RELEASE} or ${IMAGE_NAME_LATEST} "
|
||||
|
||||
function build() {
|
||||
# autopep8 --recursive --exclude=.git,__pycache__,venv --max-line-length=120 --in-place .
|
||||
cmd="docker build -t ${IMAGE_NAME_SPECIFIC_RELEASE} --build-arg DOCKER_ANDROID_VERSION=${r_v} "
|
||||
cmd="docker build --no-cache -t ${IMAGE_NAME_SPECIFIC_RELEASE} --build-arg DOCKER_ANDROID_VERSION=${r_v} "
|
||||
if [ -n "${a_v}" ]; then
|
||||
cmd+="--build-arg EMULATOR_ANDROID_VERSION=${a_v} --build-arg EMULATOR_API_LEVEL=${a_l} "
|
||||
DOCKER_BUILDKIT=1
|
||||
cmd="${cmd} --secret id=extension,src=extension.sh --build-arg EMULATOR_ANDROID_VERSION=${a_v} --build-arg EMULATOR_API_LEVEL=${a_l} "
|
||||
fi
|
||||
|
||||
if [[ "${p}" == *"genymotion"* ]]; then
|
||||
DOCKER_BUILDKIT=1
|
||||
cmd="${cmd} --secret id=extension,src=extension.sh "
|
||||
fi
|
||||
|
||||
cmd+="-f ${FOLDER_PATH} ."
|
||||
@@ -97,18 +103,14 @@ function build() {
|
||||
}
|
||||
|
||||
function test() {
|
||||
cli_path="/home/androidusr/docker-android/cli"
|
||||
results_path="test-results"
|
||||
tmp_folder="tmp"
|
||||
tmp_folder="/app/tmp"
|
||||
|
||||
mkdir -p tmp
|
||||
build
|
||||
docker run -it --rm --name test --entrypoint /bin/bash \
|
||||
-v $PWD/${tmp_folder}:${cli_path}/${tmp_folder} ${IMAGE_NAME_SPECIFIC_RELEASE} \
|
||||
-c "cd ${cli_path} && sudo rm -rf ${tmp_folder}/* && \
|
||||
nosetests -v && sudo mv .coverage ${tmp_folder} && \
|
||||
sudo cp -r ${results_path}/* ${tmp_folder} && sudo chown -R 1300:1301 ${tmp_folder} &&
|
||||
sudo chmod a+x -R ${tmp_folder}"
|
||||
docker run -it --rm -v "$PWD":/app -w /app python:3.12-slim bash \
|
||||
-c "cd cli && rm -rf ${tmp_folder}/* && \
|
||||
pip install --upgrade pip && pip install -r requirements.txt && \
|
||||
PYTHONPATH=src pytest -v && mv test-results/* ${tmp_folder}/ && chown -R 1300:1301 ${tmp_folder} && \
|
||||
chmod a+x -R ${tmp_folder}"
|
||||
}
|
||||
|
||||
function push() {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
autopep8==2.3.1
|
||||
click==8.1.8
|
||||
coverage==7.6.1
|
||||
autopep8==2.3.2
|
||||
click==8.2.1
|
||||
coverage==7.10.7
|
||||
mock==5.2.0
|
||||
nose==1.3.7
|
||||
requests==2.32.3
|
||||
pytest==8.4.2
|
||||
pytest-cov==7.0.0
|
||||
pytest-xdist==3.8.0
|
||||
requests==2.32.5
|
||||
setuptools==80.9.0
|
||||
|
||||
+7
-10
@@ -1,10 +1,7 @@
|
||||
[nosetests]
|
||||
cover-xml=true
|
||||
cover-xml-file=test-results/coverage.xml
|
||||
with-coverage=true
|
||||
cover-package=src
|
||||
cover-erase=true
|
||||
with-xunit=true
|
||||
xunit-file=test-results/xunit.xml
|
||||
cover-html=true
|
||||
cover-html-dir=test-results/coverage
|
||||
[tool:pytest]
|
||||
addopts =
|
||||
--cov=src
|
||||
--cov-report=html:test-results/html
|
||||
--cov-report=xml:test-results/coverage.xml
|
||||
--junit-xml=test-results/junit-report.xml
|
||||
testpaths = src/tests
|
||||
|
||||
+6
-4
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
app_version = os.getenv("DOCKER_ANDROID_VERSION", "test-version")
|
||||
@@ -10,12 +10,14 @@ with open("requirements.txt", "r") as f:
|
||||
|
||||
setup(
|
||||
name="docker-android",
|
||||
version=app_version,
|
||||
version="0.1",
|
||||
url="https://github.com/budtmo/docker-android",
|
||||
description="CLI for docker-android",
|
||||
author="Budi Utomo",
|
||||
author_email="budtmo.os@gmail.com",
|
||||
install_requires=reqs,
|
||||
packages=find_packages(where="src"),
|
||||
package_dir={"": "src"},
|
||||
py_modules=["cli", "docker-android"],
|
||||
entry_points={"console_scripts": "docker-android=src.app:cli"}
|
||||
)
|
||||
entry_points={"console_scripts": "docker-android=app:cli"}
|
||||
)
|
||||
+8
-8
@@ -8,14 +8,14 @@ import os
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from src.application import Application
|
||||
from src.device import DeviceType
|
||||
from src.device.emulator import Emulator
|
||||
from src.device.geny_aws import GenyAWS
|
||||
from src.device.geny_saas import GenySAAS
|
||||
from src.helper import convert_str_to_bool, get_env_value_or_raise
|
||||
from src.constants import ENV
|
||||
from src.logger import log
|
||||
from application import Application
|
||||
from device import DeviceType
|
||||
from device.emulator import Emulator
|
||||
from device.geny_aws import GenyAWS
|
||||
from device.geny_saas import GenySAAS
|
||||
from helper import convert_str_to_bool, get_env_value_or_raise
|
||||
from constants import ENV
|
||||
from logger import log
|
||||
|
||||
log.init()
|
||||
logger = logging.getLogger("App")
|
||||
|
||||
@@ -38,6 +38,7 @@ GENYMOTION_TEMPLATE_PATH = "GENYMOTION_TEMPLATE_PATH"
|
||||
# Device (Geny_SAAS)
|
||||
GENY_SAAS_USER = "GENY_SAAS_USER"
|
||||
GENY_SAAS_PASS = "GENY_SAAS_PASS"
|
||||
GENY_AUTH_TOKEN = "GENY_AUTH_TOKEN"
|
||||
GENY_SAAS_TEMPLATE_FILE_NAME = "saas.json"
|
||||
|
||||
# Device (Geny_AWS)
|
||||
|
||||
@@ -9,8 +9,8 @@ import time
|
||||
from abc import ABC, abstractmethod
|
||||
from enum import Enum
|
||||
|
||||
from src.helper import convert_str_to_bool, get_env_value_or_raise
|
||||
from src.constants import DEVICE, ENV
|
||||
from helper import convert_str_to_bool, get_env_value_or_raise
|
||||
from constants import DEVICE, ENV
|
||||
|
||||
|
||||
class DeviceType(Enum):
|
||||
|
||||
@@ -5,9 +5,9 @@ import time
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from src.device import Device, DeviceType
|
||||
from src.helper import convert_str_to_bool, get_env_value_or_raise, symlink_force
|
||||
from src.constants import ENV, UTF8
|
||||
from device import Device, DeviceType
|
||||
from helper import convert_str_to_bool, get_env_value_or_raise, symlink_force
|
||||
from constants import ENV, UTF8
|
||||
|
||||
|
||||
class Emulator(Device):
|
||||
|
||||
@@ -5,9 +5,9 @@ import shutil
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from src.device import Genymotion, DeviceType
|
||||
from src.helper import get_env_value_or_raise
|
||||
from src.constants import ENV, UTF8
|
||||
from device import Genymotion, DeviceType
|
||||
from helper import get_env_value_or_raise
|
||||
from constants import ENV, UTF8
|
||||
|
||||
|
||||
class GenyAWS(Genymotion):
|
||||
|
||||
+104
-35
@@ -1,10 +1,12 @@
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import concurrent.futures
|
||||
import uuid
|
||||
|
||||
from src.device import Genymotion, DeviceType
|
||||
from src.helper import get_env_value_or_raise
|
||||
from src.constants import ENV, UTF8
|
||||
|
||||
from device import Genymotion, DeviceType
|
||||
from helper import get_env_value_or_raise
|
||||
from constants import ENV, UTF8
|
||||
|
||||
class GenySAAS(Genymotion):
|
||||
def __init__(self) -> None:
|
||||
@@ -12,20 +14,26 @@ class GenySAAS(Genymotion):
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.device_type = DeviceType.GENY_SAAS.value
|
||||
self.created_devices = []
|
||||
|
||||
|
||||
def login(self) -> None:
|
||||
user = get_env_value_or_raise(ENV.GENY_SAAS_USER)
|
||||
password = get_env_value_or_raise(ENV.GENY_SAAS_PASS)
|
||||
subprocess.check_call(f"gmsaas auth login {user} {password} > /dev/null 2>&1", shell=True)
|
||||
if os.getenv(ENV.GENY_AUTH_TOKEN):
|
||||
auth_token = get_env_value_or_raise(ENV.GENY_AUTH_TOKEN)
|
||||
subprocess.check_call(f"gmsaas auth token {auth_token} > /dev/null 2>&1", shell=True)
|
||||
else:
|
||||
user = get_env_value_or_raise(ENV.GENY_SAAS_USER)
|
||||
password = get_env_value_or_raise(ENV.GENY_SAAS_PASS)
|
||||
subprocess.check_call(f"gmsaas auth login {user} {password} > /dev/null 2>&1", shell=True)
|
||||
self.logger.info("successfully logged in!")
|
||||
|
||||
|
||||
def create(self) -> None:
|
||||
super().create()
|
||||
|
||||
# Collect all items first
|
||||
items = []
|
||||
for item in self.get_data_from_template(ENV.GENY_SAAS_TEMPLATE_FILE_NAME):
|
||||
name = ""
|
||||
template = ""
|
||||
local_port = ""
|
||||
|
||||
# implement like this because local_port param is not a must
|
||||
for k, v in item.items():
|
||||
if k.lower() == "name":
|
||||
@@ -36,37 +44,98 @@ class GenySAAS(Genymotion):
|
||||
local_port = v
|
||||
else:
|
||||
self.logger.warning(f"'{k}' is not supported! Please check the documentation!")
|
||||
|
||||
|
||||
if not name:
|
||||
import uuid
|
||||
name = str(uuid.uuid4())
|
||||
|
||||
|
||||
if not template:
|
||||
self.shutdown_and_logout()
|
||||
raise RuntimeError(f"'template' is a must parameter and not given!")
|
||||
else:
|
||||
self.logger.info(f"name: {name}, template: {template}")
|
||||
creation_cmd = f"gmsaas instances start {template} {name}"
|
||||
try:
|
||||
instance_id = subprocess.check_output(creation_cmd.split()).decode(UTF8).replace("\n", "")
|
||||
created_device = {f"{name}": {instance_id}}
|
||||
self.created_devices.append(created_device)
|
||||
additional_args = ""
|
||||
if local_port:
|
||||
additional_args = f"--adb-serial-port {local_port}"
|
||||
connect_cmd = f"gmsaas instances adbconnect {instance_id} {additional_args}"
|
||||
subprocess.check_call(f"{connect_cmd}", shell=True)
|
||||
except Exception as e:
|
||||
self.shutdown_and_logout()
|
||||
self.logger.error(e)
|
||||
exit(1)
|
||||
|
||||
items.append({
|
||||
'name': name,
|
||||
'template': template,
|
||||
'local_port': local_port
|
||||
})
|
||||
|
||||
# Start all devices in parallel
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
|
||||
try:
|
||||
# Submit all tasks
|
||||
future_to_item = {executor.submit(self.create_instance, item): item for item in items}
|
||||
|
||||
# Collect results as they complete
|
||||
for future in concurrent.futures.as_completed(future_to_item):
|
||||
item = future_to_item[future]
|
||||
try:
|
||||
created_device = future.result()
|
||||
self.created_devices.append(created_device)
|
||||
self.logger.info(f"Successfully created device: {created_device}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Instance creation failed for {item['name']}: {e}")
|
||||
self.shutdown_and_logout()
|
||||
exit(1)
|
||||
|
||||
except Exception as e:
|
||||
self.shutdown_and_logout()
|
||||
self.logger.error(f"Parallel execution failed: {e}")
|
||||
exit(1)
|
||||
|
||||
def create_instance(self, item_data):
|
||||
"""Create a single instance and return the result"""
|
||||
name = item_data['name']
|
||||
template = item_data['template']
|
||||
local_port = item_data['local_port']
|
||||
|
||||
self.logger.info(f"name: {name}, template: {template}")
|
||||
creation_cmd = f"gmsaas instances start {template} {name}"
|
||||
|
||||
try:
|
||||
instance_id = subprocess.check_output(creation_cmd.split()).decode(UTF8).replace("\n", "")
|
||||
|
||||
# Connect to ADB
|
||||
additional_args = ""
|
||||
if local_port:
|
||||
additional_args = f"--adb-serial-port {local_port}"
|
||||
connect_cmd = f"gmsaas instances adbconnect {instance_id} {additional_args}"
|
||||
subprocess.check_call(f"{connect_cmd}", shell=True)
|
||||
|
||||
return {f"{name}": instance_id}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to create instance {name}: {e}")
|
||||
raise e
|
||||
|
||||
def stop_instance(self, device_info):
|
||||
"""Stop a single instance"""
|
||||
for name, instance_id in device_info.items():
|
||||
try:
|
||||
subprocess.check_call(f"gmsaas instances stop {instance_id}", shell=True)
|
||||
self.logger.info(f"device '{name}' is successfully removed!")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to stop device '{name}': {e}")
|
||||
return False
|
||||
|
||||
def shutdown_and_logout(self) -> None:
|
||||
if bool(self.created_devices):
|
||||
self.logger.info("Created device(s) will be removed!")
|
||||
for d in self.created_devices:
|
||||
for n, i in d.items():
|
||||
subprocess.check_call(f"gmsaas instances stop {i}", shell=True)
|
||||
self.logger.info(f"device '{n}' is successfully removed!")
|
||||
subprocess.check_call("gmsaas auth logout", shell=True)
|
||||
self.logger.info("successfully logged out!")
|
||||
|
||||
# Stop all devices in parallel
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
|
||||
# Submit all stop tasks
|
||||
futures = [executor.submit(self.stop_instance, device) for device in self.created_devices]
|
||||
|
||||
# Wait for all to complete
|
||||
for future in concurrent.futures.as_completed(futures):
|
||||
try:
|
||||
future.result()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error during device shutdown: {e}")
|
||||
|
||||
# Logout after all devices are stopped
|
||||
if os.getenv(ENV.GENY_AUTH_TOKEN):
|
||||
subprocess.check_call("gmsaas auth reset", shell=True)
|
||||
else:
|
||||
subprocess.check_call("gmsaas auth logout", shell=True)
|
||||
self.logger.info("successfully logged out!")
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging.config
|
||||
|
||||
from src.logger import LOGGING_FILE
|
||||
from logger import LOGGING_FILE
|
||||
|
||||
|
||||
def init():
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
from src.constants import ENV
|
||||
from src.tests import BaseTest
|
||||
from constants import ENV
|
||||
from tests import BaseTest
|
||||
|
||||
|
||||
class BaseDeviceTest(BaseTest):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from src.device import Device
|
||||
from src.tests.device import BaseDeviceTest
|
||||
from device import Device
|
||||
from tests.device import BaseDeviceTest
|
||||
|
||||
|
||||
class TestDevice(BaseDeviceTest):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import mock
|
||||
|
||||
from src.device.emulator import Emulator
|
||||
from src.tests.device import BaseDeviceTest
|
||||
from device.emulator import Emulator
|
||||
from tests.device import BaseDeviceTest
|
||||
|
||||
|
||||
class TestEmulator(BaseDeviceTest):
|
||||
@@ -52,32 +52,6 @@ class TestEmulator(BaseDeviceTest):
|
||||
def test_initialisation_device_exists(self):
|
||||
self.assertEqual(self.emu.is_initialized(), True)
|
||||
|
||||
@mock.patch("src.device.Device.set_status")
|
||||
@mock.patch("src.device.emulator.Emulator._add_profile")
|
||||
@mock.patch("subprocess.check_call")
|
||||
@mock.patch("src.device.emulator.Emulator._add_skin")
|
||||
@mock.patch("src.device.emulator.Emulator._use_override_config")
|
||||
@mock.patch("src.device.emulator.Emulator.is_initialized", mock.MagicMock(return_value=False))
|
||||
def test_create_device_not_exist(self, mocked_status, mocked_profile, mocked_subprocess, mocked_skin, mocked_override_config):
|
||||
self.emu.create()
|
||||
self.assertEqual(mocked_status.called, True)
|
||||
self.assertEqual(mocked_profile.called, True)
|
||||
self.assertEqual(mocked_subprocess.called, True)
|
||||
self.assertEqual(mocked_skin.called, True)
|
||||
self.assertEqual(mocked_override_config.called, True)
|
||||
|
||||
@mock.patch("src.device.Device.set_status")
|
||||
@mock.patch("src.device.emulator.Emulator._add_profile")
|
||||
@mock.patch("subprocess.check_call")
|
||||
@mock.patch("src.device.emulator.Emulator._add_skin")
|
||||
@mock.patch("src.device.emulator.Emulator._use_override_config")
|
||||
@mock.patch("src.device.emulator.Emulator.is_initialized", mock.MagicMock(return_value=True))
|
||||
def test_create_device_exists(self, mocked_status, mocked_profile, mocked_subprocess, mocked_skin, mocked_override_config):
|
||||
self.emu.create()
|
||||
self.assertEqual(mocked_status.called, False)
|
||||
self.assertEqual(mocked_profile.called, False)
|
||||
self.assertEqual(mocked_subprocess.called, False)
|
||||
|
||||
def test_check_adb_command(self):
|
||||
with mock.patch("subprocess.check_output", mock.MagicMock(return_value="1".encode("utf-8"))):
|
||||
self.emu.check_adb_command(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import os
|
||||
import mock
|
||||
|
||||
from src.helper import convert_str_to_bool, get_env_value_or_raise, symlink_force
|
||||
from src.tests import BaseTest
|
||||
from helper import convert_str_to_bool, get_env_value_or_raise, symlink_force
|
||||
from tests import BaseTest
|
||||
|
||||
|
||||
class TestHelperMethods(BaseTest):
|
||||
@@ -45,10 +45,6 @@ class TestHelperMethods(BaseTest):
|
||||
with self.assertRaises(RuntimeError):
|
||||
get_env_value_or_raise("env_key02")
|
||||
|
||||
def test_get_env_value_with_invalid_format(self):
|
||||
with mock.patch("src.logger"):
|
||||
get_env_value_or_raise(True)
|
||||
|
||||
def test_symlink(self):
|
||||
s = os.path.join("source.txt")
|
||||
t = os.path.join("target_file.txt")
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
FROM appium/appium:v2.18.0-p0
|
||||
FROM appium/appium:v3.0.2-p0
|
||||
|
||||
LABEL maintainer "Budi Utomo <budtmo.os@gmail.com>"
|
||||
ARG AUTHORS="Budi Utomo"
|
||||
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
+4
-4
@@ -50,8 +50,8 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||
#=======
|
||||
# noVNC
|
||||
#=======
|
||||
ENV NOVNC_VERSION="1.4.0" \
|
||||
WEBSOCKIFY_VERSION="0.11.0" \
|
||||
ENV NOVNC_VERSION="1.6.0" \
|
||||
WEBSOCKIFY_VERSION="0.13.0" \
|
||||
OPT_PATH="/opt"
|
||||
RUN wget -nv -O noVNC.zip "https://github.com/novnc/noVNC/archive/refs/tags/v${NOVNC_VERSION}.zip" \
|
||||
&& unzip -x noVNC.zip \
|
||||
@@ -83,8 +83,8 @@ ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
||||
RUN mkdir -p ${APP_PATH}
|
||||
COPY mixins ${APP_PATH}/mixins
|
||||
COPY cli ${APP_PATH}/cli
|
||||
RUN chown -R 1300:1301 ${APP_PATH} \
|
||||
&& pip install --quiet -e ${APP_PATH}/cli
|
||||
RUN --mount=type=secret,id=extension,dst=/tmp/extension.sh \
|
||||
bash /tmp/extension.sh
|
||||
|
||||
#===================
|
||||
# Configure OpenBox
|
||||
|
||||
+3
-8
@@ -1,12 +1,7 @@
|
||||
ARG DOCKER_ANDROID_VERSION
|
||||
FROM budtmo/docker-android:base_${DOCKER_ANDROID_VERSION}
|
||||
|
||||
#===================================================
|
||||
# Install Genymotion CLI
|
||||
# (for user management and deployment on Geny Cloud)
|
||||
#===================================================
|
||||
ENV GMSAAS_CLI_VERSION="1.7.1"
|
||||
RUN pip install gmsaas==${GMSAAS_CLI_VERSION}
|
||||
ENV GMSAAS_CLI_VERSION="1.15.0"
|
||||
|
||||
#================
|
||||
# Cloud Packages
|
||||
@@ -40,8 +35,8 @@ ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
||||
RUN mkdir -p ${APP_PATH}
|
||||
COPY mixins ${APP_PATH}/mixins
|
||||
COPY cli ${APP_PATH}/cli
|
||||
RUN chown -R 1300:1301 ${APP_PATH} \
|
||||
&& pip install --quiet -e ${APP_PATH}/cli
|
||||
RUN --mount=type=secret,id=extension,dst=/tmp/extension.sh \
|
||||
bash /tmp/extension.sh
|
||||
|
||||
#===================================
|
||||
# Create Genymotion Template folder
|
||||
|
||||
@@ -29,6 +29,7 @@ List of Docker-Images
|
||||
|13.0|33|Normal|budtmo2/docker-android-pro:emulator_13.0|budtmo2/docker-android-pro:emulator_13.0_<release_version>|
|
||||
|14.0|34|Normal|budtmo2/docker-android-pro:emulator_14.0|budtmo2/docker-android-pro:emulator_14.0_<release_version>|
|
||||
|15.0|35|Normal|budtmo2/docker-android-pro:emulator_15.0|budtmo2/docker-android-pro:emulator_15.0_<release_version>|
|
||||
|16.0|36|Normal|budtmo2/docker-android-pro:emulator_16.0|budtmo2/docker-android-pro:emulator_16.0_<release_version>|
|
||||
|9.0|28|Headless|budtmo2/docker-android-pro:emulator_headless_9.0|budtmo2/docker-android-pro:emulator_headless_9.0_<release_version>|
|
||||
|10.0|29|Headless|budtmo2/docker-android-pro:emulator_headless_10.0|budtmo2/docker-android-pro:emulator_headless_10.0_<release_version>|
|
||||
|11.0|30|Headless|budtmo2/docker-android-pro:emulator_headless_11.0|budtmo2/docker-android-pro:emulator_headless_11.0_<release_version>|
|
||||
@@ -36,6 +37,7 @@ List of Docker-Images
|
||||
|13.0|33|Headless|budtmo2/docker-android-pro:emulator_headless_13.0|budtmo2/docker-android-pro:emulator_headless_13.0_<release_version>|
|
||||
|14.0|34|Headless|budtmo2/docker-android-pro:emulator_headless_14.0|budtmo2/docker-android-pro:emulator_headless_14.0_<release_version>|
|
||||
|15.0|35|Headless|budtmo2/docker-android-pro:emulator_headless_15.0|budtmo2/docker-android-pro:emulator_headless_15.0_<release_version>|
|
||||
|16.0|36|Headless|budtmo2/docker-android-pro:emulator_headless_16.0|budtmo2/docker-android-pro:emulator_headless_16.0_<release_version>|
|
||||
|-|-|Selenium|budtmo2/docker-android-pro:selenium|budtmo2/docker-android-pro:selenium_<release_version>|
|
||||
|
||||
***Note: Headless mode does not have any Web-UI***
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
```
|
||||
export USER="xxx"
|
||||
export PASS="xxx"
|
||||
|
||||
docker run -d -p 4723:4723 -v ${PWD}/example/genycloud/saas.json:/home/androidusr/genymotion_template/saas.json -e DEVICE_TYPE=geny_saas -e GENY_SAAS_USER=${USER} -e GENY_SAAS_PASS=${PASS} -e APPIUM=true --name android-container budtmo/docker-android:genymotion
|
||||
```
|
||||
Genymotion Cloud
|
||||
----------------
|
||||
|
||||
@@ -9,12 +15,13 @@ You can use Genymotion Android virtual devices in the cloud. They are available
|
||||
Use [saas.json](../example/genymotion/saas.json) to define the devices that you want to use. You can specify the port on which the device will start so you don't need to change the device name in your tests every time you need to run those tests. Then run following command
|
||||
|
||||
```
|
||||
export USER="xxx"
|
||||
export PASS="xxx"
|
||||
export AUTH_TOKEN="xxx"
|
||||
|
||||
docker run -d -p 4723:4723 -v ${PWD}/example/genycloud/saas.json:/home/androidusr/genymotion_template/saas.json -e DEVICE_TYPE=geny_saas -e GENY_SAAS_USER=${USER} -e GENY_SAAS_PASS=${PASS} -e APPIUM=true --name android-container budtmo/docker-android:genymotion
|
||||
docker run -d -p 4723:4723 -v ${PWD}/example/genycloud/saas.json:/home/androidusr/genymotion_template/saas.json -e DEVICE_TYPE=geny_saas -e GENY_AUTH_TOKEN=${AUTH_TOKEN} -e APPIUM=true --name android-container budtmo/docker-android:genymotion
|
||||
```
|
||||
|
||||
Genymotion has deprecated credential based login since gmsaas 1.10.0, but if necessary, you can still provide them using `-e GENY_SAAS_USER=${USER} -e GENY_SAAS_PASS=${PASS}` instead of `-e GENY_AUTH_TOKEN=${AUTH_TOKEN}`.
|
||||
|
||||
The deployed device(s) are automatically connected with adb inside docker container. Stopping the emulator will remove all deployed device(s) on Genymotion SaaS and user will be logged out at the end.
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user