{"id":28665539,"url":"https://github.com/denuvosoftwaresolutions/teststation","last_synced_at":"2026-04-29T13:32:31.886Z","repository":{"id":297421581,"uuid":"996669137","full_name":"DenuvoSoftwareSolutions/teststation","owner":"DenuvoSoftwareSolutions","description":"Mobile TestStation - a easy setup for running an Android application on multiple devices and emulators.","archived":false,"fork":false,"pushed_at":"2025-06-25T08:42:38.000Z","size":7193,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-25T09:38:53.678Z","etag":null,"topics":["adb","dozzle","fastapi","mobile","streamlit","test-automation"],"latest_commit_sha":null,"homepage":"https://denuvosoftwaresolutions.github.io/teststation/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DenuvoSoftwareSolutions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-05T09:31:44.000Z","updated_at":"2025-06-25T08:42:41.000Z","dependencies_parsed_at":"2025-06-06T18:47:01.291Z","dependency_job_id":null,"html_url":"https://github.com/DenuvoSoftwareSolutions/teststation","commit_stats":null,"previous_names":["denuvosoftwaresolutions/teststation"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/DenuvoSoftwareSolutions/teststation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DenuvoSoftwareSolutions%2Fteststation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DenuvoSoftwareSolutions%2Fteststation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DenuvoSoftwareSolutions%2Fteststation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DenuvoSoftwareSolutions%2Fteststation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DenuvoSoftwareSolutions","download_url":"https://codeload.github.com/DenuvoSoftwareSolutions/teststation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DenuvoSoftwareSolutions%2Fteststation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32427507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T12:24:25.982Z","status":"ssl_error","status_checked_at":"2026-04-29T12:24:24.439Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adb","dozzle","fastapi","mobile","streamlit","test-automation"],"created_at":"2025-06-13T13:38:47.350Z","updated_at":"2026-04-29T13:32:31.881Z","avatar_url":"https://github.com/DenuvoSoftwareSolutions.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mobile TestStation\nAn easy setup for running an Android application on multiple mobile devices and emulators.\n\n# Backend REST API usage\nRequests can be sent directly to the REST API of the backend, implemented using [FastAPI](https://fastapi.tiangolo.com/).\n\nThe following example uses the [Python requests](https://requests.readthedocs.io/en/latest/) library to fetch a\nlist of test devices available and then upload an .apk file to be run on a test device named 'emulator1' for 20 seconds.\n```Python\nimport json\nimport requests\n\nurl = \"http://\u003chub\u003e:12001/getdevices/?arm64_only=false\u0026arm32_only=false\u0026amount=1\"\nr = requests.get(url=url)\ndevices = json.loads(r.content) # fetch list of test devices available\n\ntest_app = \"\u003cpathTo\u003e/testo.apk\"\nurl = \"http://\u003chub\u003e:12001/executeApp?execution_time=20\u0026devices=emulator1\"\n\nwith open(test_app, \"rb\") as f:\n    r = requests.post(url, files={\n            \"file\": (\"testo.apk\", f) # upload apk to be run on device 'emulator1' for 20 seconds\n        }\n    )\n```\n\nTo keep the REST API simple, it only contains two endpoints:\n* getdevices: list available devices (does not lock returned devices)\n* executeApp: execute specified app on selected devices (if devices can be locked)\n\nThe REST API is automatically documented by FastAPI and can be viewed at `\u003chub\u003e:12001/docs`. It is automatically shown on the [Streamlit](https://streamlit.io/) Web UI.\n\n# Quick Startup Guide\nThe fastest way to get the TestStation up and running is to build `Dockerfile.frontend`\nand run it. This automatically starts a Node, which connects the available devices and\nthe frontend with the RESTful API and the Web UI.\n\n**Build steps:**\n* `docker build -t mobile_teststation -f Dockerfile.base .` The base image is the same\n  for Hub and Node. It contains all required dependencies for the application.\n* `docker build --build-arg BASE_IMAGE=mobile_teststation -t mobile_teststation_frontend -f Dockerfile.frontend .`\n  The frontend build takes the `mobile_teststation` base image and continues from there.\n\nOnce the frontend container has been built, it can be started using:\n```sh\ndocker run --name mobile_ts_ui \\\n        --network host \\\n        --env=REL_DIR=/var/teststation/Release \\\n        --env=UI_PORT=12000 \\\n        --env=FASTAPI_IP=localhost \\\n        --env=FASTAPI_PORT=12001 \\\n        --env=GRPC_PORT=12002 \\\n        --env=GRPC_SERVER_ONE=localhost:12002 \\\n        --env=DOZZLE_WEBSITE=http://localhost:6060 \\\n        --env=KEYSTORE_FILE=\"test.jks\" \\\n        --env=KEYSTORE_PASS=\"test_pass\" \\\n        --env=KEYSTORE_KEY_ALIAS=\"thekey\" \\\n        -v /tmp:/var/teststation/Release/ \\\n        -t mobile_teststation_frontend\n```\nNote: it is assumed that everything is running locally on a Linux machine.\nTherefore localhost is used and `--network host`. If this is not the case and\nfor example the dozzle logger is running on a different machine, please change\nthe IP (and port).\n\nOnce the Docker container runs, the Web UI is available at `localhost:12000`, the RESTful\ndocumentation (FastAPI) at `localhost:12001/docs`, and the Node grpc service\nat `localhost:12002`.\n\nThe GRPC service can be tested/used via:\n```Python\nfrom src.grpc_wrapper.grpc_client import GRPCClient\n\ngrpc_client = GRPCClient(host=\"localhost\", port=12002)\nprint(grpc_client.get_operating_system())\n\n# get all available devices from the node\nret = grpc_client.get_adb_devices()\nif ret.err is None:\n    import json\n    devices = json.loads(ret.ret)\n    print(\", \".join([r[\"id\"] for r in devices]))\n# \u003e\u003e emulator1, emulator2\n```\n\nThe running Web UI will look like:\n\n\u003cimg src=\"docs/web_ui.png\" alt=\"drawing\" width=\"70%\"/\u003e\n\nThe setup can be tested with the [helloWorld.apk](helloWorld.apk) application (already signed).\nWhen a device is connected or an emulator started, the app can be started using the UI.\nAfter the run, the logcat has to contain the logline `D TESTSTATION: this log should be visible`.\n\nIf multiple Nodes are started they can be simply added to the hub by adding an\nextra environment variable starting with `GRPC_SERVER_` like\n`--env=GRPC_SERVER_TWO=111.122.133.144:12345`. All environment variables starting with\nthis prefix will be checked and added to the internal Node's list.\n\nThe `KEYSTORE_*` variables have to be defined manually. Following the steps above,\nyou will not be able to sign an application. If the application is already\nsigned, the installation and execution process will work although signing is disabled.\n\n# Node Startup\nThe Node image is based on the `mobile_teststation` image and can be build with\n`docker build --build-arg BASE_IMAGE=mobile_teststation -t mobile_teststation_grpc -f Dockerfile.backend .`\n\nThis is needed if on a machine, different from the hub machine, devices/emulators are connected\nwhich should also be accessible from the TestStation.\n\n```sh\ndocker run --name mobile_ts_grpc \\\n        --network host \\\n        --env=REL_DIR=/var/teststation/Release \\\n        --env=KEYSTORE_FILE=\"test.jks\" \\\n        --env=KEYSTORE_PASS=\"test_pass\" \\\n        --env=KEYSTORE_KEY_ALIAS=\"thekey\" \\\n        -v /tmp:/var/teststation/Release/ \\\n        -t mobile_teststation_grpc -p 12002\n```\n\n# Hub Startup \nThe startup of the Hub is explained in [Quick-Startup-Guide](#-Quick-Startup-Guide).\n\nIf `--network host` is not specified (which is not possible on MacOS based systems), the used ports\nneed to be passed to the Docker config. The same is true for `ANDROID_ADB_SERVER_ADDRESS`, as explained in the\n[technical report](https://denuvosoftwaresolutions.github.io/teststation/technical_description.html).\n\n```sh\n-p $GRPC_PORT:$GRPC_PORT \\\n-p $UI_PORT:$UI_PORT \\\n-p $FASTAPI_PORT:$FASTAPI_PORT \\\n--env=ANDROID_ADB_SERVER_ADDRESS=host.docker.internal \\\n```\n\n# Android Tools\nNeeded Android tools:\n* apksigner: to sign apk files\n* bundletool: to convert aab files to apk\n* aapt2: extract the package name from an apk\n\nAll needed tools are automatically fetched within the Dockerfile. Versions have\nbeen tagged to:\n* build-tools, Version: 35.0.0\n* bundletool, Version 1.18.1 (latest available as of June 1, 2025)\n\n# Dozzle Logger\nAll active container logs can be viewed via `\u003chub\u003e:6060`.\nThe [dozzle](https://dozzle.dev/) logger has an agent running on each backend (needs to be started\nmanually). The agents can be connected to the main hub instance which runs on a (for example)\nMacOS  machine.\n\n**Agent startup command**\n```\ndocker run -d \\\n    -p 8107:7007 \\\n    -v /var/run/docker.sock:/var/run/docker.sock \\\n    --name dozzle_logger \\\n    --restart unless-stopped \\\n    amir20/dozzle:latest agent\n```\n\n**MacOS startup command**\n```\ndocker run -d -v /var/run/docker.sock:/var/run/docker.sock \\\n    -p 6060:8080 \\\n    --name dozzle_logger \\\n    --restart unless-stopped \\\n    amir20/dozzle:latest \\\n    --remote-agent \u003cnode_1_ip\u003e:8107 \\\n    --remote-agent \u003cnode_2_ip\u003e:8107\n```\n\n# Further reading\n\nThere are two articles:\n* On the [Intrastructure and Architecture](https://denuvosoftwaresolutions.github.io/teststation/technical_description.html) of Mobile TestStation, and\n* a guide on [How to uncover hidden bugs and boost test coverage](https://denuvosoftwaresolutions.github.io/teststation/use_case_description.html) using Mobile TestStation.\n\n# License\n\nThe Mobile TestStation is copyright (c) 2025 Denuvo GmbH and licensed under [GPL-3](LICENSE).\nThe software is provided \"as is\". Licensor disclaims all warranties, express or implied, including, but \nnot limited to, the implied warranties of merchantibility and fitness for a particular purpose.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenuvosoftwaresolutions%2Fteststation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdenuvosoftwaresolutions%2Fteststation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenuvosoftwaresolutions%2Fteststation/lists"}