mirror of
https://github.com/budtmo/docker-android.git
synced 2026-07-31 04:07:25 +00:00
Compare commits
72
Commits
v2.15.0-p1
...
v3.3.0-p0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a31c2f0301 | ||
|
|
ca2b83faa0 | ||
|
|
ed48e174f6 | ||
|
|
9b6a033133 | ||
|
|
1ea2c74b18 | ||
|
|
c2e376c6f7 | ||
|
|
b21d26e151 | ||
|
|
971300eef3 | ||
|
|
c8efeea3b3 | ||
|
|
4fe7dfdd39 | ||
|
|
c86a077767 | ||
|
|
d4d79d2b7a | ||
|
|
1326fc493f | ||
|
|
a28137f92f | ||
|
|
a46dcf1825 | ||
|
|
4459fffdb2 | ||
|
|
c47e5efdad | ||
|
|
149e55b52d | ||
|
|
f5e57eecef | ||
|
|
621d37d7d1 | ||
|
|
66fab80a5b | ||
|
|
97bd5ae254 | ||
|
|
b69020fc03 | ||
|
|
04da87e3e4 | ||
|
|
80134ce080 | ||
|
|
fbfe4a08d7 | ||
|
|
d03f14dadf | ||
|
|
4b64e87ab2 | ||
|
|
8f4b541d49 | ||
|
|
71f3fe64d6 | ||
|
|
5c6b28b530 | ||
|
|
f847fbb4db | ||
|
|
564a1491ff | ||
|
|
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 | ||
|
|
602dcf15a7 | ||
|
|
1dd79c6188 | ||
|
|
7abe6c19d8 | ||
|
|
eb91462bd4 | ||
|
|
ac251e7704 | ||
|
|
b997803064 | ||
|
|
88dbde577e | ||
|
|
a51e451a1f | ||
|
|
0f8d8eb98b | ||
|
|
97b3ca2c28 |
@@ -1,5 +1,7 @@
|
||||
# Git
|
||||
.git/
|
||||
.github
|
||||
.gitignore
|
||||
|
||||
# IDE
|
||||
**/*.idea
|
||||
@@ -17,3 +19,10 @@ backup
|
||||
**/xunit.xml
|
||||
**/coverage
|
||||
tmp/
|
||||
|
||||
docker
|
||||
documentations
|
||||
example
|
||||
images
|
||||
*.md
|
||||
*.sh
|
||||
|
||||
+24
-15
@@ -9,20 +9,10 @@ updates:
|
||||
commit-message:
|
||||
prefix: "[docker] "
|
||||
target-branch: "master"
|
||||
open-pull-requests-limit: 99
|
||||
reviewers:
|
||||
- "budtmo"
|
||||
|
||||
- package-ecosystem: pip
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '01:00'
|
||||
timezone: "Europe/Berlin"
|
||||
commit-message:
|
||||
prefix: "[pip] "
|
||||
target-branch: "master"
|
||||
open-pull-requests-limit: 99
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependabot"
|
||||
- "docker"
|
||||
reviewers:
|
||||
- "budtmo"
|
||||
|
||||
@@ -35,6 +25,25 @@ updates:
|
||||
commit-message:
|
||||
prefix: "[github-action] "
|
||||
target-branch: "master"
|
||||
open-pull-requests-limit: 99
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependabot"
|
||||
- "github-action"
|
||||
reviewers:
|
||||
- "budtmo"
|
||||
|
||||
- package-ecosystem: pip
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: '01:00'
|
||||
timezone: "Europe/Berlin"
|
||||
commit-message:
|
||||
prefix: "[pip] "
|
||||
target-branch: "master"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependabot"
|
||||
- "pip"
|
||||
reviewers:
|
||||
- "budtmo"
|
||||
|
||||
@@ -7,35 +7,23 @@ on:
|
||||
|
||||
jobs:
|
||||
run_test:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8"]
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- 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
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
@@ -47,18 +35,27 @@ jobs:
|
||||
docker logout
|
||||
|
||||
release_emulator:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs: release_base
|
||||
strategy:
|
||||
matrix:
|
||||
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@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- 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
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- 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@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- 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-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
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- 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
|
||||
|
||||
@@ -45,6 +45,7 @@ Phone | Nexus 5
|
||||
Phone | Nexus One
|
||||
Phone | Nexus S
|
||||
Tablet | Nexus 7
|
||||
Tablet | Pixel C
|
||||
|
||||
Requirements
|
||||
------------
|
||||
@@ -95,15 +96,19 @@ 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'
|
||||
```
|
||||
|
||||
Then, using PowerShell, open a notepad on `notepad $env:USERPROFILE\.wslconfig`. Inside, put these other flags:
|
||||
```
|
||||
[wsl2]
|
||||
nestedVirtualization=true
|
||||
```
|
||||
3. Restart WSL2 via CMD prompt or Powershell
|
||||
|
||||
4. Restart WSL2 via CMD prompt or Powershell
|
||||
```
|
||||
wsl --shutdown
|
||||
```
|
||||
@@ -113,6 +118,8 @@ Credit goes to [Guillaume - The Parallel Interface blog](https://www.paralint.co
|
||||
|
||||
`nestedVirtualization` flag is only available to Windows 11.
|
||||
|
||||
If this setup does not work, you may have an old WSL version. In that case, ignore `\.wslconfig` and put everything on `/etc/wsl.conf`, including the `[wsl2]` flag.
|
||||
|
||||
Use-Cases
|
||||
---------
|
||||
|
||||
@@ -162,7 +169,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
|
||||
mock==5.1.0
|
||||
nose==1.3.7
|
||||
requests==2.32.3
|
||||
autopep8==2.3.2
|
||||
click==8.3.2
|
||||
coverage==7.13.5
|
||||
mock==5.2.0
|
||||
pytest==9.0.3
|
||||
pytest-cov==7.1.0
|
||||
pytest-xdist==3.8.0
|
||||
requests==2.33.1
|
||||
setuptools==82.0.1
|
||||
|
||||
+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"}
|
||||
)
|
||||
+9
-9
@@ -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")
|
||||
@@ -60,7 +60,7 @@ def cli():
|
||||
|
||||
def start_appium() -> None:
|
||||
if convert_str_to_bool(os.getenv(ENV.APPIUM)):
|
||||
cmd = f"/usr/bin/appium"
|
||||
cmd = f"/usr/local/bin/appium"
|
||||
app_appium = Application("Appium", cmd,
|
||||
os.getenv(ENV.APPIUM_ADDITIONAL_ARGS, ""), False)
|
||||
app_appium.start()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
@@ -22,7 +22,10 @@ class Emulator(Device):
|
||||
"Samsung Galaxy S7 Edge",
|
||||
"Samsung Galaxy S8",
|
||||
"Samsung Galaxy S9",
|
||||
"Samsung Galaxy S10"
|
||||
"Samsung Galaxy S10",
|
||||
"Pixel C",
|
||||
"Pixel 8",
|
||||
"Pixel 9"
|
||||
)
|
||||
|
||||
API_LEVEL = {
|
||||
@@ -107,6 +110,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))
|
||||
@@ -126,11 +153,13 @@ class Emulator(Device):
|
||||
creation_cmd = "avdmanager create avd -f -n {n} -b {it}/{si} " \
|
||||
"-k 'system-images;android-{al};{it};{si}' " \
|
||||
"-d {d} -p {pe}".format(n=self.name, it=self.img_type, si=self.sys_img,
|
||||
al=self.api_level, d=self.device.replace(" ", "\ "),
|
||||
al=self.api_level,
|
||||
d=self.device.lower().replace(" ", "_") if "pixel" in self.device.lower() else self.device.replace(" ", "\ "),
|
||||
pe=self.path_emulator)
|
||||
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:
|
||||
|
||||
@@ -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,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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
+17
-13
@@ -1,33 +1,37 @@
|
||||
FROM appium/appium:v2.15.0-p1
|
||||
FROM appium/appium:v3.3.0-p0
|
||||
|
||||
LABEL maintainer "Budi Utomo <budtmo.os@gmail.com>"
|
||||
ARG AUTHORS="Budi Utomo"
|
||||
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
|
||||
|
||||
USER root
|
||||
|
||||
#================
|
||||
# Basic Packages
|
||||
#----------------
|
||||
# ca-certificates
|
||||
# SSL client
|
||||
# python3-pip
|
||||
# python-pip
|
||||
# socat
|
||||
# Port forwarder
|
||||
# supervisor
|
||||
# Process manager
|
||||
# unzip
|
||||
# Unzip zip file
|
||||
# wget
|
||||
# Network downloader
|
||||
#================
|
||||
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||
ca-certificates \
|
||||
python3-pip \
|
||||
socat \
|
||||
supervisor \
|
||||
unzip \
|
||||
wget \
|
||||
&& apt autoremove -y \
|
||||
&& apt clean all \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
#==================
|
||||
# Configure Python
|
||||
#==================
|
||||
RUN apt-get -qqy update && \
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
python3-pip \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1
|
||||
|
||||
#=====================
|
||||
# Set release version
|
||||
|
||||
+8
-14
@@ -11,7 +11,7 @@ ENV EMULATOR_ANDROID_VERSION=${EMULATOR_ANDROID_VERSION} \
|
||||
EMULATOR_SYS_IMG=x86_64 \
|
||||
EMULATOR_IMG_TYPE=google_apis \
|
||||
EMULATOR_BROWSER=chrome
|
||||
ENV PATH ${PATH}:${ANDROID_HOME}/build-tools
|
||||
ENV PATH=${PATH}:${ANDROID_HOME}/build-tools
|
||||
RUN yes | sdkmanager --licenses \
|
||||
&& sdkmanager "platforms;android-${EMULATOR_API_LEVEL}" \
|
||||
"system-images;android-${EMULATOR_API_LEVEL};${EMULATOR_IMG_TYPE};${EMULATOR_SYS_IMG}" "emulator" \
|
||||
@@ -20,14 +20,10 @@ RUN yes | sdkmanager --licenses \
|
||||
#=============
|
||||
# UI Packages
|
||||
#-------------
|
||||
# ffmpeg
|
||||
# Video recorder
|
||||
# feh
|
||||
# Screen background
|
||||
# libxcomposite-dev
|
||||
# Window System for Emulator
|
||||
# menu
|
||||
# Debian menu
|
||||
# openbox
|
||||
# Windows manager
|
||||
# x11vnc
|
||||
@@ -36,10 +32,8 @@ RUN yes | sdkmanager --licenses \
|
||||
# Terminal emulator
|
||||
#==================
|
||||
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||
ffmpeg \
|
||||
feh \
|
||||
libxcomposite-dev \
|
||||
menu \
|
||||
openbox \
|
||||
x11vnc \
|
||||
xterm \
|
||||
@@ -50,8 +44,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 \
|
||||
@@ -78,13 +72,13 @@ EXPOSE 5900 6080
|
||||
#==========
|
||||
RUN rm -rf ${SCRIPT_PATH}
|
||||
ENV SCRIPT_PATH="docker-android"
|
||||
ENV WORK_PATH="/home/androidusr"
|
||||
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
|
||||
RUN echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
|
||||
#===================
|
||||
# Configure OpenBox
|
||||
@@ -94,7 +88,7 @@ RUN echo ${APP_PATH}/mixins/configs/display/.fehbg >> /etc/xdg/openbox/autostart
|
||||
#==================
|
||||
# Use created user
|
||||
#==================
|
||||
USER 1300:1301
|
||||
USER ${USERID}:${GROUPID}
|
||||
ENV LOG_PATH=${WORK_PATH}/logs \
|
||||
WEB_LOG_PORT=9000
|
||||
EXPOSE 9000
|
||||
@@ -107,4 +101,4 @@ RUN mkdir -p "${WORK_PATH}/.config/Android Open Source Project" \
|
||||
#=========
|
||||
STOPSIGNAL SIGTERM
|
||||
ENV DEVICE_TYPE=emulator
|
||||
ENTRYPOINT ["/home/androidusr/docker-android/mixins/scripts/run.sh"]
|
||||
CMD ["${APP_PATH}/mixins/scripts/run.sh"]
|
||||
|
||||
+5
-11
@@ -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
|
||||
@@ -35,13 +30,12 @@ RUN wget -nv -O terraform.zip "https://releases.hashicorp.com/terraform/${TERRAF
|
||||
#==========
|
||||
RUN rm -rf ${SCRIPT_PATH}
|
||||
ENV SCRIPT_PATH="docker-android"
|
||||
ENV WORK_PATH="/home/androidusr"
|
||||
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
|
||||
@@ -52,7 +46,7 @@ RUN mkdir -p ${GENYMOTION_TEMPLATE_PATH}
|
||||
#==================
|
||||
# Use created user
|
||||
#==================
|
||||
USER 1300:1301
|
||||
USER ${USERID}:${GROUPID}
|
||||
ENV LOG_PATH=${WORK_PATH}/logs \
|
||||
WEB_LOG_PORT=9000
|
||||
EXPOSE 9000
|
||||
@@ -63,4 +57,4 @@ RUN mkdir -p ${LOG_PATH}
|
||||
#=========
|
||||
STOPSIGNAL SIGTERM
|
||||
RUN gmsaas config set android-sdk-path ${ANDROID_HOME}
|
||||
ENTRYPOINT ["/home/androidusr/docker-android/mixins/scripts/run.sh"]
|
||||
CMD ["${APP_PATH}/mixins/scripts/run.sh"]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -28,6 +28,8 @@ List of Docker-Images
|
||||
|12.0|32|Normal|budtmo2/docker-android-pro:emulator_12.0|budtmo2/docker-android-pro:emulator_12.0_<release_version>|
|
||||
|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>|
|
||||
@@ -35,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***
|
||||
@@ -58,6 +61,7 @@ Phone | Nexus 5
|
||||
Phone | Nexus One
|
||||
Phone | Nexus S
|
||||
Tablet | Nexus 7
|
||||
Tablet | Pixel C
|
||||
|
||||
|
||||
Proxy
|
||||
|
||||
@@ -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