mirror of
https://github.com/budtmo/docker-android.git
synced 2026-07-31 04:07:25 +00:00
Compare commits
76
Commits
v2.19.0-p0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5e31745bf | ||
|
|
64dc5076b7 | ||
|
|
a96247bd06 | ||
|
|
c9fba363db | ||
|
|
28478f3bce | ||
|
|
a043822b04 | ||
|
|
d173cf2ffa | ||
|
|
71da27e6ad | ||
|
|
2012d5e77d | ||
|
|
34656ff759 | ||
|
|
405b0b7308 | ||
|
|
c66f55462c | ||
|
|
7be06eefef | ||
|
|
2ddfba647d | ||
|
|
49540d74fb | ||
|
|
ef717fc8a5 | ||
|
|
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 |
@@ -1,5 +1,7 @@
|
|||||||
# Git
|
# Git
|
||||||
.git/
|
.git/
|
||||||
|
.github
|
||||||
|
.gitignore
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
**/*.idea
|
**/*.idea
|
||||||
@@ -17,3 +19,10 @@ backup
|
|||||||
**/xunit.xml
|
**/xunit.xml
|
||||||
**/coverage
|
**/coverage
|
||||||
tmp/
|
tmp/
|
||||||
|
|
||||||
|
docker
|
||||||
|
documentations
|
||||||
|
example
|
||||||
|
images
|
||||||
|
*.md
|
||||||
|
*.sh
|
||||||
|
|||||||
+24
-15
@@ -9,20 +9,10 @@ updates:
|
|||||||
commit-message:
|
commit-message:
|
||||||
prefix: "[docker] "
|
prefix: "[docker] "
|
||||||
target-branch: "master"
|
target-branch: "master"
|
||||||
open-pull-requests-limit: 99
|
open-pull-requests-limit: 10
|
||||||
reviewers:
|
labels:
|
||||||
- "budtmo"
|
- "dependabot"
|
||||||
|
- "docker"
|
||||||
- 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
|
|
||||||
reviewers:
|
reviewers:
|
||||||
- "budtmo"
|
- "budtmo"
|
||||||
|
|
||||||
@@ -35,6 +25,25 @@ updates:
|
|||||||
commit-message:
|
commit-message:
|
||||||
prefix: "[github-action] "
|
prefix: "[github-action] "
|
||||||
target-branch: "master"
|
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:
|
reviewers:
|
||||||
- "budtmo"
|
- "budtmo"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
python-version: ["3.8"]
|
python-version: ["3.8"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Run unit-test
|
- name: Run unit-test
|
||||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
needs: run_test
|
needs: run_test
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Get release version
|
- name: Get release version
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
@@ -42,10 +42,10 @@ jobs:
|
|||||||
android: ["9.0", "10.0", "11.0", "12.0", "13.0", "14.0"]
|
android: ["9.0", "10.0", "11.0", "12.0", "13.0", "14.0"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Get release version
|
- name: Get release version
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
@@ -67,10 +67,10 @@ jobs:
|
|||||||
needs: release_base
|
needs: release_base
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Get release version
|
- name: Get release version
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
|
|||||||
@@ -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@v7
|
||||||
|
|
||||||
|
- 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,19 +4,17 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_test:
|
build_and_test:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.actor == 'budtmo'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- name: Checkout the repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Set up extension
|
- name: Set up extension
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -96,15 +96,19 @@ Credit goes to [Guillaume - The Parallel Interface blog](https://www.paralint.co
|
|||||||
sudo usermod -a -G kvm ${USER}
|
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]
|
[boot]
|
||||||
command = /bin/bash -c 'chown -v root:kvm /dev/kvm && chmod 660 /dev/kvm'
|
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]
|
[wsl2]
|
||||||
nestedVirtualization=true
|
nestedVirtualization=true
|
||||||
```
|
```
|
||||||
3. Restart WSL2 via CMD prompt or Powershell
|
|
||||||
|
4. Restart WSL2 via CMD prompt or Powershell
|
||||||
```
|
```
|
||||||
wsl --shutdown
|
wsl --shutdown
|
||||||
```
|
```
|
||||||
@@ -114,6 +118,8 @@ Credit goes to [Guillaume - The Parallel Interface blog](https://www.paralint.co
|
|||||||
|
|
||||||
`nestedVirtualization` flag is only available to Windows 11.
|
`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
|
Use-Cases
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -163,7 +169,7 @@ The differences between normal version and pro version are:
|
|||||||
|user-behavior-analytics|Yes|No|-|
|
|user-behavior-analytics|Yes|No|-|
|
||||||
|proxy|No|Yes|Set up company proxy on Android emulator on fly|
|
|proxy|No|Yes|Set up company proxy on Android emulator on fly|
|
||||||
|language|No|Yes|Set up language 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|
|
|root-privileged|No|Yes|Able to run command with security privileged|
|
||||||
|headless-mode|No|Yes|Save resources by using headless mode|
|
|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)|
|
|Selenium 4.x integration|No|Yes|Running Appium UI-Tests againt one (Selenium Hub) endpoint for Android- and iOS emulator(s) / device(s)|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
autopep8==2.3.2
|
autopep8==2.3.2
|
||||||
click==8.2.1
|
click==8.4.2
|
||||||
coverage==7.8.1
|
coverage==7.15.2
|
||||||
mock==5.2.0
|
mock==5.2.0
|
||||||
pytest==8.4.1
|
pytest==9.1.1
|
||||||
pytest-cov==6.2.1
|
pytest-cov==7.1.0
|
||||||
pytest-xdist==3.7.0
|
pytest-xdist==3.8.0
|
||||||
requests==2.32.3
|
requests==2.34.2
|
||||||
setuptools==80.8.0
|
setuptools==83.0.0
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ def cli():
|
|||||||
|
|
||||||
def start_appium() -> None:
|
def start_appium() -> None:
|
||||||
if convert_str_to_bool(os.getenv(ENV.APPIUM)):
|
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,
|
app_appium = Application("Appium", cmd,
|
||||||
os.getenv(ENV.APPIUM_ADDITIONAL_ARGS, ""), False)
|
os.getenv(ENV.APPIUM_ADDITIONAL_ARGS, ""), False)
|
||||||
app_appium.start()
|
app_appium.start()
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ class Emulator(Device):
|
|||||||
"Samsung Galaxy S8",
|
"Samsung Galaxy S8",
|
||||||
"Samsung Galaxy S9",
|
"Samsung Galaxy S9",
|
||||||
"Samsung Galaxy S10",
|
"Samsung Galaxy S10",
|
||||||
"Pixel C"
|
"Pixel C",
|
||||||
|
"Pixel 8",
|
||||||
|
"Pixel 9"
|
||||||
)
|
)
|
||||||
|
|
||||||
API_LEVEL = {
|
API_LEVEL = {
|
||||||
@@ -151,7 +153,8 @@ class Emulator(Device):
|
|||||||
creation_cmd = "avdmanager create avd -f -n {n} -b {it}/{si} " \
|
creation_cmd = "avdmanager create avd -f -n {n} -b {it}/{si} " \
|
||||||
"-k 'system-images;android-{al};{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,
|
"-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)
|
pe=self.path_emulator)
|
||||||
self.logger.info(f"Command to create emulator: '{creation_cmd}'")
|
self.logger.info(f"Command to create emulator: '{creation_cmd}'")
|
||||||
subprocess.check_call(creation_cmd, shell=True)
|
subprocess.check_call(creation_cmd, shell=True)
|
||||||
|
|||||||
+89
-28
@@ -1,19 +1,20 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import concurrent.futures
|
||||||
|
import uuid
|
||||||
|
|
||||||
from device import Genymotion, DeviceType
|
from device import Genymotion, DeviceType
|
||||||
from helper import get_env_value_or_raise
|
from helper import get_env_value_or_raise
|
||||||
from constants import ENV, UTF8
|
from constants import ENV, UTF8
|
||||||
|
|
||||||
|
|
||||||
class GenySAAS(Genymotion):
|
class GenySAAS(Genymotion):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.logger = logging.getLogger(self.__class__.__name__)
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
self.device_type = DeviceType.GENY_SAAS.value
|
self.device_type = DeviceType.GENY_SAAS.value
|
||||||
self.created_devices = []
|
self.created_devices = []
|
||||||
|
|
||||||
def login(self) -> None:
|
def login(self) -> None:
|
||||||
if os.getenv(ENV.GENY_AUTH_TOKEN):
|
if os.getenv(ENV.GENY_AUTH_TOKEN):
|
||||||
auth_token = get_env_value_or_raise(ENV.GENY_AUTH_TOKEN)
|
auth_token = get_env_value_or_raise(ENV.GENY_AUTH_TOKEN)
|
||||||
@@ -23,14 +24,16 @@ class GenySAAS(Genymotion):
|
|||||||
password = get_env_value_or_raise(ENV.GENY_SAAS_PASS)
|
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)
|
subprocess.check_call(f"gmsaas auth login {user} {password} > /dev/null 2>&1", shell=True)
|
||||||
self.logger.info("successfully logged in!")
|
self.logger.info("successfully logged in!")
|
||||||
|
|
||||||
def create(self) -> None:
|
def create(self) -> None:
|
||||||
super().create()
|
super().create()
|
||||||
|
|
||||||
|
# Collect all items first
|
||||||
|
items = []
|
||||||
for item in self.get_data_from_template(ENV.GENY_SAAS_TEMPLATE_FILE_NAME):
|
for item in self.get_data_from_template(ENV.GENY_SAAS_TEMPLATE_FILE_NAME):
|
||||||
name = ""
|
name = ""
|
||||||
template = ""
|
template = ""
|
||||||
local_port = ""
|
local_port = ""
|
||||||
|
|
||||||
# implement like this because local_port param is not a must
|
# implement like this because local_port param is not a must
|
||||||
for k, v in item.items():
|
for k, v in item.items():
|
||||||
if k.lower() == "name":
|
if k.lower() == "name":
|
||||||
@@ -41,40 +44,98 @@ class GenySAAS(Genymotion):
|
|||||||
local_port = v
|
local_port = v
|
||||||
else:
|
else:
|
||||||
self.logger.warning(f"'{k}' is not supported! Please check the documentation!")
|
self.logger.warning(f"'{k}' is not supported! Please check the documentation!")
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
import uuid
|
|
||||||
name = str(uuid.uuid4())
|
name = str(uuid.uuid4())
|
||||||
|
|
||||||
if not template:
|
if not template:
|
||||||
self.shutdown_and_logout()
|
self.shutdown_and_logout()
|
||||||
raise RuntimeError(f"'template' is a must parameter and not given!")
|
raise RuntimeError(f"'template' is a must parameter and not given!")
|
||||||
else:
|
|
||||||
self.logger.info(f"name: {name}, template: {template}")
|
items.append({
|
||||||
creation_cmd = f"gmsaas instances start {template} {name}"
|
'name': name,
|
||||||
try:
|
'template': template,
|
||||||
instance_id = subprocess.check_output(creation_cmd.split()).decode(UTF8).replace("\n", "")
|
'local_port': local_port
|
||||||
created_device = {f"{name}": {instance_id}}
|
})
|
||||||
self.created_devices.append(created_device)
|
|
||||||
additional_args = ""
|
# Start all devices in parallel
|
||||||
if local_port:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
|
||||||
additional_args = f"--adb-serial-port {local_port}"
|
try:
|
||||||
connect_cmd = f"gmsaas instances adbconnect {instance_id} {additional_args}"
|
# Submit all tasks
|
||||||
subprocess.check_call(f"{connect_cmd}", shell=True)
|
future_to_item = {executor.submit(self.create_instance, item): item for item in items}
|
||||||
except Exception as e:
|
|
||||||
self.shutdown_and_logout()
|
# Collect results as they complete
|
||||||
self.logger.error(e)
|
for future in concurrent.futures.as_completed(future_to_item):
|
||||||
exit(1)
|
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:
|
def shutdown_and_logout(self) -> None:
|
||||||
if bool(self.created_devices):
|
if bool(self.created_devices):
|
||||||
self.logger.info("Created device(s) will be removed!")
|
self.logger.info("Created device(s) will be removed!")
|
||||||
for d in self.created_devices:
|
|
||||||
for n, i in d.items():
|
# Stop all devices in parallel
|
||||||
subprocess.check_call(f"gmsaas instances stop {i}", shell=True)
|
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
|
||||||
self.logger.info(f"device '{n}' is successfully removed!")
|
# 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):
|
if os.getenv(ENV.GENY_AUTH_TOKEN):
|
||||||
subprocess.check_call("gmsaas auth reset", shell=True)
|
subprocess.check_call("gmsaas auth reset", shell=True)
|
||||||
else:
|
else:
|
||||||
subprocess.check_call("gmsaas auth logout", shell=True)
|
subprocess.check_call("gmsaas auth logout", shell=True)
|
||||||
self.logger.info("successfully logged out!")
|
self.logger.info("successfully logged out!")
|
||||||
+15
-12
@@ -1,4 +1,4 @@
|
|||||||
FROM appium/appium:v2.19.0-p0
|
FROM appium/appium:v3.5.2-p0
|
||||||
|
|
||||||
ARG AUTHORS="Budi Utomo"
|
ARG AUTHORS="Budi Utomo"
|
||||||
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
|
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
|
||||||
@@ -8,27 +8,30 @@ USER root
|
|||||||
#================
|
#================
|
||||||
# Basic Packages
|
# Basic Packages
|
||||||
#----------------
|
#----------------
|
||||||
|
# ca-certificates
|
||||||
|
# SSL client
|
||||||
|
# python3-pip
|
||||||
|
# python-pip
|
||||||
# socat
|
# socat
|
||||||
# Port forwarder
|
# Port forwarder
|
||||||
# supervisor
|
# supervisor
|
||||||
# Process manager
|
# Process manager
|
||||||
|
# unzip
|
||||||
|
# Unzip zip file
|
||||||
|
# wget
|
||||||
|
# Network downloader
|
||||||
#================
|
#================
|
||||||
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
python3-pip \
|
||||||
socat \
|
socat \
|
||||||
supervisor \
|
supervisor \
|
||||||
|
unzip \
|
||||||
|
wget \
|
||||||
&& apt autoremove -y \
|
&& apt autoremove -y \
|
||||||
&& apt clean all \
|
&& apt clean all \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1
|
||||||
#==================
|
|
||||||
# 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
|
|
||||||
|
|
||||||
#=====================
|
#=====================
|
||||||
# Set release version
|
# Set release version
|
||||||
|
|||||||
+6
-12
@@ -11,7 +11,7 @@ ENV EMULATOR_ANDROID_VERSION=${EMULATOR_ANDROID_VERSION} \
|
|||||||
EMULATOR_SYS_IMG=x86_64 \
|
EMULATOR_SYS_IMG=x86_64 \
|
||||||
EMULATOR_IMG_TYPE=google_apis \
|
EMULATOR_IMG_TYPE=google_apis \
|
||||||
EMULATOR_BROWSER=chrome
|
EMULATOR_BROWSER=chrome
|
||||||
ENV PATH ${PATH}:${ANDROID_HOME}/build-tools
|
ENV PATH=${PATH}:${ANDROID_HOME}/build-tools
|
||||||
RUN yes | sdkmanager --licenses \
|
RUN yes | sdkmanager --licenses \
|
||||||
&& sdkmanager "platforms;android-${EMULATOR_API_LEVEL}" \
|
&& sdkmanager "platforms;android-${EMULATOR_API_LEVEL}" \
|
||||||
"system-images;android-${EMULATOR_API_LEVEL};${EMULATOR_IMG_TYPE};${EMULATOR_SYS_IMG}" "emulator" \
|
"system-images;android-${EMULATOR_API_LEVEL};${EMULATOR_IMG_TYPE};${EMULATOR_SYS_IMG}" "emulator" \
|
||||||
@@ -20,14 +20,10 @@ RUN yes | sdkmanager --licenses \
|
|||||||
#=============
|
#=============
|
||||||
# UI Packages
|
# UI Packages
|
||||||
#-------------
|
#-------------
|
||||||
# ffmpeg
|
|
||||||
# Video recorder
|
|
||||||
# feh
|
# feh
|
||||||
# Screen background
|
# Screen background
|
||||||
# libxcomposite-dev
|
# libxcomposite-dev
|
||||||
# Window System for Emulator
|
# Window System for Emulator
|
||||||
# menu
|
|
||||||
# Debian menu
|
|
||||||
# openbox
|
# openbox
|
||||||
# Windows manager
|
# Windows manager
|
||||||
# x11vnc
|
# x11vnc
|
||||||
@@ -36,10 +32,8 @@ RUN yes | sdkmanager --licenses \
|
|||||||
# Terminal emulator
|
# Terminal emulator
|
||||||
#==================
|
#==================
|
||||||
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||||
ffmpeg \
|
|
||||||
feh \
|
feh \
|
||||||
libxcomposite-dev \
|
libxcomposite-dev \
|
||||||
menu \
|
|
||||||
openbox \
|
openbox \
|
||||||
x11vnc \
|
x11vnc \
|
||||||
xterm \
|
xterm \
|
||||||
@@ -50,8 +44,8 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
|||||||
#=======
|
#=======
|
||||||
# noVNC
|
# noVNC
|
||||||
#=======
|
#=======
|
||||||
ENV NOVNC_VERSION="1.4.0" \
|
ENV NOVNC_VERSION="1.7.0" \
|
||||||
WEBSOCKIFY_VERSION="0.11.0" \
|
WEBSOCKIFY_VERSION="0.13.0" \
|
||||||
OPT_PATH="/opt"
|
OPT_PATH="/opt"
|
||||||
RUN wget -nv -O noVNC.zip "https://github.com/novnc/noVNC/archive/refs/tags/v${NOVNC_VERSION}.zip" \
|
RUN wget -nv -O noVNC.zip "https://github.com/novnc/noVNC/archive/refs/tags/v${NOVNC_VERSION}.zip" \
|
||||||
&& unzip -x noVNC.zip \
|
&& unzip -x noVNC.zip \
|
||||||
@@ -78,13 +72,13 @@ EXPOSE 5900 6080
|
|||||||
#==========
|
#==========
|
||||||
RUN rm -rf ${SCRIPT_PATH}
|
RUN rm -rf ${SCRIPT_PATH}
|
||||||
ENV SCRIPT_PATH="docker-android"
|
ENV SCRIPT_PATH="docker-android"
|
||||||
ENV WORK_PATH="/home/androidusr"
|
|
||||||
ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
||||||
RUN mkdir -p ${APP_PATH}
|
RUN mkdir -p ${APP_PATH}
|
||||||
COPY mixins ${APP_PATH}/mixins
|
COPY mixins ${APP_PATH}/mixins
|
||||||
COPY cli ${APP_PATH}/cli
|
COPY cli ${APP_PATH}/cli
|
||||||
RUN --mount=type=secret,id=extension,dst=/tmp/extension.sh \
|
RUN --mount=type=secret,id=extension,dst=/tmp/extension.sh \
|
||||||
bash /tmp/extension.sh
|
bash /tmp/extension.sh
|
||||||
|
RUN echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
|
|
||||||
#===================
|
#===================
|
||||||
# Configure OpenBox
|
# Configure OpenBox
|
||||||
@@ -94,7 +88,7 @@ RUN echo ${APP_PATH}/mixins/configs/display/.fehbg >> /etc/xdg/openbox/autostart
|
|||||||
#==================
|
#==================
|
||||||
# Use created user
|
# Use created user
|
||||||
#==================
|
#==================
|
||||||
USER 1300:1301
|
USER ${USERID}:${GROUPID}
|
||||||
ENV LOG_PATH=${WORK_PATH}/logs \
|
ENV LOG_PATH=${WORK_PATH}/logs \
|
||||||
WEB_LOG_PORT=9000
|
WEB_LOG_PORT=9000
|
||||||
EXPOSE 9000
|
EXPOSE 9000
|
||||||
@@ -107,4 +101,4 @@ RUN mkdir -p "${WORK_PATH}/.config/Android Open Source Project" \
|
|||||||
#=========
|
#=========
|
||||||
STOPSIGNAL SIGTERM
|
STOPSIGNAL SIGTERM
|
||||||
ENV DEVICE_TYPE=emulator
|
ENV DEVICE_TYPE=emulator
|
||||||
ENTRYPOINT ["/home/androidusr/docker-android/mixins/scripts/run.sh"]
|
CMD ["${APP_PATH}/mixins/scripts/run.sh"]
|
||||||
|
|||||||
+3
-4
@@ -1,7 +1,7 @@
|
|||||||
ARG DOCKER_ANDROID_VERSION
|
ARG DOCKER_ANDROID_VERSION
|
||||||
FROM budtmo/docker-android:base_${DOCKER_ANDROID_VERSION}
|
FROM budtmo/docker-android:base_${DOCKER_ANDROID_VERSION}
|
||||||
|
|
||||||
ENV GMSAAS_CLI_VERSION="1.14.1"
|
ENV GMSAAS_CLI_VERSION="1.15.0"
|
||||||
|
|
||||||
#================
|
#================
|
||||||
# Cloud Packages
|
# Cloud Packages
|
||||||
@@ -30,7 +30,6 @@ RUN wget -nv -O terraform.zip "https://releases.hashicorp.com/terraform/${TERRAF
|
|||||||
#==========
|
#==========
|
||||||
RUN rm -rf ${SCRIPT_PATH}
|
RUN rm -rf ${SCRIPT_PATH}
|
||||||
ENV SCRIPT_PATH="docker-android"
|
ENV SCRIPT_PATH="docker-android"
|
||||||
ENV WORK_PATH="/home/androidusr"
|
|
||||||
ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
ENV APP_PATH=${WORK_PATH}/${SCRIPT_PATH}
|
||||||
RUN mkdir -p ${APP_PATH}
|
RUN mkdir -p ${APP_PATH}
|
||||||
COPY mixins ${APP_PATH}/mixins
|
COPY mixins ${APP_PATH}/mixins
|
||||||
@@ -47,7 +46,7 @@ RUN mkdir -p ${GENYMOTION_TEMPLATE_PATH}
|
|||||||
#==================
|
#==================
|
||||||
# Use created user
|
# Use created user
|
||||||
#==================
|
#==================
|
||||||
USER 1300:1301
|
USER ${USERID}:${GROUPID}
|
||||||
ENV LOG_PATH=${WORK_PATH}/logs \
|
ENV LOG_PATH=${WORK_PATH}/logs \
|
||||||
WEB_LOG_PORT=9000
|
WEB_LOG_PORT=9000
|
||||||
EXPOSE 9000
|
EXPOSE 9000
|
||||||
@@ -58,4 +57,4 @@ RUN mkdir -p ${LOG_PATH}
|
|||||||
#=========
|
#=========
|
||||||
STOPSIGNAL SIGTERM
|
STOPSIGNAL SIGTERM
|
||||||
RUN gmsaas config set android-sdk-path ${ANDROID_HOME}
|
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"]
|
||||||
|
|||||||
@@ -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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|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>|
|
|-|-|Selenium|budtmo2/docker-android-pro:selenium|budtmo2/docker-android-pro:selenium_<release_version>|
|
||||||
|
|
||||||
***Note: Headless mode does not have any Web-UI***
|
***Note: Headless mode does not have any Web-UI***
|
||||||
|
|||||||
Reference in New Issue
Block a user