From 28e65e50f711970234a1fb5f835925cd8e497791 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Sun, 16 Oct 2022 14:22:53 +0800 Subject: [PATCH] fix: unittests --- converter.py | 176 ----------- demo/.debugtalk_gen.py | 23 -- demo/.env | 3 - demo/.gitignore | 14 - demo/debugtalk.py | 62 ---- demo/har/.keep | 0 demo/proj.json | 5 - demo/testcases/demo.json | 176 ----------- demo/testcases/ref_testcase.yml | 33 -- demo/testcases/requests.json | 136 -------- demo/testcases/requests.yml | 62 ---- docs/CHANGELOG.md | 12 +- .../data/postman/postman_collection_test.json | 81 ----- .../postman/postman_collection_test_test.py | 55 ---- google_style.py | 297 ------------------ hrp/internal/myexec/cmd_windows.go | 9 +- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/demo/main_test.go | 2 + httprunner/__init__.py | 3 +- httprunner/step_android.py | 136 -------- httprunner/step_android_test.py | 42 --- main.go | 59 ---- pyproject.toml | 2 +- 23 files changed, 21 insertions(+), 1369 deletions(-) delete mode 100644 converter.py delete mode 100644 demo/.debugtalk_gen.py delete mode 100644 demo/.env delete mode 100644 demo/.gitignore delete mode 100644 demo/debugtalk.py delete mode 100644 demo/har/.keep delete mode 100644 demo/proj.json delete mode 100644 demo/testcases/demo.json delete mode 100644 demo/testcases/ref_testcase.yml delete mode 100644 demo/testcases/requests.json delete mode 100644 demo/testcases/requests.yml delete mode 100644 examples/data/postman/postman_collection_test.json delete mode 100644 examples/data/postman/postman_collection_test_test.py delete mode 100644 google_style.py delete mode 100644 httprunner/step_android.py delete mode 100644 httprunner/step_android_test.py delete mode 100644 main.go diff --git a/converter.py b/converter.py deleted file mode 100644 index a54bc377..00000000 --- a/converter.py +++ /dev/null @@ -1,176 +0,0 @@ -import io -import json -import pprint -import re -import textwrap -from typing import Any - -from mitmproxy import http -from mitmproxy.utils import strutils - - -def curl_command(flow: http.HTTPFlow) -> str: - data = "curl " - - request = flow.request.copy() - request.decode(strict=False) - - for k, v in request.headers.items(multi=True): - data += "-H '%s:%s' " % (k, v) - - if request.method != "GET": - data += "-X %s " % request.method - - data += "'%s'" % request.url - - if request.content: - data += " --data-binary '%s'" % strutils.bytes_to_escaped_str( - request.content, escape_single_quotes=True - ) - - return data - - -def python_arg(arg: str, val: Any) -> str: - if not val: - return "" - if arg: - arg += "=" - arg_str = "{}{},\n".format(arg, pprint.pformat(val, 79 - len(arg))) - return textwrap.indent(arg_str, " " * 4) - - -def python_code(flow: http.HTTPFlow): - code = io.StringIO() - - def writearg(arg, val): - code.write(python_arg(arg, val)) - - code.write("import requests\n") - code.write("\n") - if flow.request.method.lower() in ("get", "post", "put", "head", "delete", "patch"): - code.write("response = requests.{}(\n".format(flow.request.method.lower())) - else: - code.write("response = requests.request(\n") - writearg("", flow.request.method) - url_without_query = flow.request.url.split("?", 1)[0] - writearg("", url_without_query) - - writearg("params", list(flow.request.query.fields)) - - headers = flow.request.headers.copy() - # requests adds those by default. - for x in (":authority", "host", "content-length"): - headers.pop(x, None) - writearg("headers", dict(headers)) - try: - if "json" not in flow.request.headers.get("content-type", ""): - raise ValueError() - writearg("json", json.loads(flow.request.text)) - except ValueError: - writearg("data", flow.request.content) - - code.seek(code.tell() - 2) # remove last comma - code.write("\n)\n") - code.write("\n") - code.write("print(response.text)") - - return code.getvalue() - - -def locust_code(flow): - code = textwrap.dedent( - """ - from locust import HttpLocust, TaskSet, task - class UserBehavior(TaskSet): - def on_start(self): - ''' on_start is called when a Locust start before any task is scheduled ''' - self.{name}() - @task() - def {name}(self): - url = self.locust.host + '{path}' - {headers}{params}{data} - self.response = self.client.request( - method='{method}', - url=url,{args} - ) - ### Additional tasks can go here ### - class WebsiteUser(HttpLocust): - task_set = UserBehavior - min_wait = 1000 - max_wait = 3000 -""" - ).strip() - - name = re.sub("\W|^(?=\d)", "_", flow.request.path.strip("/").split("?", 1)[0]) - if not name: - new_name = "_".join([str(flow.request.host), str(flow.request.timestamp_start)]) - name = re.sub("\W|^(?=\d)", "_", new_name) - - path_without_query = flow.request.path.split("?")[0] - - args = "" - headers = "" - - def conv(x): - return strutils.bytes_to_escaped_str(x, escape_single_quotes=True) - - if flow.request.headers: - lines = [ - (conv(k), conv(v)) - for k, v in flow.request.headers.fields - if conv(k).lower() not in [":authority", "host", "cookie"] - ] - lines = [" '%s': '%s',\n" % (k, v) for k, v in lines] - headers += "\n headers = {\n%s }\n" % "".join(lines) - args += "\n headers=headers," - - params = "" - if flow.request.query: - lines = [ - " %s: %s,\n" % (repr(k), repr(v)) - for k, v in flow.request.query.collect() - ] - params = "\n params = {\n%s }\n" % "".join(lines) - args += "\n params=params," - - data = "" - if flow.request.content: - data = "\n data = '''%s'''\n" % conv(flow.request.content) - args += "\n data=data," - - code = code.format( - name=name, - path=path_without_query, - headers=headers, - params=params, - data=data, - method=flow.request.method, - args=args, - ) - - return code - - -def locust_task(flow): - code = locust_code(flow) - start_task = len(code.split("@task")[0]) - 4 - end_task = -19 - len(code.split("### Additional")[1]) - task_code = code[start_task:end_task] - - return task_code - - -def url(flow): - return flow.request.url - - -EXPORTERS = [ - ("content", "c", None), - ("headers+content", "h", None), - ("url", "u", url), - ("as curl command", "r", curl_command), - ("as python code", "p", python_code), - ("as locust code", "l", locust_code), - ("as locust task", "t", locust_task), -] diff --git a/demo/.debugtalk_gen.py b/demo/.debugtalk_gen.py deleted file mode 100644 index a57fef72..00000000 --- a/demo/.debugtalk_gen.py +++ /dev/null @@ -1,23 +0,0 @@ -# NOTE: Generated By hrp v4.1.4, DO NOT EDIT! - -import sys -import os - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -from debugtalk import * - - -if __name__ == "__main__": - import funppy - funppy.register("get_user_agent", get_user_agent) - funppy.register("sleep", sleep) - funppy.register("sum", sum) - funppy.register("sum_ints", sum_ints) - funppy.register("sum_two_int", sum_two_int) - funppy.register("sum_two_string", sum_two_string) - funppy.register("sum_strings", sum_strings) - funppy.register("concatenate", concatenate) - funppy.register("setup_hook_example", setup_hook_example) - funppy.register("teardown_hook_example", teardown_hook_example) - funppy.serve() diff --git a/demo/.env b/demo/.env deleted file mode 100644 index 59ecc742..00000000 --- a/demo/.env +++ /dev/null @@ -1,3 +0,0 @@ -base_url=https://postman-echo.com -USERNAME=debugtalk -PASSWORD=123456 \ No newline at end of file diff --git a/demo/.gitignore b/demo/.gitignore deleted file mode 100644 index 4c8cb60c..00000000 --- a/demo/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -reports/ -*.so -.vscode/ -.idea/ -.DS_Store -output/ -__pycache__/ -*.pyc -.python-version -logs/ - -# plugin -debugtalk.bin -debugtalk.so diff --git a/demo/debugtalk.py b/demo/debugtalk.py deleted file mode 100644 index 334a46c7..00000000 --- a/demo/debugtalk.py +++ /dev/null @@ -1,62 +0,0 @@ -import logging -import time -from typing import List - - -# commented out function will be filtered -# def get_headers(): -# return {"User-Agent": "hrp"} - - -def get_user_agent(): - return "hrp/funppy" - - -def sleep(n_secs): - time.sleep(n_secs) - - -def sum(*args): - result = 0 - for arg in args: - result += arg - return result - - -def sum_ints(*args: List[int]) -> int: - result = 0 - for arg in args: - result += arg - return result - - -def sum_two_int(a: int, b: int) -> int: - return a + b - - -def sum_two_string(a: str, b: str) -> str: - return a + b - - -def sum_strings(*args: List[str]) -> str: - result = "" - for arg in args: - result += arg - return result - - -def concatenate(*args: List[str]) -> str: - result = "" - for arg in args: - result += str(arg) - return result - - -def setup_hook_example(name): - logging.warning("setup_hook_example") - return f"setup_hook_example: {name}" - - -def teardown_hook_example(name): - logging.warning("teardown_hook_example") - return f"teardown_hook_example: {name}" diff --git a/demo/har/.keep b/demo/har/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/demo/proj.json b/demo/proj.json deleted file mode 100644 index 08277e5f..00000000 --- a/demo/proj.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "project_name": "demo", - "create_time": "2022-06-23T11:15:39.635136+08:00", - "hrp_version": "v4.1.4" -} diff --git a/demo/testcases/demo.json b/demo/testcases/demo.json deleted file mode 100644 index 8e50e2aa..00000000 --- a/demo/testcases/demo.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "config": { - "name": "demo with complex mechanisms", - "base_url": "https://postman-echo.com", - "variables": { - "a": "${sum(10, 2.3)}", - "b": 3.45, - "n": "${sum_ints(1, 2, 2)}", - "varFoo1": "${gen_random_string($n)}", - "varFoo2": "${max($a, $b)}" - } - }, - "teststeps": [ - { - "name": "transaction 1 start", - "transaction": { - "name": "tran1", - "type": "start" - } - }, - { - "name": "get with params", - "request": { - "method": "GET", - "url": "/get", - "params": { - "foo1": "$varFoo1", - "foo2": "$varFoo2" - }, - "headers": { - "User-Agent": "HttpRunnerPlus" - } - }, - "variables": { - "b": 34.5, - "n": 3, - "name": "get with params", - "varFoo2": "${max($a, $b)}" - }, - "setup_hooks": [ - "${setup_hook_example($name)}" - ], - "teardown_hooks": [ - "${teardown_hook_example($name)}" - ], - "extract": { - "varFoo1": "body.args.foo1" - }, - "validate": [ - { - "check": "status_code", - "assert": "equals", - "expect": 200, - "msg": "check response status code" - }, - { - "check": "headers.\"Content-Type\"", - "assert": "startswith", - "expect": "application/json" - }, - { - "check": "body.args.foo1", - "assert": "length_equals", - "expect": 5, - "msg": "check args foo1" - }, - { - "check": "$varFoo1", - "assert": "length_equals", - "expect": 5, - "msg": "check args foo1" - }, - { - "check": "body.args.foo2", - "assert": "equals", - "expect": "34.5", - "msg": "check args foo2" - } - ] - }, - { - "name": "transaction 1 end", - "transaction": { - "name": "tran1", - "type": "end" - } - }, - { - "name": "post json data", - "request": { - "method": "POST", - "url": "/post", - "body": { - "foo1": "$varFoo1", - "foo2": "${max($a, $b)}" - } - }, - "validate": [ - { - "check": "status_code", - "assert": "equals", - "expect": 200, - "msg": "check status code" - }, - { - "check": "body.json.foo1", - "assert": "length_equals", - "expect": 5, - "msg": "check args foo1" - }, - { - "check": "body.json.foo2", - "assert": "equals", - "expect": 12.3, - "msg": "check args foo2" - } - ] - }, - { - "name": "post form data", - "request": { - "method": "POST", - "url": "/post", - "headers": { - "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" - }, - "body": { - "foo1": "$varFoo1", - "foo2": "${max($a, $b)}", - "time": "${get_timestamp()}" - } - }, - "extract": { - "varTime": "body.form.time" - }, - "validate": [ - { - "check": "status_code", - "assert": "equals", - "expect": 200, - "msg": "check status code" - }, - { - "check": "body.form.foo1", - "assert": "length_equals", - "expect": 5, - "msg": "check args foo1" - }, - { - "check": "body.form.foo2", - "assert": "equals", - "expect": "12.3", - "msg": "check args foo2" - } - ] - }, - { - "name": "get with timestamp", - "request": { - "method": "GET", - "url": "/get", - "params": { - "time": "$varTime" - } - }, - "validate": [ - { - "check": "body.args.time", - "assert": "length_equals", - "expect": 13, - "msg": "check extracted var timestamp" - } - ] - } - ] -} diff --git a/demo/testcases/ref_testcase.yml b/demo/testcases/ref_testcase.yml deleted file mode 100644 index c0932124..00000000 --- a/demo/testcases/ref_testcase.yml +++ /dev/null @@ -1,33 +0,0 @@ -config: - name: "request methods testcase: reference testcase" - variables: - foo1: testsuite_config_bar1 - expect_foo1: testsuite_config_bar1 - expect_foo2: config_bar2 - base_url: "https://postman-echo.com" - verify: False - -teststeps: -- - name: request with functions - variables: - foo1: testcase_ref_bar1 - expect_foo1: testcase_ref_bar1 - testcase: testcases/requests.yml - export: - - foo3 -- - name: post form data - variables: - foo1: bar1 - request: - method: POST - url: /post - headers: - User-Agent: ${get_user_agent()} - Content-Type: "application/x-www-form-urlencoded" - body: "foo1=$foo1&foo2=$foo3" - validate: - - eq: ["status_code", 200] - - eq: ["body.form.foo1", "bar1"] - - eq: ["body.form.foo2", "bar21"] \ No newline at end of file diff --git a/demo/testcases/requests.json b/demo/testcases/requests.json deleted file mode 100644 index 4c01ec74..00000000 --- a/demo/testcases/requests.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "config": { - "name": "request methods testcase with functions", - "variables": { - "foo1": "config_bar1", - "foo2": "config_bar2", - "expect_foo1": "config_bar1", - "expect_foo2": "config_bar2" - }, - "headers": { - "User-Agent": "${get_user_agent()}" - }, - "base_url": "https://postman-echo.com", - "verify": false, - "export": [ - "foo3" - ] - }, - "teststeps": [ - { - "name": "get with params", - "variables": { - "foo1": "${ENV(USERNAME)}", - "foo2": "bar21", - "sum_v": "${sum_two_int(10000000, 20000000)}" - }, - "request": { - "method": "GET", - "url": "/get", - "params": { - "foo1": "$foo1", - "foo2": "$foo2", - "sum_v": "$sum_v" - } - }, - "extract": { - "foo3": "body.args.foo2" - }, - "validate": [ - { - "check": "status_code", - "assert": "equal", - "expect": 200, - "msg": "check status_code" - }, - { - "check": "body.args.foo1", - "assert": "equal", - "expect": "debugtalk", - "msg": "check body.args.foo1" - }, - { - "check": "body.args.sum_v", - "assert": "equal", - "expect": "30000000", - "msg": "check body.args.sum_v" - }, - { - "check": "body.args.foo2", - "assert": "equal", - "expect": "bar21", - "msg": "check body.args.foo2" - } - ] - }, - { - "name": "post raw text", - "variables": { - "foo1": "bar12", - "foo3": "bar32" - }, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "Content-Type": "text/plain" - }, - "body": "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3." - }, - "validate": [ - { - "check": "status_code", - "assert": "equal", - "expect": 200, - "msg": "check status_code" - }, - { - "check": "body.data", - "assert": "equal", - "expect": "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.", - "msg": "check body.data" - } - ] - }, - { - "name": "post form data", - "variables": { - "foo2": "bar23" - }, - "request": { - "method": "POST", - "url": "/post", - "headers": { - "Content-Type": "application/x-www-form-urlencoded" - }, - "body": "foo1=$foo1&foo2=$foo2&foo3=$foo3" - }, - "validate": [ - { - "check": "status_code", - "assert": "equal", - "expect": 200, - "msg": "check status_code" - }, - { - "check": "body.form.foo1", - "assert": "equal", - "expect": "$expect_foo1", - "msg": "check body.form.foo1" - }, - { - "check": "body.form.foo2", - "assert": "equal", - "expect": "bar23", - "msg": "check body.form.foo2" - }, - { - "check": "body.form.foo3", - "assert": "equal", - "expect": "bar21", - "msg": "check body.form.foo3" - } - ] - } - ] -} \ No newline at end of file diff --git a/demo/testcases/requests.yml b/demo/testcases/requests.yml deleted file mode 100644 index 5922ab12..00000000 --- a/demo/testcases/requests.yml +++ /dev/null @@ -1,62 +0,0 @@ -config: - name: "request methods testcase with functions" - variables: - foo1: config_bar1 - foo2: config_bar2 - expect_foo1: config_bar1 - expect_foo2: config_bar2 - headers: - User-Agent: ${get_user_agent()} - verify: False - export: ["foo3"] - -teststeps: -- - name: get with params - variables: - foo1: ${ENV(USERNAME)} - foo2: bar21 - sum_v: "${sum_two_int(10000000, 20000000)}" - request: - method: GET - url: $base_url/get - params: - foo1: $foo1 - foo2: $foo2 - sum_v: $sum_v - extract: - foo3: "body.args.foo2" - validate: - - eq: ["status_code", 200] - - eq: ["body.args.foo1", "debugtalk"] - - eq: ["body.args.sum_v", "30000000"] - - eq: ["body.args.foo2", "bar21"] -- - name: post raw text - variables: - foo1: "bar12" - foo3: "bar32" - request: - method: POST - url: $base_url/post - headers: - Content-Type: "text/plain" - body: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3." - validate: - - eq: ["status_code", 200] - - eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32."] -- - name: post form data - variables: - foo2: bar23 - request: - method: POST - url: $base_url/post - headers: - Content-Type: "application/x-www-form-urlencoded" - body: "foo1=$foo1&foo2=$foo2&foo3=$foo3" - validate: - - eq: ["status_code", 200] - - eq: ["body.form.foo1", "$expect_foo1"] - - eq: ["body.form.foo2", "bar23"] - - eq: ["body.form.foo3", "bar21"] diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3a22afa5..432d07d7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,8 +1,11 @@ # Release History -## v4.3.0 (2022-09-01) +## v4.3.0 (2022-10-16) -- feat: support iOS UI automation with WebDriverAgent +- feat: support iOS UI automation with [WebDriverAgent] +- feat support Android UI automation with [uiautomator2] +- feat: integrage ios device management with [gidevice] +- refactor: make boomer/uixt/httpstat as sub package ## v4.2.1 (2022-09-01) @@ -673,4 +676,7 @@ reference: [v2-changelog] [locust]: https://locust.io/ [black]: https://github.com/psf/black [loguru]: https://github.com/Delgan/loguru -[v2-changelog]: https://github.com/httprunner/httprunner/blob/v2/docs/CHANGELOG.md \ No newline at end of file +[v2-changelog]: https://github.com/httprunner/httprunner/blob/v2/docs/CHANGELOG.md +[WebDriverAgent]: https://github.com/appium/WebDriverAgent +[uiautomator2]: https://github.com/appium/appium-uiautomator2-server +[gidevice]: https://github.com/electricbubble/gidevice diff --git a/examples/data/postman/postman_collection_test.json b/examples/data/postman/postman_collection_test.json deleted file mode 100644 index 8592d93b..00000000 --- a/examples/data/postman/postman_collection_test.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "config": { - "name": "postman collection demo" - }, - "teststeps": [ - { - "name": "folder1 - folder2 - Get with params", - "request": { - "method": "GET", - "url": "https://postman-echo.com/get", - "params": { - "k1": "v1", - "k2": "v2" - } - } - }, - { - "name": "folder3 - Post form-data", - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "upload": { - "intro_key": "intro.txt", - "k1": "v1", - "k2": "v2", - "logo_key": "logo.jpeg" - } - } - }, - { - "name": "folder3 - Post x-www-form-urlencoded", - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "headers": { - "Content-Type": "application/x-www-form-urlencoded" - }, - "body": { - "k1": "v1", - "k2": "v2" - } - } - }, - { - "name": "folder3 - Post raw json", - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "k1": "v1", - "k2": "v2" - } - } - }, - { - "name": "folder3 - Post raw text", - "request": { - "method": "POST", - "url": "https://postman-echo.com/post", - "headers": { - "Content-Type": "text/plain" - }, - "body": "have a nice day" - } - }, - { - "name": "Get request headers", - "request": { - "method": "GET", - "url": "https://postman-echo.com/headers", - "headers": { - "Connection": "close", - "User-Agent": "HttpRunner" - } - } - } - ] -} diff --git a/examples/data/postman/postman_collection_test_test.py b/examples/data/postman/postman_collection_test_test.py deleted file mode 100644 index 4a813aa8..00000000 --- a/examples/data/postman/postman_collection_test_test.py +++ /dev/null @@ -1,55 +0,0 @@ -# NOTE: Generated By HttpRunner v4.1.4 -# FROM: postman/postman_collection_test.json -from httprunner import HttpRunner, Config, Step, RunRequest - - -class TestCasePostmanCollectionTest(HttpRunner): - - config = Config("postman collection demo") - - teststeps = [ - Step( - RunRequest("folder1 - folder2 - Get with params") - .get("https://postman-echo.com/get") - .with_params(**{"k1": "v1", "k2": "v2"}) - ), - Step( - RunRequest("folder3 - Post form-data") - .post("https://postman-echo.com/post") - .upload( - **{ - "intro_key": "intro.txt", - "k1": "v1", - "k2": "v2", - "logo_key": "logo.jpeg", - } - ) - ), - Step( - RunRequest("folder3 - Post x-www-form-urlencoded") - .post("https://postman-echo.com/post") - .with_headers(**{"Content-Type": "application/x-www-form-urlencoded"}) - .with_data({"k1": "v1", "k2": "v2"}) - ), - Step( - RunRequest("folder3 - Post raw json") - .post("https://postman-echo.com/post") - .with_headers(**{"Content-Type": "application/json"}) - .with_json({"k1": "v1", "k2": "v2"}) - ), - Step( - RunRequest("folder3 - Post raw text") - .post("https://postman-echo.com/post") - .with_headers(**{"Content-Type": "text/plain"}) - .with_data("have a nice day") - ), - Step( - RunRequest("Get request headers") - .get("https://postman-echo.com/headers") - .with_headers(**{"Connection": "close", "User-Agent": "HttpRunner"}) - ), - ] - - -if __name__ == "__main__": - TestCasePostmanCollectionTest().test_start() diff --git a/google_style.py b/google_style.py deleted file mode 100644 index 9ba4349f..00000000 --- a/google_style.py +++ /dev/null @@ -1,297 +0,0 @@ -# -*- coding: utf-8 -*- -"""Example Google style docstrings. - -This module demonstrates documentation as specified by the `Google Python -Style Guide`_. Docstrings may extend over multiple lines. Sections are created -with a section header and a colon followed by a block of indented text. - -Example: - Examples can be given using either the ``Example`` or ``Examples`` - sections. Sections support any reStructuredText formatting, including - literal blocks:: - - $ python example_google.py - -Section breaks are created by resuming unindented text. Section breaks -are also implicitly created anytime a new section starts. - -Attributes: - module_level_variable1 (int): Module level variables may be documented in - either the ``Attributes`` section of the module docstring, or in an - inline docstring immediately following the variable. - - Either form is acceptable, but the two should not be mixed. Choose - one convention to document module level variables and be consistent - with it. - -Todo: - * For module TODOs - * You have to also use ``sphinx.ext.todo`` extension - -.. _Google Python Style Guide: - http://google.github.io/styleguide/pyguide.html - -""" - -module_level_variable1 = 12345 - -module_level_variable2 = 98765 -"""int: Module level variable documented inline. - -The docstring may span multiple lines. The type may optionally be specified -on the first line, separated by a colon. -""" - - -def function_with_types_in_docstring(param1, param2): - """Example function with types documented in the docstring. - - `PEP 484`_ type annotations are supported. If attribute, parameter, and - return types are annotated according to `PEP 484`_, they do not need to be - included in the docstring: - - Args: - param1 (int): The first parameter. - param2 (str): The second parameter. - - Returns: - bool: The return value. True for success, False otherwise. - - .. _PEP 484: - https://www.python.org/dev/peps/pep-0484/ - - """ - - -def function_with_pep484_type_annotations(param1: int, param2: str) -> bool: - """Example function with PEP 484 type annotations. - - Args: - param1: The first parameter. - param2: The second parameter. - - Returns: - The return value. True for success, False otherwise. - - """ - - -def module_level_function(param1, param2=None, *args, **kwargs): - """This is an example of a module level function. - - Function parameters should be documented in the ``Args`` section. The name - of each parameter is required. The type and description of each parameter - is optional, but should be included if not obvious. - - If \*args or \*\*kwargs are accepted, - they should be listed as ``*args`` and ``**kwargs``. - - The format for a parameter is:: - - name (type): description - The description may span multiple lines. Following - lines should be indented. The "(type)" is optional. - - Multiple paragraphs are supported in parameter - descriptions. - - Args: - param1 (int): The first parameter. - param2 (:obj:`str`, optional): The second parameter. Defaults to None. - Second line of description should be indented. - *args: Variable length argument list. - **kwargs: Arbitrary keyword arguments. - - Returns: - bool: True if successful, False otherwise. - - The return type is optional and may be specified at the beginning of - the ``Returns`` section followed by a colon. - - The ``Returns`` section may span multiple lines and paragraphs. - Following lines should be indented to match the first line. - - The ``Returns`` section supports any reStructuredText formatting, - including literal blocks:: - - { - 'param1': param1, - 'param2': param2 - } - - Raises: - AttributeError: The ``Raises`` section is a list of all exceptions - that are relevant to the interface. - ValueError: If `param2` is equal to `param1`. - - """ - if param1 == param2: - raise ValueError("param1 may not be equal to param2") - return True - - -def example_generator(n): - """Generators have a ``Yields`` section instead of a ``Returns`` section. - - Args: - n (int): The upper limit of the range to generate, from 0 to `n` - 1. - - Yields: - int: The next number in the range of 0 to `n` - 1. - - Examples: - Examples should be written in doctest format, and should illustrate how - to use the function. - - >>> print([i for i in example_generator(4)]) - [0, 1, 2, 3] - - """ - for i in range(n): - yield i - - -class ExampleError(Exception): - """Exceptions are documented in the same way as classes. - - The __init__ method may be documented in either the class level - docstring, or as a docstring on the __init__ method itself. - - Either form is acceptable, but the two should not be mixed. Choose one - convention to document the __init__ method and be consistent with it. - - Note: - Do not include the `self` parameter in the ``Args`` section. - - Args: - msg (str): Human readable string describing the exception. - code (:obj:`int`, optional): Error code. - - Attributes: - msg (str): Human readable string describing the exception. - code (int): Exception error code. - - """ - - def __init__(self, msg, code): - self.msg = msg - self.code = code - - -class ExampleClass(object): - """The summary line for a class docstring should fit on one line. - - If the class has public attributes, they may be documented here - in an ``Attributes`` section and follow the same formatting as a - function's ``Args`` section. Alternatively, attributes may be documented - inline with the attribute's declaration (see __init__ method below). - - Properties created with the ``@property`` decorator should be documented - in the property's getter method. - - Attributes: - attr1 (str): Description of `attr1`. - attr2 (:obj:`int`, optional): Description of `attr2`. - - """ - - def __init__(self, param1, param2, param3): - """Example of docstring on the __init__ method. - - The __init__ method may be documented in either the class level - docstring, or as a docstring on the __init__ method itself. - - Either form is acceptable, but the two should not be mixed. Choose one - convention to document the __init__ method and be consistent with it. - - Note: - Do not include the `self` parameter in the ``Args`` section. - - Args: - param1 (str): Description of `param1`. - param2 (:obj:`int`, optional): Description of `param2`. Multiple - lines are supported. - param3 (:obj:`list` of :obj:`str`): Description of `param3`. - - """ - self.attr1 = param1 - self.attr2 = param2 - self.attr3 = param3 #: Doc comment *inline* with attribute - - #: list of str: Doc comment *before* attribute, with type specified - self.attr4 = ["attr4"] - - self.attr5 = None - """str: Docstring *after* attribute, with type specified.""" - - @property - def readonly_property(self): - """str: Properties should be documented in their getter method.""" - return "readonly_property" - - @property - def readwrite_property(self): - """:obj:`list` of :obj:`str`: Properties with both a getter and setter - should only be documented in their getter method. - - If the setter method contains notable behavior, it should be - mentioned here. - """ - return ["readwrite_property"] - - @readwrite_property.setter - def readwrite_property(self, value): - value - - def example_method(self, param1, param2): - """Class methods are similar to regular functions. - - Note: - Do not include the `self` parameter in the ``Args`` section. - - Args: - param1: The first parameter. - param2: The second parameter. - - Returns: - True if successful, False otherwise. - - """ - return True - - def __special__(self): - """By default special members with docstrings are not included. - - Special members are any methods or attributes that start with and - end with a double underscore. Any special member with a docstring - will be included in the output, if - ``napoleon_include_special_with_doc`` is set to True. - - This behavior can be enabled by changing the following setting in - Sphinx's conf.py:: - - napoleon_include_special_with_doc = True - - """ - pass - - def __special_without_docstring__(self): - pass - - def _private(self): - """By default private members are not included. - - Private members are any methods or attributes that start with an - underscore and are *not* special. By default they are not included - in the output. - - This behavior can be changed such that private members *are* included - by changing the following setting in Sphinx's conf.py:: - - napoleon_include_private_with_doc = True - - """ - pass - - def _private_without_docstring(self): - pass diff --git a/hrp/internal/myexec/cmd_windows.go b/hrp/internal/myexec/cmd_windows.go index c70cac84..6844058f 100644 --- a/hrp/internal/myexec/cmd_windows.go +++ b/hrp/internal/myexec/cmd_windows.go @@ -3,9 +3,12 @@ package myexec import ( + "os" "os/exec" + "path/filepath" "syscall" + "github.com/pkg/errors" "github.com/rs/zerolog/log" ) @@ -48,7 +51,7 @@ func ensurePython3Venv(venvDir string, packages ...string) (python3 string, err // check if .venv exists if _, err := os.Stat(venvDir); err == nil { // .venv exists, remove first - if err := ExecCommand("del", "/q", venvDir); err != nil { + if err := RunCommand("del", "/q", venvDir); err != nil { return "", errors.Wrap(err, "remove existed venv failed") } } @@ -56,10 +59,10 @@ func ensurePython3Venv(venvDir string, packages ...string) (python3 string, err // create python3 .venv // notice: --symlinks should be specified for windows // https://github.com/actions/virtual-environments/issues/2690 - if err := ExecCommand(systemPython, "-m", "venv", "--symlinks", venvDir); err != nil { + if err := RunCommand(systemPython, "-m", "venv", "--symlinks", venvDir); err != nil { // fix: failed to symlink on Windows log.Warn().Msg("failed to create python3 .venv by using --symlinks, try to use --copies") - if err := ExecCommand(systemPython, "-m", "venv", "--copies", venvDir); err != nil { + if err := RunCommand(systemPython, "-m", "venv", "--copies", venvDir); err != nil { return "", errors.Wrap(err, "create python3 venv failed") } } diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index d9e3391e..a28eeaba 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.3.0-beta-10160931 \ No newline at end of file +v4.3.0-beta-10161439 \ No newline at end of file diff --git a/hrp/pkg/uixt/demo/main_test.go b/hrp/pkg/uixt/demo/main_test.go index 044f3f92..6dac96d2 100644 --- a/hrp/pkg/uixt/demo/main_test.go +++ b/hrp/pkg/uixt/demo/main_test.go @@ -1,3 +1,5 @@ +//go:build localtest + package demo import ( diff --git a/httprunner/__init__.py b/httprunner/__init__.py index f2195b32..4592b08c 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -1,4 +1,4 @@ -__version__ = "v4.3.0-beta-10160931" +__version__ = "v4.3.0-beta-10161439" __description__ = "One-stop solution for HTTP(S) testing." @@ -19,6 +19,7 @@ from httprunner.step_thrift_request import ( StepThriftRequestValidation, ) + __all__ = [ "__version__", "__description__", diff --git a/httprunner/step_android.py b/httprunner/step_android.py deleted file mode 100644 index 6a485cc8..00000000 --- a/httprunner/step_android.py +++ /dev/null @@ -1,136 +0,0 @@ -from typing import Text - -from loguru import logger -import uiautomator2 as u2 - -from httprunner.models import IStep, StepResult, TStep, TStepAndroidUI -from httprunner.runner import HttpRunner - - -def run_android_ui(runner: HttpRunner, step: TStep) -> StepResult: - step_result = StepResult( - name=step.name, - step_type="android_ui", - success=False, - ) - logger.info(f"run android ui action: {step.android.method}, param: {step.android.param}") - - return step_result - - -class StepAndroidControl(IStep): - - def __init__(self, step: TStep): - self.__step = step - - def start_app(self, package_name: Text) -> "StepAndroidControl": - return self - - def stop_app(self, package_name: Text) -> "StepAndroidControl": - return self - - def start_watcher(self) -> "StepAndroidControl": - return self - - def stop_watcher(self) -> "StepAndroidControl": - return self - - def start_camera(self) -> "StepAndroidControl": - return self - - def stop_camera(self) -> "StepAndroidControl": - return self - - def start_record(self) -> "StepAndroidControl": - return self - - def stop_record(self) -> "StepAndroidControl": - return self - - def struct(self) -> TStep: - return self.__step - - def name(self) -> Text: - return self.__step.name - - def type(self) -> Text: - return "android-control" - - def run(self, runner: HttpRunner): - return run_android_ui(runner, self.__step) - - -class StepAndroidUI(IStep): - - def __init__(self, step: TStep): - self.__step = step - - def press_back(self) -> "StepAndroidUI": - self.__step.android.method = "press" - self.__step.android.param = "back" - return self - - def press_home(self) -> "StepAndroidUI": - self.__step.android.method = "press" - self.__step.android.param = "home" - return self - - def sleep(self, time: int) -> "StepAndroidUI": - self.__step.android.method = "sleep" - self.__step.android.param = time - return self - - def swipe_up(self) -> "StepAndroidUI": - self.__step.android.method = "swipe" - self.__step.android.param = [0.25, 0.5, 0.75, 0.5] - return self - - def swipe_down(self) -> "StepAndroidUI": - self.__step.android.method = "swipe" - self.__step.android.param = [0.75, 0.5, 0.25, 0.5] - return self - - def swipe_left(self) -> "StepAndroidUI": - self.__step.android.method = "swipe" - self.__step.android.param = [0.5, 0.75, 0.5, 0.25] - return self - - def swipe_right(self) -> "StepAndroidUI": - self.__step.android.method = "swipe" - self.__step.android.param = [0.5, 0.25, 0.5, 0.75] - return self - - def swipe(self, from_x: float, from_y: float, to_x: float, to_y: float) -> "StepAndroidUI": - self.__step.android.method = "swipe" - self.__step.android.param = [from_x, from_y, to_x, to_y] - return self - - def click(self, text: Text) -> "StepAndroidUI": - self.__step.android.method = "click" - self.__step.android.param = text - return self - - def struct(self) -> TStep: - return self.__step - - def name(self) -> Text: - return self.__step.name - - def type(self) -> Text: - return "android-ui" - - def run(self, runner: HttpRunner): - return run_android_ui(runner, self.__step) - - -class RunAndroidUI(object): - - def __init__(self, name: Text): - self.__step = TStep(name=name) - self.__step.android = TStepAndroidUI() - - def control(self) -> StepAndroidControl: - return StepAndroidControl(self.__step) - - def ui(self) -> StepAndroidUI: - return StepAndroidUI(self.__step) diff --git a/httprunner/step_android_test.py b/httprunner/step_android_test.py deleted file mode 100644 index fe484a89..00000000 --- a/httprunner/step_android_test.py +++ /dev/null @@ -1,42 +0,0 @@ -from httprunner import HttpRunner, Config, Step, RunAndroidUI - - -class TestCaseAndroidDemo(HttpRunner): - - config = ( - Config("demo for android UI test") - .variables( - **{ - "foo1": "config_bar1", - "foo2": "config_bar2", - "expect_foo1": "config_bar1", - "expect_foo2": "config_bar2", - } - ) - .android() - .serial("xxx") - .package_name("xxx") - .install_apk("xxx") - ) - - teststeps = [ - # Step( - # RunAndroidUI("start app").control().start_app("com.ss.android.ugc.aweme") - # ), - Step( - RunAndroidUI("back home").ui().press_home() - ), - Step( - RunAndroidUI("back home").control().start_app() - ), - Step( - RunAndroidUI("swipe up").ui().swipe_up() - ), - Step( - RunAndroidUI("swipe up").ui().swipe_up() - ), - ] - - -if __name__ == "__main__": - TestCaseAndroidDemo().test_start() diff --git a/main.go b/main.go deleted file mode 100644 index 5d81a823..00000000 --- a/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "log" - "os" - "strings" - - "github.com/electricbubble/gadb" -) - -func main() { - adbClient, err := gadb.NewClient() - checkErr(err, "fail to connect adb server") - - devices, err := adbClient.DeviceList() - checkErr(err) - - if len(devices) == 0 { - log.Fatalln("list of devices is empty") - } - - dev := devices[0] - - userHomeDir, _ := os.UserHomeDir() - apk, err := os.Open(userHomeDir + "/Desktop/xuexi_android_10002068.apk") - checkErr(err) - - log.Println("starting to push apk") - - remotePath := "/data/local/tmp/xuexi_android_10002068.apk" - err = dev.PushFile(apk, remotePath) - checkErr(err, "adb push") - - log.Println("push completed") - - log.Println("starting to install apk") - - shellOutput, err := dev.RunShellCommand("pm install", remotePath) - checkErr(err, "pm install") - if !strings.Contains(shellOutput, "Success") { - log.Fatalln("fail to install: ", shellOutput) - } - - log.Println("install completed") - -} - -func checkErr(err error, msg ...string) { - if err == nil { - return - } - - var output string - if len(msg) != 0 { - output = msg[0] + " " - } - output += err.Error() - log.Fatalln(output) -} diff --git a/pyproject.toml b/pyproject.toml index 921a4bc8..c3339ecf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "httprunner" -version = "v4.3.0-beta-10160931" +version = "v4.3.0-beta-10161439" description = "One-stop solution for HTTP(S) testing." license = "Apache-2.0" readme = "README.md"