new joyhub_backend
This commit is contained in:
131
joyhub_backend/library/joyhub_interface.py
Normal file
131
joyhub_backend/library/joyhub_interface.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import allure
|
||||
import requests
|
||||
|
||||
from joyhub_backend.library.auth import JoyhubAuth, TIMEOUT
|
||||
|
||||
|
||||
MANAGER_BASE_URL = os.getenv(
|
||||
"JOYHUB_MANAGER_BASE_URL",
|
||||
"http://test-manager-api.best-envision.com",
|
||||
)
|
||||
|
||||
|
||||
class JoyhubInterface(object):
|
||||
def __init__(self):
|
||||
self.auth = JoyhubAuth()
|
||||
self.session = requests.Session()
|
||||
self.base_url = MANAGER_BASE_URL.rstrip("/") + "/"
|
||||
|
||||
def request(self, case_name, method, path, body=None, query=None, headers=None, expected_code=0):
|
||||
url = path if path.startswith("http") else urljoin(self.base_url, path.lstrip("/"))
|
||||
request_headers = self.auth.auth_headers()
|
||||
if headers:
|
||||
request_headers.update({key: value for key, value in headers.items() if key.lower() != "authorization"})
|
||||
|
||||
with allure.step("操作步骤:{}".format(case_name)):
|
||||
self._attach_request(url, method, request_headers, body, query)
|
||||
logging.info("case: %s", case_name)
|
||||
logging.info("request url: %s", url)
|
||||
logging.info("request method: %s", method)
|
||||
logging.info("request headers: %s", request_headers)
|
||||
logging.info("request body: %s", body)
|
||||
logging.info("request query: %s", query)
|
||||
|
||||
request_kwargs = {
|
||||
"method": method,
|
||||
"url": url,
|
||||
"params": query,
|
||||
"headers": request_headers,
|
||||
"timeout": TIMEOUT,
|
||||
}
|
||||
if method.upper() in ("POST", "PUT", "PATCH"):
|
||||
request_kwargs["json"] = body
|
||||
elif body:
|
||||
request_kwargs["params"] = dict(query or {}, **body) if isinstance(body, dict) else query
|
||||
response = self.session.request(**request_kwargs)
|
||||
self._attach_response(response)
|
||||
self._attach_log(case_name, url, method, request_headers, body, query, response)
|
||||
logging.info("response status: %s", response.status_code)
|
||||
logging.info("response body: %s", response.text)
|
||||
|
||||
is_business_api = self._is_business_api(url)
|
||||
assertion_text = "HTTP状态码为200,且业务code为{}".format(expected_code) if is_business_api else "HTTP状态码为2xx,兼容非JSON/SSE响应"
|
||||
allure.attach(assertion_text, "断言内容", allure.attachment_type.TEXT)
|
||||
with allure.step("断言内容:{}".format(assertion_text)):
|
||||
try:
|
||||
if is_business_api:
|
||||
assert response.status_code == 200, "HTTP状态码期望200,实际{},响应{}".format(
|
||||
response.status_code, response.text
|
||||
)
|
||||
data = self._safe_json(response)
|
||||
assert isinstance(data, dict), "业务接口响应不是JSON对象,响应{}".format(response.text)
|
||||
assert "code" in data, "响应缺少 code 字段,响应{}".format(data)
|
||||
assert data.get("code") == expected_code, "业务code期望{},实际{},msg={},响应{}".format(
|
||||
expected_code, data.get("code"), data.get("msg"), data
|
||||
)
|
||||
else:
|
||||
assert 200 <= response.status_code < 300, "HTTP状态码期望2xx,实际{},响应{}".format(
|
||||
response.status_code, response.text
|
||||
)
|
||||
data = self._non_json_result(response)
|
||||
allure.attach("无", "断言失败原因", allure.attachment_type.TEXT)
|
||||
return data
|
||||
except AssertionError as error:
|
||||
allure.attach(str(error), "断言失败原因", allure.attachment_type.TEXT)
|
||||
raise AssertionError("断言失败原因:{}".format(error))
|
||||
|
||||
@staticmethod
|
||||
def _attach_request(url, method, headers, body, query):
|
||||
allure.attach(str(url), "请求url", allure.attachment_type.TEXT)
|
||||
allure.attach(str(method), "请求方式", allure.attachment_type.TEXT)
|
||||
allure.attach(json.dumps(headers, ensure_ascii=False, indent=2), "请求头", allure.attachment_type.JSON)
|
||||
allure.attach(json.dumps(query or {}, ensure_ascii=False, indent=2), "请求query", allure.attachment_type.JSON)
|
||||
allure.attach(json.dumps(body or {}, ensure_ascii=False, indent=2), "请求体", allure.attachment_type.JSON)
|
||||
|
||||
@staticmethod
|
||||
def _attach_response(response):
|
||||
allure.attach(str(response.status_code), "响应状态码", allure.attachment_type.TEXT)
|
||||
content_type = response.headers.get("Content-Type", "")
|
||||
attachment_type = allure.attachment_type.JSON if "json" in content_type.lower() else allure.attachment_type.TEXT
|
||||
allure.attach(response.text, "响应体/日志", attachment_type)
|
||||
|
||||
def _is_business_api(self, url):
|
||||
return url.startswith(self.base_url)
|
||||
|
||||
@staticmethod
|
||||
def _safe_json(response):
|
||||
if not response.text.strip():
|
||||
return None
|
||||
return response.json()
|
||||
|
||||
@staticmethod
|
||||
def _non_json_result(response):
|
||||
try:
|
||||
data = response.json()
|
||||
except ValueError:
|
||||
data = {
|
||||
"status_code": response.status_code,
|
||||
"content_type": response.headers.get("Content-Type", ""),
|
||||
"text": response.text,
|
||||
}
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _attach_log(case_name, url, method, headers, body, query, response):
|
||||
log_text = "\n".join([
|
||||
"case: {}".format(case_name),
|
||||
"request url: {}".format(url),
|
||||
"request method: {}".format(method),
|
||||
"request headers: {}".format(headers),
|
||||
"request query: {}".format(query or {}),
|
||||
"request body: {}".format(body or {}),
|
||||
"response status: {}".format(response.status_code),
|
||||
"response body: {}".format(response.text),
|
||||
])
|
||||
allure.attach(log_text, "日志", allure.attachment_type.TEXT)
|
||||
Reference in New Issue
Block a user