pytest-dsl 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_dsl/__init__.py +10 -0
- pytest_dsl/cli.py +44 -0
- pytest_dsl/conftest_adapter.py +4 -0
- pytest_dsl/core/__init__.py +0 -0
- pytest_dsl/core/auth_provider.py +409 -0
- pytest_dsl/core/auto_decorator.py +181 -0
- pytest_dsl/core/auto_directory.py +81 -0
- pytest_dsl/core/context.py +23 -0
- pytest_dsl/core/custom_auth_example.py +425 -0
- pytest_dsl/core/dsl_executor.py +329 -0
- pytest_dsl/core/dsl_executor_utils.py +84 -0
- pytest_dsl/core/global_context.py +103 -0
- pytest_dsl/core/http_client.py +411 -0
- pytest_dsl/core/http_request.py +810 -0
- pytest_dsl/core/keyword_manager.py +109 -0
- pytest_dsl/core/lexer.py +139 -0
- pytest_dsl/core/parser.py +197 -0
- pytest_dsl/core/parsetab.py +76 -0
- pytest_dsl/core/plugin_discovery.py +187 -0
- pytest_dsl/core/utils.py +146 -0
- pytest_dsl/core/variable_utils.py +267 -0
- pytest_dsl/core/yaml_loader.py +62 -0
- pytest_dsl/core/yaml_vars.py +75 -0
- pytest_dsl/docs/custom_keywords.md +140 -0
- pytest_dsl/examples/__init__.py +5 -0
- pytest_dsl/examples/assert/assertion_example.auto +44 -0
- pytest_dsl/examples/assert/boolean_test.auto +34 -0
- pytest_dsl/examples/assert/expression_test.auto +49 -0
- pytest_dsl/examples/http/__init__.py +3 -0
- pytest_dsl/examples/http/builtin_auth_test.auto +79 -0
- pytest_dsl/examples/http/csrf_auth_test.auto +64 -0
- pytest_dsl/examples/http/custom_auth_test.auto +76 -0
- pytest_dsl/examples/http/file_reference_test.auto +111 -0
- pytest_dsl/examples/http/http_advanced.auto +91 -0
- pytest_dsl/examples/http/http_example.auto +147 -0
- pytest_dsl/examples/http/http_length_test.auto +55 -0
- pytest_dsl/examples/http/http_retry_assertions.auto +91 -0
- pytest_dsl/examples/http/http_retry_assertions_enhanced.auto +94 -0
- pytest_dsl/examples/http/http_with_yaml.auto +58 -0
- pytest_dsl/examples/http/new_retry_test.auto +22 -0
- pytest_dsl/examples/http/retry_assertions_only.auto +52 -0
- pytest_dsl/examples/http/retry_config_only.auto +49 -0
- pytest_dsl/examples/http/retry_debug.auto +22 -0
- pytest_dsl/examples/http/retry_with_fix.auto +21 -0
- pytest_dsl/examples/http/simple_retry.auto +20 -0
- pytest_dsl/examples/http/vars.yaml +55 -0
- pytest_dsl/examples/http_clients.yaml +48 -0
- pytest_dsl/examples/keyword_example.py +70 -0
- pytest_dsl/examples/test_assert.py +16 -0
- pytest_dsl/examples/test_http.py +168 -0
- pytest_dsl/keywords/__init__.py +10 -0
- pytest_dsl/keywords/assertion_keywords.py +610 -0
- pytest_dsl/keywords/global_keywords.py +51 -0
- pytest_dsl/keywords/http_keywords.py +430 -0
- pytest_dsl/keywords/system_keywords.py +17 -0
- pytest_dsl/main_adapter.py +7 -0
- pytest_dsl/plugin.py +44 -0
- pytest_dsl-0.1.0.dist-info/METADATA +537 -0
- pytest_dsl-0.1.0.dist-info/RECORD +63 -0
- pytest_dsl-0.1.0.dist-info/WHEEL +5 -0
- pytest_dsl-0.1.0.dist-info/entry_points.txt +5 -0
- pytest_dsl-0.1.0.dist-info/licenses/LICENSE +21 -0
- pytest_dsl-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
@name: 只使用retry_assertions的断言重试示例
|
2
|
+
@description: 不使用断言级别的retry标记,只使用独立的retry_assertions配置块
|
3
|
+
@tags: [HTTP, API, 断言重试]
|
4
|
+
@author: Felix
|
5
|
+
@date: 2024-06-15
|
6
|
+
|
7
|
+
# 使用全局retry_assertions配置所有断言
|
8
|
+
[HTTP请求],客户端:'default',配置:'''
|
9
|
+
method: GET
|
10
|
+
url: https://httpbin.org/delay/1
|
11
|
+
asserts:
|
12
|
+
- ["status", "eq", 200]
|
13
|
+
- ["response_time", "lt", 500] # 可能会失败,因为请求延迟约1秒
|
14
|
+
# 全局重试配置
|
15
|
+
retry_assertions:
|
16
|
+
count: 2
|
17
|
+
interval: 1
|
18
|
+
all: true # 重试所有断言
|
19
|
+
''',步骤名称:"全局断言重试配置示例"
|
20
|
+
|
21
|
+
# 使用特定断言索引重试
|
22
|
+
[HTTP请求],客户端:'default',配置:'''
|
23
|
+
method: GET
|
24
|
+
url: https://httpbin.org/delay/1
|
25
|
+
asserts:
|
26
|
+
- ["status", "eq", 200] # 索引0
|
27
|
+
- ["response_time", "lt", 500] # 索引1,需要重试
|
28
|
+
# 只重试指定索引的断言
|
29
|
+
retry_assertions:
|
30
|
+
count: 3
|
31
|
+
interval: 0.5
|
32
|
+
indices: [1] # 只重试response_time断言
|
33
|
+
''',步骤名称:"特定断言索引重试示例"
|
34
|
+
|
35
|
+
# 使用特定断言配置
|
36
|
+
[HTTP请求],客户端:'default',配置:'''
|
37
|
+
method: GET
|
38
|
+
url: https://httpbin.org/delay/1
|
39
|
+
asserts:
|
40
|
+
- ["status", "eq", 200] # 索引0
|
41
|
+
- ["response_time", "lt", 500] # 索引1,使用特定配置
|
42
|
+
- ["body", "contains", "url"] # 索引2
|
43
|
+
# 为特定断言提供自定义配置
|
44
|
+
retry_assertions:
|
45
|
+
specific:
|
46
|
+
"1": { # 索引1的特定配置
|
47
|
+
count: 4,
|
48
|
+
interval: 0.3
|
49
|
+
}
|
50
|
+
''',步骤名称:"特定断言配置重试示例"
|
51
|
+
|
52
|
+
[打印],内容:'测试完成!'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
@name: 只使用全局配置的断言重试示例
|
2
|
+
@description: 测试只使用retry_assertions配置的断言重试功能
|
3
|
+
@tags: [HTTP, API, 断言重试]
|
4
|
+
@author: Felix
|
5
|
+
@date: 2024-06-15
|
6
|
+
|
7
|
+
# 使用全局retry_assertions配置
|
8
|
+
[HTTP请求],客户端:'default',配置:'''
|
9
|
+
method: GET
|
10
|
+
url: https://httpbin.org/delay/1
|
11
|
+
asserts:
|
12
|
+
- ["status", "eq", 200]
|
13
|
+
- ["response_time", "lt", 500]
|
14
|
+
retry_assertions:
|
15
|
+
count: 2
|
16
|
+
interval: 1
|
17
|
+
all: true
|
18
|
+
''',步骤名称:"全局断言重试示例"
|
19
|
+
|
20
|
+
# 使用indices指定重试断言
|
21
|
+
[HTTP请求],客户端:'default',配置:'''
|
22
|
+
method: GET
|
23
|
+
url: https://httpbin.org/delay/1
|
24
|
+
asserts:
|
25
|
+
- ["status", "eq", 200]
|
26
|
+
- ["response_time", "lt", 500]
|
27
|
+
retry_assertions:
|
28
|
+
count: 3
|
29
|
+
interval: 0.5
|
30
|
+
indices: [1]
|
31
|
+
''',步骤名称:"指定索引重试示例"
|
32
|
+
|
33
|
+
# 使用specific为特定断言配置不同参数
|
34
|
+
[HTTP请求],客户端:'default',配置:'''
|
35
|
+
method: GET
|
36
|
+
url: https://httpbin.org/delay/1
|
37
|
+
asserts:
|
38
|
+
- ["status", "eq", 200]
|
39
|
+
- ["response_time", "lt", 500]
|
40
|
+
- ["body", "contains", "url"]
|
41
|
+
retry_assertions:
|
42
|
+
specific:
|
43
|
+
"1": {
|
44
|
+
count: 4,
|
45
|
+
interval: 0.3
|
46
|
+
}
|
47
|
+
''',步骤名称:"特定断言配置示例"
|
48
|
+
|
49
|
+
[打印],内容:'测试完成!'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
@name: 断言重试调试示例
|
2
|
+
@description: 使用更严格的断言条件测试断言重试功能
|
3
|
+
@tags: [HTTP, API, 断言重试, 调试]
|
4
|
+
@author: Felix
|
5
|
+
@date: 2024-06-15
|
6
|
+
|
7
|
+
[打印],内容:'开始测试断言重试功能 - 故意设置极低的响应时间限制'
|
8
|
+
|
9
|
+
# 使用非常低的响应时间限制确保断言失败
|
10
|
+
[HTTP请求],客户端:'default',配置:'''
|
11
|
+
method: GET
|
12
|
+
url: https://httpbin.org/delay/1
|
13
|
+
asserts:
|
14
|
+
- ["status", "eq", 200] # 这个会通过
|
15
|
+
- ["response_time", "lt", 50] # 设置极低的值确保失败,1秒的延迟应该会超过50ms
|
16
|
+
retry_assertions:
|
17
|
+
count: 2
|
18
|
+
interval: 0.5
|
19
|
+
all: true
|
20
|
+
''',步骤名称:"故意触发断言失败的示例"
|
21
|
+
|
22
|
+
[打印],内容:'测试完成 - 如果执行到这里,说明重试逻辑正常工作'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
@name: 全局断言重试示例
|
2
|
+
@description: 使用全局retry_assertions配置测试断言重试功能
|
3
|
+
@tags: [HTTP, API, 断言重试]
|
4
|
+
@author: Felix
|
5
|
+
@date: 2024-06-15
|
6
|
+
|
7
|
+
# 使用全局retry_assertions配置
|
8
|
+
[HTTP请求],客户端:'default',配置:'''
|
9
|
+
method: GET
|
10
|
+
url: https://httpbin.org/delay/1
|
11
|
+
asserts:
|
12
|
+
- ["status", "eq", 200]
|
13
|
+
- ["response_time", "lt", 1000]
|
14
|
+
# 全局重试配置
|
15
|
+
retry_assertions:
|
16
|
+
count: 2
|
17
|
+
interval: 1
|
18
|
+
indices: [1] # 只重试response_time断言
|
19
|
+
''',步骤名称:"全局重试配置示例"
|
20
|
+
|
21
|
+
[打印],内容:'测试完成!'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
@name: 简单断言重试示例
|
2
|
+
@description: 测试断言重试功能的基本使用
|
3
|
+
@tags: [HTTP, API, 断言重试]
|
4
|
+
@author: Felix
|
5
|
+
@date: 2024-06-01
|
6
|
+
|
7
|
+
# 使用独立的retry_assertions配置
|
8
|
+
[HTTP请求],客户端:'default',配置:'''
|
9
|
+
method: GET
|
10
|
+
url: https://httpbin.org/delay/1
|
11
|
+
asserts:
|
12
|
+
- ["status", "eq", 200]
|
13
|
+
- ["response_time", "lt", 5000]
|
14
|
+
retry_assertions:
|
15
|
+
count: 2
|
16
|
+
interval: 1
|
17
|
+
all: true
|
18
|
+
''',步骤名称:"简单断言重试示例"
|
19
|
+
|
20
|
+
[打印],内容:'测试完成!'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# HTTP客户端配置
|
2
|
+
http_clients:
|
3
|
+
default: # 默认客户端配置
|
4
|
+
base_url: https://httpbin.org
|
5
|
+
headers:
|
6
|
+
User-Agent: pytest-dsl-client/1.0
|
7
|
+
Accept: application/json
|
8
|
+
timeout: 30
|
9
|
+
verify_ssl: true
|
10
|
+
session: true
|
11
|
+
|
12
|
+
jsonplaceholder: # JSONPlaceholder API客户端
|
13
|
+
base_url: https://jsonplaceholder.typicode.com
|
14
|
+
headers:
|
15
|
+
User-Agent: pytest-dsl-client/1.0
|
16
|
+
Accept: application/json
|
17
|
+
timeout: 15
|
18
|
+
verify_ssl: true
|
19
|
+
session: true
|
20
|
+
retry:
|
21
|
+
max_retries: 2
|
22
|
+
retry_interval: 1
|
23
|
+
retry_on_status: [500, 502, 503, 504]
|
24
|
+
|
25
|
+
# HTTP请求模板
|
26
|
+
http_templates:
|
27
|
+
json_post:
|
28
|
+
method: POST
|
29
|
+
request:
|
30
|
+
headers:
|
31
|
+
Content-Type: application/json
|
32
|
+
json: {}
|
33
|
+
asserts:
|
34
|
+
- ["status", "in", [200, 201]]
|
35
|
+
|
36
|
+
api_auth:
|
37
|
+
method: POST
|
38
|
+
url: /auth/login
|
39
|
+
request:
|
40
|
+
headers:
|
41
|
+
Content-Type: application/json
|
42
|
+
json:
|
43
|
+
username: ""
|
44
|
+
password: ""
|
45
|
+
captures:
|
46
|
+
token: ["jsonpath", "$.token"]
|
47
|
+
asserts:
|
48
|
+
- ["status", "eq", 200]
|
49
|
+
- ["jsonpath", "$.token", "exists"]
|
50
|
+
|
51
|
+
# 测试数据
|
52
|
+
api_test_data:
|
53
|
+
username: test_user
|
54
|
+
password: password123
|
55
|
+
user_id: 10
|
@@ -0,0 +1,48 @@
|
|
1
|
+
http_clients:
|
2
|
+
hmac_auth:
|
3
|
+
base_url: https://httpbin.org
|
4
|
+
headers:
|
5
|
+
User-Agent: pytest-dsl-client/1.0
|
6
|
+
Accept: application/json
|
7
|
+
timeout: 30
|
8
|
+
verify_ssl: true
|
9
|
+
session: true
|
10
|
+
auth:
|
11
|
+
type: custom
|
12
|
+
provider_name: hmac_aws_auth
|
13
|
+
|
14
|
+
jwt_auth:
|
15
|
+
base_url: https://httpbin.org
|
16
|
+
headers:
|
17
|
+
User-Agent: pytest-dsl-client/1.0
|
18
|
+
Accept: application/json
|
19
|
+
timeout: 30
|
20
|
+
verify_ssl: true
|
21
|
+
session: true
|
22
|
+
auth:
|
23
|
+
type: custom
|
24
|
+
provider_name: jwt_refresh_auth
|
25
|
+
|
26
|
+
wechat_auth:
|
27
|
+
base_url: https://httpbin.org
|
28
|
+
headers:
|
29
|
+
User-Agent: pytest-dsl-client/1.0
|
30
|
+
Accept: application/json
|
31
|
+
timeout: 30
|
32
|
+
verify_ssl: true
|
33
|
+
session: true
|
34
|
+
auth:
|
35
|
+
type: custom
|
36
|
+
provider_name: wechat_miniapp_auth
|
37
|
+
|
38
|
+
multi_step_auth:
|
39
|
+
base_url: https://httpbin.org
|
40
|
+
headers:
|
41
|
+
User-Agent: pytest-dsl-client/1.0
|
42
|
+
Accept: application/json
|
43
|
+
timeout: 30
|
44
|
+
verify_ssl: true
|
45
|
+
session: true
|
46
|
+
auth:
|
47
|
+
type: custom
|
48
|
+
provider_name: multi_step_auth
|
@@ -0,0 +1,70 @@
|
|
1
|
+
"""
|
2
|
+
示例: 如何在您的项目中创建自定义关键字
|
3
|
+
|
4
|
+
将该文件放在您项目的 keywords 目录下,
|
5
|
+
例如: my_project/keywords/my_keywords.py
|
6
|
+
|
7
|
+
pytest-dsl 会自动导入这些关键字。
|
8
|
+
"""
|
9
|
+
|
10
|
+
from pytest_dsl.core.keyword_manager import keyword_manager
|
11
|
+
|
12
|
+
# 示例1: 简单关键字
|
13
|
+
@keyword_manager.register('打印消息', [
|
14
|
+
{'name': '消息', 'mapping': 'message', 'description': '要打印的消息内容'},
|
15
|
+
])
|
16
|
+
def print_message(**kwargs):
|
17
|
+
"""打印一条消息到控制台
|
18
|
+
|
19
|
+
Args:
|
20
|
+
message: 要打印的消息
|
21
|
+
context: 测试上下文 (自动传入)
|
22
|
+
"""
|
23
|
+
message = kwargs.get('message', '')
|
24
|
+
print(f"自定义关键字消息: {message}")
|
25
|
+
return True
|
26
|
+
|
27
|
+
# 示例2: 带返回值的关键字
|
28
|
+
@keyword_manager.register('生成随机数', [
|
29
|
+
{'name': '最小值', 'mapping': 'min_value', 'description': '随机数范围最小值'},
|
30
|
+
{'name': '最大值', 'mapping': 'max_value', 'description': '随机数范围最大值'},
|
31
|
+
])
|
32
|
+
def generate_random(**kwargs):
|
33
|
+
"""生成指定范围内的随机整数
|
34
|
+
|
35
|
+
Args:
|
36
|
+
min_value: 最小值
|
37
|
+
max_value: 最大值
|
38
|
+
context: 测试上下文 (自动传入)
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
随机整数
|
42
|
+
"""
|
43
|
+
import random
|
44
|
+
min_value = int(kwargs.get('min_value', 1))
|
45
|
+
max_value = int(kwargs.get('max_value', 100))
|
46
|
+
|
47
|
+
result = random.randint(min_value, max_value)
|
48
|
+
return result
|
49
|
+
|
50
|
+
# 示例3: 操作上下文的关键字
|
51
|
+
@keyword_manager.register('保存到上下文', [
|
52
|
+
{'name': '键名', 'mapping': 'key', 'description': '保存在上下文中的键名'},
|
53
|
+
{'name': '值', 'mapping': 'value', 'description': '要保存的值'},
|
54
|
+
])
|
55
|
+
def save_to_context(**kwargs):
|
56
|
+
"""将值保存到测试上下文中
|
57
|
+
|
58
|
+
Args:
|
59
|
+
key: 键名
|
60
|
+
value: 要保存的值
|
61
|
+
context: 测试上下文 (自动传入)
|
62
|
+
"""
|
63
|
+
key = kwargs.get('key')
|
64
|
+
value = kwargs.get('value')
|
65
|
+
context = kwargs.get('context')
|
66
|
+
|
67
|
+
if key and context:
|
68
|
+
context.set(key, value)
|
69
|
+
return True
|
70
|
+
return False
|
@@ -0,0 +1,168 @@
|
|
1
|
+
"""装饰器测试示例
|
2
|
+
|
3
|
+
该示例展示如何使用auto_dsl装饰器创建测试类
|
4
|
+
"""
|
5
|
+
|
6
|
+
from pytest_dsl.core.auto_decorator import auto_dsl
|
7
|
+
from pytest_dsl.core.auth_provider import register_auth_provider, CustomAuthProvider
|
8
|
+
import requests
|
9
|
+
import json
|
10
|
+
import logging
|
11
|
+
import sys
|
12
|
+
|
13
|
+
# 配置日志输出
|
14
|
+
logging.basicConfig(
|
15
|
+
level=logging.DEBUG, # 设置为DEBUG级别
|
16
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
17
|
+
stream=sys.stdout
|
18
|
+
)
|
19
|
+
logger = logging.getLogger("CSRF_AUTH_DEBUG")
|
20
|
+
|
21
|
+
|
22
|
+
@auto_dsl("./http")
|
23
|
+
class TestHttp:
|
24
|
+
"""HTTP测试类
|
25
|
+
|
26
|
+
该类使用auto_dsl装饰器,测试http目录下的.auto文件。
|
27
|
+
"""
|
28
|
+
pass
|
29
|
+
|
30
|
+
# 定义自定义认证提供者
|
31
|
+
class HMACAuthProvider(CustomAuthProvider):
|
32
|
+
def apply_auth(self, request_kwargs):
|
33
|
+
if "headers" not in request_kwargs:
|
34
|
+
request_kwargs["headers"] = {}
|
35
|
+
request_kwargs["headers"]["Authorization"] = "HMAC-SHA256 test_signature"
|
36
|
+
request_kwargs["headers"]["X-Amz-Date"] = "20240501T120000Z"
|
37
|
+
return request_kwargs
|
38
|
+
|
39
|
+
class JWTAuthProvider(CustomAuthProvider):
|
40
|
+
def apply_auth(self, request_kwargs):
|
41
|
+
if "headers" not in request_kwargs:
|
42
|
+
request_kwargs["headers"] = {}
|
43
|
+
request_kwargs["headers"]["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.example_token"
|
44
|
+
return request_kwargs
|
45
|
+
|
46
|
+
class WeChatAuthProvider(CustomAuthProvider):
|
47
|
+
def apply_auth(self, request_kwargs):
|
48
|
+
if "headers" not in request_kwargs:
|
49
|
+
request_kwargs["headers"] = {}
|
50
|
+
request_kwargs["headers"]["X-Wx-Openid"] = "test_openid"
|
51
|
+
request_kwargs["headers"]["X-Wx-Session-Key"] = "test_session_key"
|
52
|
+
return request_kwargs
|
53
|
+
|
54
|
+
class MultiStepAuthProvider(CustomAuthProvider):
|
55
|
+
def apply_auth(self, request_kwargs):
|
56
|
+
if "headers" not in request_kwargs:
|
57
|
+
request_kwargs["headers"] = {}
|
58
|
+
request_kwargs["headers"]["Authorization"] = "Bearer multi_step_token"
|
59
|
+
return request_kwargs
|
60
|
+
|
61
|
+
class CSRFLoginAuthProvider(CustomAuthProvider):
|
62
|
+
"""CSRF登录认证提供者
|
63
|
+
|
64
|
+
该提供者实现了一个需要先登录获取CSRF令牌,然后在后续请求中使用该令牌的认证流程。
|
65
|
+
为了适应httpbin.org的测试,这里模拟了CSRF认证流程。
|
66
|
+
"""
|
67
|
+
def __init__(self):
|
68
|
+
self._csrf_token = None
|
69
|
+
self._session = requests.Session()
|
70
|
+
logger.setLevel(logging.DEBUG) # 设置日志级别为DEBUG
|
71
|
+
|
72
|
+
def apply_auth(self, request_kwargs):
|
73
|
+
# 确保headers存在
|
74
|
+
if "headers" not in request_kwargs:
|
75
|
+
request_kwargs["headers"] = {}
|
76
|
+
|
77
|
+
# 如果还没有CSRF令牌,先登录获取
|
78
|
+
if not self._csrf_token:
|
79
|
+
self._login()
|
80
|
+
|
81
|
+
# 添加CSRF令牌到请求头
|
82
|
+
request_kwargs["headers"]["X-Csrf-Token"] = self._csrf_token
|
83
|
+
|
84
|
+
# 设置Content-Type头
|
85
|
+
# 如果请求中有JSON数据
|
86
|
+
if "json" in request_kwargs:
|
87
|
+
request_kwargs["headers"]["Content-Type"] = "application/json"
|
88
|
+
logger.debug(f"请求体 (JSON): {json.dumps(request_kwargs['json'])}")
|
89
|
+
# 如果请求中有表单数据
|
90
|
+
elif "data" in request_kwargs:
|
91
|
+
# 如果data是字典,默认为表单数据
|
92
|
+
if isinstance(request_kwargs["data"], dict):
|
93
|
+
if "Content-Type" not in request_kwargs["headers"]:
|
94
|
+
request_kwargs["headers"]["Content-Type"] = "application/x-www-form-urlencoded"
|
95
|
+
logger.debug(f"请求体 (form): {request_kwargs['data']}")
|
96
|
+
|
97
|
+
# 调试信息:打印请求信息
|
98
|
+
method = request_kwargs.get('method', 'GET')
|
99
|
+
url = request_kwargs.get('url', '')
|
100
|
+
logger.debug(f"发送请求: {method} {url}")
|
101
|
+
logger.debug(f"请求头: {json.dumps(request_kwargs.get('headers', {}))}")
|
102
|
+
|
103
|
+
return request_kwargs
|
104
|
+
|
105
|
+
def clean_auth_state(self, request_kwargs=None):
|
106
|
+
"""清理CSRF认证状态
|
107
|
+
|
108
|
+
清理CSRF认证相关的状态,包括令牌和会话。
|
109
|
+
|
110
|
+
Args:
|
111
|
+
request_kwargs: 请求参数
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
更新后的请求参数
|
115
|
+
"""
|
116
|
+
# 重置CSRF令牌
|
117
|
+
logger.debug("清理CSRF认证状态")
|
118
|
+
self._csrf_token = None
|
119
|
+
|
120
|
+
# 如果有会话,清理会话
|
121
|
+
if self._session:
|
122
|
+
self._session.cookies.clear()
|
123
|
+
logger.debug("已清理CSRF会话cookie")
|
124
|
+
|
125
|
+
# 处理请求参数
|
126
|
+
if request_kwargs:
|
127
|
+
if "headers" not in request_kwargs:
|
128
|
+
request_kwargs["headers"] = {}
|
129
|
+
|
130
|
+
# 移除CSRF相关头
|
131
|
+
csrf_headers = ['X-Csrf-Token', 'X-CSRF-Token', 'csrf-token', 'CSRF-Token']
|
132
|
+
for header in csrf_headers:
|
133
|
+
if header in request_kwargs["headers"]:
|
134
|
+
request_kwargs["headers"].pop(header)
|
135
|
+
logger.debug(f"已移除请求头: {header}")
|
136
|
+
|
137
|
+
# 标记会话已管理
|
138
|
+
self.manage_session = True
|
139
|
+
|
140
|
+
return request_kwargs if request_kwargs else {}
|
141
|
+
|
142
|
+
def _login(self):
|
143
|
+
"""执行登录流程获取CSRF令牌
|
144
|
+
|
145
|
+
由于httpbin.org没有实际的登录系统,这里模拟一个登录流程
|
146
|
+
"""
|
147
|
+
# 对于测试目的,生成一个模拟的CSRF令牌
|
148
|
+
self._csrf_token = "csrf_token_12345678"
|
149
|
+
logger.debug(f"生成CSRF令牌: {self._csrf_token}")
|
150
|
+
|
151
|
+
# 如果使用真实API,可以使用类似下面的代码
|
152
|
+
# 1. 获取登录页面,提取CSRF令牌
|
153
|
+
# login_page = self._session.get("https://httpbin.org/headers")
|
154
|
+
# login_page.raise_for_status()
|
155
|
+
|
156
|
+
# 2. 执行登录请求
|
157
|
+
# login_response = self._session.post(
|
158
|
+
# "https://httpbin.org/anything",
|
159
|
+
# json={"username": "test_user", "password": "test_password"}
|
160
|
+
# )
|
161
|
+
# login_response.raise_for_status()
|
162
|
+
|
163
|
+
# 注册自定义认证提供者
|
164
|
+
register_auth_provider("hmac_aws_auth", HMACAuthProvider)
|
165
|
+
register_auth_provider("jwt_refresh_auth", JWTAuthProvider)
|
166
|
+
register_auth_provider("wechat_miniapp_auth", WeChatAuthProvider)
|
167
|
+
register_auth_provider("multi_step_auth", MultiStepAuthProvider)
|
168
|
+
register_auth_provider("csrf_login_auth", CSRFLoginAuthProvider)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"""
|
2
|
+
自动导入所有关键字模块以注册关键字
|
3
|
+
"""
|
4
|
+
from . import system_keywords
|
5
|
+
from . import global_keywords # 全局变量关键字
|
6
|
+
from . import assertion_keywords
|
7
|
+
from . import http_keywords # HTTP请求关键字
|
8
|
+
|
9
|
+
# 可以在这里添加更多关键字模块的导入
|
10
|
+
__all__ = ['system_keywords', 'global_keywords', 'assertion_keywords', 'http_keywords']
|