mirror of
https://github.com/budtmo/docker-android.git
synced 2026-07-31 04:07:25 +00:00
Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -13,7 +13,7 @@ jobs:
|
||||
python-version: ["3.8"]
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Run unit-test
|
||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
needs: run_test
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Get release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
android: ["9.0", "10.0", "11.0", "12.0", "13.0", "14.0"]
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
needs: release_base
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Run Test on Demand
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up extension
|
||||
run: |
|
||||
echo "${{ secrets.extension }}" > extension.sh
|
||||
chmod 700 extension.sh
|
||||
shell: bash
|
||||
|
||||
- name: Build base image
|
||||
run: script -e -c "./app.sh build base test"
|
||||
|
||||
- name: Build sample image
|
||||
run: script -e -c "./app.sh build emulator test 11.0"
|
||||
|
||||
- name: Run unit-test
|
||||
run: script -e -c "./app.sh test emulator test 11.0 && sudo mv tmp/* ."
|
||||
|
||||
- name: Publish test result
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
@@ -4,16 +4,14 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.actor == 'budtmo'
|
||||
steps:
|
||||
- name: Checkout the repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -96,7 +96,7 @@ Credit goes to [Guillaume - The Parallel Interface blog](https://www.paralint.co
|
||||
sudo usermod -a -G kvm ${USER}
|
||||
```
|
||||
|
||||
2. Add necessary flags to `/etc/wsl2.conf` to their respective sections.
|
||||
2. Add necessary flags to `/etc/wsl.conf` to their respective sections.
|
||||
```
|
||||
[boot]
|
||||
command = /bin/bash -c 'chown -v root:kvm /dev/kvm && chmod 660 /dev/kvm'
|
||||
@@ -163,7 +163,7 @@ The differences between normal version and pro version are:
|
||||
|user-behavior-analytics|Yes|No|-|
|
||||
|proxy|No|Yes|Set up company proxy on Android emulator on fly|
|
||||
|language|No|Yes|Set up language on Android emulator on fly|
|
||||
|Newer Android version|No|Yes|Support other newer Android version e.g. Android 15, etc|
|
||||
|Newer Android version|No|Yes|Support other newer Android version e.g. Android 15, Android 16, etc|
|
||||
|root-privileged|No|Yes|Able to run command with security privileged|
|
||||
|headless-mode|No|Yes|Save resources by using headless mode|
|
||||
|Selenium 4.x integration|No|Yes|Running Appium UI-Tests againt one (Selenium Hub) endpoint for Android- and iOS emulator(s) / device(s)|
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
autopep8==2.3.2
|
||||
click==8.2.1
|
||||
coverage==7.8.1
|
||||
click==8.3.0
|
||||
coverage==7.11.3
|
||||
mock==5.2.0
|
||||
pytest==8.4.1
|
||||
pytest-cov==6.2.1
|
||||
pytest-xdist==3.7.0
|
||||
requests==2.32.3
|
||||
setuptools==80.8.0
|
||||
pytest==9.0.0
|
||||
pytest-cov==7.0.0
|
||||
pytest-xdist==3.8.0
|
||||
requests==2.32.5
|
||||
setuptools==80.9.0
|
||||
|
||||
+89
-28
@@ -1,19 +1,20 @@
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import concurrent.futures
|
||||
import uuid
|
||||
|
||||
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:
|
||||
super().__init__()
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.device_type = DeviceType.GENY_SAAS.value
|
||||
self.created_devices = []
|
||||
|
||||
|
||||
def login(self) -> None:
|
||||
if os.getenv(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)
|
||||
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":
|
||||
@@ -41,40 +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!")
|
||||
|
||||
# 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!")
|
||||
self.logger.info("successfully logged out!")
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM appium/appium:v2.19.0-p0
|
||||
FROM appium/appium:v3.1.1-p0
|
||||
|
||||
ARG AUTHORS="Budi Utomo"
|
||||
LABEL author="${AUTHORS} <budtmo.os@gmail.com>"
|
||||
|
||||
+2
-2
@@ -50,8 +50,8 @@ RUN apt-get -qqy update && apt-get -qqy install --no-install-recommends \
|
||||
#=======
|
||||
# noVNC
|
||||
#=======
|
||||
ENV NOVNC_VERSION="1.4.0" \
|
||||
WEBSOCKIFY_VERSION="0.11.0" \
|
||||
ENV NOVNC_VERSION="1.6.0" \
|
||||
WEBSOCKIFY_VERSION="0.13.0" \
|
||||
OPT_PATH="/opt"
|
||||
RUN wget -nv -O noVNC.zip "https://github.com/novnc/noVNC/archive/refs/tags/v${NOVNC_VERSION}.zip" \
|
||||
&& unzip -x noVNC.zip \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
ARG 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
|
||||
|
||||
@@ -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***
|
||||
|
||||
Reference in New Issue
Block a user