From 332b4000523c4cd9246f714242a46d8751c35795 Mon Sep 17 00:00:00 2001 From: better629 Date: Tue, 23 Jan 2024 14:37:15 +0800 Subject: [PATCH] update android_ext_env --- .../android_env/android_ext_env.py | 21 ++++-- .../android_env/test_android_ext_env.py | 74 +++++++++++++++++++ 2 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 tests/metagpt/environment/android_env/test_android_ext_env.py diff --git a/metagpt/environment/android_env/android_ext_env.py b/metagpt/environment/android_env/android_ext_env.py index d7a63b5e7..f5e62eb5e 100644 --- a/metagpt/environment/android_env/android_ext_env.py +++ b/metagpt/environment/android_env/android_ext_env.py @@ -4,12 +4,12 @@ import subprocess from pathlib import Path -from typing import Optional +from typing import Any, Optional from pydantic import Field from metagpt.const import ADB_EXEC_FAIL -from metagpt.env.base_env import ExtEnv, mark_as_readable, mark_as_writeable +from metagpt.environment.base_env import ExtEnv, mark_as_readable, mark_as_writeable class AndroidExtEnv(ExtEnv): @@ -19,6 +19,13 @@ class AndroidExtEnv(ExtEnv): width: int = Field(default=720, description="device screen width") height: int = Field(default=1080, description="device screen height") + def __init__(self, **data: Any): + super().__init__(**data) + if data.get("device_id"): + (width, height) = self.device_shape + self.width = data.get("width", width) + self.height = data.get("height", height) + @property def adb_prefix_si(self): """adb cmd prefix with `device_id` and `shell input`""" @@ -47,7 +54,7 @@ class AndroidExtEnv(ExtEnv): shape = (0, 0) shape_res = self.execute_adb_with_cmd(adb_cmd) if shape_res != ADB_EXEC_FAIL: - shape = map(int, shape_res.split(": ")[1].split("x")) + shape = tuple(map(int, shape_res.split(": ")[1].split("x"))) return shape def list_devices(self): @@ -66,13 +73,13 @@ class AndroidExtEnv(ExtEnv): local_save_dir: local dir to store image from virtual machine """ assert self.screenshot_dir - ss_remote_path = str(Path(self.screenshot_dir.joinpath(f"{ss_name}.png"))) + ss_remote_path = str(Path(self.screenshot_dir).joinpath(f"{ss_name}.png")) ss_cmd = f"{self.adb_prefix_shell} screencap -p {ss_remote_path}" ss_res = self.execute_adb_with_cmd(ss_cmd) res = ADB_EXEC_FAIL if ss_res != ADB_EXEC_FAIL: - ss_local_path = str(Path(local_save_dir.joinpath(f"{ss_name}.png"))) + ss_local_path = str(Path(local_save_dir).joinpath(f"{ss_name}.png")) pull_cmd = f"{self.adb_prefix} pull {ss_remote_path} {ss_local_path}" pull_res = self.execute_adb_with_cmd(pull_cmd) if pull_res != ADB_EXEC_FAIL: @@ -87,7 +94,7 @@ class AndroidExtEnv(ExtEnv): res = ADB_EXEC_FAIL if xml_res != ADB_EXEC_FAIL: - xml_local_path = str(Path(local_save_dir.joinpath(f"{xml_name}.xml"))) + xml_local_path = str(Path(local_save_dir).joinpath(f"{xml_name}.xml")) pull_cmd = f"{self.adb_prefix} pull {xml_remote_path} {xml_local_path}" pull_res = self.execute_adb_with_cmd(pull_cmd) if pull_res != ADB_EXEC_FAIL: @@ -138,7 +145,7 @@ class AndroidExtEnv(ExtEnv): else: return ADB_EXEC_FAIL - duration = 100 if quick else 400 + duration = 100 if if_quick else 400 adb_cmd = f"{self.adb_prefix_si} swipe {x} {y} {x + offset[0]} {y + offset[1]} {duration}" swipe_res = self.execute_adb_with_cmd(adb_cmd) return swipe_res diff --git a/tests/metagpt/environment/android_env/test_android_ext_env.py b/tests/metagpt/environment/android_env/test_android_ext_env.py new file mode 100644 index 000000000..20ab619bd --- /dev/null +++ b/tests/metagpt/environment/android_env/test_android_ext_env.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Desc : the unittest of AndroidExtEnv + + +from metagpt.const import ADB_EXEC_FAIL +from metagpt.environment.android_env.android_ext_env import AndroidExtEnv + + +def mock_device_shape(self, adb_cmd: str) -> str: + return "shape: 720x1080" + + +def mock_device_shape_invalid(self, adb_cmd: str) -> str: + return ADB_EXEC_FAIL + + +def mock_list_devices(self, adb_cmd: str) -> str: + return "devices\nPixel5" + + +def mock_get_screenshot(self, adb_cmd: str) -> str: + return "screenshot_xxxx-xx-xx" + + +def mock_get_xml(self, adb_cmd: str) -> str: + return "xml_xxxx-xx-xx" + + +def mock_write_read_operation(self, adb_cmd: str) -> str: + return "OK" + + +def test_android_ext_env(mocker): + device_id = "Pixel5" + mocker.patch( + "metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_device_shape + ) + + ext_env = AndroidExtEnv(device_id=device_id, screenshot_dir="/data2/", xml_dir="/data2/") + assert ext_env.adb_prefix == f"adb -s {device_id} " + assert ext_env.adb_prefix_shell == f"adb -s {device_id} shell " + assert ext_env.adb_prefix_si == f"adb -s {device_id} shell input " + + assert ext_env.device_shape == (720, 1080) + + mocker.patch( + "metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_device_shape_invalid + ) + assert ext_env.device_shape == (0, 0) + + mocker.patch( + "metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_list_devices + ) + assert ext_env.list_devices() == [device_id] + + mocker.patch( + "metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_get_screenshot + ) + assert ext_env.get_screenshot("screenshot_xxxx-xx-xx", "/data/") == "/data/screenshot_xxxx-xx-xx.png" + + mocker.patch("metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_get_xml) + assert ext_env.get_xml("xml_xxxx-xx-xx", "/data/") == "/data/xml_xxxx-xx-xx.xml" + + mocker.patch( + "metagpt.environment.android_env.android_ext_env.AndroidExtEnv.execute_adb_with_cmd", mock_write_read_operation + ) + res = "OK" + assert ext_env.system_back() == res + assert ext_env.system_tap(10, 10) == res + assert ext_env.user_input("test_input") == res + assert ext_env.user_longpress(10, 10) == res + assert ext_env.user_swipe(10, 10) == res + assert ext_env.user_swipe_to((10, 10), (20, 20)) == res