change: replace jsonschema validation with pydantic

This commit is contained in:
debugtalk
2020-04-09 18:50:06 +08:00
17 changed files with 51 additions and 915 deletions
+1
View File
@@ -4,6 +4,7 @@
**Changed** **Changed**
- replace jsonschema validation with pydantic
- remove compatibility with testcase/testsuite format v1 - remove compatibility with testcase/testsuite format v1
## 3.0.1 (2020-03-24) ## 3.0.1 (2020-03-24)
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = "3.0.1" __version__ = "3.0.2"
__description__ = "One-stop solution for HTTP(S) testing." __description__ = "One-stop solution for HTTP(S) testing."
__all__ = ["__version__", "__description__"] __all__ = ["__version__", "__description__"]
+3 -3
View File
@@ -277,7 +277,7 @@ def load_test_file(path: str) -> dict:
loaded_content["type"] = "testsuite" loaded_content["type"] = "testsuite"
elif "teststeps" in raw_content: elif "teststeps" in raw_content:
# file_type: testcase (format version 2) # file_type: testcase
loaded_content = load_testcase(raw_content) loaded_content = load_testcase(raw_content)
loaded_content["path"] = path loaded_content["path"] = path
loaded_content["type"] = "testcase" loaded_content["type"] = "testcase"
@@ -329,12 +329,12 @@ def load_project_data(test_path, dot_env_path=None):
# locate PWD and load debugtalk.py functions # locate PWD and load debugtalk.py functions
project_mapping["PWD"] = project_working_directory project_mapping["PWD"] = project_working_directory
project_mapping["functions"] = debugtalk_functions project_mapping["functions"] = debugtalk_functions
project_mapping["test_path"] = os.path.abspath(test_path)[len(project_working_directory)+1:] project_mapping["test_path"] = os.path.abspath(test_path)[len(project_working_directory) + 1:]
return project_mapping return project_mapping
def load_cases(path, dot_env_path=None): def load_cases(path: str, dot_env_path: str = None):
""" load testcases from file path, extend and merge with api/testcase definitions. """ load testcases from file path, extend and merge with api/testcase definitions.
Args: Args:
+17 -44
View File
@@ -1,70 +1,43 @@
import io
import json
import os import os
import platform
import jsonschema
from loguru import logger from loguru import logger
from pydantic import ValidationError
from httprunner import exceptions from httprunner import exceptions
from httprunner.schema import Api, TestCase, TestSuite
schemas_root_dir = os.path.join(os.path.dirname(__file__), "schemas")
common_schema_path = os.path.join(schemas_root_dir, "common.schema.json")
api_schema_path = os.path.join(schemas_root_dir, "api.schema.json")
testcase_schema_path = os.path.join(schemas_root_dir, "testcase.schema.json")
testsuite_schema_path = os.path.join(schemas_root_dir, "testsuite.schema.json")
with io.open(api_schema_path, encoding='utf-8') as f:
api_schema = json.load(f)
with io.open(common_schema_path, encoding='utf-8') as f:
if platform.system() == "Windows":
absolute_base_path = 'file:///' + os.path.abspath(schemas_root_dir).replace("\\", "/") + '/'
else:
# Linux, Darwin
absolute_base_path = "file://" + os.path.abspath(schemas_root_dir) + "/"
common_schema = json.load(f)
resolver = jsonschema.RefResolver(absolute_base_path, common_schema)
with io.open(testcase_schema_path, encoding='utf-8') as f:
testcase_schema = json.load(f)
with io.open(testsuite_schema_path, encoding='utf-8') as f:
testsuite_schema = json.load(f)
class JsonSchemaChecker(object): class JsonSchemaChecker(object):
@staticmethod
def validate_format(content, scheme):
""" check api/testcase/testsuite format if valid
"""
try:
jsonschema.validate(content, scheme, resolver=resolver)
except jsonschema.exceptions.ValidationError as ex:
logger.error(str(ex))
raise exceptions.FileFormatError
return True
@staticmethod @staticmethod
def validate_api_format(content): def validate_api_format(content):
""" check api format if valid """ check api format if valid
""" """
return JsonSchemaChecker.validate_format(content, api_schema) try:
Api.parse_obj(content)
except ValidationError as ex:
logger.error(ex)
raise exceptions.FileFormatError
@staticmethod @staticmethod
def validate_testcase_format(content): def validate_testcase_format(content):
""" check testcase format if valid """ check testcase format if valid
""" """
return JsonSchemaChecker.validate_format(content, testcase_schema) try:
TestCase.parse_obj(content)
except ValidationError as ex:
logger.error(ex)
raise exceptions.FileFormatError
@staticmethod @staticmethod
def validate_testsuite_format(content): def validate_testsuite_format(content):
""" check testsuite format if valid """ check testsuite format if valid
""" """
return JsonSchemaChecker.validate_format(content, testsuite_schema) try:
TestSuite.parse_obj(content)
except ValidationError as ex:
logger.error(ex)
raise exceptions.FileFormatError
def is_test_path(path): def is_test_path(path):
-59
View File
@@ -1,59 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"description": "httprunner api schema definition",
"type": "object",
"properties": {
"name": {
"$ref": "common.schema.json#/definitions/name"
},
"base_url": {
"$ref": "common.schema.json#/definitions/base_url"
},
"variables": {
"$ref": "common.schema.json#/definitions/variables"
},
"request": {
"$ref": "common.schema.json#/definitions/request"
},
"setup_hooks": {
"$ref": "common.schema.json#/definitions/hook"
},
"teardown_hooks": {
"$ref": "common.schema.json#/definitions/hook"
},
"extract": {
"$ref": "common.schema.json#/definitions/extract"
},
"validate": {
"$ref": "common.schema.json#/definitions/validate"
}
},
"required": [
"name",
"request"
],
"examples": [
{
"name": "demo api",
"variables": {
"var1": "value1",
"var2": "value2"
},
"request": {
"url": "/api/path/$var1",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"json": {
"key": "$var2"
},
"validate": [
{
"eq": ["status_code", 200]
}
]
}
}
]
}
@@ -1,392 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"description": "common json schema definitions for httprunner api/testcase/testsuite",
"definitions": {
"name": {
"description": "used as api/teststep/testcase/testsuite identification",
"type": "string",
"examples": [
"basic test for httpbin"
]
},
"base_url": {
"description": "The base_url will be used with relative URI",
"type": "string",
"examples": [
"https://httpbin.org"
]
},
"variables": {
"description": "define variables for api/teststep/testcase/testsuite",
"oneOf": [
{
"type": "object",
"examples": [
{
"var1": "value1",
"var2": "value2"
}
]
},
{
"type": "array",
"items": {
"type": "object",
"maxProperties": 1,
"minProperties": 1
},
"examples": [
[
{
"var1": "value1"
},
{
"var2": "value2"
}
]
]
},
{
"type": "string",
"pattern": "^\\$.*",
"examples": [
"$prepared_variables",
"${prepare_variables()}",
"${prepare_variables($a, $b)}"
]
}
]
},
"verify": {
"description": "whether to verify the servers TLS certificate",
"type": "boolean",
"examples": [
true,
false
]
},
"hook": {
"description": "used to define setup_hooks/teardown_hooks for api/teststep/testcase",
"type": "array",
"items": {
"oneOf": [
{
"description": "call setup/teardown hook functions, return nothing",
"type": "string",
"examples": [
[
"${sleep(2)}",
"${hook_print(setup)}",
"${modify_request_json($request, android)}",
"${alter_response($response)}"
]
]
},
{
"description": "call setup/teardown hook functions, return value and assign to variable",
"type": "object",
"examples": [
{
"total": "${sum_two(1, 5)}"
},
{
"filed_name": "get_decoded_response_field($response)"
}
]
}
]
}
},
"config": {
"description": "used in testcase/testsuite to configure common fields",
"type": "object",
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"base_url": {
"$ref": "#/definitions/base_url"
},
"variables": {
"$ref": "#/definitions/variables"
},
"setup_hooks": {
"$ref": "#/definitions/hook"
},
"teardown_hooks": {
"$ref": "#/definitions/hook"
},
"verify": {
"$ref": "#/definitions/verify"
}
},
"required": ["name"]
},
"request": {
"description": "used to define a api request. properties is the same as python package `requests.request`",
"type": "object",
"properties": {
"method": {
"type": "string",
"description": "request method",
"enum": [
"GET",
"POST",
"OPTIONS",
"HEAD",
"PUT",
"PATCH",
"DELETE",
"CONNECT",
"TRACE"
]
},
"url": {
"description": "request url, may be absolute or relative URI",
"type": "string",
"examples": [
"http://httpbin.org/get?a=1&b=2",
"/get?a=1&b=2",
"get?a=1&b=2"
]
},
"params": {
"description": "query string for request url",
"type": "object",
"examples": [
{
"a": 1,
"b": 2
}
]
},
"data": {
"anyOf": [
{
"description": "request body in json format",
"type": "object",
"examples": [
{
"a": 1,
"b": 2
}
]
},
{
"description": "request body in application/x-www-form-urlencoded format",
"type": "string",
"examples": [
"a=1&b=2"
]
},
{
"description": "request body prepared with function, or reference a variable",
"type": "string",
"examples": [
"$post_data",
"${prepare_data($a, $b)}"
]
}
]
},
"json": {
"oneOf": [
{
"description": "request body in json format",
"type": "object"
},
{
"description": "request body prepared with function, or reference a variable",
"type": "string",
"pattern": "^\\$.*",
"examples": [
"$post_data",
"${prepare_post_data($a, $b)}"
]
}
]
},
"headers": {
"description": "request headers",
"oneOf": [
{
"description": "request headers in json format",
"type": "object",
"examples": [
{
"User-Agent": "python-requests/2.18.4",
"Content-Type": "application/json"
}
]
},
{
"description": "request headers prepared with function, or reference a variable",
"type": "string",
"examples": [
"$prepared_headers",
"${prepare_headers($a, $b)}"
]
}
]
},
"cookies": {
"description": "request cookies",
"type": "object"
},
"files": {
"description": "request files, used to upload files",
"type": "object"
},
"auth": {
"description": "Auth tuple to enable Basic/Digest/Custom HTTP Auth.",
"type": "array"
},
"timeout": {
"description": "How many seconds to wait for the server to send data before giving up",
"type": "number",
"examples": [
120
]
},
"allow_redirects": {
"description": "Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to True",
"type": "boolean"
},
"proxies": {
"description": "Dictionary mapping protocol to the URL of the proxy",
"type": "object"
},
"verify": {
"description": "configure verify for current api/teststep",
"$ref": "#/definitions/verify"
},
"stream": {
"description": "if False, the response content will be immediately downloaded.",
"type": "boolean"
},
"upload": {
"description": "upload files",
"type": "object",
"examples": [
{
"file": "data/file_to_upload",
"md5": "123"
}
]
}
},
"required": [
"method",
"url"
]
},
"extract": {
"description": "used to extract session variables for later requests",
"oneOf": [
{
"type": "object",
"patternProperties": {
"^[A-Za-z_][A-Za-z0-9_]*$": {
"description": "extraction rule for session variable, maybe in jsonpath/regex/jmespath",
"type": "string"
}
},
"examples": [
{
"code__by_jsonpath": "$.code",
"item_id__by_jsonpath": "$..items.*.id",
"var_name__by_regex": "\"LB[\\d]*(.*)RB[\\d]*\"",
"content_type": "headers.content-type",
"first_name": "content.person.name.first_name"
}
]
},
{
"type": "array",
"items": {
"type": "object",
"patternProperties": {
"^[A-Za-z_][A-Za-z0-9_]*$": {
"description": "extraction rule for session variable, maybe in jsonpath/regex/jmespath",
"type": "string"
}
},
"minProperties": 1,
"maxProperties": 1
},
"examples": [
{
"code__by_jsonpath": "$.code"
},
{
"item_id__by_jsonpath": "$..items.*.id"
},
{
"var_name__by_regex": "\"LB[\\d]*(.*)RB[\\d]*\""
},
{
"content_type": "headers.content-type"
},
{
"first_name": "content.person.name.first_name"
}
]
}
]
},
"validate": {
"description": "used to validate response fields",
"type": "array",
"items": {
"description": "one validator definition",
"oneOf": [
{
"type": "object",
"properties": {
"check": {
"type": "string"
},
"comparator": {
"type": "string"
},
"expect": {
"description": "expected value"
}
},
"required": ["check", "expect"],
"examples": [
{
"check": "body.code",
"comparator": "gt",
"expect": 0
},
{
"check": "status_code",
"expect": 200
}
]
},
{
"type": "object",
"patternProperties": {
"^[A-Za-z_][A-Za-z0-9_]*$": {
"description": "validate_func_name: [check_value, expect_value]",
"type": "array",
"minItems": 2,
"maxItems": 2
}
},
"examples": [
{
"eq": ["status_code", 200]
},
{
"gt": ["body.code", 0]
}
]
}
]
}
}
}
}
@@ -1,184 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"description": "httprunner testcase schema definition",
"type": "object",
"definitions": {
"teststep": {
"type": "object",
"oneOf": [
{
"properties": {
"name": {
"$ref": "common.schema.json#/definitions/name"
},
"request": {
"description": "define api request directly",
"$ref": "common.schema.json#/definitions/request"
},
"variables": {
"$ref": "common.schema.json#/definitions/variables"
},
"extract": {
"$ref": "common.schema.json#/definitions/extract"
},
"validate": {
"$ref": "common.schema.json#/definitions/validate"
},
"setup_hooks": {
"$ref": "common.schema.json#/definitions/hook"
},
"teardown_hooks": {
"$ref": "common.schema.json#/definitions/hook"
}
},
"required": [
"name",
"request"
]
},
{
"properties": {
"name": {
"$ref": "common.schema.json#/definitions/name"
},
"api": {
"description": "api reference, value is api file relative path",
"type": "string"
},
"variables": {
"$ref": "common.schema.json#/definitions/variables"
},
"extract": {
"oneOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"$ref": "common.schema.json#/definitions/extract"
}
]
},
"validate": {
"$ref": "common.schema.json#/definitions/validate"
},
"setup_hooks": {
"$ref": "common.schema.json#/definitions/hook"
},
"teardown_hooks": {
"$ref": "common.schema.json#/definitions/hook"
}
},
"required": [
"name",
"api"
]
},
{
"properties": {
"name": {
"$ref": "common.schema.json#/definitions/name"
},
"testcase": {
"description": "testcase reference, value is testcase file relative path",
"type": "string"
},
"variables": {
"$ref": "common.schema.json#/definitions/variables"
},
"extract": {
"type": "array",
"items": {
"type": "string"
}
},
"setup_hooks": {
"$ref": "common.schema.json#/definitions/hook"
},
"teardown_hooks": {
"$ref": "common.schema.json#/definitions/hook"
}
},
"required": [
"name",
"testcase"
]
}
]
}
},
"properties": {
"config": {
"$ref": "common.schema.json#/definitions/config"
},
"teststeps": {
"description": "teststep of a testcase",
"type": "array",
"minItems": 1,
"items": {
"$ref": "testcase.schema.json#/definitions/teststep"
}
}
},
"required": [
"config",
"teststeps"
],
"examples": [
{
"config": {
"name": "testcase name"
},
"teststeps": [
{
"name": "api 1",
"api": "/path/to/api1"
},
{
"name": "api 2",
"api": "/path/to/api2"
}
]
},
{
"config": {
"name": "demo testcase",
"variables": {
"device_sn": "ABC",
"username": "${ENV(USERNAME)}",
"password": "${ENV(PASSWORD)}"
},
"base_url": "http://127.0.0.1:5000"
},
"teststeps": [
{
"name": "demo step 1",
"api": "path/to/api1.yml",
"variables": {
"user_agent": "iOS/10.3",
"device_sn": "$device_sn"
},
"extract": [
{
"token": "content.token"
}
],
"validate": [
{
"eq": ["status_code", 200]
}
]
},
{
"name": "demo step 2",
"api": "path/to/api2.yml",
"variables": {
"token": "$token"
}
}
]
}
]
}
@@ -1,88 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"description": "httprunner testsuite schema definition",
"type": "object",
"definitions": {
"testcase": {
"type": "object",
"properties": {
"name": {
"$ref": "common.schema.json#/definitions/name"
},
"variables": {
"$ref": "common.schema.json#/definitions/variables"
},
"parameters": {
"description": "generate cartesian product variables with parameters, each group of variables will be run once",
"type": "object"
},
"testcase": {
"description": "testcase reference, value is testcase file relative path",
"type": "string"
}
},
"required": [
"testcase"
]
}
},
"properties": {
"config": {
"$ref": "common.schema.json#/definitions/config"
},
"testcases": {
"description": "testcase of a testsuite",
"type": "array",
"minItems": 1,
"items": {
"$ref": "testsuite.schema.json#/definitions/testcase"
}
}
},
"required": [
"config",
"testcases"
],
"examples": [
{
"config": {
"name": "testsuite name"
},
"testcases": [
{
"name": "testcase 1",
"testcase": "/path/to/testcase1"
},
{
"name": "testcase 2",
"testcase": "/path/to/testcase2"
}
]
},
{
"config": {
"name": "demo testsuite",
"variables": {
"device_sn": "XYZ"
},
"base_url": "http://127.0.0.1:5000"
},
"testcases": [
{
"name": "call demo_testcase with data 1",
"testcase": "path/to/demo_testcase.yml",
"variables": {
"device_sn": "$device_sn"
}
},
{
"name": "call demo_testcase with data 2",
"testcase": "path/to/demo_testcase.yml",
"variables": {
"device_sn": "$device_sn"
}
}
]
}
]
}
+2
View File
@@ -1 +1,3 @@
from .api import Api
from .testcase import ProjectMeta, TestCase, TestCases from .testcase import ProjectMeta, TestCase, TestCases
from .testsuite import TestSuite
+6 -6
View File
@@ -1,4 +1,4 @@
from pydantic import BaseModel from pydantic import BaseModel, Field
from httprunner.schema import common from httprunner.schema import common
@@ -7,8 +7,8 @@ class Api(BaseModel):
name: common.Name name: common.Name
request: common.Request request: common.Request
variables: common.Variables variables: common.Variables
base_url: common.BaseUrl base_url: common.BaseUrl = ""
setup_hooks: common.Hook setup_hooks: common.Hook = []
teardown_hooks: common.Hook teardown_hooks: common.Hook = []
extract: common.Extract extract: common.Extract = {}
validate: common.Validate validation: common.Validate = Field([], alias="validate")
+3 -3
View File
@@ -1,11 +1,11 @@
from enum import Enum from enum import Enum
from typing import Dict, List, Any, Tuple from typing import Dict, List, Any
from pydantic import BaseModel, HttpUrl, Field from pydantic import BaseModel, HttpUrl, Field
Name = str Name = str
Url = HttpUrl Url = str
BaseUrl = str BaseUrl = HttpUrl
Variables = Dict[str, Any] Variables = Dict[str, Any]
Headers = Dict[str, str] Headers = Dict[str, str]
Verify = bool Verify = bool
+2 -1
View File
@@ -13,7 +13,8 @@ class ProjectMeta(BaseModel):
class TestStep(BaseModel): class TestStep(BaseModel):
name: common.Name name: common.Name
request: common.Request api: str = None # TODO: replace with FilePath
request: common.Request = None
extract: Dict[str, str] = {} extract: Dict[str, str] = {}
validation: common.Validate = Field([], alias="validate") validation: common.Validate = Field([], alias="validate")
+10
View File
@@ -0,0 +1,10 @@
from typing import List
from pydantic import BaseModel
from httprunner.schema import common, TestCase
class TestSuite(BaseModel):
config: common.TestsConfig
testcases: List[TestCase]
Generated
+1 -128
View File
@@ -12,20 +12,6 @@ version = "0.2.2"
python = "<3.7" python = "<3.7"
version = "2.4" version = "2.4"
[[package]]
category = "main"
description = "Classes Without Boilerplate"
name = "attrs"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.3.0"
[package.extras]
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
[[package]] [[package]]
category = "main" category = "main"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
@@ -176,22 +162,6 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.11" version = "0.11"
[[package]]
category = "main"
description = "Read metadata from Python packages"
marker = "python_version < \"3.8\""
name = "importlib-metadata"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.3.0"
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
[[package]] [[package]]
category = "dev" category = "dev"
description = "Various helpers to pass data to untrusted environments and back." description = "Various helpers to pass data to untrusted environments and back."
@@ -222,28 +192,6 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.82" version = "0.82"
[[package]]
category = "main"
description = "An implementation of JSON Schema validation for Python"
name = "jsonschema"
optional = false
python-versions = "*"
version = "3.2.0"
[package.dependencies]
attrs = ">=17.4.0"
pyrsistent = ">=0.14.0"
setuptools = "*"
six = ">=1.11.0"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = "*"
[package.extras]
format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"]
[[package]] [[package]]
category = "main" category = "main"
description = "Python logging made (stupidly) simple" description = "Python logging made (stupidly) simple"
@@ -271,18 +219,6 @@ optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.1.1" version = "1.1.1"
[[package]]
category = "main"
description = "More routines for operating on iterables, beyond itertools"
marker = "python_version < \"3.8\""
name = "more-itertools"
optional = false
python-versions = "*"
version = "5.0.0"
[package.dependencies]
six = ">=1.0.0,<2.0.0"
[[package]] [[package]]
category = "main" category = "main"
description = "Data validation and settings management using python 3.6 type hinting" description = "Data validation and settings management using python 3.6 type hinting"
@@ -301,17 +237,6 @@ dotenv = ["python-dotenv (>=0.10.4)"]
email = ["email-validator (>=1.0.3)"] email = ["email-validator (>=1.0.3)"]
typing_extensions = ["typing-extensions (>=3.7.2)"] typing_extensions = ["typing-extensions (>=3.7.2)"]
[[package]]
category = "main"
description = "Persistent/Functional/Immutable data structures"
name = "pyrsistent"
optional = false
python-versions = "*"
version = "0.15.6"
[package.dependencies]
six = "*"
[[package]] [[package]]
category = "main" category = "main"
description = "YAML parser and emitter for Python" description = "YAML parser and emitter for Python"
@@ -349,14 +274,6 @@ version = "0.9.1"
[package.dependencies] [package.dependencies]
requests = ">=2.0.1,<3.0.0" requests = ">=2.0.1,<3.0.0"
[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "1.13.0"
[[package]] [[package]]
category = "dev" category = "dev"
description = "The little ASGI library that shines." description = "The little ASGI library that shines."
@@ -438,24 +355,8 @@ version = "1.0.1"
[package.extras] [package.extras]
dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"]
[[package]]
category = "main"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\""
name = "zipp"
optional = false
python-versions = ">=2.7"
version = "0.6.0"
[package.dependencies]
more-itertools = "*"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pathlib2", "contextlib2", "unittest2"]
[metadata] [metadata]
content-hash = "8ef61f687de82f9bd0c92c521e2cc890454a4da6ca7f80d0f30973551540c4ae" content-hash = "ff30b34e5d7a0934029a6ea20ebd43fc9ea769c4bbb2e63890de6d399d756da0"
python-versions = "^3.6" python-versions = "^3.6"
[metadata.files] [metadata.files]
@@ -463,10 +364,6 @@ aiocontextvars = [
{file = "aiocontextvars-0.2.2-py2.py3-none-any.whl", hash = "sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3"}, {file = "aiocontextvars-0.2.2-py2.py3-none-any.whl", hash = "sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3"},
{file = "aiocontextvars-0.2.2.tar.gz", hash = "sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa"}, {file = "aiocontextvars-0.2.2.tar.gz", hash = "sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa"},
] ]
attrs = [
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
]
certifi = [ certifi = [
{file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"},
{file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"},
@@ -580,10 +477,6 @@ immutables = [
{file = "immutables-0.11-cp37-cp37m-win_amd64.whl", hash = "sha256:6b6d8d035e5888baad3db61dfb167476838a63afccecd927c365f228bb55754c"}, {file = "immutables-0.11-cp37-cp37m-win_amd64.whl", hash = "sha256:6b6d8d035e5888baad3db61dfb167476838a63afccecd927c365f228bb55754c"},
{file = "immutables-0.11.tar.gz", hash = "sha256:d6850578a0dc6530ac19113cfe4ddc13903df635212d498f176fe601a8a5a4a3"}, {file = "immutables-0.11.tar.gz", hash = "sha256:d6850578a0dc6530ac19113cfe4ddc13903df635212d498f176fe601a8a5a4a3"},
] ]
importlib-metadata = [
{file = "importlib_metadata-1.3.0-py2.py3-none-any.whl", hash = "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"},
{file = "importlib_metadata-1.3.0.tar.gz", hash = "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45"},
]
itsdangerous = [ itsdangerous = [
{file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
{file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
@@ -595,10 +488,6 @@ jinja2 = [
jsonpath = [ jsonpath = [
{file = "jsonpath-0.82.tar.gz", hash = "sha256:46d3fd2016cd5b842283d547877a02c418a0fe9aa7a6b0ae344115a2c990fef4"}, {file = "jsonpath-0.82.tar.gz", hash = "sha256:46d3fd2016cd5b842283d547877a02c418a0fe9aa7a6b0ae344115a2c990fef4"},
] ]
jsonschema = [
{file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
{file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
]
loguru = [ loguru = [
{file = "loguru-0.4.1-py3-none-any.whl", hash = "sha256:074b3caa6748452c1e4f2b302093c94b65d5a4c5a4d7743636b4121e06437b0e"}, {file = "loguru-0.4.1-py3-none-any.whl", hash = "sha256:074b3caa6748452c1e4f2b302093c94b65d5a4c5a4d7743636b4121e06437b0e"},
{file = "loguru-0.4.1.tar.gz", hash = "sha256:a6101fd435ac89ba5205a105a26a6ede9e4ddbb4408a6e167852efca47806d11"}, {file = "loguru-0.4.1.tar.gz", hash = "sha256:a6101fd435ac89ba5205a105a26a6ede9e4ddbb4408a6e167852efca47806d11"},
@@ -633,11 +522,6 @@ markupsafe = [
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
] ]
more-itertools = [
{file = "more-itertools-5.0.0.tar.gz", hash = "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4"},
{file = "more_itertools-5.0.0-py2-none-any.whl", hash = "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc"},
{file = "more_itertools-5.0.0-py3-none-any.whl", hash = "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"},
]
pydantic = [ pydantic = [
{file = "pydantic-1.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:07911aab70f3bc52bb845ce1748569c5e70478ac977e106a150dd9d0465ebf04"}, {file = "pydantic-1.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:07911aab70f3bc52bb845ce1748569c5e70478ac977e106a150dd9d0465ebf04"},
{file = "pydantic-1.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:012c422859bac2e03ab3151ea6624fecf0e249486be7eb8c6ee69c91740c6752"}, {file = "pydantic-1.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:012c422859bac2e03ab3151ea6624fecf0e249486be7eb8c6ee69c91740c6752"},
@@ -654,9 +538,6 @@ pydantic = [
{file = "pydantic-1.4-py36.py37.py38-none-any.whl", hash = "sha256:72184c1421103cca128300120f8f1185fb42a9ea73a1c9845b1c53db8c026a7d"}, {file = "pydantic-1.4-py36.py37.py38-none-any.whl", hash = "sha256:72184c1421103cca128300120f8f1185fb42a9ea73a1c9845b1c53db8c026a7d"},
{file = "pydantic-1.4.tar.gz", hash = "sha256:f17ec336e64d4583311249fb179528e9a2c27c8a2eaf590ec6ec2c6dece7cb3f"}, {file = "pydantic-1.4.tar.gz", hash = "sha256:f17ec336e64d4583311249fb179528e9a2c27c8a2eaf590ec6ec2c6dece7cb3f"},
] ]
pyrsistent = [
{file = "pyrsistent-0.15.6.tar.gz", hash = "sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b"},
]
pyyaml = [ pyyaml = [
{file = "PyYAML-5.2-cp27-cp27m-win32.whl", hash = "sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc"}, {file = "PyYAML-5.2-cp27-cp27m-win32.whl", hash = "sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc"},
{file = "PyYAML-5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4"}, {file = "PyYAML-5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4"},
@@ -678,10 +559,6 @@ requests-toolbelt = [
{file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"}, {file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"},
{file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"}, {file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"},
] ]
six = [
{file = "six-1.13.0-py2.py3-none-any.whl", hash = "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd"},
{file = "six-1.13.0.tar.gz", hash = "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"},
]
starlette = [ starlette = [
{file = "starlette-0.12.9.tar.gz", hash = "sha256:c2ac9a42e0e0328ad20fe444115ac5e3760c1ee2ac1ff8cdb5ec915c4a453411"}, {file = "starlette-0.12.9.tar.gz", hash = "sha256:c2ac9a42e0e0328ad20fe444115ac5e3760c1ee2ac1ff8cdb5ec915c4a453411"},
] ]
@@ -725,7 +602,3 @@ win32-setctime = [
{file = "win32_setctime-1.0.1-py3-none-any.whl", hash = "sha256:568fd636c68350bcc54755213fe01966fe0a6c90b386c0776425944a0382abef"}, {file = "win32_setctime-1.0.1-py3-none-any.whl", hash = "sha256:568fd636c68350bcc54755213fe01966fe0a6c90b386c0776425944a0382abef"},
{file = "win32_setctime-1.0.1.tar.gz", hash = "sha256:b47e5023ec7f0b4962950902b15bc56464a380d869f59d27dbf9ab423b23e8f9"}, {file = "win32_setctime-1.0.1.tar.gz", hash = "sha256:b47e5023ec7f0b4962950902b15bc56464a380d869f59d27dbf9ab423b23e8f9"},
] ]
zipp = [
{file = "zipp-0.6.0-py2.py3-none-any.whl", hash = "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"},
{file = "zipp-0.6.0.tar.gz", hash = "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e"},
]
+1 -2
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "httprunner" name = "httprunner"
version = "3.0.1" version = "3.0.2"
description = "One-stop solution for HTTP(S) testing." description = "One-stop solution for HTTP(S) testing."
license = "Apache-2.0" license = "Apache-2.0"
readme = "README.md" readme = "README.md"
@@ -36,7 +36,6 @@ jinja2 = "^2.10.3"
har2case = "^0.3.1" har2case = "^0.3.1"
filetype = "^1.0.5" filetype = "^1.0.5"
jsonpath = "^0.82" jsonpath = "^0.82"
jsonschema = "^3.2.0"
pydantic = "^1.4" pydantic = "^1.4"
loguru = "^0.4.1" loguru = "^0.4.1"
+3 -3
View File
@@ -24,9 +24,9 @@
"os_platform": "ios", "os_platform": "ios",
"user_agent": "iOS/10.3" "user_agent": "iOS/10.3"
}, },
"extract": [ "extract": {
{"session_token": "content.token"} "session_token": "content.token"
], },
"validate": [ "validate": [
{"eq": ["status_code", 200]}, {"eq": ["status_code", 200]},
{"len_eq": ["content.token", 16]} {"len_eq": ["content.token", 16]}
+1 -1
View File
@@ -21,7 +21,7 @@ teststeps:
os_platform: 'ios' os_platform: 'ios'
app_version: '2.8.6' app_version: '2.8.6'
extract: extract:
- session_token: content.token session_token: content.token
validate: validate:
- eq: ["status_code", 200] - eq: ["status_code", 200]
- len_eq: ["content.token", 16] - len_eq: ["content.token", 16]