RESTful API 参考手册
接口路径
__version__= "3.1"
class Prefix:
UserServer = "api-user"
CaseServer = "api-case"
AssetServer = "api-asset"
TaskServer = "api-task"
接口请求方法
class RquestApi():
def __init__(self):
super(RquestApi, self).__init__()
self._headers = {"Content-Type": "application/json"}
self._token = os.environ.get(EnvPath.token)
self._host_ip = SimOneUrl
self.get = "GET"
self.post = "POST"
self.delete = "DELETE"
self.put = "PUT"
def send(self, method: str, url: str, **kwargs)->Response:
"""
发送请求
method: 请求方法
url: 请求地址
kwargs: 请求参数
"""
self.headers.update({"Authorization": self.token})
complete_url = urljoin(self._host_ip, url)
data = dict()
data['method'] = method
data['url'] = complete_url
data['headers'] = self.headers
data.update(kwargs)
print(data)
response = request(verify=False, **data)
print("response:%s"%str(response.content.decode("utf-8")))
self._status_code = response.status_code
self._response_code = response.json().get("code")
return response
@property
def token(self):
return self._token
@property
def headers(self):
return self._headers
@headers.setter
def headers(self, value):
self._headers = value
登录相关接口
单机版登录
接口
def standalone_login_api(self):
"""
接口名称:单机版登录
请求方式:get
请求路径:standalone_login_url = Prefix.UserServer + "/users/standalone"
"""
return self.send(self.get, self.standalone_login_url).json()
登录实现
class Enterprise(RquestApi):
def __init__(self):
super(Enterprise, self).__init__()
self.label = "Enterprise"
@property
def _get_token(self):
try:
response = standalone_login_api()
print('standalone login request result:' + str(response))
token = response['data']['token']
print("token:%s" % token)
return token
except Exception as e:
print(str(e))
raise print(e)
云端版登录
接口
def cloud_login_api(self, userinfo: dict):
"""
接口名称:云端版登录
请求参数:userinfo #userinfo只能以字典形式传参
请求方式:post
请求路径:cloud_login_url = Prefix.UserServer + "/users/login"
参数示例:userinfo: body {"username":xxx, "password": xxx}
"""
return self.send(self.post, self.cloud_login_url, json=userinfo).json()
def check_username_api(self, username:str):
"""
接口名称:用户校验
请求参数:username #字符串形式传参
请求方式:post
请求路径:cloud_login_url = Prefix.UserServer + "/users/check"
"""
payload = {'username': username}
return self.send(self.post, self.login_check, json=payload).json()
加密方式
import base64
from Crypto.Cipher import AES
class Encryption:
@staticmethod
def pad(text):
"""
填充函数,使被加密数据的字节码长度是block_size的整数倍
"""
length = AES.block_size
count = len(text.encode('utf-8'))
add = length - (count % length)
entext = text + (chr(add) * add)
return entext
@staticmethod
def str_aes(string:str,key:str):
"""
aes 加密
@param string:
@param key:
@return:
"""
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
res = aes.encrypt(Encryption.pad(string).encode("utf8"))
msg = str(base64.b64encode(res), encoding="utf8")
return msg
@staticmethod
def get_str_aes(self, string: str, username: str, key: str = "eGeVQh0lRyq41I41") -> str:
'''
@param string:
@param username:
@param key: AES加密的key
@return:
'''
check_token = check_username_api(username)
target_string = check_token["data"]["checkToken"] + string
msg = Encryption.str_aes(target_string, key)
return msg
登录实现
class Cloud(RquestApi):
def __init__(self, login_data):
super(Cloud, self).__init__()
self.label = "Cloud"
self.login_data = login_data
@property
def _get_token(self):
# print(self.title)
try:
new_login_data = copy.deepcopy(self.login_data)
new_login_data['password'] = Encryption.get_str_aes(string=new_login_data['password'],
username=new_login_data['username'])
print('cloud login data:' + str(new_login_data))
response = cloud_login_api(userinfo=new_login_data)
print('cloud login request result:' + str(response))
token = response['data']['token']
print(token)
return token
except Exception as e:
print(str(e))
raise print('get token error ')
案例库目录相关接口
"""============================案例库目录接口================================="""
def get_category_api(self):
"""
接口名称:获取案例库列表
请求方式:get
请求路径:categories_url = Prefix.CaseServer + "/categories"
"""
return self.send(self.get, self.categories_url).json()
def create_category_api(self, cate_name:str):
"""
接口名称:创建案例库
请求参数:cate_name #字符串形式传参
请求方式:post
请求路径:categories_url = Prefix.CaseServer + "/categories"
"""
payload = {"parentId": "", "name": cate_name}
return self.send(self.post,self.categories_url,json=payload).json()
def get_category_case_api(self,cate_id:str):
"""
接口名称:获取当前案例库所有案例
请求参数:cate_id #字符串形式传参
请求方式:get
请求路径:get_cases_url = Prefix.CaseServer + "/cases?page=1&filter={category}&pageSize=100"
"""
return self.send(self.get,self.get_cases_url.format(category=cate_id)).json()
def delete_category_api(self, cate_id:str):
'''
接口名称:删除指定案例库
请求参数:cate_id #字符串形式传参
请求方式:delet
请求路径:delete_categories_url = Prefix.CaseServer + "/categories/{}"
'''
return self.send(self.delete,self.delete_categories_url.format(cate_id)).json()
上传文件相关接口
"""============================上传文件相关接口================================="""
class UploadFile(InitRquest):
def file_md5_check(self,file_path:str,raw:bool=False):
"""
接口名称:文件md5检查
请求参数:file_path: 文件路径 #file_path只能以字符串形式输入
row #raw:只能以bool类型输入
请求方式:get
请求路径:file_md5_url = Prefix.AssetServer + "/files/{}?raw={}"
"""
global url
file_md5 = HashTools.file_md5(file_path)
if raw:
url = self.file_md5_url.format(file_md5,"true")
else:
url = self.file_md5_url.format(file_md5, "false")
print(file_md5)
return self.send(self.get,url).json()
def upload_file(self, file_path:str,index:int,chunks:int,category:str,file_md5:str,raw:bool=False):
"""
接口名称:上传文件
请求参数:file_path: 文件路径 #字符串形式传参
index: 上传序列 #整数形式传参
chunks: chunks总数 #整数形式传参
category: 类别 #字符串形式传参
file_md5: 文件MD5 #字符串形式传参
请求方式:post
请求路径:upload_file_url = Prefix.AssetServer + "/files/{}/upload?raw={}"
"""
global url
self.headers={}
file_size = os.path.getsize(file_path)
file_name = file_path.split(os.sep)[-1]
files = {'file': open(os.path.join(file_path), 'rb')}
if not file_md5:
file_md5 = HashTools.file_md5(file_path)
if raw:
url = self.upload_file_url.format(file_md5,"true")
else:
url = self.upload_file_url.format(file_md5, "false")
upload_payload = {"params": json.dumps({"filename": file_name,
"index": index,
"chunks": chunks,
"filesize": file_size,
"uploadId": Generator.random_uuid(),
"category": category})}
return self.send(self.post, url, data=upload_payload, files=files).json()
测试案例相关接口
"""============================案例接口================================="""
def import_case_api(self,payload:dict):
"""
接口名称:案例导入
请求参数:payload #字典形式传递
请求方式:post
请求路径:case_import_url = Prefix.AssetServer+"/cases/import"
"""
#需要以json形式传递参数
return self.send(self.post, self.case_import_url,data=json.dumps(payload)).json()
def get_case_detail_api(self, case_id:str):
"""
接口名称:获取案例信息
请求参数:case_id #字符串形式传递
请求方式:get
请求路径:case_details_url = Prefix.CaseServer + "/cases/{case_id}/data"
"""
return self.send(self.get, url).json()
def delete_case_api(self, case_id:list):
'''
接口名称:删除案例
请求参数:case_id:案例id #列表形式传递
请求方式:post
请求路径:delete_case_url = Prefix.CaseServer + "/trash"
'''
payload = {"id": case_id}
return self.send(self.post,self.delete_case_url,json = payload).json()
测试任务相关接口
"""============================测试任务相关接口================================="""
def create_task_api(self,payload:dict):
"""
接口名称:创建task
请求参数:payload #字典形式传参
请求方式:post
请求路径:create_task_url = Prefix.TaskServer + "/tasks"
参数示例:payload: eg {"caseIds": ["3dd03c09-3ba9-4f7a-b988-fde88296095a"],
"taskName": "task_name"}
"""
return self.send(self.post,self.create_task_url,json=payload).json()
def stop_task_api(self,payload:dict):
"""
接口名称:task停止
请求参数:payload #字典形式传参
请求方式:post
请求路径:stop_task_url = Prefix.TaskServer + "/tasks/stop"
参数示例:payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
"""
return self.send(self.post,self.stop_task_url,json=payload).json()
def stop_sessions_api(self,payload:dict):
"""
接口名称:sessions停止
请求参数:payload #字典形式传参
请求方式:post
请求路径:stop_sessions_url = Prefix.TaskServer + "/sessions/stop"
参数示例:payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
"""
return self.send(self.post,self.stop_sessions_url,json=payload).json()
def delete_sessions_api(self,payload:dict):
"""
接口名称:sessions删除
请求参数:payload #以字典形式传参
请求方式:post
请求路径:delete_sessions_url = Prefix.TaskServer + "/sessions/delete"
参数示例:payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
"""
return self.send(self.post,self.delete_sessions_url,json=payload).json()
def delete_task_api(self,payload:dict):
"""
接口名称:task删除
请求参数:payload #字典形式传参
请求方式:post
请求路径:delete_task_url = Prefix.TaskServer + "/tasks/delete"
参数示例:payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
"""
return self.send(self.post,self.delete_task_url,json=payload).json()
def get_task_result_api(self,task_id:str):
"""
接口名称:获取指定task的结果
请求参数:task_id
请求方式:get
请求路径:task_result_url = Prefix.TaskServer + "/tasks/task?taskIds={id}"
参数类型:task_id只能以字符串形式传参
"""
return self.send(self.get,self.task_result_url.format(id=task_id)).json()
def pause_task_api(self,task_id:str):
"""
接口名称:暂停任务
请求参数:task_id #字符串形式传参
请求方式:post
请求路径:pause_task_url = Prefix.TaskServer + "/sessions/{task_id}/pause"
"""
return self.send(self.post, self.pause_task_url.format(task_id=task_id),json={}).json()
def resume_task_api(self,task_id:str):
"""
接口名称:暂停任务后开始
请求参数:task_id #字符串形式传参
请求方式:post
请求路径:resume_task_url = Prefix.TaskServer + "/sessions/{task_id}/resume"
"""
return self.send(self.post, self.resume_task_url.format(task_id=task_id),json={}).json()
主车相关接口
"""============================主车相关接口================================="""
def import_vehicle_api(self,payload:dict):
"""
接口名称:导入主车
请求参数:payload #字典形式传参
请求方式:post
请求路径:import_vehicle_url = Prefix.AssetServer + "/vehicles/import"
参数示例:payload: eg {"vehicleData": {"byId": {vehicle_id: vehicle_data},
"allIds": [vehicle_id]}}
"""
return self.send(self.post,self.import_vehicle_url,json=payload).json()
def get_vehicle_api(self):
"""
接口名称:获取主车信息
请求方式:get
请求路径:get_vehicle_url = Prefix.AssetServer + "/vehicles"
"""
return self.send(self.get,self.get_vehicle_url).json()
def delete_vehicles_api(self, vehicles_id: str):
"""
接口名称:删除主车
请求参数:vehicles_id:主车id #字符串形式传参
请求方式:delete
请求路径:delete_vehicle_url = Prefix.AssetServer + "/vehicles/{vehicles_id}"
参数类型:vehicles_id只能以字符串形式传参
"""
url = self.delete_vehicle_url.format(vehicles_id=vehicles_id)
return self.send(self.delete, url)
地图相关接口
"""============================地图相关接口================================="""
def import_map_api(self,payload:dict,files:dict):
"""
接口名称:导入地图
请求参数:payload #字典形式传参
files #字典形式传参
请求方式:post
请求路径:import_map_url = Prefix.AssetServer+"/maps"
参数示例:
data: eg: {params:
{"category":"test_field","id":"member21","name":"member21",
"size":512,"ppm":10,"bgColor":"#dddddd","reproject":true,
"reprojectOrigin":false,"reprojectOriginLat":0,"reprojectOriginLng":0,
"tags":[],"notes":"",
"header":{
"minX":-210.20535534122396,"minY":-149.68815701999185,"minZ":-1.862645149230957e-9,
"maxX":237.95535534122394,"maxY":135.43815701999196,"maxZ":2.7940070024635385e-9,
"localEnuExt":"6378137,0,0;0,1,0;0,0,1;1,0,0"
}
}
}
files: {"xodr": binary, "thumbnail": binary}
"""
self.headers = {}
return self.send(self.post,self.import_map_url,data=payload,files=files).json()
def get_map_api(self):
"""
接口名称:获取地图
请求方式:get
请求路径:get_map_url = Prefix.CaseServer+"/maps?pageSize=100"
"""
return self.send(self.get, self.get_map_url).json()
def start_sce_api(self,payload:dict):
"""
接口名称:启动路网服务
请求参数:payload #字典形式传参
请求方式:post
请求路径:road_service_url = Prefix.TaskServer+"/sce"
参数示例:payload: {"mapId": mapId,"md5":md5}
"""
return self.send(self.post,self.road_service_url,json=payload).json()
def delete_map_api(self,payload:dict):
"""
接口名称:删除地图
请求参数:payload #字典形式传参
请求方式:post
请求路径:delete_map_url = Prefix.CaseServer + "/maps/trash"
参数示例:payload: eg:{ids: ["27a0bbc4-5d4d-48c1-9187-62df794dadae"]}
"""
return self.send(self.post, self.delete_map_url, json=payload).json()
def laneTypeIfInside_api(self,map_id:str,payload:dict):
"""
接口名称:坐标是否在地图车道内
请求参数: map_id: 地图id #字符串形式传参
payload: 位置坐标 #字典形式传参
请求方式:post
请求路径:laneTypeIfInside_url = Prefix.TaskServer+"/sce/{map_id}/location/laneTypeIfInside"
参数示例:payload: eg:{ids: ["27a0bbc4-5d4d-48c1-9187-62df794dadae"]}
"""
return self.send(self.post,self.laneTypeIfInside_url.format(map_id=map_id),json=payload).json()
数据驱动相关接口
"""============================数据驱动相关接口================================="""
class DataDrivenAPI(InitRquest):
"""数据驱动接口"""
def import_data_driven_api(self,file_path:str,dd_serial:str):
"""
接口名称:导入数据驱动的全流程的接口
请求参数:file_path: 数据驱动文件 #字符串形式传参
dd_serial: 导入后序列号,防止重复 #字符串形式传参
请求方式:post
请求路径:import_data_driven_url = Prefix.AssetServer+"/dd"
"""
global id
file_size = os.path.getsize(file_path)
filename = os.path.basename(file_path)
disfilename = filename.split(".")[0] + "_" + dd_serial
filesize = os.path.getsize(file_path)
# api/dd
body = {"datatype": "excel",
"displayname": disfilename,
"filename": filename,
"filesize": filesize
}
log.info("***************" + str(body))
response = self.send(self.post,self.import_data_driven_url,json=body)
assert response.status_code == 200, "******* request error:%s ****************" % response.status_code
if response.status_code == 200:
if response.json()['code'] == 0:
id = response.json()['data']['id']
# api/dd/{id}
body1 = {"status": "uploading"}
self.send(self.put, self.import_data_driven_url+"/{}".format(id), json=body1)
# /api/files/{file_md5}?raw=true
md5_res = UploadFile().file_md5_check(file_path,raw=True)
file_md5 = md5_res['data']["id"]
if md5_res['data']['size'] == 0:
chunks = DataTools.round_up(file_size / gp.chunk_size)
for i in range(chunks):
UploadFile().upload_file(file_path=file_path,index=i,chunks=chunks,category="rawdata",file_md5=file_md5,raw=True)
# api/dd/move
move_param = {"source": file_md5, "target": filename}
log.info("move_param:%s" % move_param)
response_move = self.send(self.post,self.import_data_driven_url+"/move", json=move_param)
log.info("response_move status_code:%s" % response_move.status_code)
assert response_move.status_code == 204, "******* request error:%s ****************" % response_move.status_code
# api/dd/{id}
body2 = {"status": "upload-ok"}
response = self.send(self.put, self.import_data_driven_url + "/{}".format(id), json=body2)
assert response.status_code == 204, "******* request error:%s ****************" % response.status_code
# # api/dd/{id}/start
url_start = self.import_data_driven_url+"/{}/start".format(id)
response = self.send(self.post, url_start, json={})
assert response.status_code == 201, "******* request error:%s ****************" % response.status_code
return id
else:
log.info("资源已存在")
def delete_data_driven_api(self,id:str):
"""
接口名称:删除指定数据驱动
请求参数:id:数据驱动源id #字符串形式传参
请求方式:delete
请求路径:delete_data_dirven_url = Prefix.AssetServer+"/dd/{id}"
"""
return self.send(self.delete,self.delete_data_dirven_url.format(id)).json()
资源相关接口
"""============================资源相关接口================================="""
def import_assets_api(self,payload:dict):
"""
接口名称:导入资源API
请求参数:payload #字典形式传参
请求方式:post
请求路径:import_asset_url = Prefix.AssetServer+"/assets"
"""
return self.send(self.post,self.import_asset_url,data=json.dumps(payload)).json()
def assets_isrepeat_api(self,payload:dict):
"""
接口名称:资源查重API
请求参数:payload #字典形式传参
请求方式:post
请求路径:import_asset_url = Prefix.AssetServer+"/assets"
请求参数示例:payload: eg:{'name': 'API控制', 'schema': 'controller'}
"""
return self.send(self.post,self.asset_repeat_url,json=payload).json()
def get_assets_api(self,schema:str):
"""
接口名称:获取指定资源信息
请求参数:schema #字符串形式传参
请求方式:get
请求路径:get_asset_url = Prefix.AssetServer+"/assets?schema={}"
"""
return self.send(self.get,self.get_asset_url.format(schema)).json()
def delete_assets_api(self,id:str):
"""
接口名称:删除指定的资源
请求参数:id: 资源id #字符串形式传参
请求方式:delete
请求路径:delete_asset_url = Prefix.AssetServer+"/assets/{}"
"""
return self.send(self.delete,self.delete_asset_url).json()