Compare commits

..
17 Commits
Author SHA1 Message Date
budi c434ae7770 Updated base image 2025-07-31 19:04:33 +02:00
budi ff9f9268e3 Updated docu 2025-07-28 12:49:43 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
27e95cd197 [pip] Bump coverage from 7.9.2 to 7.10.0 (#519)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.9.2 to 7.10.0.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.9.2...7.10.0)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-25 09:39:58 +02:00
budi 1f1224599e Modified github action build 2025-07-04 10:09:16 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
846cd2ed09 [pip] Bump coverage from 7.8.1 to 7.9.2 (#516)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.8.1 to 7.9.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.8.1...7.9.2)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.9.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-04 08:54:21 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b5fbe9777e [pip] Bump pytest-xdist from 3.7.0 to 3.8.0 (#515)
Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.7.0 to 3.8.0.
- [Release notes](https://github.com/pytest-dev/pytest-xdist/releases)
- [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.7.0...v3.8.0)

---
updated-dependencies:
- dependency-name: pytest-xdist
  dependency-version: 3.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 08:27:44 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
21ffb20ca6 [pip] Bump setuptools from 80.8.0 to 80.9.0 (#513)
Bumps [setuptools](https://github.com/pypa/setuptools) from 80.8.0 to 80.9.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v80.8.0...v80.9.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-version: 80.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-30 17:00:40 +02:00
budi c0368d3d71 Updated base image and adjusted 2025-06-26 23:10:08 +02:00
Dave GolombekandGitHub 6e5ed8386a Add Genymotion auth tokens (#512)
As described in #511, Genymotion has deprecated credential based
login. This adds support for passing in an auth token instead.

This could also check for the GENYMOTION_API_TOKEN env variable being
set and skipping the login entirely, but I haven't added that in favor
of keeping the explicit token check during login.

This also updates the default version of the gmsaas package to the
latest release.
2025-06-20 08:42:58 +02:00
budi 602dcf15a7 Updated ubuntu on the runner 2025-04-28 11:15:58 +02:00
budi 1dd79c6188 Updated base image 2025-04-28 11:10:20 +02:00
budi 7abe6c19d8 Updated ubuntu on the runner 2025-04-28 11:09:42 +02:00
Jiří ČernýandGitHub eb91462bd4 Allow to override emulator config from config file defined by path in EVN (#492) 2025-04-28 11:08:52 +02:00
Budi UtomoandGitHub ac251e7704 Merge pull request #493 from jirkace/device_pixel
Allow to use Pixel C as emulator device
2025-03-11 08:37:56 +01:00
blackie b997803064 Allow to use Pixel C as emulator device 2025-03-11 00:07:47 +01:00
Budi UtomoandGitHub 88dbde577e Merge pull request #491 from budtmo/dependabot/pip/master/mock-5.2.0
[pip] Bump mock from 5.1.0 to 5.2.0
2025-03-04 14:41:52 +01:00
dependabot[bot]andGitHub a51e451a1f [pip] Bump mock from 5.1.0 to 5.2.0
Bumps [mock](https://github.com/testing-cabal/mock) from 5.1.0 to 5.2.0.
- [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/testing-cabal/mock/compare/5.1.0...5.2.0)

---
updated-dependencies:
- dependency-name: mock
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-04 00:45:42 +00:00
26 changed files with 234 additions and 131 deletions
+24 -18
View File
@@ -7,7 +7,7 @@ on:
jobs:
run_test:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.8"]
@@ -15,23 +15,11 @@ jobs:
- name: Checkout the repo
uses: actions/checkout@v4
- 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-20.04
runs-on: ubuntu-24.04
needs: run_test
steps:
- name: Checkout the repo
@@ -47,7 +35,7 @@ jobs:
docker logout
release_emulator:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
needs: release_base
strategy:
matrix:
@@ -56,9 +44,18 @@ jobs:
- name: Checkout the repo
uses: actions/checkout@v4
- 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}}
@@ -66,15 +63,24 @@ jobs:
docker logout
release_genymotion:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
needs: release_base
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- 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}}
+32
View File
@@ -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@v4
- 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)
+15 -5
View File
@@ -4,21 +4,31 @@ on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build_and_test:
runs-on: ubuntu-20.04
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
- 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
View File
@@ -17,4 +17,4 @@ tmp/
# Dev-files
n*.txt
test-*.sh
e*.sh
+2 -1
View File
@@ -45,6 +45,7 @@ Phone | Nexus 5
Phone | Nexus One
Phone | Nexus S
Tablet | Nexus 7
Tablet | Pixel C
Requirements
------------
@@ -162,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)|
+14 -12
View File
@@ -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() {
+8 -5
View File
@@ -1,6 +1,9 @@
autopep8==2.3.1
click==8.1.8
coverage==7.6.1
mock==5.1.0
nose==1.3.7
autopep8==2.3.2
click==8.2.1
coverage==7.10.0
mock==5.2.0
pytest==8.4.1
pytest-cov==6.2.1
pytest-xdist==3.8.0
requests==2.32.3
setuptools==80.9.0
+7 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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")
+2
View File
@@ -30,6 +30,7 @@ EMULATOR_IMG_TYPE = "EMULATOR_IMG_TYPE"
EMULATOR_NAME = "EMULATOR_NAME"
EMULATOR_NO_SKIN = "EMULATOR_NO_SKIN"
EMULATOR_SYS_IMG = "EMULATOR_SYS_IMG"
EMULATOR_CONFIG_PATH = "EMULATOR_CONFIG_PATH"
# Device (Genymotion - General)
GENYMOTION_TEMPLATE_PATH = "GENYMOTION_TEMPLATE_PATH"
@@ -37,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)
+2 -2
View File
@@ -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):
+30 -4
View File
@@ -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):
@@ -22,7 +22,8 @@ class Emulator(Device):
"Samsung Galaxy S7 Edge",
"Samsung Galaxy S8",
"Samsung Galaxy S9",
"Samsung Galaxy S10"
"Samsung Galaxy S10",
"Pixel C"
)
API_LEVEL = {
@@ -107,6 +108,30 @@ class Emulator(Device):
symlink_force(path_device_profile_source, self.path_device_profile_target)
self.logger.info("Samsung device profile is linked")
def _use_override_config(self) -> None:
override_confg_path = os.getenv(ENV.EMULATOR_CONFIG_PATH)
if override_confg_path is None:
self.logger.info(f"The environment variable 'EMULATOR_CONFIG_PATH' is not set")
return
self.logger.info(f"Environment variable 'EMULATOR_CONFIG_PATH' found: {override_confg_path}")
if not os.path.isfile(override_confg_path):
self.logger.warning(f"Source file '{override_confg_path}' does not exist.")
return
if not os.access(override_confg_path, os.R_OK):
self.logger.warning(f"Source file '{override_confg_path}' is not readable.")
return
try:
with open(override_confg_path, 'r') as src, open(self.path_emulator_config, 'a') as dst:
dst.write(src.read())
self.logger.info(f"Content from '{override_confg_path}' successfully appended to '{self.path_emulator_config}'.")
except Exception as e:
self.logger.error(f"An error occurred while copying file content: {e}")
def _add_skin(self) -> None:
device_skin_path = os.path.join(
self.path_emulator_skins, "{fn}".format(fn=self.file_name))
@@ -131,6 +156,7 @@ class Emulator(Device):
self.logger.info(f"Command to create emulator: '{creation_cmd}'")
subprocess.check_call(creation_cmd, shell=True)
self._add_skin()
self._use_override_config()
self.logger.info(f"{self.device_type} is created!")
def change_permission(self) -> None:
+3 -3
View File
@@ -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):
+15 -7
View File
@@ -1,9 +1,10 @@
import logging
import os
import subprocess
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):
@@ -14,9 +15,13 @@ class GenySAAS(Genymotion):
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:
@@ -68,5 +73,8 @@ class GenySAAS(Genymotion):
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)
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 -1
View File
@@ -1,6 +1,6 @@
import logging.config
from src.logger import LOGGING_FILE
from logger import LOGGING_FILE
def init():
+2 -2
View File
@@ -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):
+2 -2
View File
@@ -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):
+24 -25
View File
@@ -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,29 +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.is_initialized", mock.MagicMock(return_value=False))
def test_create_device_not_exist(self, mocked_status, mocked_profile, mocked_subprocess, mocked_skin):
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)
@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.is_initialized", mock.MagicMock(return_value=True))
def test_create_device_exists(self, mocked_status, mocked_profile, mocked_subprocess, mocked_skin):
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(
@@ -85,3 +62,25 @@ class TestEmulator(BaseDeviceTest):
with self.assertRaises(RuntimeError):
self.emu.check_adb_command(
self.emu.ReadinessCheck.BOOTED, "mocked_command", "1", 3, 0)
def test_use_override_config_no_env(self):
with mock.patch("os.getenv", return_value=None):
self.emu._use_override_config()
def test_use_override_config_file_not_exist(self):
with mock.patch("os.getenv", return_value="mock/path/to/config"):
with mock.patch("os.path.isfile", return_value=False):
self.emu._use_override_config()
def test_use_override_config_file_not_readable(self):
with mock.patch("os.getenv", return_value="mock/path/to/config"):
with mock.patch("os.path.isfile", return_value=True):
with mock.patch("os.access", return_value=False):
self.emu._use_override_config()
def test_use_override_config_malformed_content(self):
with mock.patch("os.getenv", return_value="mock/path/to/config"):
with mock.patch("os.path.isfile", return_value=True):
with mock.patch("os.access", return_value=True):
with mock.patch("builtins.open", mock.mock_open(read_data="malformed data")):
self.emu._use_override_config()
+2 -6
View File
@@ -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
View File
@@ -1,6 +1,7 @@
FROM appium/appium:v2.16.2-p0
FROM appium/appium:v2.19.0-p3
LABEL maintainer "Budi Utomo <budtmo.os@gmail.com>"
ARG AUTHORS="Budi Utomo"
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
USER root
+2 -2
View File
@@ -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
View File
@@ -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.14.1"
#================
# 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
+13
View File
@@ -57,5 +57,18 @@ Possible environment variable to configure the Emulator:
The user can also pass needed arguments to android emulator through environment variable ***EMULATOR_ADDITIONAL_ARGS***. Please check [this page](https://developer.android.com/studio/run/emulator-commandline) for possible arguments that can be passed.
EMULATOR - OVERRIDE CONFIG FILE
-------------------------------
To utilize this feature, ensure the following setup:
- Set the config file path into environment variable EMULATOR_CONFIG_PATH, eg. `/tmp/emulator-override-config.ini` (the file name doesn't matter)
- Mount the file as Docker volume (parameter `-v` for Docker run command) to the path as you set into ENV
Example:
```shell
docker run -d -p 6080:6080 -e /tmp/emulator-override-config.ini -v /path/on/your/machine/emulator-override-config.ini:/tmp/emulator-override-config.ini -e EMULATOR_DEVICE="Samsung Galaxy S10" -e WEB_VNC=true --device /dev/kvm --name android-container budtmo/docker-android:emulator_14.0
```
[<- BACK TO README](../README.md)
+3
View File
@@ -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***
@@ -59,6 +61,7 @@ Phone | Nexus 5
Phone | Nexus One
Phone | Nexus S
Tablet | Nexus 7
Tablet | Pixel C
Proxy
+10 -3
View File
@@ -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.
```