Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6a3ee2eb0 | ||
|
|
49873e7f05 |
No files matched your search
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "artemis-showcase-ui",
|
"name": "artemis-showcase-ui",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "artemis-showcase-ui",
|
"name": "artemis-showcase-ui",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/cdk": "^22.1.5",
|
"@angular/cdk": "^22.1.5",
|
||||||
"@angular/common": "^22.1.4",
|
"@angular/common": "^22.1.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "artemis-showcase-ui",
|
"name": "artemis-showcase-ui",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve --proxy-config proxy.conf.json",
|
"start": "ng serve --proxy-config proxy.conf.json",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ from artemis.clients.screen_client_factory import create_screen_client
|
|||||||
from artemis.context import ArtemisContext, DeviceContext, DevicePlatform
|
from artemis.context import ArtemisContext, DeviceContext, DevicePlatform
|
||||||
from artemis.controllers.unified_controller import UnifiedMobileController
|
from artemis.controllers.unified_controller import UnifiedMobileController
|
||||||
from artemis.platform import platform
|
from artemis.platform import platform
|
||||||
|
from artemis.runtime.adb_endpoint import AdbEndpoint
|
||||||
from artemis.utils.app_launch_utils import launch_app_with_retries
|
from artemis.utils.app_launch_utils import launch_app_with_retries
|
||||||
|
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ def _get_controller(device_serial: str | None = None):
|
|||||||
port_str = os.environ.get("ADB_PORT", "5037")
|
port_str = os.environ.get("ADB_PORT", "5037")
|
||||||
port = int(port_str) if port_str.isdigit() else 5037
|
port = int(port_str) if port_str.isdigit() else 5037
|
||||||
if "ADB_SERVER_SOCKET" not in os.environ and (host != "localhost" or port != 5037):
|
if "ADB_SERVER_SOCKET" not in os.environ and (host != "localhost" or port != 5037):
|
||||||
os.environ["ADB_SERVER_SOCKET"] = f"tcp:{host}:{port}"
|
os.environ["ADB_SERVER_SOCKET"] = AdbEndpoint.create(host, port).client_socket
|
||||||
adb = AdbClient(host=host, port=port)
|
adb = AdbClient(host=host, port=port)
|
||||||
|
|
||||||
devices = adb.device_list()
|
devices = adb.device_list()
|
||||||
|
|||||||
@@ -92,6 +92,19 @@ class AdbEndpoint:
|
|||||||
def mode(self) -> str:
|
def mode(self) -> str:
|
||||||
return "local" if self.is_local_default else "remote"
|
return "local" if self.is_local_default else "remote"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_host(self) -> str:
|
||||||
|
"""ADB only permits daemon auto-start for the literal host 'localhost'.
|
||||||
|
|
||||||
|
Keep forwarded/custom-port endpoints explicit, even on loopback, so a
|
||||||
|
missing tunnel never starts a different local daemon at that address.
|
||||||
|
"""
|
||||||
|
return "localhost" if self.is_local_default else self.host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_socket(self) -> str:
|
||||||
|
return f"tcp:localhost:{self.port}" if self.is_local_default else self.socket
|
||||||
|
|
||||||
def to_dict(self) -> dict[str, Any]:
|
def to_dict(self) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
**asdict(self),
|
**asdict(self),
|
||||||
@@ -108,7 +121,7 @@ class AdbEndpoint:
|
|||||||
target = environment if environment is not None else os.environ
|
target = environment if environment is not None else os.environ
|
||||||
target["ADB_HOST"] = self.host
|
target["ADB_HOST"] = self.host
|
||||||
target["ADB_PORT"] = str(self.port)
|
target["ADB_PORT"] = str(self.port)
|
||||||
target["ADB_SERVER_SOCKET"] = self.socket
|
target["ADB_SERVER_SOCKET"] = self.client_socket
|
||||||
target[ADB_ENDPOINT_ID_ENV] = self.identity
|
target[ADB_ENDPOINT_ID_ENV] = self.identity
|
||||||
return target
|
return target
|
||||||
|
|
||||||
@@ -145,7 +158,7 @@ class AdbSession:
|
|||||||
return [
|
return [
|
||||||
self.adb_path,
|
self.adb_path,
|
||||||
"-H",
|
"-H",
|
||||||
self.endpoint.host,
|
self.endpoint.client_host,
|
||||||
"-P",
|
"-P",
|
||||||
str(self.endpoint.port),
|
str(self.endpoint.port),
|
||||||
*arguments,
|
*arguments,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from artemis.runtime.adb_endpoint import AdbSession, current_adb_endpoint
|
||||||
from artemis.runtime.device_lock import DeviceExecutionLock
|
from artemis.runtime.device_lock import DeviceExecutionLock
|
||||||
from artemis.toolchain import toolchain
|
from artemis.toolchain import toolchain
|
||||||
from artemis.utils.logger import get_logger
|
from artemis.utils.logger import get_logger
|
||||||
@@ -242,23 +243,29 @@ class DevicePool:
|
|||||||
|
|
||||||
async def _start_adb_server(self, timeout: float) -> None:
|
async def _start_adb_server(self, timeout: float) -> None:
|
||||||
"""Best-effort bounded `adb start-server` so later queries hit a warm daemon."""
|
"""Best-effort bounded `adb start-server` so later queries hit a warm daemon."""
|
||||||
|
endpoint = current_adb_endpoint()
|
||||||
|
if not endpoint.is_local_default:
|
||||||
|
return
|
||||||
adb = self._resolve_adb()
|
adb = self._resolve_adb()
|
||||||
if not adb:
|
if not adb:
|
||||||
return
|
return
|
||||||
proc = None
|
proc = None
|
||||||
try:
|
try:
|
||||||
clean_env = os.environ.copy()
|
session = AdbSession(endpoint, adb_path=adb)
|
||||||
clean_env.pop("ADB_SERVER_SOCKET", None)
|
|
||||||
proc = await asyncio.create_subprocess_exec(
|
proc = await asyncio.create_subprocess_exec(
|
||||||
adb,
|
*session.command(["start-server"]),
|
||||||
"start-server",
|
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
env=clean_env,
|
env=session.environment(),
|
||||||
)
|
)
|
||||||
await asyncio.wait_for(proc.communicate(), timeout=timeout)
|
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
output = (stderr or stdout).decode(errors="replace").strip()
|
||||||
|
logger.warning(
|
||||||
|
f"Local ADB server startup failed (exit {proc.returncode}): {output}"
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(f"adb start-server warm-up did not complete: {exc}")
|
logger.warning(f"Local ADB server startup did not complete: {exc}")
|
||||||
if proc is not None:
|
if proc is not None:
|
||||||
try:
|
try:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "artemis"
|
name = "artemis"
|
||||||
version = "1.3.2"
|
version = "1.3.3"
|
||||||
description = "Autonomous AI Assistant for Mobile Automation"
|
description = "Autonomous AI Assistant for Mobile Automation"
|
||||||
|
|
||||||
authors = [
|
authors = [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2026 Google LLC
|
# Copyright 2026 Google LLC
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -91,12 +91,23 @@ function Update-EnvironmentPath {
|
|||||||
|
|
||||||
function Start-LocalAdbServer {
|
function Start-LocalAdbServer {
|
||||||
if (Test-CommandExists "adb") {
|
if (Test-CommandExists "adb") {
|
||||||
|
$adbErrorPreference = $ErrorActionPreference
|
||||||
try {
|
try {
|
||||||
$origSocket = $env:ADB_SERVER_SOCKET
|
# Windows PowerShell 5.1 wraps native stderr in ErrorRecord objects.
|
||||||
Remove-Item Env:\ADB_SERVER_SOCKET -ErrorAction SilentlyContinue
|
# ADB prints normal daemon-start messages there, so inspect its exit code.
|
||||||
& adb start-server 2>$null | Out-Null
|
$ErrorActionPreference = "Continue"
|
||||||
if ($origSocket) { $env:ADB_SERVER_SOCKET = $origSocket }
|
# Explicit options ignore inherited remote-server environment settings.
|
||||||
} catch {}
|
$adbOutput = & adb -H localhost -P 5037 start-server 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host " [警告] 本机 ADB 服务启动失败(退出码 $LASTEXITCODE)。" -ForegroundColor Yellow
|
||||||
|
Write-Host ($adbOutput | Out-String).Trim() -ForegroundColor Yellow
|
||||||
|
Write-Host " [操作] 请检查 ADB 安装、端口占用或安全软件拦截;本机设备暂不可用。" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host " [警告] 本机 ADB 服务启动异常:$_" -ForegroundColor Yellow
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $adbErrorPreference
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-5
@@ -126,12 +126,23 @@ function Update-EnvironmentPath {
|
|||||||
|
|
||||||
function Start-LocalAdbServer {
|
function Start-LocalAdbServer {
|
||||||
if (Test-CommandExists "adb") {
|
if (Test-CommandExists "adb") {
|
||||||
|
$adbErrorPreference = $ErrorActionPreference
|
||||||
try {
|
try {
|
||||||
$origSocket = $env:ADB_SERVER_SOCKET
|
# Windows PowerShell 5.1 wraps native stderr in ErrorRecord objects.
|
||||||
Remove-Item Env:\ADB_SERVER_SOCKET -ErrorAction SilentlyContinue
|
# ADB prints normal daemon-start messages there, so inspect its exit code.
|
||||||
& adb start-server 2>$null | Out-Null
|
$ErrorActionPreference = "Continue"
|
||||||
if ($origSocket) { $env:ADB_SERVER_SOCKET = $origSocket }
|
# Explicit options ignore inherited remote-server environment settings.
|
||||||
} catch {}
|
$adbOutput = & adb -H localhost -P 5037 start-server 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host " [警告] 本机 ADB 服务启动失败(退出码 $LASTEXITCODE)。" -ForegroundColor Yellow
|
||||||
|
Write-Host ($adbOutput | Out-String).Trim() -ForegroundColor Yellow
|
||||||
|
Write-Host " [操作] 请检查 ADB 安装、端口占用或安全软件拦截;本机设备暂不可用。" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host " [警告] 本机 ADB 服务启动异常:$_" -ForegroundColor Yellow
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $adbErrorPreference
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -323,7 +323,9 @@ async def test_queue_worker_cmd_construction():
|
|||||||
endpoint = enqueue_result["tasks"][0]["adb_endpoint"]
|
endpoint = enqueue_result["tasks"][0]["adb_endpoint"]
|
||||||
assert executed_kwargs[0]["env"]["ADB_HOST"] == endpoint["host"]
|
assert executed_kwargs[0]["env"]["ADB_HOST"] == endpoint["host"]
|
||||||
assert executed_kwargs[0]["env"]["ADB_PORT"] == str(endpoint["port"])
|
assert executed_kwargs[0]["env"]["ADB_PORT"] == str(endpoint["port"])
|
||||||
assert executed_kwargs[0]["env"]["ADB_SERVER_SOCKET"] == endpoint["socket"]
|
assert executed_kwargs[0]["env"]["ADB_SERVER_SOCKET"] == (
|
||||||
|
"tcp:localhost:5037" if endpoint["is_local_default"] else endpoint["socket"]
|
||||||
|
)
|
||||||
assert executed_kwargs[0]["env"]["ARTEMIS_ADB_ENDPOINT_ID"] == endpoint["identity"]
|
assert executed_kwargs[0]["env"]["ARTEMIS_ADB_ENDPOINT_ID"] == endpoint["identity"]
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
assert executed_kwargs[0]["creationflags"] == (
|
assert executed_kwargs[0]["creationflags"] == (
|
||||||
|
|||||||
@@ -70,6 +70,34 @@ def test_adb_session_builds_explicit_endpoint_command_and_environment():
|
|||||||
assert environment[ADB_ENDPOINT_ID_ENV] == endpoint.identity
|
assert environment[ADB_ENDPOINT_ID_ENV] == endpoint.identity
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("host", ["127.0.0.1", "localhost", "::1"])
|
||||||
|
def test_local_endpoint_allows_adb_auto_start_without_changing_task_identity(host):
|
||||||
|
endpoint = AdbServerEndpoint(host, 5037)
|
||||||
|
session = AdbSession(endpoint, adb_path="adb")
|
||||||
|
inherited = {
|
||||||
|
"ADB_SERVER_SOCKET": "tcp:remote.example:5040",
|
||||||
|
"ANDROID_ADB_SERVER_ADDRESS": "remote.example",
|
||||||
|
"ANDROID_ADB_SERVER_PORT": "5040",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert session.command(["devices"]) == ["adb", "-H", "localhost", "-P", "5037", "devices"]
|
||||||
|
environment = session.environment(inherited)
|
||||||
|
assert environment["ADB_SERVER_SOCKET"] == "tcp:localhost:5037"
|
||||||
|
assert environment["ADB_HOST"] == host
|
||||||
|
assert environment[ADB_ENDPOINT_ID_ENV] == endpoint.identity
|
||||||
|
assert inherited["ADB_SERVER_SOCKET"] == "tcp:remote.example:5040"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("host", "port"), [("127.0.0.1", 5038), ("::1", 5038), ("server.example", 5037)]
|
||||||
|
)
|
||||||
|
def test_forwarded_endpoint_never_uses_local_daemon_auto_start(host, port):
|
||||||
|
endpoint = AdbServerEndpoint(host, port)
|
||||||
|
session = AdbSession(endpoint, adb_path="adb")
|
||||||
|
assert session.command(["devices"])[2] == host
|
||||||
|
assert session.environment({})["ADB_SERVER_SOCKET"] == endpoint.socket
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_connect_activates_forwarded_server_after_success(monkeypatch):
|
async def test_connect_activates_forwarded_server_after_success(monkeypatch):
|
||||||
captured: dict[str, object] = {}
|
captured: dict[str, object] = {}
|
||||||
@@ -253,7 +281,7 @@ async def test_use_local_server_restores_standard_endpoint(monkeypatch):
|
|||||||
assert result["success"] is True
|
assert result["success"] is True
|
||||||
assert result["endpoint"] == AdbServerEndpoint("127.0.0.1", 5037).to_dict()
|
assert result["endpoint"] == AdbServerEndpoint("127.0.0.1", 5037).to_dict()
|
||||||
assert settings.ADB_PORT == 5037
|
assert settings.ADB_PORT == 5037
|
||||||
assert os.environ["ADB_SERVER_SOCKET"] == "tcp:127.0.0.1:5037"
|
assert os.environ["ADB_SERVER_SOCKET"] == "tcp:localhost:5037"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import pytest
|
|||||||
|
|
||||||
from artemis.runtime.device_lock import DeviceExecutionLock
|
from artemis.runtime.device_lock import DeviceExecutionLock
|
||||||
from artemis.runtime.device_pool import DevicePool, DeviceStatus
|
from artemis.runtime.device_pool import DevicePool, DeviceStatus
|
||||||
|
from artemis.config import settings
|
||||||
|
|
||||||
device_pool_module = importlib.import_module("artemis.runtime.device_pool")
|
device_pool_module = importlib.import_module("artemis.runtime.device_pool")
|
||||||
|
|
||||||
@@ -245,6 +246,45 @@ def test_warm_up_without_adb_returns_false(monkeypatch):
|
|||||||
assert asyncio.run(pool.warm_up_async(settle_timeout=0.0)) is False
|
assert asyncio.run(pool.warm_up_async(settle_timeout=0.0)) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_adb_warmup_does_not_start_local_server_for_remote_endpoint(monkeypatch):
|
||||||
|
monkeypatch.setattr(settings, "ADB_HOST", "127.0.0.1")
|
||||||
|
monkeypatch.setattr(settings, "ADB_PORT", 5038)
|
||||||
|
|
||||||
|
async def unexpected_spawn(*args, **kwargs):
|
||||||
|
pytest.fail("A forwarded endpoint must not start a local ADB daemon")
|
||||||
|
|
||||||
|
monkeypatch.setattr(asyncio, "create_subprocess_exec", unexpected_spawn)
|
||||||
|
asyncio.run(DevicePool(adb_path="adb")._start_adb_server(timeout=1.0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_adb_warmup_reports_failed_start_with_local_command(monkeypatch):
|
||||||
|
monkeypatch.setattr(settings, "ADB_HOST", "127.0.0.1")
|
||||||
|
monkeypatch.setattr(settings, "ADB_PORT", 5037)
|
||||||
|
monkeypatch.setenv("ADB_SERVER_SOCKET", "tcp:remote.example:5040")
|
||||||
|
captured = {}
|
||||||
|
warnings = []
|
||||||
|
|
||||||
|
class FailedProcess:
|
||||||
|
returncode = 1
|
||||||
|
|
||||||
|
async def communicate(self):
|
||||||
|
return b"", b"cannot bind listener"
|
||||||
|
|
||||||
|
async def spawn(*args, **kwargs):
|
||||||
|
captured["command"] = args
|
||||||
|
captured["env"] = kwargs["env"]
|
||||||
|
return FailedProcess()
|
||||||
|
|
||||||
|
monkeypatch.setattr(asyncio, "create_subprocess_exec", spawn)
|
||||||
|
monkeypatch.setattr(device_pool_module.logger, "warning", warnings.append)
|
||||||
|
asyncio.run(DevicePool(adb_path="adb")._start_adb_server(timeout=1.0))
|
||||||
|
assert captured["command"] == ("adb", "-H", "localhost", "-P", "5037", "start-server")
|
||||||
|
assert captured["env"]["ADB_SERVER_SOCKET"] == "tcp:localhost:5037"
|
||||||
|
assert len(warnings) == 1
|
||||||
|
assert "exit 1" in warnings[0]
|
||||||
|
assert "cannot bind listener" in warnings[0]
|
||||||
|
|
||||||
|
|
||||||
def test_try_list_devices_distinguishes_failure_from_empty(monkeypatch):
|
def test_try_list_devices_distinguishes_failure_from_empty(monkeypatch):
|
||||||
pool = DevicePool()
|
pool = DevicePool()
|
||||||
monkeypatch.setattr(pool, "_query_adb_devices_sync", lambda timeout=None: None)
|
monkeypatch.setattr(pool, "_query_adb_devices_sync", lambda timeout=None: None)
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
"""Run just the ADB startup functions with fake commands; never touch host ADB."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not shutil.which("powershell.exe"), reason="Windows PowerShell required")
|
||||||
|
@pytest.mark.parametrize("script_name", ["start.ps1", "install_deps.ps1"])
|
||||||
|
@pytest.mark.parametrize("outcome", ["success", "failure", "exception"])
|
||||||
|
def test_adb_startup_reports_failure_and_preserves_server_environment(
|
||||||
|
tmp_path, script_name, outcome
|
||||||
|
):
|
||||||
|
harness = tmp_path / "adb-startup.ps1"
|
||||||
|
harness.write_text(
|
||||||
|
"""
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
|
||||||
|
$tokens = $null
|
||||||
|
$parseErrors = $null
|
||||||
|
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
|
||||||
|
$env:ADB_TEST_SCRIPT, [ref]$tokens, [ref]$parseErrors)
|
||||||
|
if ($parseErrors.Count) { throw ($parseErrors | Out-String) }
|
||||||
|
$function = $ast.Find({ param($node)
|
||||||
|
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and
|
||||||
|
$node.Name -eq 'Start-LocalAdbServer'
|
||||||
|
}, $true)
|
||||||
|
Invoke-Expression $function.Extent.Text
|
||||||
|
function Test-CommandExists { return $true }
|
||||||
|
function adb {
|
||||||
|
Write-Host ('ADB_ARGS=' + ($args -join '|'))
|
||||||
|
if ($env:ADB_TEST_OUTCOME -eq 'exception') { throw 'fixture launch error' }
|
||||||
|
Write-Error 'fixture stderr' -ErrorAction Continue
|
||||||
|
$global:LASTEXITCODE = $(if ($env:ADB_TEST_OUTCOME -eq 'failure') { 7 } else { 0 })
|
||||||
|
}
|
||||||
|
Start-LocalAdbServer
|
||||||
|
if ($env:ADB_SERVER_SOCKET -ne 'tcp:remote.example:5040') { throw 'Socket was changed' }
|
||||||
|
if ($env:ANDROID_ADB_SERVER_ADDRESS -ne 'remote.example') { throw 'Host was changed' }
|
||||||
|
if ($env:ANDROID_ADB_SERVER_PORT -ne '5040') { throw 'Port was changed' }
|
||||||
|
if ($ErrorActionPreference -ne 'Stop') { throw 'Error preference was changed' }
|
||||||
|
Write-Host 'HARNESS_OK'
|
||||||
|
""",
|
||||||
|
encoding="utf-8-sig",
|
||||||
|
)
|
||||||
|
result = subprocess.run(
|
||||||
|
["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", str(harness)],
|
||||||
|
env={
|
||||||
|
**os.environ,
|
||||||
|
"ADB_TEST_SCRIPT": str(ROOT / "scripts" / script_name),
|
||||||
|
"ADB_TEST_OUTCOME": outcome,
|
||||||
|
"ADB_SERVER_SOCKET": "tcp:remote.example:5040",
|
||||||
|
"ANDROID_ADB_SERVER_ADDRESS": "remote.example",
|
||||||
|
"ANDROID_ADB_SERVER_PORT": "5040",
|
||||||
|
},
|
||||||
|
capture_output=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, result.stdout + result.stderr
|
||||||
|
assert "ADB_ARGS=-H|localhost|-P|5037|start-server" in result.stdout
|
||||||
|
assert "HARNESS_OK" in result.stdout
|
||||||
|
if outcome == "success":
|
||||||
|
assert "[警告]" not in result.stdout
|
||||||
|
elif outcome == "failure":
|
||||||
|
assert "退出码 7" in result.stdout
|
||||||
|
assert "fixture stderr" in result.stdout
|
||||||
|
else:
|
||||||
|
assert "启动异常" in result.stdout
|
||||||
|
assert "fixture launch error" in result.stdout
|
||||||
Reference in new issue
Block a user