Restful API 运行控制
提供基于 HTTP 的 Restful API,支持 Web 服务接口,控制 SimOne 界面的运行流程,比如可控制创建案例库,导入导出案例,运行停止案例等。
接口文档:
使用参考手册
1. 步骤描述
-
创建一个python文件 依次将接口路径、依赖、请求方法粘贴进去
-
顺序粘贴对应的 功能实现 模块代码
-
登录功能 必须要有并且在首位调用所有的操作都需要依赖登录功能携带的token
-
粘贴调用示例并稍微根据自己的环境做一些参数修改比如 请求路径修改 , 使用案例库案例名称修改 等,即可成功调用API
-
修改以下几处位置:
1# 路径地址与云端账户需要修改为自己对应的账户
2SimOneUrl = "http://127.0.0.1:30083"
3loginData = {
4 "username": 'admin',
5 "password": 'admin',
6}
7
8
9if __name__ == '__main__':
10 # 云端登录
11 LoginPolicy("cloud")
12 # 单机版本登录
13 LoginPolicy("standalone")
14
备注: 附录参考代码是根据步骤描述中的顺序进行粘贴并可以成功运行的代码示例,如有疑惑请查看附录参考代码!!
2. 接口路径与依赖库
1import base64
2import copy
3import inspect
4import random
5from os.path import exists
6
7from Crypto.Cipher import AES
8from faker import Faker
9from requests import request, Response
10import json
11from urllib.parse import urljoin
12import os
13import time
14
15# 路径地址与云端账户需要修改为自己对应的账户
16SimOneUrl = "http://127.0.0.1:30083/"
17loginData = {
18 "username": 'admin',
19 "password": 'admin',
20}
21
22fake = Faker('zh_CN')
23
24interval = 10
25
26# header
27header = {
28 "Content-Type": "application/json",
29}
30
31
32# Environment Path
33class EnvPath:
34 token = "TOKEN"
35
36
37class Prefix:
38 UserServer = "api-user"
39 CaseServer = "api-case"
40 AssetServer = "api-asset"
41 TaskServer = "api-task"
42
43# token
44_token = os.environ.get(EnvPath.token)
45
46
47""" 登录相关接口 """
48user_check_url = Prefix.UserServer + "/users/check"
49health = Prefix.UserServer + "/health" # 检查服务是否正常
50cloud_login_url = Prefix.UserServer + "/users/login" # 云端登录
51standalone_login_url = Prefix.UserServer + "/users/standalone" # 单机版登录
52login_check = Prefix.UserServer + "/users/check" # user check
53
54""" 案例库目录相关接口 """
55categories_url = Prefix.CaseServer + "/categories" # 案例库目录
56get_categories_url = Prefix.CaseServer + "/categories?withCases=false" # 获取所有案例库
57get_cases_url = "api-case/cases?page=1&filter={category}&pageSize=100"
58# get_cases_url = Prefix.CaseServer + "/cases?page={page}&filter={category}&pageSize=100" # 获取当前案例库的所有案例
59delete_categories_url = Prefix.CaseServer + "/categories/{}" # 删除案例库目录
60
61""" 上传文件相关接口 """
62file_md5_url = Prefix.AssetServer + "/files/{}?raw={}" # 验证文件MD5
63upload_file_url = Prefix.AssetServer + "/files/{}/upload?raw={}" # 上传文件
64
65""" 测试案例相关接口 """
66case_import_url = Prefix.AssetServer + "/cases/import" # 导入案例
67case_details_url = Prefix.CaseServer + "/cases/{case_id}/data" # 案例详情
68delete_case_url = Prefix.CaseServer + "/trash" # 删除案例
69convert_replay_case_url = Prefix.TaskServer + "/tasks/{id}/convert2case" # 转换回放案例
70case_def_url = Prefix.CaseServer + "/cases/{case_id}" # 案例概要
71update_case_url = Prefix.AssetServer + "/cases/update" # 编辑案例 # doing
72
73""" 测试任务相关接口 """
74create_task_url = Prefix.TaskServer + "/tasks" # 创建task
75stop_task_url = Prefix.TaskServer + "/tasks/stop" # 停止task
76stop_sessions_url = Prefix.TaskServer + "/sessions/stop" # 会话停止
77delete_task_url = Prefix.TaskServer + "/tasks/delete" # 删除task
78delete_sessions_url = Prefix.TaskServer + "/sessions/delete" # 删除停止
79result_url = Prefix.TaskServer + "/tasks/task?taskIds={task_id}" # 删除停止 案例运行结果详情
80task_info = Prefix.TaskServer + "/tasks/task" # 删除停止 案例运行结果详情
81pause_task_url = Prefix.TaskServer + "/sessions/{task_id}/pause" # 任务暂停
82resume_task_url = Prefix.TaskServer + "/sessions/{task_id}/resume" # 任务暂停后开始
83task_result_url = Prefix.TaskServer + "/tasks/task?taskIds={id}" # 删除停止 案例运行结果详情
84
85""" 主车相关接口 """
86import_vehicle_url = Prefix.AssetServer + "/vehicles/import" # 导入主车
87delete_vehicle_url = Prefix.AssetServer + "/vehicles/{vehicles_id}" # 删除主车
88get_vehicle_url = Prefix.AssetServer + "/vehicles" # get获取主车信息 post创建主车
89get_vehicles_url = Prefix.AssetServer + "/vehicles"
90
91""" 地图相关接口 """
92import_map_url = Prefix.AssetServer + "/maps" # 导入地图
93delete_map_url = Prefix.CaseServer + "/maps/trash" # 删除地图
94get_map_url = Prefix.CaseServer + "/maps?pageSize=100" # 获取地图相关信息
95road_service_url = Prefix.TaskServer + "/sce" # 启动路网服务
96laneTypeIfInside_url = Prefix.TaskServer + "/sce/{map_id}/location/laneTypeIfInside" # 监测点是否在车道内
97
98""" 数据驱动相关接口 """
99import_data_driven_url = Prefix.AssetServer + "/dd" # 导入数据驱动源
100delete_data_dirven_url = Prefix.AssetServer + "/dd/{id}" # 删除数据驱动源
101
102""" 资源相关接口 """
103import_asset_url = Prefix.AssetServer + "/assets" # 资源导入
104asset_repeat_url = Prefix.AssetServer + "/assets/isrepeat" # 资源查重
105get_asset_url = Prefix.AssetServer + "/assets?schema={}" # 获取资源信息
106delete_asset_url = Prefix.AssetServer + "/assets/{}" # 删除对应资源
107
108""" 案例导出相关 """
109export_case_url = Prefix.AssetServer + "/cases/export" # 案例导出
110download_case_url = Prefix.AssetServer + "/{pake_id}" # 案例下载
111
112""" 测试案例集相关 """
113get_suites_url = Prefix.AssetServer + "/suites" # 获取测试集
114run_suite_url = Prefix.TaskServer + "/tasks" # 运行测试集
115get_task_list_url = Prefix.TaskServer + "/tasks?finished=true&page=0&pageSize=12&own=true&expandedIds={task_set_id}" # 获取测试案例集合
116queue_status_url = Prefix.TaskServer + "/tasks/queue?own=true" # 套件运行状态检查
117
118""" 案例判定相关 """
119get_judgements_url = Prefix.AssetServer + "/cases/{caseId}/judgements" # 获取更新 所有判定信息
120get_judgement_url = "api-asset/cases/{caseId}/judgements/{judgementId}" # 获取更新 单个判定信息
121
122"""测试报告导出相关"""
123export_report_url = Prefix.TaskServer + "/sessions/{sessions_id}/report" # 导出测试报告
124download_report_url = "/report/{sessions_id}_zh-Hans.pdf" # 下载测试报告
3. 接口请求方法
1class RquestApi():
2 def __init__(self):
3 super(RquestApi, self).__init__()
4 self._headers = {"Content-Type": "application/json"}
5 self._token = os.environ.get(EnvPath.token)
6 self._host_ip = SimOneUrl
7 self.get = "GET"
8 self.post = "POST"
9 self.delete = "DELETE"
10 self.put = "PUT"
11
12 def send(self, method: str, url: str, **kwargs) -> Response:
13 """
14 发送请求
15 method: 请求方法
16 url: 请求地址
17 kwargs: 请求参数
18 """
19 self.headers.update({"Authorization": self.token})
20 complete_url = urljoin(self._host_ip, url)
21 data = dict()
22 data['method'] = method
23 data['url'] = complete_url
24 data['headers'] = self.headers
25 data.update(kwargs)
26 print(data)
27 response = request(verify=False, **data)
28 try:
29 print("response:%s" % str(response.content.decode("utf-8")))
30 self._status_code = response.status_code
31 self._response_code = response.json().get("code")
32 except:
33 pass
34 return response
35
36 @property
37 def token(self):
38 return self._token
39
40 @property
41 def headers(self):
42 return self._headers
43
44 @headers.setter
45 def headers(self, value):
46 self._headers = value
4. 云端登录
云端API
1def cloud_login_api(self, userinfo: dict):
2 """
3 接口名称:云端版登录
4 请求参数:userinfo
5 请求方式:post
6 请求路径:cloud_login_url = Prefix.UserServer + "/users/login"
7 参数示例:userinfo: body {"username":xxx, "password": xxx}
8 """
9 return self.send(self.post, self.cloud_login_url, json=userinfo).json()
10
11def check_username_api(self, username:str):
12 """
13 接口名称:用户校验
14 请求参数:username
15 请求方式:post
16 请求路径:cloud_login_url = Prefix.UserServer + "/users/check"
17 """
18 payload = {'username': username}
19 return self.send(self.post, self.login_check, json=payload).json()
#### 功能实现
```python
class LoginBusiness(RquestApi):
def cloud_login_api(self, userinfo: dict):
"""
云端登录API
@param userinfo:
@return:
"""
return self.send(self.post, cloud_login_url, json=userinfo).json()
def check_username_api(self, username: str):
"""
校验用户名称是否合格
@param username:
@return:
"""
payload = {'username': username}
return self.send(self.post, login_check, json=payload).json()
def getCheckToken(self) -> str:
"""
校验token是否合格
@return:
"""
getCheckUrl = os.path.join(SimOneUrl, user_check_url)
payload = {'username': loginData['username']}
response = self.send(self.post, getCheckUrl, json=payload)
checkToken = json.loads(response.content.decode("utf-8"))['data']['checkToken']
return checkToken
def pad(self, text):
"""
填充函数,使被加密数据的字节码长度是block_size的整数倍
@param text:
@return:
"""
length = AES.block_size
count = len(text.encode('utf-8'))
add = length - (count % length)
entext = text + (chr(add) * add)
return entext
def str_aes(self, string: str, key: str):
"""
aes 加密
@param string:
@param key:
@return:
"""
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
res = aes.encrypt(self.pad(string).encode("utf8"))
msg = str(base64.b64encode(res), encoding="utf8")
return msg
def get_str_aes(self, string: str, username: str, key: str = "eGeVQh0lRyq41I41") -> str:
'''
@param string:
@param username:
@param key: AES加密的key
@return:
'''
check_token = self.check_username_api(username)
target_string = check_token["data"]["checkToken"] + string
msg = self.str_aes(target_string, key)
return msg
@property
def _cloud_std_login(self):
"""
云端版本登陆方式
@return:
"""
try:
new_login_data = copy.deepcopy(loginData)
new_login_data['password'] = self.get_str_aes(string=new_login_data['password'],
username=new_login_data['username'])
print('cloud login data:' + str(new_login_data))
response = self.cloud_login_api(userinfo=new_login_data)
print("-------", response)
print('cloud login request result:' + str(response))
token = response['data']['token']
os.environ[EnvPath.token] = token
print(token)
return token
except Exception as e:
print(str(e))
raise print('get token error ')
# 登录入口
class LoginPolicy():
standalone = "standalone"
cloud = "cloud"
def __new__(cls, env_name):
if env_name == cls.standalone:
return LoginBusiness()._enterprise_std_login
elif env_name == cls.cloud:
return LoginBusiness()._cloud_std_login
else:
return print("----------input error---------------")
云端调用示例
1SimOneUrl = "http://127.0.0.1:30083"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6
7if __name__ == '__main__':
8 LoginPolicy("cloud")
正确返回结果
cloud login request result:{'code': 0, 'data': {'token': 'f2e3e458-264b-44fb-9f95-319a978ddec3'}}
5. 单机版登录
单机版API
1def enterprise_login_api(self):
2 """
3 Interface name: Enterprise standalone version login
4 Request parameters: None
5 Request method: get
6 Request path: SimOneUrl + standalone_login_url
7 Parameter example: userinfo: body {"username":xxx, "password": xxx}
8 """
9 getLoginUrl = os.path.join(SimOneUrl, standalone_login_url)
10 response = self.send(self.get, url=getLoginUrl)
11 return response
#### 功能实现
```python
class LoginBusiness(RquestApi):
def cloud_login_api(self, userinfo: dict):
"""
云端登录API
@param userinfo:
@return:
"""
return self.send(self.post, cloud_login_url, json=userinfo).json()
def check_username_api(self, username: str):
"""
校验用户名称是否合格
@param username:
@return:
"""
payload = {'username': username}
return self.send(self.post, login_check, json=payload).json()
def getCheckToken(self) -> str:
"""
校验token是否合格
@return:
"""
getCheckUrl = os.path.join(SimOneUrl, user_check_url)
payload = {'username': loginData['username']}
response = self.send(self.post, getCheckUrl, json=payload)
checkToken = json.loads(response.content.decode("utf-8"))['data']['checkToken']
return checkToken
def pad(self, text):
"""
填充函数,使被加密数据的字节码长度是block_size的整数倍
@param text:
@return:
"""
length = AES.block_size
count = len(text.encode('utf-8'))
add = length - (count % length)
entext = text + (chr(add) * add)
return entext
def str_aes(self, string: str, key: str):
"""
aes 加密
@param string:
@param key:
@return:
"""
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
res = aes.encrypt(self.pad(string).encode("utf8"))
msg = str(base64.b64encode(res), encoding="utf8")
return msg
def get_str_aes(self, string: str, username: str, key: str = "eGeVQh0lRyq41I41") -> str:
'''
@param string:
@param username:
@param key: AES加密的key
@return:
'''
check_token = self.check_username_api(username)
target_string = check_token["data"]["checkToken"] + string
msg = self.str_aes(target_string, key)
return msg
def enterprise_login_api(self):
"""
@return:
"""
getLoginUrl = os.path.join(SimOneUrl, standalone_login_url)
response = self.send(self.get, url=getLoginUrl)
return response
@property
def _enterprise_std_login(self):
"""
单机版本登录方式
@return:
"""
try:
getLoginUrl = os.path.join(SimOneUrl, standalone_login_url)
response = self.send(self.get, url=getLoginUrl)
token = json.loads(response.content.decode("utf-8"))['data']['token']
os.environ[EnvPath.token] = token
except Exception as e:
print(str(e))
token = ""
# raise AssertionError('get token error ')
return token
@property
def _cloud_std_login(self):
"""
云端版本登陆方式
@return:
"""
try:
new_login_data = copy.deepcopy(loginData)
new_login_data['password'] = self.get_str_aes(string=new_login_data['password'],
username=new_login_data['username'])
print('cloud login data:' + str(new_login_data))
response = self.cloud_login_api(userinfo=new_login_data)
print("-------", response)
print('cloud login request result:' + str(response))
token = response['data']['token']
os.environ[EnvPath.token] = token
print(token)
return token
except Exception as e:
print(str(e))
raise print('get token error ')
class LoginPolicy():
standalone = "standalone"
cloud = "cloud"
def __new__(cls, env_name):
if env_name == cls.standalone:
return LoginBusiness()._enterprise_std_login
elif env_name == cls.cloud:
return LoginBusiness()._cloud_std_login
else:
return print("----------input error---------------")
调用示例
1if __name__ == '__main__':
2 LoginPolicy("standalone")
返回结果
1```json
2{
3 "method": "GET",
4 "url": "http://172.31.9.85:30083/api-user/users/standalone",
5 "headers": {
6 "Content-Type": "application/json",
7 "Authorization": null
8 }
9}
Response:
1{
2 "code": 0,
3 "data": {
4 "token": "b557f84a-070d-4ce3-8f70-8c0021428bed"
5 }
6}
### 6. 案例库相关
#### 6.1 创建案例库
##### API
“”" def create_category_api(self, cate_name:str): ‘’’ 创建案例库 @param cate_name: 案例库名 @return: ‘’’ payload = {“parentId”: “”, “name”: cate_name} return self.send(self.post,self.categories_url,json=payload).json() “”"
##### 功能实现
```python
class Suite(RquestApi):
def __init__(self):
super(Suite, self).__init__()
self._cyclical = 0
self.category_name = "Automation_" + str(random.randint(0,9999))
def create_category_api(self, cate_name:str):
'''
创建案例库
@param cate_name: 案例库名
@return:
'''
payload = {"parentId": "", "name": cate_name}
return self.send(self.post,categories_url,json=payload).json()
def create_category(self, cate_name:str = None)->str:
'''
创建案例库
@param cate_name:
@return:
'''
if not cate_name:
cate_name = self.category_name
print(f"案例库目录名称:{cate_name}")
response = self.create_category_api(cate_name)
cate_id = response["data"]["categoryId"]
print(f"案例库目录 id :{cate_id}")
return cate_id
def main():
suite = Suite()
suite.create_category()
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-case/categories', 'headers': {'Content-Type': 'application/json', 'Authorization': 'a2b6beb8-f582-4b15-b063-d92c506452dd'}, 'json': {'parentId': '', 'name': 'Automation_5538'}}
response:{"code":0,"data":{"name":"Automation_5538","categoryId":"feeea7d0-439e-4796-a239-0f7d8f484d01"}}
案例库目录 id :feeea7d0-439e-4796-a239-0f7d8f484d01
6.2 获取案例库列表
API
"""
def get_category_api(self):
"""
获取案例库列表
@return: response
"""
return self.send(self.get, self.categories_url).json()
"""
功能实现
1 def get_category_api(self):
2 """
3 获取案例库列表
4 @return: response
5 """
6 return self.send(self.get, categories_url).json()
7
8 def get_category(self,userid:str=None)->dict:
9 """
10 获取案例库
11 @param userid: 用户id desc:admin->builtIn
12 @return:
13 """
14 cate_dict={"data":{},"parentId":{}}
15 response = self.get_category_api()
16 cate_dict["total"] = response["data"]["total"]
17 if not userid:
18 print("获取当前所有的案例库目录信息")
19 for one in response["data"]["categories"]:
20 cate_dict["data"].setdefault(one["name"],one["id"])
21 cate_dict["parentId"].setdefault(one["name"],one["parentId"])
22 else:
23 print("获取用户{}的案例库目录信息".format(userid))
24 for one in response["data"]["categories"]:
25 if one["userId"] == userid:
26 cate_dict["data"].setdefault(one["name"],one["id"])
27 cate_dict["parentId"].setdefault(one["name"], one["parentId"])
28 print("获取到的案例库->%s"%str(cate_dict))
29 return cate_dict
30
31def main():
32 suite = Suite()
33 suite.create_category()
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
获取到的案例库->{'data': {'智能网联场景库': 'f58fdcf4-c36b-11eb-81fd-1831bf08c354', 'V2X泛化': 'f58fdcf4-c36b-11eb-81fd-1831bf08c354', '前向碰撞预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '交叉路口碰撞预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '盲区变道预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '异常车辆提醒': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '车辆失控预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '道路危险状况提示': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '限速预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '弱势交通参与者碰撞预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '绿波车速引导': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '车内标牌': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '左转辅助': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '前方拥堵提醒': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '紧急车辆提醒': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '闯红灯预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '逆向超车预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', '紧急制动预警': 'fbdc25a4-f982-4db7-9e39-7ca68b5acd76', 'new': '', 'Automation_5538': ''}, 'total': 15}
6.3 获取案例库列表
API
"""
def get_category_case_api(self,cate_id:str):
"""
获取当前案例库所有案例
@param cate_name: 案例库名
@return:
"""
return self.send(self.get,self.get_cases_url.format(category=cate_id)).json()
"""
功能实现
1 def get_category_case_api(self,cate_id:str):
2 """
3 获取当前案例库所有案例
4 @param cate_name: 案例库名
5 @return:
6 """
7 return self.send(self.get,get_cases_url.format(category=cate_id)).json()
8
9 def get_cases_category(self, cate_id: list):
10 """
11 获取当前案例库的所有案例
12 @param cate_id: 案例库目录id
13 @return:
14 """
15
16 def url_code(url: str, way: str):
17 from urllib import parse
18 if way == "unquote":
19 return parse.unquote(url)
20 elif way == "quote":
21 return parse.quote(url)
22 page_size = 100
23 # print("get all case id from api by category_id")
24 _filter = {"keyword": "", "categories": cate_id}
25 string = json.dumps(_filter).replace(" ", "")
26 filter = url_code(string, UrlCodeType.quote).replace("%", "%25")
27 response = self.send(self.get, get_cases_url.format(page="1", category=filter)).json()
28 # get case id
29 # print("get_cases_category 入参cate_id:%s" % cate_id)
30 cases_num = response['data']['total']
31 if cases_num >= page_size:
32 if cases_num % page_size == 0:
33 page = cases_num // page_size
34 else:
35 page = cases_num // page_size + 1
36 else:
37 page = 1
38
39 def update_case_id(response, page_size):
40 case_name = response['data']['caseDefs'][page_size]['name']
41 case_id = response['data']['caseDefs'][page_size]['id']
42 case_id_list.append(case_id)
43 cases_dict.setdefault(case_name, [case_id])
44
45
46 cases_dict = {}
47 case_id_list = []
48 # 如果案例数量是100以内
49 if cases_num <= page_size:
50 for i in range(cases_num):
51 update_case_id(response=response, page_size=i)
52 else:
53 # 如果案例数量超过100了,固定获取案例数量为100个就翻页
54 for i in range(page):
55 response = self.send(self.get, self.get_cases_url.format(page=str(i + 1), category=filter)).json()
56 # cases_num % page_size 是取整表示没有到达最后一页
57 # if i == 0 or i > 0 and cases_num % page_size == 0:
58 if i + 1 != page:
59 # print("xxx page_size:",page_size)
60 for j in range(page_size):
61 # print("xxx j:",j)
62 update_case_id(response=response, page_size=j)
63 # 到最后一页了,因为案例数量不固定所以需要单独计算获取的个数
64 else:
65 for j in range(cases_num % page_size):
66 update_case_id(response=response, page_size=j)
67 return cases_dict, case_id_list
68
69def main(catgory_name):
70 suite = Suite()
71 cate_id_dict = suite.get_category()
72 # 案例库名称可以自己指定
73 cate_id = [cate_id_dict["data"][catgory_name]]
74 suite.get_cases_category(cate_id)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main('转向冲突')
返回值
{'method': 'GET', 'url': 'http://172.31.9.85:30083/api-case/cases?page=1&filter=%257B%2522keyword%2522%253A%2522%2522%252C%2522categories%2522%253A%255B%25220863fa00-4618-11e9-803b-61333d8d0423%2522%255D%257D&pageSize=100', 'headers': {'Content-Type': 'application/json', 'Authorization': '5022f578-187b-47ca-bed8-8d452c8738c5'}}
response:{"code":0,"data":{"total":1,"caseDefs":[{"thumbnail":null,"data":{"schema":"casedef","vehicles":[{"id":"simonedriver","name":"SimOneDriver控制","classId":"MKZ","physicalGradeSensor":0}],"id":"25834d95-d7c2-4f5f-af0e-5d8937e35064","opponent":"openscenario","userId":"18392614332","mapId":"Junction5","categoryId":"0863fa00-4618-11e9-803b-61333d8d0423","name":"转向冲突8","tags":["十字路口","机动车","转向"],"lastModified":1642420795018,"selected":false,"builtIn":true,"created":1642420795018,"version":{"major":3,"minor":0,"build":0,"patch":2},"createUsername":"standalone","createUserRole":0,"revision":{"id":0,"userId":"standalone","timestamp":1608881493476},"updateUsername":"standalone","notes":"本车转向,与前车发生冲突","joinway":"import","thumbnail":"","mapName":"五车道路口"},"id_":97,"updateUserId":"18392614332","created":1642420795134,"builtIn":true,"terminal":null,"userId":"18392614332","tags":["转向","机动车","十字路口"],"total":1,"invalidedFlag":"","deleteTime":0,"opponent":"openscenario","name":"转向冲突8","editRevision":"5712fa29-188d-4653-81d2-b5e56baaeb45","mapId":"Junction5","id":"25834d95-d7c2-4f5f-af0e-5d8937e35064","lastModified":1642420795134,"vehicleId":["simonedriver"],"categoryId":"0863fa00-4618-11e9-803b-61333d8d0423"}],"page":1}}
6.4 获取案例库中子集目录案例ID
API
"""
def get_category_api(self):
"""
获取案例库列表
@return: response
"""
return self.send(self.get, categories_url).json()
"""
功能实现
1def get_all_cate_id_list(self, cate_id) -> list:
2
3 """
4 @param cate_id: 案例库ID
5 @return: cate_id_list
6 """
7 all_cate_list = [cate_id]
8 response = self.get_category_api()
9 def get_cate_id(current_cate_id):
10 categories = response["data"]["categories"]
11 for category in categories:
12 if current_cate_id == category["parentId"] and category["id"] not in all_cate_list:
13 all_cate_list.append(category["id"])
14 get_cate_id(category["id"])
15
16 get_cate_id(cate_id)
17 print("all_cate_list:", all_cate_list)
18 return all_cate_list
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 # main("new", "test_4")
9 test = Suite()
10 test.get_all_cate_id_list("dbaf8d6e-af07-44a6-b7c7-d8b7f2fd6616")
返回值
all_cate_list: ['dbaf8d6e-af07-44a6-b7c7-d8b7f2fd6616', 'c8557561-5729-43e1-9d65-91498f7a1129']
7. 案例相关
7.1 获取案例信息
API
"""
def get_case_detail_api(self, case_id:str):
"""
获取案例信息
@param params: /{case_id}/data
@return: response
"""
url = self.case_details_url.format(case_id=case_id)
return self.send(self.get, url).json()
"""
功能实现
1 def get_case_detail_api(self, case_id: str):
2 """
3 获取案例信息
4 @param : /{case_id}/data
5 @return: response
6 """
7 url = case_details_url.format(case_id=case_id)
8 return self.send(self.get, url).json()
9
10 def get_case_detail(self, case_id: str):
11 """
12
13 @param case_id: 测试案例id
14 @return:
15 """
16 response = self.get_case_detail_api(case_id)
17 return response
18
19
20def main(catgory_name):
21 suite = Suite()
22 cate_id_dict = suite.get_category()
23 # 案例库名称可以自己指定
24 cate_id = [cate_id_dict["data"][catgory_name]]
25 # suite.get_cases_category(cate_id)
26 cases_dict, case_id_list = suite.get_cases_category(cate_id)
27 suite.get_case_detail(case_id_list[0])
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main('转向冲突')
返回值
{'code': 0, 'data': {'schema': 'casedata', 'caseId': '25834d95-d7c2-4f5f-af0e-5d8937e35064', 'sensors': {'byId': {}, 'allIds': []}, 'judgements': {'byId': {'timeout': {'id': 'timeout', 'name': '超时', 'type': 'timeout', 'enabled': True, 'scope': {'type': 'global', 'position': {'x': 0, 'y': 0, 'z': 0}, 'heading': {'x': 0, 'y': 0, 'z': 0, 'w': 1}, 'size': {'x': 10, 'y': 10, 'z': 0}}, 'conditions': [{'variable': 'timeout', 'value': 600}], 'settings': {'action': 'failure', 'logLevel': 'error', 'logInfo': ''}, 'builtIn': True, 'lock': True, 'userId': 'admin', 'schema': 'judgement'}, 'collision': {'id': 'collision', }..........}
7.2 案例导入
API
"""
def import_case_api(self, payload: dict):
"""
案例导入
@param payload:
@return:
"""
return self.send(self.post, case_import_url, data=json.dumps(payload)).json()
def file_md5_check(self, file_path: str, raw: bool = False):
"""
文件md5检查
@param file_path: 文件路径
@return:
"""
# global url
def file_md5(filename: str):
"""
以文件内容md5加密
@param filename:
@return:
"""
with open(filename, 'rb') as f:
contents = f.read()
return hashlib.md5(contents).hexdigest()
file_md5 = file_md5(file_path)
# print("file_md5:", file_md5)
if raw:
url = file_md5_url.format(file_md5, "true")
else:
url = file_md5_url.format(file_md5, "false")
# print("file_md5:",file_md5)
# print(self.send(self.get, url).json())
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,
uuid: str = Faker('zh_CN').uuid4()):
"""
上传文件
@param file_path: 文件路径
@param index: 上传序列
@param chunks: chunks总数
@param category: 类别
@param file_md5: 文件MD5
@return:
"""
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:
def file_md5(filename: str):
"""
以文件内容md5加密
@param filename:
@return:
"""
with open(filename, 'rb') as f:
contents = f.read()
return hashlib.md5(contents).hexdigest()
file_md5 = file_md5(file_path)
if raw:
url = upload_file_url.format(file_md5, "true")
else:
url = upload_file_url.format(file_md5, "false")
upload_payload = {"params": json.dumps({"filename": file_name,
"index": index,
"chunks": chunks,
"filesize": file_size,
"uploadId": uuid,
"category": category})}
response = self.send(self.post, url, data=upload_payload, files=files).json()
# print(f"-----upload_file-- url:{url} upload_payload:{upload_payload} files:{files} response:{response}")
print("uuid:", uuid)
return uuid, response
"""
功能实现
1 def file_md5_check(self, file_path: str, raw: bool = False):
2 """
3 文件md5检查
4 @param file_path: 文件路径
5 @return:
6 """
7
8 # global url
9 def file_md5(filename: str):
10 """
11 以文件内容md5加密
12 @param filename:
13 @return:
14 """
15 with open(filename, 'rb') as f:
16 contents = f.read()
17 return hashlib.md5(contents).hexdigest()
18
19 file_md5 = file_md5(file_path)
20 # print("file_md5_check file_md5:", file_md5)
21 # file_md5_url = "api-asset/files/{}?raw={}" # 验证文件MD5
22 if raw:
23 url = file_md5_url.format(file_md5, "true")
24 else:
25 url = file_md5_url.format(file_md5, "false")
26 response = self.send(self.get, url).json()
27 # print(f"-----file_md5_check:{url} get response:",response)
28 return response
29
30 def remove_file(self, sim_path: str):
31 """
32 remove files that except (.sim .zip .xosc)
33 :param sim_path:
34 """
35 for item in os.listdir(sim_path):
36 sim_file = os.path.join(sim_path, item)
37 try:
38 if os.path.isfile(sim_file):
39 os.remove(sim_file)
40 # print(f'{sim_file} 文件删除成功')
41 elif os.path.isdir(sim_file):
42 shutil.rmtree(sim_file)
43 # print(f'{sim_file} 文件夹删除成功')
44 except OSError as e:
45 print(f'Error: {e.filename} - {e.strerror}.')
46 def get_caseid(self, sim_path: str, sim_list: list):
47 """
48 get the caseid before import according to
49 :param sim_path: string, the path to the .sim file
50 :sim_list run_sim: list, cases that need to be run
51 :return: list, caseid before import
52 """
53 # print("sim_path:",sim_path)
54 # print("sim_list:",sim_list)
55 file_list = os.listdir(sim_path)
56 # print("file_list:",file_list)
57 target_run = list()
58 for item in file_list:
59 for run_sim_item in sim_list:
60 # if ('31map.sim' in item) and ('all_sim' in choose_run):
61 if os.path.join(sim_path, run_sim_item + '.sim') == os.path.join(sim_path, item):
62 target_run.append(item)
63 # print("target_run:",target_run)
64 if not target_run:
65 target_run = file_list
66 # print("更新后target_run:",target_run)
67 extract_dir = os.path.join(sim_path, "extract_dir")
68 # print("extract_dir:",extract_dir)
69 if not os.path.exists(extract_dir):
70 os.makedirs(extract_dir)
71 for item in target_run:
72 if item == "extract_dir":
73 continue
74 # zip_file = os.path.join(sim_path, item).replace('.sim', '.zip') # 当文件名中有两个.sim时会有BUG
75 zip_file = os.path.join(extract_dir, item[:-4] + ".zip") if item.endswith(".sim") else os.path.join(
76 extract_dir, item)
77 # print("zip_file:",zip_file)
78 try:
79 if item.endswith(".sim") or item.endswith(".zip"):
80 # print("try item:",item)
81 shutil.copy(os.path.join(sim_path, item), zip_file)
82 except Exception as e:
83 pass
84 try:
85 with zipfile.ZipFile(zip_file) as zfile:
86 # print("执行到这。。。")
87 zfile.extractall(path=extract_dir)
88 # print("执行到这2。。。")
89 except Exception as e:
90 raise Exception(f"解压{zip_file}失败,异常信息:{e}")
91 temp = list(filter(lambda x: 'json' in x, os.listdir(extract_dir)))
92 # print("temp:",temp)
93 if temp == []: # 从3.3.0版本起案例解压后是文件夹,则上一条语句执行后temp为空
94 for d in os.listdir(extract_dir):
95 # print("extract_dir目录下的内容:",d)
96 if os.path.isdir(os.path.join(extract_dir, d)):
97 temp.append(d)
98 # print("临时测试temp:",temp)
99 all_case_id = list(set(temp)) # 去重
100 # print("all_case_id:",all_case_id)
101 old_case_id = list(filter(lambda x: 'vehicle' not in x, all_case_id))
102 # print("old_case_id:",old_case_id)
103 self.remove_file(extract_dir)
104 # print("执行到这3。。。")
105 return old_case_id
106 all_case_id = list(map(lambda x: x.replace('.json', ''), temp))
107 all_case_id = list(set(all_case_id)) # 去重
108 old_case_id = list(filter(lambda x: 'vehicles' not in x, all_case_id))
109 self.remove_file(extract_dir)
110 return old_case_id
111
112 def upload_file(self, file_path: str, index: int, chunks: int, category: str, file_md5: str, raw: bool = False,
113 uuid: str = Faker('zh_CN').uuid4()):
114 """
115 上传文件
116 @param file_path: 文件路径
117 @param index: 上传序列
118 @param chunks: chunks总数
119 @param category: 类别
120 @param file_md5: 文件MD5
121 @return:
122 """
123 global url
124 # self.headers = {}
125 self.headers = {"ProjectId": 'default'} # 江淮3.5.0
126 file_size = os.path.getsize(file_path)
127 file_name = file_path.split(os.sep)[-1]
128 files = {'file': open(os.path.join(file_path), 'rb')}
129
130 if not file_md5:
131 def file_md5(filename: str):
132 """
133 以文件内容md5加密
134 @param filename:
135 @return:
136 """
137 with open(filename, 'rb') as f:
138 contents = f.read()
139 return hashlib.md5(contents).hexdigest()
140
141 file_md5 = file_md5(file_path)
142 if raw:
143 url = upload_file_url.format(file_md5, "true")
144 else:
145 url = upload_file_url.format(file_md5, "false")
146
147 upload_payload = {"params": json.dumps({"filename": file_name,
148 "index": index,
149 "chunks": chunks,
150 "filesize": file_size,
151 "uploadId": uuid,
152 "category": category})}
153 response = self.send(self.post, url, data=upload_payload, files=files).json()
154 # print(f"-----upload_file-- url:{url} upload_payload:{upload_payload} files:{files} response:{response}")
155 print("uuid:", uuid)
156 return uuid, response
157
158 def import_case_api(self, payload: dict):
159 """
160 案例导入
161 @param payload:
162 @return:
163 """
164 # print("********* import_case_api payload********",payload)
165 self.headers.update({"Content-Type": "application/json;charset=UTF-8"})
166 return self.send(self.post, case_import_url, data=json.dumps(payload)).json()
167
168 def import_case(self, file_path: str, file_name: str, cate_id: str):
169 """
170 导入案例到指定的案例库目录
171 @param file_path: 案例文件路径
172 @param file_name: 案例文件名
173 @param cate_id: 案例库目录id
174 @return: [重要] 此处返回的并不是导入成功后的案例ID,而是导入案例文件里的原ID
175 """
176 case_file_path = os.path.join(file_path, file_name)
177 filename = file_name.split(".")[0]
178 file_size = os.path.getsize(case_file_path)
179 md5_res = self.file_md5_check(case_file_path)
180 md5_res_info = md5_res["data"]
181 file_md5 = md5_res_info["id"]
182 global ext
183 global path_ext
184 if file_name.split(".")[1] == "xosc":
185 ext = "xosc"
186 case_id_list = [f"{filename}"]
187 includes = case_id_list
188 overrides_id = case_id_list[0]
189 overrides_name = filename
190 overrides_path = filename + ".xosc"
191 elif file_name.split(".")[1] == "sim":
192 ext = "sim"
193 case_id_list = self.get_caseid(file_path, [filename])
194 includes = case_id_list
195 overrides_id = case_id_list[0]
196 overrides_name = filename
197 overrides_path = case_id_list[0] + "/case/" + filename + ".json"
198 elif file_name.split(".")[1] == "zip":
199 ext = "zip"
200 case_id_list = self.get_caseid(file_path, [filename])
201 print("case_id_list:", case_id_list)
202 includes = case_id_list[0] + "/case/" + filename
203 overrides_id = includes
204 overrides_name = includes
205 overrides_path = includes + ".xosc"
206 else:
207 raise f"导入案例不支持{file_name.split('.')[1]}格式,用例中断"
208 case_payload = {"category": cate_id,
209 "ext": ext,
210 "file": file_md5,
211 "id": "2222222222",
212 "includes": includes,
213 "includesMap": True,
214 "includesStopTrigger": True,
215 "includesVehicle": True,
216 "name": filename,
217 # "overrides": [],
218 "overrides": [{
219 "id": overrides_id,
220 "missingMap": False,
221 "missingVehicle": False,
222 "name": overrides_name,
223 "path": overrides_path,
224 "replaceMap": False,
225 "replaceVehicle": True
226 }],
227 "categoryInfo": {},
228 "needRemoveCases": {}
229 }
230
231 def round_up(data):
232 """
233 func:向上取整
234 Args:
235 data: float
236 Returns: int
237
238 """
239 return math.ceil(data)
240
241 chunk_size = 2 * 1024 * 1024
242 if md5_res_info['size'] == 0:
243 chunks = round_up(file_size / chunk_size)
244 for i in range(chunks):
245 self.upload_file(file_path=case_file_path, index=i, chunks=chunks, category="case", file_md5=file_md5)
246 response = self.import_case_api(payload=case_payload)
247 else:
248 response = self.import_case_api(payload=case_payload)
249 # print("临时测试 import_case case_payload:", case_payload)
250 # print("-----import_case_api response -->>> ", response)
251 return case_id_list, response # [重要] 此处返回的并不是导入成功后的案例ID,而是导入案例文件里的原ID
252
253
254 def import_flow(self, category_name: str, file_path: str, file_name: str):
255 '''
256 导入文件流程
257 可导入的文件类型为 .xosc 或者 .sim格式
258 @param category_name: 案例库名称
259 @param file_path: 文件路径比如 r"D:\System
260 @param file_name:文件名称比如 123.xosc or 123.sim
261 '''
262 cate_id = self.get_category()
263 cate_idname = cate_id["data"][category_name]
264 self.import_case(file_path, file_name, cate_idname)
265
266def main():
267 suite = Suite()
268 # cate_id_dict = suite.get_category()
269 # 案例库名称可以自己指定
270 # cate_id = [cate_id_dict["data"][catgory_name]]
271 # suite.get_cases_category(cate_id)
272 # cases_dict, case_id_list = suite.get_cases_category(cate_id)
273 # suite.get_case_detail(case_id_list[0])
274 suite.import_flow("new",r"C:\Users\Administrator\Desktop\test", "test.xosc")
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
response:{"code":0,"data":{"id":"2222222222"}}
7.3 案例导出
API
"""
def export_case_api(self, payload: dict) -> json:
"""
导出测试案例
@param payload:dict
@return:response
"""
return self.send(self.post, export_case_url, data=json.dumps(payload)).json()
def download_case_api(self, pake_id: str) -> bytes:
"""
下载测试案例
@param pake_id: pake_id
@return:response
"""
return self.send(self.get, download_case_url.format(pake_id=pake_id)).content
"""
功能实现
1 def export_case_api(self, payload: dict) -> json:
2 """
3 导出测试案例
4 @param payload:dict
5 @return:response
6 """
7 return self.send(self.post, export_case_url, data=json.dumps(payload)).json()
8
9 def download_case_api(self, pake_id: str) -> bytes:
10 """
11 下载测试案例
12 @param pake_id: pake_id
13 @return:response
14 """
15 return self.send(self.get, download_case_url.format(pake_id=pake_id)).content
16
17 def download_case(self, case_id: list) -> bytes:
18 """
19 获取二进制测试案例内容
20 @param case_id: case_id_list
21 @return: bytes
22 """
23 # 取pake_id
24 pake_id = self.export_case(case_id)["data"]["id"]
25 print(f"download_case_bytes:{self.download_case_api(pake_id=pake_id)}")
26 return self.download_case_api(pake_id=pake_id)
27
28 def export_case(self, case_id: list, _format: str = ".sim", vehicle: bool = True, includesMap: bool = True,
29 includesObstacle: bool = True):
30
31 """
32 @param case_id: case_id_list
33 @param _format: sim or xosc
34 @param vehicle: True or False
35 @return: response
36 """
37
38 if _format == ".sim" or _format == ".xosc":
39 payload = {
40 "caseIds": case_id,
41 "includesVehicle": vehicle,
42 "includesMap": includesMap, # 3.5.0
43 "includesObstacle": includesObstacle,
44 "format": _format,
45 "pathinfo": [{"id": caseId, "parentId": None} for caseId in case_id]
46 }
47 response = self.export_case_api(payload)
48 return response
49 else:
50 raise Exception(f"-------------input format={_format} error----------------")
51
52 def get_all_cate_id_list(self, cate_id) -> list:
53
54 """
55 @param cate_name_list: 案例名称列表
56 @return: cate_id_list
57 """
58 all_cate_list = [cate_id]
59 response = self.get_category_api()
60 def get_cate_id(current_cate_id):
61 categories = response["data"]["categories"]
62 for category in categories:
63 if current_cate_id == category["parentId"] and category["id"] not in all_cate_list:
64 all_cate_list.append(category["id"])
65 get_cate_id(category["id"])
66
67 get_cate_id(cate_id)
68 all_cate_list = [j for i in all_cate_list for j in i]
69 print("all_cate_list:", all_cate_list)
70 return all_cate_list
71
72 def download_case_flow(self, category_name: str, downloadPath: str, downloadName: str) -> None:
73 """
74 @param cate_name: 案例库名称
75 @param downloadPath: 下载路径
76 @param downloadName: 下载包的名称
77 @return: None
78 """
79 cate_id_dict = self.get_category()[0]
80 cate_id_str = [cate_id_dict["data"][category_name]]
81 # cate_method=CategoryBusiness()
82 cate_id_list = self.get_all_cate_id_list(cate_id_str)
83
84
85 case_id_list = self.get_cases_category(cate_id_list)[1]
86 downloadResponse = self.download_case(case_id_list)
87 # 取 format 的实际参数
88 _format = inspect.getfullargspec(self.export_case)[3][0]
89 # 下载的文件路径
90 downloadPake = os.path.join(downloadPath, downloadName + _format)
91 with open(downloadPake, 'wb') as f:
92 f.write(downloadResponse)
93 print(f"导出的案例路径为:{downloadPake}")
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 download_case_flow(category_name, downloadPath, downloadName)
返回值
run_task response:{'code': 0, 'data': {'sessionId': '3f90ef1b-f5e1-4ab7-b24f-7f94b9d7f1cb', 'taskIds': ['d2973d5b-7fef-4d83-af5d-ec108db815df']}}
7.4 案例场景编辑
API
"""
def case_def_api(self, case_id: str):
"""
案例概要
@param case_id:
@return:
"""
return self.send(self.get, case_def_url.format(case_id=case_id)).json()
def case_data_api(self, case_id: str):
"""
案例详情
@param case_id:
@return:
"""
return self.send(self.get, case_details_url.format(case_id=case_id)).json()
def update_case_api(self, payload: dict):
"""
案例编辑
@param payload:
@return:
"""
self.headers.update({"Content-Type": "application/json"})
return self.send(self.post, update_case_url, data=json.dumps(payload)).json()
def get_vehicles_api(self):
"""
获取主车信息
@return:
"""
return self.send(self.get, get_vehicles_url).json()
"""
功能实现
1 def case_def_api(self, case_id: str):
2 """
3 案例概要
4 @param case_id:
5 @return:
6 """
7 return self.send(self.get, case_def_url.format(case_id=case_id)).json()
8
9 def case_data_api(self, case_id: str):
10 """
11 案例详情
12 @param case_id:
13 @return:
14 """
15 return self.send(self.get, case_details_url.format(case_id=case_id)).json()
16
17 def update_case_api(self, payload: dict):
18 """
19 案例编辑
20 @param payload:
21 @return:
22 """
23 self.headers.update({"Content-Type": "application/json"})
24 return self.send(self.post, update_case_url, data=json.dumps(payload)).json()
25
26 def get_vehicles_api(self):
27 """
28 获取主车信息
29 @return:
30 """
31 return self.send(self.get, get_vehicles_url).json()
32
33
34 def get_vehicle_name(self, vehicle_id: str):
35 res = self.get_vehicles_api()
36 print(f"get_vehicle_api response: {res}")
37 data = res["data"]["list"]["byId"]
38 for key in data:
39 if key == vehicle_id:
40 print(f"找到主车ID为{vehicle_id}的主车名称:{data[key]['name']}")
41 return data[key]["name"]
42 print(f"没有找到主车ID为{vehicle_id}的主车")
43 return None
44
45
46 def update_case(self, case_id: str,
47 map_name: str = None,
48 map_id: str = None,
49 vehicle_id: str = None,
50 main_vehicle_speed: int = None):
51 """
52 编辑案例
53 @param case_id: 案例ID
54 @param map_name: 地图名称
55 @param map_id: 地图ID
56 @param vehicle_id: 主车ID
57 @param main_vehicle_speed: 主车速度
58 @return: 更新主车或地图后的案例
59 """
60 case_def = self.case_def_api(case_id=case_id)
61 case_data = self.case_data_api(case_id=case_id)
62 print("临时测试 原case_def:", case_def)
63 print("临时测试 原case_data:", case_data)
64 print("update_case case_id:", case_id)
65 print("update_case map_name:", map_name)
66 print("update_case map_id:", map_id)
67 print("update_case vehicle_id:", vehicle_id)
68
69 if vehicle_id:
70 vehicle_name = self.get_vehicle_name(vehicle_id)
71 case_data["data"]["openSCENARIO"]["Entities"]["ScenarioObject"][0]["Vehicle"][
72 "name"] = vehicle_name # 3.5.0
73 case_data["data"]["openSCENARIO"]["Entities"]["ScenarioObject"][0]["Vehicle"]["Properties"][
74 "Property"][0]["value"] = vehicle_id # 3.4.0 没有加这一行 此行待确认是否可以删除
75 for key in case_data["data"]["openSCENARIO"]["Entities"]["ScenarioObject"][0]["Vehicle"]["Properties"][
76 "Property"]:
77 if key["name"] == 'model':
78 key["value"] = vehicle_id
79 print(key)
80 if key["name"] == 'name':
81 key["value"] = vehicle_name
82 print(key)
83 if map_id:
84 case_def["data"]["data"]["mapId"] = map_id
85 case_def["data"]["data"]["mapName"] = map_name.split(".")[0]
86 case_data["data"]["openSCENARIO"]["RoadNetwork"]["LogicFile"]["filepath"] = map_id + "." + \
87 map_name.split(".")[1]
88 case_payload = {"casedef": case_def["data"]["data"],
89 "casedata": case_data["data"],
90 "needRefresh": True}
91 if main_vehicle_speed:
92 privates = case_data["data"]["openSCENARIO"]['Storyboard']['Init']['Actions']['Private']
93 for private in privates:
94 if private["entityRef"] == "Ego":
95 for PrivateAction in private["PrivateAction"]:
96 if PrivateAction.get('LongitudinalAction'):
97 PrivateAction['LongitudinalAction']['SpeedAction']['SpeedActionTarget'][
98 'AbsoluteTargetSpeed']['value'] = main_vehicle_speed
99
100 response = self.update_case_api(payload=case_payload)
101 # print("临时测试 update_case response",response)
102 if response['code'] != 0:
103 raise Exception("编辑案例异常,接口返回:" + response)
104 return response
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 test = Suite()
9 test.update_case(case_id,map_name,map_id,vehicle_id,main_vehicle_speed)
返回值
update_case_api response {'code': 0, 'msg': 'ok', 'data': {'code': 0, 'msg': 'ok'}}
7.5 保存回放案例
API
"""
def convert_replay_case_api(self, task_id: str, category_id: str, replay_case_name: str):
"""
转换回放案例
@param case_id: 需要转转换的案例ID
@param category_id: 存放案例库目录ID
@param replay_case_name: 转换后的回放案例名称
@return:
"""
payload = {
"name": replay_case_name,
"categoryId": category_id,
"opponent": "record",
"ego2npc": False,
"notes": "",
"tags": ""
}
return self.send(self.get, convert_replay_case_url.format(id=task_id), data=json.dumps(payload))
"""
功能实现
1 def convert_replay_case_api(self, task_id: str, category_id: str, replay_case_name: str):
2 """
3 转换回放案例
4 @param case_id: 需要转转换的案例ID
5 @param category_id: 存放案例库目录ID
6 @param replay_case_name: 转换后的回放案例名称
7 @return:
8 """
9 payload = {
10 "name": replay_case_name,
11 "categoryId": category_id,
12 "opponent": "record",
13 "ego2npc": False,
14 "notes": "",
15 "tags": ""
16 }
17 return self.send(self.get, convert_replay_case_url.format(id=task_id), data=json.dumps(payload))
18
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 suite = Suite()
9 suite.convert_replay_case_api(task_id="4c3f93ff-3f4a-4bea-ac04-507759fed4d2",
10 category_id="ab21e34c-9df8-433f-89e7-8a66ec42529d", replay_case_name="TestCase")
返回值
{code:0,success:True}
8. 运行任务相关
8.1 运行任务
API
"""
def create_task_api(self,payload:dict):
"""
创建task
@param payload: eg {"caseIds": ["3dd03c09-3ba9-4f7a-b988-fde88296095a"],
"taskName": "task_name"}
@return:
"""
return self.send(self.post,self.create_task_url,json=payload).json()
"""
功能实现
注意: 此功能 3.4 以前包括3.4的版本 和 3.5 以后的版本有所区分请注意
1 def create_task_api(self,payload:dict):
2 """
3 创建task
4 @param payload: eg {"caseIds": ["3dd03c09-3ba9-4f7a-b988-fde88296095a"],
5 "taskName": "task_name"}
6 @return:
7 """
8 return self.send(self.post,create_task_url,json=payload).json()
9
10 def run_task(self, caseid: list, vehicle_id: str = None, withEvaluation: bool = False, version: float = 3.5):
11 """
12 运行测试任务集合
13 Run task set
14 @param caseid: caseid
15 @param vehicle_id: vehicle_id
16 @param withEvaluation: withEvaluation
17 @param version: version
18 @return:
19 """
20 task_name = "taskName_" + time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())
21 if version >= 3.5:
22 payload = {"caseIds": caseid,
23 "taskName": task_name,
24 "withEvaluation": withEvaluation,
25 "controllers": [{"id": "Default", "name": "默认控制器", "algorithmId": "SimOneDriver"},
26 {"id": "AutoDrive", "name": "自驾控制器", "algorithmId": "SimOneDriver"}]}
27 else:
28 payload = {"caseIds": caseid, "taskName": task_name, "speed": 1}
29 if vehicle_id:
30 payload.update({"overrideVehicleId": vehicle_id})
31 response = self.send(self.post, url=create_task_url, json=payload).json()
32
33 data = response['data']
34 return data['sessionId'], data['taskIds']
35
36def main(catgory_name,case_name):
37 suite = Suite()
38 cate_id_dict = suite.get_category()
39 # 案例库名称可以自己指定
40 cate_id = [cate_id_dict["data"][catgory_name]]
41 suite.get_cases_category(cate_id)
42 cases_dict, case_id_list = suite.get_cases_category(cate_id)
43 suite.get_case_detail(case_id_list[0])
44 # suite.import_flow("new",r"C:\Users\Administrator\Desktop\test", "test.xosc")
45 # 案例名称逻辑
46 if case_name:
47 case_id_list = cases_dict[case_name]
48 # print(f" case_name:{case_name}")
49 suite.run_task(caseid=case_id_list)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("Automation_5538","test_4-copy")
返回值
run_task response:{'code': 0, 'data': {'sessionId': '3f90ef1b-f5e1-4ab7-b24f-7f94b9d7f1cb', 'taskIds': ['d2973d5b-7fef-4d83-af5d-ec108db815df']}}
8.2 结束任务
API
"""
def stop_task_api(self, payload: dict):
"""
task停止API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, stop_task_url, json=payload).json()
def stop_sessions_api(self, payload: dict):
"""
sessions停止API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, stop_sessions_url, json=payload).json()
"""
功能实现
1 def stop_task_api(self, payload: dict):
2 """
3 task停止API
4 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
5 @return:
6 """
7 return self.send(self.post, stop_task_url, json=payload).json()
8
9 def stop_sessions_api(self, payload: dict):
10 """
11 sessions停止API
12 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
13 @return:
14 """
15 return self.send(self.post, stop_sessions_url, json=payload).json()
16
17 def stop_task(self, task_id: list, sessions_id: list):
18 """
19 停止任务和会话
20 @param task_id:
21 @param sessions_id:
22 @return:
23 """
24 task_payload = {"ids": task_id}
25 self.stop_task_api(task_payload)
26 sessions_id = {"ids": sessions_id}
27 self.stop_sessions_api(sessions_id)
28
29
30def main(catgory_name, case_name):
31 suite = Suite()
32 cate_id_dict = suite.get_category()
33 # 案例库名称可以自己指定
34 cate_id = [cate_id_dict["data"][catgory_name]]
35 suite.get_cases_category(cate_id)
36 cases_dict, case_id_list = suite.get_cases_category(cate_id)
37 suite.get_case_detail(case_id_list[0])
38 # suite.import_flow("new",r"C:\Users\Administrator\Desktop\test", "test.xosc")
39 # 案例名称逻辑
40 if case_name:
41 case_id_list = cases_dict[case_name]
42 # print(f" case_name:{case_name}")
43 session_id,task_ids = suite.run_task(caseid=case_id_list)
44 time.sleep(10)
45 suite.stop_task(task_ids, [session_id])
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("Automation_5538", "test_4-copy")
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/tasks/stop', 'headers': {'Content-Type': 'application/json', 'Authorization': 'ae04e5b4-6a7a-4ad4-b476-33f946e717d5'}, 'json': {'ids': ['8d18f2f6-fd8b-48ae-86a0-0a3bbee1763c']}}
response:{"code":0,"data":{}}
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/sessions/stop', 'headers': {'Content-Type': 'application/json', 'Authorization': 'ae04e5b4-6a7a-4ad4-b476-33f946e717d5'}, 'json': {'ids': ['fc25f9de-7a21-4f0d-8906-a830b7e799ab']}}
response:{"code":0,"data":{}}
8.3 暂停任务&重新开始
API
"""
def pause_task_api(self,task_id:str):
"""
暂停任务
@param task_id:
@return:
"""
return self.send(self.post, self.pause_task_url.format(task_id=task_id),json={}).json()
def resume_task_api(self,task_id:str):
"""
暂停任务后开始
@param task_id:
@return:
"""
return self.send(self.post, self.resume_task_url.format(task_id=task_id),json={}).json()
"""
功能实现
1 def pause_task_api(self,task_id:str):
2 """
3 暂停任务
4 @param task_id:
5 @return:
6 """
7 return self.send(self.post, pause_task_url.format(task_id=task_id),json={}).json()
8
9 def resume_task_api(self,task_id:str):
10 """
11 暂停任务后开始
12 @param task_id:
13 @return:
14 """
15 return self.send(self.post, resume_task_url.format(task_id=task_id),json={}).json()
16
17
18def main(catgory_name, case_name):
19 suite = Suite()
20 cate_id_dict = suite.get_category()
21 # 案例库名称可以自己指定
22 cate_id = [cate_id_dict["data"][catgory_name]]
23 suite.get_cases_category(cate_id)
24 cases_dict, case_id_list = suite.get_cases_category(cate_id)
25 suite.get_case_detail(case_id_list[0])
26 # suite.import_flow("new",r"C:\Users\Administrator\Desktop\test", "test.xosc")
27 # 案例名称逻辑
28 if case_name:
29 case_id_list = cases_dict[case_name]
30 # print(f" case_name:{case_name}")
31 session_id ,task_ids = suite.run_task(caseid=case_id_list)
32 time.sleep(5)
33 suite.stop_task(task_ids, [session_id])
34 for i in task_ids:
35 suite.pause_task_api("c686a2de-47fa-4604-b354-36f8fe2b9d75")
36
37 time.sleep(5)
38 for i in task_ids:
39 suite.resume_task_api("c686a2de-47fa-4604-b354-36f8fe2b9d75")
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("Automation_5538", "test_4-copy")
返回值
{'method': 'GET', 'url': 'http://172.31.9.85:30083/api-case/cases/f5bbfb2c-619a-4812-90c2-75a84247a4db/data', 'headers': {'Content-Type': 'application/json', 'Authorization': 'beff0aaa-a060-4e9e-9f54-58362549b3f0'}}
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/sessions/c686a2de-47fa-4604-b354-36f8fe2b9d75/resume', 'headers': {'Content-Type': 'application/json', 'Authorization': 'beff0aaa-a060-4e9e-9f54-58362549b3f0'}, 'json': {}}
response:{"code":0,"data":{}}
8.4 删除任务
API
"""
def delete_sessions_api(self, payload: dict):
"""
sessions删除API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, delete_sessions_url, json=payload).json()
def delete_task_api(self, payload: dict):
"""
task删除API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, delete_task_url, json=payload).json()
"""
功能实现
1 def delete_sessions_api(self, payload: dict):
2 """
3 sessions删除API
4 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
5 @return:
6 """
7 return self.send(self.post, delete_sessions_url, json=payload).json()
8
9 def delete_task_api(self, payload: dict):
10 """
11 task删除API
12 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
13 @return:
14 """
15 return self.send(self.post, delete_task_url, json=payload).json()
16
17 def delete_task(self, sessions_id: list, task_id: list):
18 """
19 删除任务和会话
20 @param sessions_id:
21 @param task_id:
22 @return:
23 """
24 sessions_id = {"ids": sessions_id}
25 self.delete_sessions_api(sessions_id)
26 task_payload = {"ids": task_id}
27 self.delete_task_api(task_payload)
28
29
30def main(catgory_name, case_name):
31 suite = Suite()
32 cate_id_dict = suite.get_category()
33 # 案例库名称可以自己指定
34 cate_id = [cate_id_dict["data"][catgory_name]]
35 suite.get_cases_category(cate_id)
36 cases_dict, case_id_list = suite.get_cases_category(cate_id)
37 suite.get_case_detail(case_id_list[0])
38 # suite.import_flow("new",r"C:\Users\Administrator\Desktop\test", "test.xosc")
39 # 案例名称逻辑
40 if case_name:
41 case_id_list = cases_dict[case_name]
42 # print(f" case_name:{case_name}")
43 session_id ,task_ids = suite.run_task(caseid=case_id_list)
44 time.sleep(5)
45 # suite.stop_task(task_ids, [session_id])
46 suite.delete_task([session_id],task_ids)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("Automation_5538", "test_4-copy")
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/sessions/delete', 'headers': {'Content-Type': 'application/json', 'Authorization': '5a3662a3-2fbb-4790-b40d-42f600e63801'}, 'json': {'ids': ['bc344bf1-4bd3-493e-a4d3-95f98dcc3e48']}}
response:{"code":0,"data":{}}
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/tasks/delete', 'headers': {'Content-Type': 'application/json', 'Authorization': '5a3662a3-2fbb-4790-b40d-42f600e63801'}, 'json': {'ids': ['18a0fafe-d1e2-404b-b5e8-b4f3ea4c8e86']}}
response:{"code":0,"msg":"success"}
8.5 判断任务是否正在运行
API
"""
def get_result(self, task_id: list, index: int = None):
"""
:param task_id:
:return:
"""
task_id_str = ",".join(task_id)
# print(task_id_str)
response = self.send(self.get, url=result_url.format(task_id=task_id_str)).json()
data = response["data"]["tasks"]
result = []
for one in data:
result.append({"pass": one["pass"], "is_ended": True if one["key"] == "ended" else False})
if not index:
return result
else:
return result[index]
"""
功能实现
1
2 def get_result(self, task_id: list, index: int = None):
3 """
4 :param task_id:
5 :return:
6 """
7 task_id_str = ",".join(task_id)
8 # print(task_id_str)
9 response = self.send(self.get, url=result_url.format(task_id=task_id_str)).json()
10 data = response["data"]["tasks"]
11 result = []
12 for one in data:
13 result.append({"pass": one["pass"], "is_ended": True if one["key"] == "ended" else False})
14 if not index:
15 return result
16 else:
17 return result[index]
18 def is_ended(self, task_id: list, case_name=None):
19 """
20 判断案例是否运行结束
21 @param task_id: 任务id
22 @param case_name: 案例名称
23 @return:
24 """
25 interval = 10
26 while (1):
27 result = self.get_result(task_id, -1)
28 if result["is_ended"]:
29 print('Case status:end of run')
30 if case_name:
31 print(f'Name of the current ending case->{case_name}')
32 return False
33 else:
34 print('Case status:in progress')
35 if case_name:
36 print(f'Name of the current running case->{case_name}')
37 time.sleep(interval)
调用示例
1def main(category_name: str, case_name: str = None, vehicle_name=None):
2 """
3 @param category_name: category_name
4 @param case_name:
5 @param vehicle_name:vehicle_name
6 @return:
7 """
8 suite = Suite()
9 suite.get_category()
10 cate_id = suite.get_category()
11 cate_name = [cate_id["data"][category_name]]
12 cases_dict, case_id_list = suite.get_cases_category(cate_name)
13
14 # 主车控制相关逻辑
15 if vehicle_name:
16 vehicle_dict = suite.get_vehicle_id([vehicle_name])[1]
17 if vehicle_name not in vehicle_dict.keys():
18 print(f"vehicle_name:{vehicle_name} inexistence")
19 return
20 vehicle_id = vehicle_dict[vehicle_name]
21 else:
22 vehicle_id = None
23 print(f"vehicle_name:{vehicle_name},vehicle_id:{vehicle_id}")
24
25 # 案例名称逻辑
26 if case_name:
27 case_id_list = cases_dict[case_name]
28 print(f" case_name:{case_name}")
29
30 # 启动案例
31 session_id, task_ids = suite.run_task(case_id_list, vehicle_id=vehicle_id)
32 time.sleep(10)
33 # suite.stop_task(task_id=task_ids, sessions_id=[session_id])
34 # 等待案例运行完毕
35 # falg = suite.suite_queue_check()
36 # if falg is True:
37 # # 获取案例运行结果
38 # suite.get_task_result(task_ids)
39 suite.is_ended(task_ids)
40
41
42SimOneUrl = "http://172.31.9.85:8088/"
43loginData = {
44 "username": 'admin',
45 "password": 'admin',
46}
47LoginPolicy("standalone")
48if __name__ == '__main__':
49 main("new", "test")
返回值
response:{"code":0,"data":{"tasks":[{"parentId":"-1","loading":false,"deleted":null,"deleteTime":null,"createAt":"2024-06-19T06:22:14.000Z","updateAt":"2024-06-19T06:22:23.000Z","id":"39e2f0e7-5315-47da-b4d1-79b4427d0beb","userId":"standalone","caseId":"6b6fcd60-2d1f-11ef-905e-8f06be1a01ef","case":{"schema":"casedef"}}
9. 主车相关
9.1 导入主车
API
"""
def delete_sessions_api(self, payload: dict):
"""
sessions删除API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, delete_sessions_url, json=payload).json()
def delete_task_api(self, payload: dict):
"""
task删除API
@param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
@return:
"""
return self.send(self.post, delete_task_url, json=payload).json()
"""
功能实现
1class File:
2 """
3 文件父类
4 """
5
6 def __init__(self, file_path: str):
7 if not exists(file_path):
8 raise FileNotFoundError
9 self._file_path = file_path
10 self._data = None
11class FileReader(File):
12 """
13 读取文件
14 """
15
16 def __init__(self, file_path: str):
17 super(FileReader, self).__init__(file_path)
18
19 def read_byte(self) -> bytes:
20 with open(self._file_path, 'rb') as f:
21 return f.read()
22
23 def read_str(self) -> str:
24 with open(self._file_path, 'r', encoding='utf-8') as f:
25 return f.read()
26
27 def read_json(self) -> json:
28 with open(self._file_path, 'r', encoding='utf-8') as f:
29 return json.load(f)
30
31def import_vehicle_api(self,payload:dict):
32 """
33 导入主车
34 @param payload: eg {"vehicleData": {"byId": {vehicle_id: vehicle_data},
35 "allIds": [vehicle_id]}}
36 @return:
37 """
38 return self.send(self.post,import_vehicle_url,json=payload).json()
39
40def get_vehicle_data(file_path: str):
41 vehicle_info = FileReader(file_path).read_json()
42 vehicle_id = vehicle_info.get("id")
43 return vehicle_info, vehicle_id
44
45def import_vehicle(self, file_path:str)->str:
46 """
47 导入主车
48 @param file_path: 主车文件
49 @return: 主车id
50 """
51 vehicle_data,vehicle_id = self.get_vehicle_data(file_path)
52 payload = {"vehicleData": {"byId": {vehicle_id: vehicle_data},
53 "allIds": [vehicle_id]}}
54 result = self.import_vehicle_api(payload)
55 return result["data"]["id"]
56
57def main(suite_name:str=None):
58 suite = Suite()
59 # suite.get_suite(suite_name)
60 suite.import_vehicle('c:/test.json')
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/sessions/delete', 'headers': {'Content-Type': 'application/json', 'Authorization': '5a3662a3-2fbb-4790-b40d-42f600e63801'}, 'json': {'ids': ['bc344bf1-4bd3-493e-a4d3-95f98dcc3e48']}}
response:{"code":0,"data":{}}
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/tasks/delete', 'headers': {'Content-Type': 'application/json', 'Authorization': '5a3662a3-2fbb-4790-b40d-42f600e63801'}, 'json': {'ids': ['18a0fafe-d1e2-404b-b5e8-b4f3ea4c8e86']}}
response:{"code":0,"msg":"success"}
9.2 删除主车
API
"""
def delete_vehicles_api(self, vehicles_id: str):
"""
删除主车
@param vehicles_id: 主车id
@return:
"""
url = self.delete_vehicle_url.format(vehicles_id=vehicles_id)
return self.send(self.delete, url)
"""
功能实现
1 def delete_vehicles_api(self, vehicles_id: str):
2 """
3 删除主车
4 @param vehicles_id: 主车id
5 @return:
6 """
7 url = delete_vehicle_url.format(vehicles_id=vehicles_id)
8 return self.send(self.delete, url)
9
10 def delete_vehicle(self,id:str):
11 """
12 删除主车
13 @param id: 主车id
14 @return:
15 """
16 self.delete_vehicles_api(id)
17def main(category_name:str,case_name:str=None,vehicle_name:str=None):
18 suite = Suite()
19 suite.get_category()
20 cate_id = suite.get_category()
21 cate_name = [cate_id["data"][category_name]]
22 cases_dict, case_id_list = suite.get_cases_category(cate_name)
23 print(case_name)
24 # 主车控制相关逻辑
25 if vehicle_name:
26 vehicle_dict = suite.get_vehicle_id([vehicle_name])[1]
27 if vehicle_name not in vehicle_dict.keys():
28 print(f"vehicle_name:{vehicle_name} inexistence")
29 return
30 vehicle_id = vehicle_dict[vehicle_name]
31 else:
32 vehicle_id = None
33 print(f"vehicle_name:{vehicle_name},vehicle_id:{vehicle_id}")
34 suite.delete_vehicle(vehicle_id)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("转向冲突", "转向冲突8", "test")
返回值
response:{"code":0,"data":{"id":"cce9e320-0db0-11ef-98b6-f5137907bac2"}}
9.3 获取主车信息
API
"""
def get_vehicle_api(self):
"""
获取主车信息
@return:
"""
return self.send(self.get,self.get_vehicle_url).json()
"""
功能实现
1 def get_vehicle_api(self):
2 """
3 获取主车信息
4 @return:
5 """
6 return self.send(self.get, get_vehicle_url).json()
7
8
9 def get_vehicle(self, userid: str = None):
10 """
11 根据用户信息获取主车信息
12 @param userid:
13 @return:
14 """
15 global vehicle_data
16 vehicle_data = {}
17 res = self.get_vehicle_api()
18 # print(f"get_vehicle_api response ->: {res}")
19 data = res["data"]["list"]["byId"]
20 id_list = res["data"]["list"]["allIds"]
21 if userid:
22 for id in id_list:
23 if data[id]["userId"] == userid:
24 vehicle_data.setdefault(data[id]["name"], data[id]["id"])
25 else:
26 for id in id_list:
27 vehicle_data.setdefault(data[id]["userId"], {}).update({data[id]["name"]: data[id]["id"]})
28 print("获取到的主车信息->:{}".format(str(vehicle_data)))
29 return vehicle_data
30
31 def get_vehicle_id(self, vehicle_name: list) -> list and dict:
32 """
33 根据主车名称获取主车ID
34 @param vehicle_name:
35 @return:
36 """
37 vehicle_id_dict = {}
38 vehicle_id_list = []
39 vehicle_list = []
40 for i in vehicle_name:
41 for k, v in self.get_vehicle().items():
42 vehicle_list.append(v)
43 for vehicle_dict in vehicle_list:
44 # print("vehicle_dict", vehicle_dict)
45 vehicle_dict_key = dict(vehicle_dict).items()
46 for vehicle_dict_k, vehicle_dict_v in vehicle_dict_key:
47 if i in vehicle_dict_k:
48 vehicle_name_id = vehicle_dict[i]
49 vehicle_id_list.append(vehicle_name_id)
50 vehicle_id_dict.setdefault(i, vehicle_name_id)
51
52 print("vehicle_id_list->:", vehicle_id_list, "\nvehicle_id_dict->:", vehicle_id_dict)
53 return vehicle_id_list, vehicle_id_dict
54
55
56
57def main(category_name:str,case_name:str=None,vehicle_name:str=None):
58 suite = Suite()
59 suite = Suite()
60 suite.get_category()
61 cate_id = suite.get_category()
62 cate_name = [cate_id["data"][category_name]]
63 cases_dict, case_id_list = suite.get_cases_category(cate_name)
64
65 # 主车控制相关逻辑
66 if vehicle_name:
67 vehicle_dict = suite.get_vehicle_id([vehicle_name])[1]
68 if vehicle_name not in vehicle_dict.keys():
69 print(f"vehicle_name:{vehicle_name} inexistence")
70 return
71 vehicle_id = vehicle_dict[vehicle_name]
72 else:
73 vehicle_id = None
74 print(f"vehicle_name:{vehicle_name},vehicle_id:{vehicle_id}")
75
76 # 案例名称逻辑
77 if case_name:
78 case_id_list = cases_dict[case_name]
79 print(f" case_name:{case_name}")
80
81 # 启动案例
82 session_id, task_ids = suite.run_task(case_id_list, vehicle_id=vehicle_id)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("转向冲突", "转向冲突8", "手动控制-默认")
返回值
{'method': 'GET', 'url': 'http://172.31.9.85:30083/api-asset/vehicles', 'headers': {'Content-Type': 'application/json', 'Authorization': 'e5033d43-2368-4fd0-9c4b-299c4d3ba8d9'}}
10. 测试集相关
10.1 获取测试集
API
"""
def get_suite_api(self):
"""
get_suite
@return:
"""
return self.send(self.get, url=get_suites_url).json()
"""
运行测试集
1 def get_suite_api(self):
2 """
3 get_suite
4 @return:
5 """
6 return self.send(self.get, url=get_suites_url).json()
7
8
9 def get_suite(self,suite_name:str=None):
10 """
11 :return:
12 """
13 response = self.get_suite_api()
14 data = response['data']
15 suite_dict = {}
16 for id in data['allIds']:
17 suite_dict.setdefault(data['byId'][id]['name'], {}).update({"caseIds": data['byId'][id]['caseIds']})
18 print("suite_dict",suite_dict)
19 if not suite_name:
20 return suite_dict
21 else:
22 #print("suite_dict[suite_name]:",suite_dict[suite_name])
23 return suite_dict[suite_name]
24
25def main(suite_name:str=None):
26 suite = Suite()
27 suite.get_suite(suite_name)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("test")
返回值
response:{"code":0,"data":{"byId":{"ea6d0670-0db5-11ef-98b6-f5137907bac2":{"schema":"suite","id":"ea6d0670-0db5-11ef-98b6-f5137907bac2","userId":"standalone","parentId":"","name":"test","created":1715226044506,"lastModified":1715226044506,"createUserRole":1,"caseIds":["f5bbfb2c-619a-4812-90c2-75a84247a4db"]}},"allIds":["ea6d0670-0db5-11ef-98b6-f5137907bac2"]}}
suite_dict {'test': {'caseIds': ['f5bbfb2c-619a-4812-90c2-75a84247a4db']}}
10.2 运行测试集
API
"""
def get_suite_api(self):
"""
get_suite
@return:
"""
return self.send(self.get, url=get_suites_url).json()
def run_suite_api(self, payload:dict):
"""
run_suite
@param payload: payload
@return:
"""
return self.send(self.post, url=self.run_suite_url, json=payload).json()
"""
功能实现
1 def get_suite_api(self):
2 """
3 get_suite
4 @return:
5 """
6 return self.send(self.get, url=get_suites_url).json()
7
8
9 def get_suite(self,suite_name:str=None):
10 """
11 :return:
12 """
13 response = self.get_suite_api()
14 data = response['data']
15 suite_dict = {}
16 for id in data['allIds']:
17 suite_dict.setdefault(data['byId'][id]['name'], {}).update({"caseIds": data['byId'][id]['caseIds']})
18 print("suite_dict",suite_dict)
19 if not suite_name:
20 return suite_dict
21 else:
22 #print("suite_dict[suite_name]:",suite_dict[suite_name])
23 return suite_dict[suite_name]
24
25 def run_suite_api(self, payload: dict):
26 """
27 run_suite
28 @param payload: payload
29 @return:
30 """
31 return self.send(self.post, url=run_suite_url, json=payload).json()
32
33
34 def run_suite(self,suite_name:str,taskName:str =None,vehicle_id:str=None):
35 if taskName is None:
36 def creat_task_name():
37 return "taskName_" + time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())
38 taskName = creat_task_name()
39 caseid_list=self.get_suite(suite_name)['caseIds']
40 payload = {'caseIds': caseid_list,
41 'taskName': taskName}
42 if vehicle_id:
43 # vehicle_module = VehicleBusiness()
44 # vehicle_module.get_vehicle()
45 payload.update({"overrideVehicleId":vehicle_id})
46 response=self.run_suite_api(payload)
47 data = response['data']
48 return data['sessionId'], data['taskIds']
49
50def main(suite_name:str=None):
51 suite = Suite()
52 # suite.get_suite(suite_name)
53 suite.run_suite(suite_name)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("test")
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-task/tasks', 'headers': {'Content-Type': 'application/json', 'Authorization': '7d4c315b-dbd1-4f4b-8552-ff66be9346ec'}, 'json': {'caseIds': ['f5bbfb2c-619a-4812-90c2-75a84247a4db'], 'taskName': 'taskName_2024-05-09_11:49:56'}}
response:{"code":0,"data":{"sessionId":"5b4fc9fb-8da4-42f4-8eef-7e4522b85dd4","taskIds":["0b933b59-b4d6-49e8-b656-de52a8561fb6"]}}
10.3 获取运行案例集信息
API
"""
def suite_queue_api(self):
"""
suite_queue
@return:
"""
return self.send(self.get, url=self.queue_status_url).json()
"""
功能实现
1 def suite_queue_api(self):
2 """
3 suite_queue
4 @return:
5 """
6 return self.send(self.get, url=queue_status_url).json()
7
8
9 def suite_queue_check(self,n=10):
10 """
11 @param n:cycle index
12 @return:
13 """
14 if n==1:
15 print("-----------------------The test case run fail--------------------------------------")
16 return False
17 while(1):
18 try:
19 assert self.suite_queue_api()
20 response = self.suite_queue_api()
21 assert response["code"]==0
22 except Exception as e:
23 return -1
24 queue_info = response["data"]
25 running,pending,waiting = queue_info["running"],queue_info["pending"],queue_info["waiting"]
26
27 if running == 0 and pending == 0 and waiting == 0:
28 print("-----------------------The test case run finish--------------------------------------")
29 return True
30 else:
31 time.sleep(interval)
32
33def main(suite_name:str=None):
34 suite = Suite()
35 # suite.get_suite(suite_name)
36 suite.run_suite(suite_name)
37 suite.suite_queue_check()
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("test")
返回值
{'method': 'GET', 'url': 'http://172.31.9.85:30083/api-task/tasks/queue?own=true', 'headers': {'Content-Type': 'application/json', 'Authorization': 'f083c671-f6fe-4d64-b775-3f0539eca7c9'}}
response:{"code":0,"data":{"total":2,"running":1,"pending":1,"waiting":1,"finished":0,"estimatedTaskDuration":87.22495652173913}}
10.4 获取任务集中的task_id
API
"""
def get_taskassemble_api(self):
'''
获取测试案例集
@param
@return:
'''
return self.send(self.get, get_taskassemble_url).json()
"""
功能实现
1 def get_taskassemble_api(self):
2 '''
3 获取测试案例集
4 @param
5 @return:
6 '''
7 return self.send(self.get, get_taskassemble_url).json()
8 def get_task_id_of_task_set(self) -> list:
9 """
10 获取任务集合中所有测试案例的task_id
11 @return: list
12 """
13 response = self.get_taskassemble_api()
14 _task_id_list = response["data"]["list"]
15 index = 0
16 task_set_id_list = []
17 for i in _task_id_list:
18 index += 1
19 task_set_id_list.append(i["id"])
20 print("task_set_id_list", task_set_id_list)
21 return task_set_id_list
22def main(suite_name:str=None):
23 suite = Suite()
24 suite.run_suite(suite_name)
25 suite.get_task_id_of_task_set()
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("test")
返回值
task_set_id_list [id1,id2,...]
11. 地图相关
11.1 导入地图
API
"""
def import_map_api(self, payload: dict, files: dict):
"""
导入地图API
@param payload:传参字典
@param files: 传参文件
@return:
"""
self.headers = {}
return self.send(self.post, import_map_url, data=payload, files=files).json()
"""
功能实现
1 def import_map_api(self, payload: dict, files: dict):
2 """
3 导入地图API
4 @param payload:传参字典
5 @param files: 传参文件
6 @return:
7 """
8 self.headers = {}
9 return self.send(self.post, import_map_url, data=payload, files=files).json()
10
11 def import_map(self, xodr_path: str, thumbnail_path: str):
12 """
13 导入地图方法
14 @param xodr_path: 地图文件
15 @param thumbnail_path: 地图对应的图像
16 @return:
17 """
18 payload = {"params": json.dumps(
19 {"category": "customized", "id": "new_" + Faker('zh_CN').uuid4(),
20 "name": os.path.splitext(os.path.basename(xodr_path))[0], "size": 512,
21 "ppm": 10, "bgColor": "#dddddd", "reproject": True, "reprojectOrigin": False, "reprojectOriginLat": 0,
22 "reprojectOriginLng": 0, "tags": [], "notes": "",
23 "header": {"minX": -210.20535534122396, "minY": -149.68815701999185, "minZ": -1.862645149230957e-9,
24 "maxX": 237.95535534122394, "maxY": 135.43815701999196, "maxZ": 2.7940070024635385e-9,
25 "centerX": 97.12480158531203, "centerY": 24.463606820251727, "centerZ": 100,
26 "localEnuExt": "6378137,0,0;0,1,0;0,0,1;1,0,0"}})}
27 files = {'xodr': open(xodr_path, 'rb'), "thumbnail": open(thumbnail_path, 'rb')}
28 result = self.import_map_api(payload, files)
29 if result["code"] == 0:
30 print(f"导入地图{xodr_path}成功,id:{result['data']['mapId']}")
31 else:
32 print(f"导入地图{xodr_path}失败,返回结果:{result}")
33 raise f"导入地图{xodr_path}失败,返回结果:{result}"
34 res_dict = {"code": result["code"], "mapId": result["data"]["mapId"],
35 "name": os.path.basename(os.path.basename(xodr_path))}
36 return res_dict
37
38
39def main():
40 suite = Suite()
41
42 suite.import_map(r"D:\Project\SimOneAutomation\simone_automation\Sysdata\Public\import\Map\xodr\标志牌测试.xodr",
43 r"D:\Project\SimOneAutomation\simone_automation\Sysdata\Public\import\Map\img\import_map.png"
44 )
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
{'method': 'POST', 'url': 'http://172.31.9.85:30083/api-asset/maps', 'headers': {'Authorization': '92400a5e-0e20-4d34-bfb3-05f9344f4889'}, 'data': {'params': '{"category": "customized", "id": "", "name": "\\u6807\\u5fd7\\u724c\\u6d4b\\u8bd5", "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-09, "maxX": 237.95535534122394, "maxY": 135.43815701999196, "maxZ": 2.7940070024635385e-09, "centerX": 97.12480158531203, "centerY": 24.463606820251727, "centerZ": 100, "localEnuExt": "6378137,0,0;0,1,0;0,0,1;1,0,0"}}'}, 'files': {'xodr': <_io.BufferedReader name='D:\\Project\\SimOneAutomation\\simone_automation\\Sysdata\\Public\\import\\Map\\xodr\\标志牌测试.xodr'>, 'thumbnail': <_io.BufferedReader name='D:\\Project\\SimOneAutomation\\simone_automation\\Sysdata\\Public\\import\\Map\\img\\import_map.png'>}}
response:{"code":0,"data":{"mapId":"01ca5bba-d804-4d32-900f-742fa958d47f"}}
import map D:\Project\SimOneAutomation\simone_automation\Sysdata\Public\import\Map\xodr\标志牌测试.xodrsuccess
11.2 获取地图信息
API
"""
def get_map_api(self):
"""
获取地图
@return:
"""
return self.send(self.get, self.get_map_url).json()
"""
功能实现
1 def get_map_api(self):
2 """
3 获取地图
4 @return:
5 """
6 return self.send(self.get, self.get_map_url).json()
7 def get_map_id(self,userid:str=None,map_name:str=None):
8 """
9 按条件获取地图信息,默认获取所有地图
10 @param userid: 用户id
11 @param map_name: 地图名字
12 @return:
13 """
14 global map_data
15 map_data={}
16 try:
17 result = self.get_map_api()
18 # print(len(result['data']['maps']))
19 map_info = result['data']['maps']
20
21 if userid:
22 for map in map_info:
23 if map["userId"] == userid:
24 map_data.setdefault(map["name"],map["id"])
25 elif map_name:
26 for map in map_info:
27 if map["name"] == map_name:
28 map_data = {map["name"]: map["id"]}
29 else:
30 for map in map_info:
31 map_data.setdefault(map["userId"],{}).update({map["name"]: map["id"]})
32 return map_data
33
34 except Exception as e:
35 print(e)
36def main():
37 suite = Suite()
38
39 suite.get_map_id()
40
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
response:{"code":0,"data"...}
11.3 删除地图
API
"""
def delete_map_api(self,payload:dict):
"""
删除地图
@param payload: eg:{ids: ["27a0bbc4-5d4d-48c1-9187-62df794dadae"]}
@return:
"""
return self.send(self.post, delete_map_url, json=payload).json()
"""
功能实现
1 def delete_map_api(self,payload:dict):
2 """
3 删除地图
4 @param payload: eg:{ids: ["27a0bbc4-5d4d-48c1-9187-62df794dadae"]}
5 @return:
6 """
7 return self.send(self.post, delete_map_url, json=payload).json()
8
9 def delete_map(self,id:list):
10 """
11 批量删除地图
12 @param id: 地图id列表
13 @return:
14 """
15 print("删除的地图列表-》{}".format(str(id)))
16 payload = {"ids": id}
17 self.delete_map_api(payload)
18
19
20def main():
21 suite = Suite()
22
23 suite.delete(["'92400a5e-0e20-4d34-bfb3-05f9344f4889'"])
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
response:{"code":0,"data"...}
12. 判定相关
12.1 获取案例判定信息
API
"""
def get_judgements_api(self, caseId, judgementId=None):
"""
获取判定信息API
@param caseId: 案例ID
@param judgementId: 判定ID
@return:
"""
if judgementId:
url = get_judgement_url.format(caseId=caseId,judgementId=judgementId)
else:
url = get_judgements_url.format(caseId=caseId)
response = self.send(self.get, url).json()
return response
"""
功能实现
1 def get_judgements_api(self, caseId, judgementId=None):
2 """
3 获取判定信息API
4 @param caseId: 案例ID
5 @param judgementId: 判定ID
6 @return:
7 """
8 if judgementId:
9 url = get_judgement_url.format(caseId=caseId,judgementId=judgementId)
10 else:
11 url = get_judgements_url.format(caseId=caseId)
12 response = self.send(self.get, url).json()
13 return response
14
15 def get_judgements_method(self, caseId:str, judgementId:str = None):
16 """
17 获取判定信息
18 @param caseId: 案例ID
19 @param judgementId: 判定ID
20 @return:
21 """
22 response = self.get_judgements_api(caseId,judgementId)
23 print("得到的扩展判定信息:",response["data"][1])
24 return response
25
26
27def main():
28 suite = Suite()
29
30 suite.get_judgements_api("ebd4cf06-b66f-4e03-9294-5f60f55d453a")
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
response:{"code":0,"msg":"success","data":[{"id":"timeout","name":"超时","type":"timeout","category":"general","enabled":true,"scope":{"type":"global","position":{"x":0,"y":0,"z":0},"heading":{"x":0,"y":0,"z":0,"w":1},"size":{"x":10,"y":10,"z":0}},"conditions":[{"variable":"timeout","value":600}],"settings":{"action":"failure","logLevel":"error","logInfo":""},"builtIn":true,"lock":true,"userId":"admin","schema":"judgement"},{"id":"collision","name":"碰撞","type":"collision","category":"general","enabled":true,"scope":{"type":"global","position":{"x":0,"y":0,"z":0},"heading":{"x":0,"y":0,"z":0,"w":1},"size":{"x":10,"y":10,"z":0}},"conditions":[],"settings":{"action":"failure","logLevel":"error","logInfo":""},"builtIn":true,"lock":true,"userId":"admin","schema":"judgement"}]}
12.2 更新判定信息
API
"""
def update_judgement_method(self, caseId, judgementId="collision"):
__collision = {"schema": "judgement", "settings": {"logLevel": "error", "action": "failure", "logInfo": ""},
"scope": {"size": {"x": 10, "y": 10, "z": 0}, "heading": {"w": 1, "x": 0, "y": 0, "z": 0},
"position": {"x": 0, "y": 0, "z": 0},
"type": "global"}, "builtIn": True,
"name": "碰撞", "lock": True, "id": "collision",
"type": "collision", "category": "general",
"conditions": [], "userId": "admin",
"enabled": True}
payload = json.dumps(__collision)
judgement_url = "api-asset/cases/{caseId}/judgements/{judgementId}"
response = self.send(self.put, judgement_url.format(caseId=caseId, judgementId=judgementId), data=payload)
print("更新扩展判定信息")
print("status_code:", response.status_code)
"""
功能实现
1 def update_judgement_method(self, caseId, judgementId="collision"):
2 __collision = {"schema": "judgement", "settings": {"logLevel": "error", "action": "failure", "logInfo": ""},
3 "scope": {"size": {"x": 10, "y": 10, "z": 0}, "heading": {"w": 1, "x": 0, "y": 0, "z": 0},
4 "position": {"x": 0, "y": 0, "z": 0},
5 "type": "global"}, "builtIn": True,
6 "name": "碰撞", "lock": True, "id": "collision",
7 "type": "collision", "category": "general",
8 "conditions": [], "userId": "admin",
9 "enabled": True}
10 payload = json.dumps(__collision)
11 judgement_url = "api-asset/cases/{caseId}/judgements/{judgementId}"
12 response = self.send(self.put, judgement_url.format(caseId=caseId, judgementId=judgementId), data=payload)
13 print("更新扩展判定信息")
14 print("status_code:", response.status_code)
15
16
17def main(category_name: str, case_name: str):
18 """
19 category_name:案例库名称
20 case_name:案例名称
21 reset:是否重置判定
22 """
23 LoginPolicy("standalone")
24 suite = Suite()
25 suite.get_category()
26
27 # 获取caseid逻辑
28 cate_id = suite.get_category()
29 cate_name = [cate_id["data"][category_name]]
30 cases_dict, case_id_list = suite.get_cases_category(cate_name)
31 case_id = cases_dict[case_name][0]
32 suite.get_judgements_method(case_id)
33 suite.update_judgement_method(case_id)
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main("new", "test_4")
返回值
更新扩展判定信息
status_code: 202
13. 任务运行结果相关
13.1 获取运行案例集信息
API
"""
def get_task_result_api(self,task_id:str):
"""
获取指定task的结果
@param task_id:
@return:
"""
return self.send(self.get,task_result_url.format(id=task_id)).json()
"""
功能实现
1 def get_task_result_api(self,task_id:str):
2 """
3 获取指定task的结果
4 @param task_id:
5 @return:
6 """
7 return self.send(self.get,task_result_url.format(id=task_id)).json()
8
9 def get_task_result(self, task_id_list: list = None) -> list:
10 """
11 获取任务集中的 案例名称,caseId,task_id,运行结果
12 @param task_id_list: 任务id列表
13 @param task_set_id: 任务集合id
14 @return:
15 """
16
17 task_result_list = []
18 for task_id in task_id_list:
19 result = self.get_task_result_api(task_id)
20 case_name = result["data"]["tasks"][0]["case"]["name"]
21 case_id = result["data"]["tasks"][0]["caseId"]
22 task_id = result["data"]["tasks"][0]["id"]
23 task_result = result["data"]["tasks"][0]["pass"]
24 if task_result != True: task_result = False
25 task_result_list.append({"case_name": case_name,
26 "case_id": case_id,
27 "task_id": task_id,
28 "task_result": task_result})
29 print("task_result_list->", task_result_list)
30 return task_result_list
31
32
33def main():
34 suite = Suite()
35 # 入参id taskid 可以用 run_task方法中的返回值获取
36 suite.get_task_result(["51ec8581-4563-49c4-8ce1-ba96962b278b"])
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 main()
返回值
task_result_list-> [{'case_name': 'test_4-copy', 'case_id': 'f5bbfb2c-619a-4812-90c2-75a84247a4db', 'task_id': '51ec8581-4563-49c4-8ce1-ba96962b278b', 'task_result': False}]
13.2 获取任务集列表信息
API
"""
def get_task_list_api(self):
"""
获取任务列表集合
"""
response = self.send(self.get, url=get_task_list_url).json()
"""
功能实现
1 def get_task_list_api(self):
2 """
3 获取任务列表集合
4 """
5 response = self.send(self.get, url=get_task_list_url).json()
调用示例
1SimOneUrl = "http://172.31.9.85:30083/"
2loginData = {
3 "username": 'admin',
4 "password": 'admin',
5}
6LoginPolicy("standalone")
7if __name__ == '__main__':
8 test = Suite()
9 test.get_task_list_api()
返回值
response:{"code":0,"data":{"list":[{"parentId":null,"deleted":null,"deleteTime":null,"createAt":"2024-05-16T02:34:13.000Z","updateAt":"2024-05-16T02:35:08.000Z",....}
13.3 下载测试报告
API
"""
def export_report_api(self, sessions_id: str):
"""
导出测试报告API
@param sessions_id: sessions_id
@return: Response
"""
self.headers.update({"Language": "zh-Hans"})
return self.send(self.get, export_report_url.format(sessions_id=sessions_id)).json()
def download_report_api(self, sessions_id: str):
"""
下载测试报告API
@param sessions_id: sessions_id
@return: Response
"""
return self.send(self.get, download_report_url.format(sessions_id=sessions_id)).content
"""
功能实现
1 def export_report_api(self, sessions_id: str):
2 """
3 导出测试报告API
4 @param sessions_id: sessions_id
5 @return: Response
6 """
7 self.headers.update({"Language": "zh-Hans"})
8 return self.send(self.get, export_report_url.format(sessions_id=sessions_id)).json()
9
10 def download_report_api(self, sessions_id: str):
11 """
12 下载测试报告API
13 @param sessions_id: sessions_id
14 @return: Response
15 """
16
17 return self.send(self.get, download_report_url.format(sessions_id=sessions_id)).content
18
19 def download_report(self, sessions_id: str, download_path: str, download_name: str) -> None:
20 """
21 下载测试报告
22 @param sessions_id: sessions_id
23 @return: Response
24 """
25 self.export_report_api(sessions_id)
26 pdf_data = self.download_report_api(sessions_id)
27 download_pathname = os.path.join(download_path, download_name)
28 with open(download_pathname, mode="wb") as f:
29 f.write(pdf_data)
调用示例
1LoginPolicy("standalone")
2if __name__ == '__main__':
3 test = Suite()
4 # 测试任务集ID
5 test.download_report("54c0806b-ba80-4821-ae25-49f7c284f486", r"C:\Users\Administrator\Desktop\test", "test.pdf")
返回值
response:{"code":0,"data":{"success":true}}
测试报告二进制数据
14. 附录参考代码
1import base64
2import copy
3import hashlib
4import math
5import random
6import shutil
7import zipfile
8from datetime import datetime
9from os.path import exists
10from uuid import uuid4
11
12from Crypto.Cipher import AES
13from faker import Faker
14from requests import request, Response
15import json
16from urllib.parse import urljoin
17import os
18import time
19
20fake = Faker('zh_CN')
21
22interval = 10
23
24# header
25header = {
26 "Content-Type": "application/json",
27}
28
29
30# Environment Path
31class EnvPath:
32 token = "TOKEN"
33
34
35class Prefix:
36 UserServer = "api-user"
37 CaseServer = "api-case"
38 AssetServer = "api-asset"
39 TaskServer = "api-task"
40
41
42# token
43_token = os.environ.get(EnvPath.token)
44
45""" 登录相关接口 """
46user_check_url = Prefix.UserServer + "/users/check"
47health = Prefix.UserServer + "/health" # 检查服务是否正常
48cloud_login_url = Prefix.UserServer + "/users/login" # 云端登录
49standalone_login_url = Prefix.UserServer + "/users/standalone" # 单机版登录
50login_check = Prefix.UserServer + "/users/check" # user check
51
52""" 案例库目录相关接口 """
53categories_url = Prefix.CaseServer + "/categories" # 案例库目录
54get_categories_url = Prefix.CaseServer + "/categories?withCases=false" # 获取所有案例库
55get_cases_url = "api-case/cases?page=1&filter={category}&pageSize=100"
56get_cases_url = Prefix.CaseServer + "/cases?page={page}&filter={category}&pageSize=100" # 获取当前案例库的所有案例
57delete_categories_url = Prefix.CaseServer + "/categories/{}" # 删除案例库目录
58
59""" 上传文件相关接口 """
60file_md5_url = Prefix.AssetServer + "/files/{}?raw={}" # 验证文件MD5
61upload_file_url = Prefix.AssetServer + "/files/{}/upload?raw={}" # 上传文件
62
63""" 测试案例相关接口 """
64case_import_url = Prefix.AssetServer + "/cases/import" # 导入案例
65case_details_url = Prefix.CaseServer + "/cases/{case_id}/data" # 案例详情
66delete_case_url = Prefix.CaseServer + "/trash" # 删除案例
67convert_replay_case_url = Prefix.TaskServer + "/tasks/{id}/convert2case" # 转换回放案例
68
69""" 测试任务相关接口 """
70create_task_url = Prefix.TaskServer + "/tasks" # 创建task
71stop_task_url = Prefix.TaskServer + "/tasks/stop" # 停止task
72stop_sessions_url = Prefix.TaskServer + "/sessions/stop" # 会话停止
73delete_task_url = Prefix.TaskServer + "/tasks/delete" # 删除task
74delete_sessions_url = Prefix.TaskServer + "/sessions/delete" # 删除停止
75result_url = Prefix.TaskServer + "/tasks/task?taskIds={task_id}" # 删除停止 案例运行结果详情
76pause_task_url = Prefix.TaskServer + "/sessions/{task_id}/pause" # 任务暂停
77resume_task_url = Prefix.TaskServer + "/sessions/{task_id}/resume" # 任务暂停后开始
78task_result_url = Prefix.TaskServer + "/tasks/task?taskIds={id}" # 删除停止 案例运行结果详情
79
80""" 主车相关接口 """
81import_vehicle_url = Prefix.AssetServer + "/vehicles/import" # 导入主车
82delete_vehicle_url = Prefix.AssetServer + "/vehicles/{vehicles_id}" # 删除主车
83get_vehicle_url = Prefix.AssetServer + "/vehicles" # 获取主车信息
84
85""" 地图相关接口 """
86import_map_url = Prefix.AssetServer + "/maps" # 导入地图
87delete_map_url = Prefix.CaseServer + "/maps/trash" # 删除地图
88get_map_url = Prefix.CaseServer + "/maps?pageSize=100" # 获取地图相关信息
89road_service_url = Prefix.TaskServer + "/sce" # 启动路网服务
90laneTypeIfInside_url = Prefix.TaskServer + "/sce/{map_id}/location/laneTypeIfInside" # 监测点是否在车道内
91
92""" 数据驱动相关接口 """
93import_data_driven_url = Prefix.AssetServer + "/dd" # 导入数据驱动源
94delete_data_dirven_url = Prefix.AssetServer + "/dd/{id}" # 删除数据驱动源
95
96""" 资源相关接口 """
97import_asset_url = Prefix.AssetServer + "/assets" # 资源导入
98asset_repeat_url = Prefix.AssetServer + "/assets/isrepeat" # 资源查重
99get_asset_url = Prefix.AssetServer + "/assets?schema={}" # 获取资源信息
100delete_asset_url = Prefix.AssetServer + "/assets/{}" # 删除对应资源
101
102""" 案例导出相关 """
103export_case_url = Prefix.AssetServer + "/cases/export" # 案例导出
104download_case_url = Prefix.AssetServer + "/download/{pake_id}" # 案例下载
105
106""" 测试案例集相关 """
107get_suites_url = Prefix.AssetServer + "/suites" # 获取测试集
108run_suite_url = Prefix.TaskServer + "/tasks" # 运行测试集
109get_taskassemble_url = Prefix.TaskServer + "/tasks?finished=true&page=0&pageSize=12&own=true&expandedIds={task_set_id}" # 获取测试案例集合
110queue_status_url = Prefix.TaskServer + "/tasks/queue?own=true" # 套件运行状态检查
111
112""" 案例判定相关 """
113get_judgements_url = Prefix.AssetServer + "/cases/{caseId}/judgements"
114# get_judgement_url = get_judgements_url + "/{judgementId}"
115get_judgement_url = "api-asset/cases/{caseId}/judgements/{judgementId}"
116
117
118# f"api-asset/cases/{caseId}/judgements/{judgementId}"
119# url = f"api-asset/cases/{caseId}/judgements"
120
121class UrlCodeType:
122 unquote = "unquote"
123 quote = "quote"
124
125
126class File:
127 """
128 文件父类
129 """
130
131 def __init__(self, file_path: str):
132 if not exists(file_path):
133 raise FileNotFoundError
134 self._file_path = file_path
135 self._data = None
136
137
138class FileReader(File):
139 """
140 读取文件
141 """
142
143 def __init__(self, file_path: str):
144 super(FileReader, self).__init__(file_path)
145
146 def read_byte(self) -> bytes:
147 with open(self._file_path, 'rb') as f:
148 return f.read()
149
150 def read_str(self) -> str:
151 with open(self._file_path, 'r', encoding='utf-8') as f:
152 return f.read()
153
154 def read_json(self) -> json:
155 with open(self._file_path, 'r', encoding='utf-8') as f:
156 return json.load(f)
157
158
159class RquestApi():
160 def __init__(self):
161 super(RquestApi, self).__init__()
162 self._headers = {"Content-Type": "application/json"}
163 self._token = os.environ.get(EnvPath.token)
164 self._host_ip = SimOneUrl
165 self.get = "GET"
166 self.post = "POST"
167 self.delete = "DELETE"
168 self.put = "PUT"
169
170 def send(self, method: str, url: str, **kwargs) -> Response:
171 """
172 发送请求
173 method: 请求方法
174 url: 请求地址
175 kwargs: 请求参数
176 """
177 self.headers.update({"Authorization": self.token})
178 complete_url = urljoin(self._host_ip, url)
179 data = dict()
180 data['method'] = method
181 data['url'] = complete_url
182 data['headers'] = self.headers
183 data.update(kwargs)
184 print(data)
185 response = request(verify=False, **data)
186 try:
187 print("response:%s" % str(response.content.decode("utf-8")))
188 self._status_code = response.status_code
189 self._response_code = response.json().get("code")
190 except:
191 pass
192 return response
193
194 @property
195 def token(self):
196 return self._token
197
198 @property
199 def headers(self):
200 return self._headers
201
202 @headers.setter
203 def headers(self, value):
204 self._headers = value
205
206
207class LoginBusiness(RquestApi):
208
209 def cloud_login_api(self, userinfo: dict):
210 """
211 云端登录API
212 @param userinfo:
213 @return:
214 """
215 return self.send(self.post, cloud_login_url, json=userinfo).json()
216
217 def check_username_api(self, username: str):
218 """
219 校验用户名称是否合格
220 @param username:
221 @return:
222 """
223 payload = {'username': username}
224 return self.send(self.post, login_check, json=payload).json()
225
226 def getCheckToken(self) -> str:
227 """
228 校验token是否合格
229 @return:
230 """
231 getCheckUrl = os.path.join(SimOneUrl, user_check_url)
232 payload = {'username': loginData['username']}
233 response = self.send(self.post, getCheckUrl, json=payload)
234 checkToken = json.loads(response.content.decode("utf-8"))['data']['checkToken']
235 return checkToken
236
237 def pad(self, text):
238 """
239 填充函数,使被加密数据的字节码长度是block_size的整数倍
240 @param text:
241 @return:
242 """
243 length = AES.block_size
244 count = len(text.encode('utf-8'))
245 add = length - (count % length)
246 entext = text + (chr(add) * add)
247 return entext
248
249 def str_aes(self, string: str, key: str):
250 """
251 aes 加密
252 @param string:
253 @param key:
254 @return:
255 """
256 aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
257 res = aes.encrypt(self.pad(string).encode("utf8"))
258 msg = str(base64.b64encode(res), encoding="utf8")
259 return msg
260
261 def get_str_aes(self, string: str, username: str, key: str = "eGeVQh0lRyq41I41") -> str:
262 '''
263 @param string:
264 @param username:
265 @param key: AES加密的key
266 @return:
267 '''
268 check_token = self.check_username_api(username)
269 target_string = check_token["data"]["checkToken"] + string
270 msg = self.str_aes(target_string, key)
271 return msg
272
273 @property
274 def _cloud_std_login(self):
275 """
276 云端版本登陆方式
277 @return:
278 """
279 try:
280 new_login_data = copy.deepcopy(loginData)
281 new_login_data['password'] = self.get_str_aes(string=new_login_data['password'],
282 username=new_login_data['username'])
283 print('cloud login data:' + str(new_login_data))
284 response = self.cloud_login_api(userinfo=new_login_data)
285 print("-------", response)
286 print('cloud login request result:' + str(response))
287 token = response['data']['token']
288 os.environ[EnvPath.token] = token
289 print(token)
290 return token
291 except Exception as e:
292 print(str(e))
293 raise print('get token error ')
294
295 @property
296 def _enterprise_std_login(self):
297 """
298 单机版本登录方式
299 @return:
300 """
301 try:
302 getLoginUrl = os.path.join(SimOneUrl, standalone_login_url)
303 response = self.send(self.get, url=getLoginUrl)
304 token = json.loads(response.content.decode("utf-8"))['data']['token']
305 os.environ[EnvPath.token] = token
306 except Exception as e:
307 print(str(e))
308 token = ""
309 # raise AssertionError('get token error ')
310 return token
311
312
313# 登录入口
314class LoginPolicy():
315 standalone = "standalone"
316 cloud = "cloud"
317
318 def __new__(cls, env_name):
319 if env_name == cls.standalone:
320 return LoginBusiness()._enterprise_std_login
321 elif env_name == cls.cloud:
322 return LoginBusiness()._cloud_std_login
323 else:
324 return print("----------input error---------------")
325
326class Suite(RquestApi):
327
328 def __init__(self):
329 super(Suite, self).__init__()
330 self._cyclical = 0
331 self.category_name = "Automation_" + str(random.randint(0, 9999))
332
333 def create_category_api(self, cate_name: str):
334 '''
335 创建案例库
336 @param cate_name: 案例库名
337 @return:
338 '''
339 payload = {"parentId": "", "name": cate_name}
340 return self.send(self.post, categories_url, json=payload).json()
341
342 def create_category(self, cate_name: str = None) -> str:
343 '''
344 创建案例库
345 @param cate_name:
346 @return:
347 '''
348 if not cate_name:
349 cate_name = self.category_name
350 print(f"案例库目录名称:{cate_name}")
351 response = self.create_category_api(cate_name)
352 cate_id = response["data"]["categoryId"]
353 print(f"案例库目录 id :{cate_id}")
354 return cate_id
355
356 def get_category_api(self):
357 """
358 获取案例库列表
359 @return: response
360 """
361 return self.send(self.get, categories_url).json()
362
363 def get_category(self, userid: str = None) -> dict:
364 """
365 获取案例库
366 @param userid: 用户id desc:admin->builtIn
367 @return:
368 """
369 cate_dict = {"data": {}, "parentId": {}}
370 response = self.get_category_api()
371 cate_dict["total"] = response["data"]["total"]
372 if not userid:
373 print("获取当前所有的案例库目录信息")
374 for one in response["data"]["categories"]:
375 cate_dict["data"].setdefault(one["name"], one["id"])
376 cate_dict["parentId"].setdefault(one["name"], one["parentId"])
377 else:
378 print("获取用户{}的案例库目录信息".format(userid))
379 for one in response["data"]["categories"]:
380 if one["userId"] == userid:
381 cate_dict["data"].setdefault(one["name"], one["id"])
382 cate_dict["parentId"].setdefault(one["name"], one["parentId"])
383 print("获取到的案例库->%s" % str(cate_dict))
384 return cate_dict
385
386 def get_category_case_api(self, cate_id: str):
387 """
388 获取当前案例库所有案例
389 @param cate_name: 案例库名
390 @return:
391 """
392 return self.send(self.get, get_cases_url.format(category=cate_id)).json()
393
394 def get_cases_category(self, cate_id: list):
395 """
396 获取当前案例库的所有案例
397 @param cate_id: 案例库目录id
398 @return:
399 """
400
401 def url_code(url: str, way: str):
402 from urllib import parse
403 if way == "unquote":
404 return parse.unquote(url)
405 elif way == "quote":
406 return parse.quote(url)
407
408 page_size = 100
409 # print("get all case id from api by category_id")
410 _filter = {"keyword": "", "categories": cate_id}
411 string = json.dumps(_filter).replace(" ", "")
412 filter = url_code(string, UrlCodeType.quote).replace("%", "%25")
413 response = self.send(self.get, get_cases_url.format(page="1", category=filter)).json()
414 # get case id
415 # print("get_cases_category 入参cate_id:%s" % cate_id)
416 cases_num = response['data']['total']
417 if cases_num >= page_size:
418 if cases_num % page_size == 0:
419 page = cases_num // page_size
420 else:
421 page = cases_num // page_size + 1
422 else:
423 page = 1
424
425 def update_case_id(response, page_size):
426 case_name = response['data']['caseDefs'][page_size]['name']
427 case_id = response['data']['caseDefs'][page_size]['id']
428 case_id_list.append(case_id)
429 cases_dict.setdefault(case_name, [case_id])
430
431 cases_dict = {}
432 case_id_list = []
433 # 如果案例数量是100以内
434 if cases_num <= page_size:
435 for i in range(cases_num):
436 update_case_id(response=response, page_size=i)
437 else:
438 # 如果案例数量超过100了,固定获取案例数量为100个就翻页
439 for i in range(page):
440 response = self.send(self.get, self.get_cases_url.format(page=str(i + 1), category=filter)).json()
441 # cases_num % page_size 是取整表示没有到达最后一页
442 # if i == 0 or i > 0 and cases_num % page_size == 0:
443 if i + 1 != page:
444 # print("xxx page_size:",page_size)
445 for j in range(page_size):
446 # print("xxx j:",j)
447 update_case_id(response=response, page_size=j)
448 # 到最后一页了,因为案例数量不固定所以需要单独计算获取的个数
449 else:
450 for j in range(cases_num % page_size):
451 update_case_id(response=response, page_size=j)
452 return cases_dict, case_id_list
453
454 def get_case_detail_api(self, case_id: str):
455 """
456 获取案例信息
457 @param : /{case_id}/data
458 @return: response
459 """
460 url = case_details_url.format(case_id=case_id)
461 return self.send(self.get, url).json()
462
463 def get_case_detail(self, case_id: str):
464 """
465
466 @param case_id: 测试案例id
467 @return:
468 """
469 response = self.get_case_detail_api(case_id)
470 return response
471
472 def file_md5_check(self, file_path: str, raw: bool = False):
473 """
474 文件md5检查
475 @param file_path: 文件路径
476 @return:
477 """
478
479 # global url
480 def file_md5(filename: str):
481 """
482 以文件内容md5加密
483 @param filename:
484 @return:
485 """
486 with open(filename, 'rb') as f:
487 contents = f.read()
488 return hashlib.md5(contents).hexdigest()
489
490 file_md5 = file_md5(file_path)
491 # print("file_md5_check file_md5:", file_md5)
492 # file_md5_url = "api-asset/files/{}?raw={}" # 验证文件MD5
493 if raw:
494 url = file_md5_url.format(file_md5, "true")
495 else:
496 url = file_md5_url.format(file_md5, "false")
497 response = self.send(self.get, url).json()
498 # print(f"-----file_md5_check:{url} get response:",response)
499 return response
500
501 def remove_file(self, sim_path: str):
502 """
503 remove files that except (.sim .zip .xosc)
504 :param sim_path:
505 """
506 for item in os.listdir(sim_path):
507 sim_file = os.path.join(sim_path, item)
508 try:
509 if os.path.isfile(sim_file):
510 os.remove(sim_file)
511 # print(f'{sim_file} 文件删除成功')
512 elif os.path.isdir(sim_file):
513 shutil.rmtree(sim_file)
514 # print(f'{sim_file} 文件夹删除成功')
515 except OSError as e:
516 print(f'Error: {e.filename} - {e.strerror}.')
517
518 def get_caseid(self, sim_path: str, sim_list: list):
519 """
520 get the caseid before import according to
521 :param sim_path: string, the path to the .sim file
522 :sim_list run_sim: list, cases that need to be run
523 :return: list, caseid before import
524 """
525 # print("sim_path:",sim_path)
526 # print("sim_list:",sim_list)
527 file_list = os.listdir(sim_path)
528 # print("file_list:",file_list)
529 target_run = list()
530 for item in file_list:
531 for run_sim_item in sim_list:
532 # if ('31map.sim' in item) and ('all_sim' in choose_run):
533 if os.path.join(sim_path, run_sim_item + '.sim') == os.path.join(sim_path, item):
534 target_run.append(item)
535 # print("target_run:",target_run)
536 if not target_run:
537 target_run = file_list
538 # print("更新后target_run:",target_run)
539 extract_dir = os.path.join(sim_path, "extract_dir")
540 # print("extract_dir:",extract_dir)
541 if not os.path.exists(extract_dir):
542 os.makedirs(extract_dir)
543 for item in target_run:
544 if item == "extract_dir":
545 continue
546 # zip_file = os.path.join(sim_path, item).replace('.sim', '.zip') # 当文件名中有两个.sim时会有BUG
547 zip_file = os.path.join(extract_dir, item[:-4] + ".zip") if item.endswith(".sim") else os.path.join(
548 extract_dir, item)
549 # print("zip_file:",zip_file)
550 try:
551 if item.endswith(".sim") or item.endswith(".zip"):
552 # print("try item:",item)
553 shutil.copy(os.path.join(sim_path, item), zip_file)
554 except Exception as e:
555 pass
556 try:
557 with zipfile.ZipFile(zip_file) as zfile:
558 # print("执行到这。。。")
559 zfile.extractall(path=extract_dir)
560 # print("执行到这2。。。")
561 except Exception as e:
562 raise Exception(f"解压{zip_file}失败,异常信息:{e}")
563 temp = list(filter(lambda x: 'json' in x, os.listdir(extract_dir)))
564 # print("temp:",temp)
565 if temp == []: # 从3.3.0版本起案例解压后是文件夹,则上一条语句执行后temp为空
566 for d in os.listdir(extract_dir):
567 # print("extract_dir目录下的内容:",d)
568 if os.path.isdir(os.path.join(extract_dir, d)):
569 temp.append(d)
570 # print("临时测试temp:",temp)
571 all_case_id = list(set(temp)) # 去重
572 # print("all_case_id:",all_case_id)
573 old_case_id = list(filter(lambda x: 'vehicle' not in x, all_case_id))
574 # print("old_case_id:",old_case_id)
575 self.remove_file(extract_dir)
576 # print("执行到这3。。。")
577 return old_case_id
578 all_case_id = list(map(lambda x: x.replace('.json', ''), temp))
579 all_case_id = list(set(all_case_id)) # 去重
580 old_case_id = list(filter(lambda x: 'vehicles' not in x, all_case_id))
581 self.remove_file(extract_dir)
582 return old_case_id
583
584
585 def upload_file(self, file_path: str, index: int, chunks: int, category: str, uploadId: str, raw: bool = False):
586 """
587 上传文件
588 @param file_path: 文件路径
589 @param index: 上传序列
590 @param chunks: chunks总数
591 @param category: 类别
592 @param file_md5: 文件MD5
593 @return:
594 """
595 # self.headers = {}
596 self.headers = {"ProjectId": 'default'} # 江淮3.5.0
597 file_size = os.path.getsize(file_path)
598 file_name = file_path.split(os.sep)[-1]
599 f = open(f'{file_path}', 'rb')
600 files = [('file', (f'{file_name}', f, 'application/octet-stream'))]
601 if raw:
602 url = upload_file_url.format(uploadId, "true")
603 else:
604 url = upload_file_url.format(uploadId, "false")
605
606 upload_payload = {"params": json.dumps({"filename": file_name,
607 "index": index,
608 "chunks": chunks,
609 "filesize": file_size,
610 "uploadId": uploadId,
611 "category": category})}
612 response = self.send(self.post, url, data=upload_payload, files=files).json()
613 f.close()
614 # print(f"-----upload_file-- url:{url} upload_payload:{upload_payload} files:{files} response:{response}")
615 # print("uuid:", uploadId)
616 return uploadId
617
618 def import_case_api(self, payload: dict):
619 """
620 案例导入
621 @param payload:
622 @return:
623 """
624 # print("********* import_case_api payload********",payload)
625 self.headers.update({"Content-Type": "application/json;charset=UTF-8"})
626 return self.send(self.post, case_import_url, data=json.dumps(payload)).json()
627
628 def import_case(self, file_path: str, file_name: str, cate_id: str, override_map_id: str = ""):
629 """
630 导入案例到指定的案例库目录
631 @param override_map_id:案例当中需要关联的地图ID
632 @param file_path: 案例文件路径
633 @param file_name: 案例文件名
634 @param cate_id: 案例库目录ID
635 @return: [重要] 此处返回的并不是导入成功后的案例ID,而是导入案例文件里的原ID
636 """
637 case_file_path = os.path.join(file_path, file_name)
638 filename = file_name.split(".")[0]
639 file_size = os.path.getsize(case_file_path)
640 print("file_size : ", file_size)
641 md5_res = self.file_md5_check(case_file_path)
642 md5_res_info = md5_res["data"]
643 # file_md5 = md5_res_info["id"]
644 global ext
645 global path_ext
646 if file_name.split(".")[1] == "xosc":
647 ext = "xosc"
648 case_id_list = [f"{filename}"]
649 includes = case_id_list
650 overrides_id = case_id_list[0]
651 overrides_name = filename
652 overrides_path = filename + ".xosc"
653 elif file_name.split(".")[1] == "sim":
654 ext = "sim"
655 case_id_list = self.get_caseid(file_path, [filename])
656 includes = case_id_list
657 overrides_id = case_id_list[0]
658 overrides_name = filename
659 overrides_path = case_id_list[0] + "/case/" + filename + ".json"
660 elif file_name.split(".")[1] == "zip":
661 ext = "zip"
662 case_id_list = self.get_caseid(file_path, [filename])
663 print("case_id_list:", case_id_list)
664 includes = case_id_list[0] + "/case/" + filename
665 overrides_id = includes
666 overrides_name = includes
667 overrides_path = includes + ".xosc"
668 else:
669 raise f"导入案例不支持{file_name.split('.')[1]}格式,用例中断"
670
671 def round_up(data):
672 """
673 func:向上取整
674 Args:
675 data: float
676 Returns: int
677
678 """
679 return math.ceil(data)
680
681 upload_id = str(uuid4())
682 chunk_size = 2 * 1024 * 1024
683 # if md5_res_info['size'] == 0:
684 chunks = round_up(file_size / chunk_size)
685 self.upload_file(file_path=case_file_path, index=0, chunks=1, category="case", uploadId=upload_id)
686 if override_map_id:
687 overrides = [{"id": f"{filename}",
688 "name": f"{filename}",
689 "replaceMap": True,
690 "replaceVehicle": True,
691 "missingMap": True,
692 "overrideMapId": f"{override_map_id}",
693 "missingVehicle": True,
694 "path": f"{filename}",
695 "vehicleIds": ["default"]}]
696 else:
697 overrides = []
698 case_payload = {
699 "category": cate_id,
700 "includesMap": True,
701 "includesVehicle": True,
702 "includesStopTrigger": True,
703 "includes": includes,
704 "categoryInfo": {},
705 "needRemoveCases": {},
706 "id": upload_id,
707 "file": upload_id,
708 "name": filename,
709 "ext": ext,
710 "overrides": overrides
711 }
712 response = self.import_case_api(payload=case_payload)
713
714 return case_id_list, response # [重要] 此处返回的并不是导入成功后的案例ID,而是导入案例文件里的原ID
715
716
717
718
719 def import_flow(self, category_name: str, file_path: str, file_name: str,map_name:str=""):
720 '''
721 导入文件流程
722 可导入的文件类型为 .xosc 或者 .sim格式
723 @param map_name: 需要关联的地图名称
724 @param category_name: 案例库名称
725 @param file_path: 文件路径比如 r"D:\System
726 @param file_name:文件名称比如 123.xosc or 123.sim
727 '''
728 cate_id = self.get_category()
729 cate_idname = cate_id["data"][category_name]
730 if map_name:
731 map_id_dict = self.get_map_id(map_name=map_name)
732 print("map_id_dict -> ",map_id_dict)
733 map_id = map_id_dict[f"{map_name}"]
734 self.import_case(file_path, file_name, cate_idname,override_map_id=map_id)
735 else:
736 self.import_case(file_path, file_name, cate_idname)
737
738 def create_task_api(self, payload: dict):
739 """
740 创建task
741 @param payload: eg {"caseIds": ["3dd03c09-3ba9-4f7a-b988-fde88296095a"],
742 "taskName": "task_name"}
743 @return:
744 """
745 return self.send(self.post, create_task_url, json=payload).json()
746
747 def run_task(self, caseid: list, vehicle_id: str = None, withEvaluation: bool = False, version: float = 3.5):
748 """
749 运行测试任务集合
750 Run task set
751 @param caseid: caseid
752 @param vehicle_id: vehicle_id
753 @param withEvaluation: withEvaluation
754 @param version: version
755 @return:
756 """
757 task_name = "taskName_" + time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())
758 if version >= 3.5:
759 payload = {"caseIds": caseid,
760 "taskName": task_name,
761 "withEvaluation": withEvaluation,
762 "controllers": [{"id": "Default", "name": "默认控制器", "algorithmId": "SimOneDriver"},
763 {"id": "AutoDrive", "name": "自驾控制器", "algorithmId": "SimOneDriver"}]}
764 else:
765 payload = {"caseIds": caseid, "taskName": task_name, "speed": 1}
766 if vehicle_id:
767 payload.update({"overrideVehicleId": vehicle_id})
768 response = self.send(self.post, url=create_task_url, json=payload).json()
769
770 data = response['data']
771 return data['sessionId'], data['taskIds']
772
773 def stop_task_api(self, payload: dict):
774 """
775 task停止API
776 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
777 @return:
778 """
779 return self.send(self.post, stop_task_url, json=payload).json()
780
781 def stop_sessions_api(self, payload: dict):
782 """
783 sessions停止API
784 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
785 @return:
786 """
787 return self.send(self.post, stop_sessions_url, json=payload).json()
788
789 def stop_task(self, task_id: list, sessions_id: list):
790 """
791 停止任务和会话
792 @param task_id:
793 @param sessions_id:
794 @return:
795 """
796 task_payload = {"ids": task_id}
797 self.stop_task_api(task_payload)
798 sessions_id = {"ids": sessions_id}
799 self.stop_sessions_api(sessions_id)
800
801 def pause_task_api(self, task_id: str):
802 """
803 暂停任务
804 @param task_id:
805 @return:
806 """
807 return self.send(self.post, pause_task_url.format(task_id=task_id), json={}).json()
808
809 def resume_task_api(self, task_id: str):
810 """
811 暂停任务后开始
812 @param task_id:
813 @return:
814 """
815 return self.send(self.post, resume_task_url.format(task_id=task_id), json={}).json()
816
817 def delete_sessions_api(self, payload: dict):
818 """
819 sessions删除API
820 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
821 @return:
822 """
823 return self.send(self.post, delete_sessions_url, json=payload).json()
824
825 def delete_task_api(self, payload: dict):
826 """
827 task删除API
828 @param payload: eg {"ids":["f9e096f6-78ff-431a-a5e2-24a2de4117df"]}
829 @return:
830 """
831 return self.send(self.post, delete_task_url, json=payload).json()
832
833 def delete_task(self, sessions_id: list, task_id: list):
834 """
835 删除任务和会话
836 @param sessions_id:
837 @param task_id:
838 @return:
839 """
840 sessions_id = {"ids": sessions_id}
841 self.delete_sessions_api(sessions_id)
842 task_payload = {"ids": task_id}
843 self.delete_task_api(task_payload)
844
845 def import_vehicle_api(self, payload: dict):
846 """
847 导入主车
848 @param payload: eg {"vehicleData": {"byId": {vehicle_id: vehicle_data},
849 "allIds": [vehicle_id]}}
850 @return:
851 """
852 return self.send(self.post, import_vehicle_url, json=payload).json()
853
854 def get_vehicle_data(self, file_path: str):
855 vehicle_info = FileReader(file_path).read_json()
856 vehicle_id = vehicle_info.get("id")
857 return vehicle_info, vehicle_id
858
859 def import_vehicle(self, file_path: str) -> str:
860 """
861 导入主车
862 @param file_path: 主车文件
863 @return: 主车id
864 """
865 vehicle_data, vehicle_id = self.get_vehicle_data(file_path)
866 payload = {"vehicleData": {"byId": {vehicle_id: vehicle_data},
867 "allIds": [vehicle_id]}}
868 result = self.import_vehicle_api(payload)
869 return result["data"]["id"]
870
871 def get_vehicle_api(self):
872 """
873 获取主车信息
874 @return:
875 """
876 return self.send(self.get, get_vehicle_url).json()
877
878 def get_vehicle(self, userid: str = None):
879 """
880 根据用户信息获取主车信息
881 @param userid:
882 @return:
883 """
884 global vehicle_data
885 vehicle_data = {}
886 res = self.get_vehicle_api()
887 # print(f"get_vehicle_api response ->: {res}")
888 data = res["data"]["list"]["byId"]
889 id_list = res["data"]["list"]["allIds"]
890 if userid:
891 for id in id_list:
892 if data[id]["userId"] == userid:
893 vehicle_data.setdefault(data[id]["name"], data[id]["id"])
894 else:
895 for id in id_list:
896 vehicle_data.setdefault(data[id]["userId"], {}).update({data[id]["name"]: data[id]["id"]})
897 print("获取到的主车信息->:{}".format(str(vehicle_data)))
898 return vehicle_data
899
900 def get_vehicle_id(self, vehicle_name: list) -> list and dict:
901 """
902 根据主车名称获取主车ID
903 @param vehicle_name:
904 @return:
905 """
906 vehicle_id_dict = {}
907 vehicle_id_list = []
908 vehicle_list = []
909 for i in vehicle_name:
910 for k, v in self.get_vehicle().items():
911 vehicle_list.append(v)
912 for vehicle_dict in vehicle_list:
913 # print("vehicle_dict", vehicle_dict)
914 vehicle_dict_key = dict(vehicle_dict).items()
915 for vehicle_dict_k, vehicle_dict_v in vehicle_dict_key:
916 if i in vehicle_dict_k:
917 vehicle_name_id = vehicle_dict[i]
918 vehicle_id_list.append(vehicle_name_id)
919 vehicle_id_dict.setdefault(i, vehicle_name_id)
920
921 print("vehicle_id_list->:", vehicle_id_list, "\nvehicle_id_dict->:", vehicle_id_dict)
922 return vehicle_id_list, vehicle_id_dict
923
924 def delete_vehicles_api(self, vehicles_id: str):
925 """
926 删除主车
927 @param vehicles_id: 主车id
928 @return:
929 """
930 url = delete_vehicle_url.format(vehicles_id=vehicles_id)
931 return self.send(self.delete, url)
932
933 def delete_vehicle(self, id: str):
934 """
935 删除主车
936 @param id: 主车id
937 @return:
938 """
939 self.delete_vehicles_api(id)
940
941 def get_suite_api(self):
942 """
943 get_suite
944 @return:
945 """
946 return self.send(self.get, url=get_suites_url).json()
947
948 def get_suite(self, suite_name: str = None):
949 """
950 :return:
951 """
952 response = self.get_suite_api()
953 data = response['data']
954 suite_dict = {}
955 for id in data['allIds']:
956 suite_dict.setdefault(data['byId'][id]['name'], {}).update({"caseIds": data['byId'][id]['caseIds']})
957 print("suite_dict", suite_dict)
958 if not suite_name:
959 return suite_dict
960 else:
961 # print("suite_dict[suite_name]:",suite_dict[suite_name])
962 return suite_dict[suite_name]
963
964 def run_suite_api(self, payload: dict):
965 """
966 run_suite
967 @param payload: payload
968 @return:
969 """
970 return self.send(self.post, url=run_suite_url, json=payload).json()
971
972 def run_suite(self, suite_name: str, taskName: str = None, vehicle_id: str = None):
973 if taskName is None:
974 def creat_task_name():
975 return "taskName_" + time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())
976
977 taskName = creat_task_name()
978 caseid_list = self.get_suite(suite_name)['caseIds']
979 payload = {'caseIds': caseid_list,
980 'taskName': taskName}
981 if vehicle_id:
982 # vehicle_module = VehicleBusiness()
983 # vehicle_module.get_vehicle()
984 payload.update({"overrideVehicleId": vehicle_id})
985 response = self.run_suite_api(payload)
986 data = response['data']
987 return data['sessionId'], data['taskIds']
988
989 def suite_queue_api(self):
990 """
991 suite_queue
992 @return:
993 """
994 return self.send(self.get, url=queue_status_url).json()
995
996 def suite_queue_check(self, n=10):
997 """
998 @param n:cycle index
999 @return:
1000 """
1001 if n == 1:
1002 print("-----------------------The test case run fail--------------------------------------")
1003 return False
1004 while (1):
1005 try:
1006 assert self.suite_queue_api()
1007 response = self.suite_queue_api()
1008 assert response["code"] == 0
1009 except Exception as e:
1010 return -1
1011 queue_info = response["data"]
1012 running, pending, waiting = queue_info["running"], queue_info["pending"], queue_info["waiting"]
1013
1014 if running == 0 and pending == 0 and waiting == 0:
1015 print("-----------------------The test case run finish--------------------------------------")
1016 return True
1017 else:
1018 time.sleep(interval)
1019
1020 def get_result(self, task_id: list, index: int = None):
1021 """
1022 :param task_id:
1023 :return:
1024 """
1025 task_id_str = ",".join(task_id)
1026 # print(task_id_str)
1027 response = self.send(self.get, url=result_url.format(task_id=task_id_str)).json()
1028 data = response["data"]["tasks"]
1029 result = []
1030 for one in data:
1031 result.append({"pass": one["pass"], "is_ended": True if one["key"] == "ended" else False})
1032 if not index:
1033 return result
1034 else:
1035 return result[index]
1036
1037 def is_ended(self, task_id: list, case_name=None):
1038 """
1039 判断案例是否运行结束
1040 @param task_id: 任务id
1041 @param case_name: 案例名称
1042 @return:
1043 """
1044 interval = 10
1045 while (1):
1046 result = self.get_result(task_id, -1)
1047 if result["is_ended"]:
1048 print('Case status:end of run')
1049 if case_name:
1050 print(f'Name of the current ending case->{case_name}')
1051 return False
1052 else:
1053 print('Case status:in progress')
1054 if case_name:
1055 print(f'Name of the current running case->{case_name}')
1056 time.sleep(interval)
1057
1058 def get_taskassemble_api(self, task_set_id):
1059 '''
1060 获取测试案例集
1061 @param
1062 @return:
1063 '''
1064 return self.send(self.get, get_taskassemble_url.format(task_set_id=task_set_id)).json()
1065
1066 def get_task_id_of_task_set(self, task_set_id: str) -> list:
1067 """
1068 获取任务集合中所有测试案例的task_id
1069 @param task_set_id: 任务集合id
1070 @return: list
1071 """
1072 response = self.get_taskassemble_api(task_set_id)
1073 _task_id_list = response["data"]["list"]
1074 # print("---------------------------------task_id_list-----------------------")
1075 # print(_task_id_list)
1076 index = 0
1077 task_id_list = []
1078 for i in _task_id_list:
1079 index += 1
1080 # print(f"------------------------第{index}个元素----------------")
1081 # print(i)
1082 if i['parentId'] == task_set_id:
1083 # print(i)
1084 task_id_list.append(i["id"])
1085 # print("task_id_list",task_id_list)
1086 return task_id_list
1087
1088 def get_task_result_api(self, task_id: str):
1089 """
1090 获取指定task的结果
1091 @param task_id:
1092 @return:
1093 """
1094 return self.send(self.get, task_result_url.format(id=task_id)).json()
1095
1096 def get_task_result(self, task_id_list: list = None) -> list:
1097 """
1098 获取任务集中的 案例名称,caseId,task_id,运行结果
1099 @param task_id_list: 任务id列表
1100 @param task_set_id: 任务集合id
1101 @return:
1102 """
1103
1104 task_result_list = []
1105 for task_id in task_id_list:
1106 result = self.get_task_result_api(task_id)
1107 case_name = result["data"]["tasks"][0]["case"]["name"]
1108 case_id = result["data"]["tasks"][0]["caseId"]
1109 task_id = result["data"]["tasks"][0]["id"]
1110 task_result = result["data"]["tasks"][0]["pass"]
1111 if task_result != True: task_result = False
1112 task_result_list.append({"case_name": case_name,
1113 "case_id": case_id,
1114 "task_id": task_id,
1115 "task_result": task_result})
1116 print("task_result_list->", task_result_list)
1117 return task_result_list
1118
1119 def import_map_api(self, payload: dict, files: dict):
1120 """
1121 导入地图API
1122 @param payload:传参字典
1123 @param files: 传参文件
1124 @return:
1125 """
1126 self.headers = {}
1127 return self.send(self.post, import_map_url, data=payload, files=files).json()
1128
1129 def import_map(self, xodr_path: str, thumbnail_path: str):
1130 """
1131 导入地图方法
1132 @param xodr_path: 地图文件
1133 @param thumbnail_path: 地图对应的图像
1134 @return:
1135 """
1136 payload = {"params": json.dumps(
1137 {"category": "customized", "id": "new_" + Faker('zh_CN').uuid4(),
1138 "name": os.path.splitext(os.path.basename(xodr_path))[0], "size": 512,
1139 "ppm": 10, "bgColor": "#dddddd", "reproject": True, "reprojectOrigin": False, "reprojectOriginLat": 0,
1140 "reprojectOriginLng": 0, "tags": [], "notes": "",
1141 "header": {"minX": -210.20535534122396, "minY": -149.68815701999185, "minZ": -1.862645149230957e-9,
1142 "maxX": 237.95535534122394, "maxY": 135.43815701999196, "maxZ": 2.7940070024635385e-9,
1143 "centerX": 97.12480158531203, "centerY": 24.463606820251727, "centerZ": 100,
1144 "localEnuExt": "6378137,0,0;0,1,0;0,0,1;1,0,0"}})}
1145 files = {'xodr': open(xodr_path, 'rb'), "thumbnail": open(thumbnail_path, 'rb')}
1146 result = self.import_map_api(payload, files)
1147 if result["code"] == 0:
1148 print(f"导入地图{xodr_path}成功,id:{result['data']['mapId']}")
1149 else:
1150 print(f"导入地图{xodr_path}失败,返回结果:{result}")
1151 raise f"导入地图{xodr_path}失败,返回结果:{result}"
1152 res_dict = {"code": result["code"], "mapId": result["data"]["mapId"],
1153 "name": os.path.basename(os.path.basename(xodr_path))}
1154 return res_dict
1155
1156 def get_map_api(self):
1157 """
1158 获取地图
1159 @return:
1160 """
1161 return self.send(self.get, get_map_url).json()
1162
1163 def get_map_id(self, userid: str = None, map_name: str = None):
1164 """
1165 按条件获取地图信息,默认获取所有地图
1166 @param userid: 用户id
1167 @param map_name: 地图名字
1168 @return:
1169 """
1170 global map_data
1171 map_data = {}
1172 try:
1173 result = self.get_map_api()
1174 # print(len(result['data']['maps']))
1175 map_info = result['data']['maps']
1176
1177 if userid:
1178 for map in map_info:
1179 if map["userId"] == userid:
1180 map_data.setdefault(map["name"], map["id"])
1181 elif map_name:
1182 for map in map_info:
1183 if map["name"] == map_name:
1184 map_data = {map["name"]: map["id"]}
1185 else:
1186 for map in map_info:
1187 map_data.setdefault(map["userId"], {}).update({map["name"]: map["id"]})
1188 return map_data
1189
1190 except Exception as e:
1191 print(e)
1192
1193 def delete_map_api(self, payload: dict):
1194 """
1195 删除地图
1196 @param payload: eg:{ids: ["27a0bbc4-5d4d-48c1-9187-62df794dadae"]}
1197 @return:
1198 """
1199 return self.send(self.post, delete_map_url, json=payload).json()
1200
1201 def delete_map(self, id: list):
1202 """
1203 批量删除地图
1204 @param id: 地图id列表
1205 @return:
1206 """
1207 print("删除的地图列表-》{}".format(str(id)))
1208 payload = {"ids": id}
1209 self.delete_map_api(payload)
1210
1211 def get_judgements_api(self, caseId, judgementId=None):
1212 """
1213 获取判定信息API
1214 @param caseId: 案例ID
1215 @param judgementId: 判定ID
1216 @return:
1217 """
1218 if judgementId:
1219 url = get_judgement_url.format(caseId=caseId, judgementId=judgementId)
1220 else:
1221 url = get_judgements_url.format(caseId=caseId)
1222 response = self.send(self.get, url).json()
1223 return response
1224
1225 def get_judgements_method(self, caseId: str, judgementId: str = None):
1226 """
1227 获取判定信息
1228 @param caseId: 案例ID
1229 @param judgementId: 判定ID
1230 @return:
1231 """
1232 response = self.get_judgements_api(caseId, judgementId)
1233 print("得到的扩展判定信息:", response["data"][1])
1234 return response
1235
1236 def update_judgement_api(self, caseId, judgementId="collision", payload: dict = None):
1237 """
1238 @param caseId: caseId
1239 @param judgementId: judgementId
1240 @return:
1241 """
1242 if not payload:
1243 payload = {"schema": "judgement", "settings": {"logLevel": "error", "action": "failure", "logInfo": ""},
1244 "scope": {"size": {"x": 10, "y": 10, "z": 0}, "heading": {"w": 1, "x": 0, "y": 0, "z": 0},
1245 "position": {"x": 0, "y": 0, "z": 0},
1246 "type": "global"}, "builtIn": True,
1247 "name": "碰撞", "lock": True, "id": "collision",
1248 "type": "collision", "category": "general",
1249 "conditions": [], "userId": "admin",
1250 "enabled": True}
1251 response = self.send(self.put, get_judgement_url.format(caseId=caseId, judgementId=judgementId),
1252 data=json.dumps(payload))
1253 return response
1254
1255 def update_judgement_method(self, caseId, judgementId="collision"):
1256 __collision = {"schema": "judgement", "settings": {"logLevel": "error", "action": "failure", "logInfo": ""},
1257 "scope": {"size": {"x": 10, "y": 10, "z": 0}, "heading": {"w": 1, "x": 0, "y": 0, "z": 0},
1258 "position": {"x": 0, "y": 0, "z": 0},
1259 "type": "global"}, "builtIn": True,
1260 "name": "碰撞", "lock": True, "id": "collision",
1261 "type": "collision", "category": "general",
1262 "conditions": [], "userId": "admin",
1263 "enabled": True}
1264 payload = json.dumps(__collision)
1265 judgement_url = "api-asset/cases/{caseId}/judgements/{judgementId}"
1266 response = self.send(self.put, judgement_url.format(caseId=caseId, judgementId=judgementId), data=payload)
1267 print("更新扩展判定信息")
1268 print("status_code:", response.status_code)
1269
1270
1271def main(category_name: str, case_name: str = None, vehicle_name=None):
1272 """
1273 @param category_name: category_name
1274 @param case_name:
1275 @param vehicle_name:vehicle_name
1276 @return:
1277 """
1278 suite = Suite()
1279 suite.get_category()
1280 cate_id = suite.get_category()
1281 cate_name = [cate_id["data"][category_name]]
1282 cases_dict, case_id_list = suite.get_cases_category(cate_name)
1283
1284 # 主车控制相关逻辑
1285 if vehicle_name:
1286 vehicle_dict = suite.get_vehicle_id([vehicle_name])[1]
1287 if vehicle_name not in vehicle_dict.keys():
1288 print(f"vehicle_name:{vehicle_name} inexistence")
1289 return
1290 vehicle_id = vehicle_dict[vehicle_name]
1291 else:
1292 vehicle_id = None
1293 print(f"vehicle_name:{vehicle_name},vehicle_id:{vehicle_id}")
1294
1295 # 案例名称逻辑
1296 if case_name:
1297 case_id_list = cases_dict[case_name]
1298 print(f" case_name:{case_name}")
1299
1300 # 启动案例
1301 session_id, task_ids = suite.run_task(case_id_list, vehicle_id=vehicle_id)
1302 time.sleep(10)
1303 # suite.stop_task(task_id=task_ids, sessions_id=[session_id])
1304 # 等待案例运行完毕
1305 falg = suite.suite_queue_check()
1306 if falg is True:
1307 # 获取案例运行结果
1308 suite.get_task_result(task_ids)
1309
1310
1311SimOneUrl = "http://127.0.0.1:30083/"
1312loginData = {
1313 "username": 'admin',
1314 "password": 'admin',
1315}
1316LoginPolicy("standalone")
1317if __name__ == '__main__':
1318 main("入门案例", "构建标准案例2.0")
1 用户登录接口文档
SimOne Web User Server
1.1 登录接口
Path: /api-user/user/login
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必须 |
类型 |
示例 |
|---|---|---|---|---|---|
|
username |
query |
账号名称 |
Yes |
string |
zhangsan |
|
password |
query |
鉴权 token,有效期 30s |
Yes |
string |
qKP1Cgv3NysooGPKHRiiKGqQEjLjkbBFy2FqbkaY6ew |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
token |
当前用户鉴权 Token |
Yes |
string |
备注:
密码是通过一定加密算法计算得到的需要联系售后支持以获取生成方法
1.2 获取用户登录 token
Path: /api-user/user/check
Method: POST
Headers: Headers
请求参数
|
参数名称 |
位于 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
username |
body |
用户 id |
Yes |
string |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
checkToken |
当前用户鉴权 Token |
Yes |
string |
1.3 单机版获取 authToken
Path: /api-user/user/standalone
Method: GET
Headers: Headers
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
token |
当前用户鉴权 Token |
Yes |
string |
1.4 登出
Path: /api-user/user/logout
Method: POST
Headers: Headers
返回数据
无
1.5 判断是否为云端环境
Path: /api-user/user/isCloud
Method: GET
Headers: Headers
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
isCloud |
是否云端环境 |
Yes |
boolean |
通用请求头
Headers
|
参数名称 |
参数值 |
是否必填 |
示例 |
|---|---|---|---|
|
Content-Type |
application/json |
Yes |
|
|
Authorization |
string |
Yes |
“6a82749b-7d4e-46a3-a932-e5ca21f34f16” |
|
projectId |
string 默认值:
|
Yes |
|
2 任务服务接口文档
SimOne Web Task Server
2.1 服务状态接口
2.1.1 获取服务健康状态
Path: /api-task/health
Method: GET
Headers: Headers
请求参数
无
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
version |
版本 |
Yes |
string |
|
current |
当前状态 |
Yes |
number |
|
maximum |
最大状态 |
No |
number |
|
message |
当前状态信息 |
No |
string |
|
level |
服务当前等级 |
No |
“info” | “error” | “warning” |
|
code |
服务错误代码 |
No |
number |
2.2 任务接口
2.2.1 获取运行的任务或回放的任务 id
Path: /api-task/sessions/isPlay
Method: GET
Headers: Headers
请求参数
无
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
testingSessionIds |
运行的任务 id |
Yes |
string[] |
|
replaySessionIds |
回放的任务 id |
Yes |
string[] |
2.2.2 获取回放任务状态
Path: /api-task/sessions/replayTasks
Method: GET
Headers: Headers
请求参数
无
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
replayTasks |
回放任务状态 |
Yes |
Record<string, ReplayTaskInfo > |
2.2.3 获取任务队列
Path: /api-task/sessions/queue
Method: GET
Headers: Headers
请求参数
无
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
queue |
排队信息 |
Yes |
Record<string, number> |
2.2.4 恢复暂停任务集
Path: /api-task/sessions/:id/resume
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.2.5 暂停任务
Path: /api-task/sessions/:id/pause
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.2.6 获取任务报告
Path: /api-task/sessions/:id/report
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务集 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
success |
是否成功 |
Yes |
boolean |
备注
返回 success true 之后使用/report/:id_zh-Hans.pdf 地址进行下载,例 sessionId 为 123456,下载地址为:原网页网址/report/123456_zh-Hans.pdf
2.2.7 任务下一帧
Path: /api-task/sessions/step
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
body |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.2.8 修改仿真速度
Path: /api-task/sessions/speed
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
body |
任务 id |
Yes |
string |
|
speed |
body |
任务速度 |
Yes |
number |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.2.9 任务跳转
Path: /api-task/sessions/skipTo
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
body |
任务 id |
Yes |
string |
|
seconds |
body |
任务时间 |
Yes |
number |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
无
2.2.10 更新主车控制
Path: /api-task/sessions/updateVehicleControl
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
body |
任务 id |
Yes |
string |
|
egoId |
body |
主车 id |
Yes |
string |
|
vehicleControl |
body |
主车控制 |
Yes |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
无
2.2.11 获取回放任务数据
Path: /api-task/sessions/:id/replayChartData
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
timestamp |
时间戳 |
Yes |
string |
|
taskId |
任务 id |
Yes |
string |
|
caseId |
案例 id |
Yes |
string |
|
taskUuid |
任务 uuid |
No |
string |
|
timeMs |
时间 |
No |
number |
|
durationMs |
持续时间 |
No |
number |
|
fps |
帧率 |
No |
number |
|
speed |
速度 |
No |
number |
|
mainvehicles |
主车 |
No |
2.2.12 获取回放任务状态
Path: /api-task/sessions/:id/taskState
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
taskId |
任务 id |
Yes |
string |
|
isPlay |
是否是回放 |
Yes |
number |
2.2.13 停止任务集
Path: /api-task/sessions/stop
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
任务集 id |
Yes |
string[] |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.2.14 删除任务集
Path: /api-task/sessions/delete
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
任务集 id |
Yes |
string[] |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3 任务运行时接口
2.3.1 获取任务列表
Path: /api-task/tasks/
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
finished |
query |
是否已完成 |
Yes |
boolean |
|
page |
query |
页数 |
Yes |
string |
|
pageSize |
query |
每页数量 |
Yes |
string |
|
own |
query |
是否是自己的任务 |
Yes |
boolean |
|
expandedIds |
query |
展开的任务 id |
Yes |
string[] |
|
filters |
query |
筛选 |
No |
string[] |
|
searchFilter |
query |
搜索 |
No |
string |
|
startTime |
query |
开始时间 |
No |
number |
|
endTime |
query |
结束时间 |
No |
number |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
list |
任务列表 |
Yes |
TaskListItem [] |
|
page |
页数 |
Yes |
number |
|
total |
总页数 |
Yes |
number |
|
pageSize |
每页数量 |
Yes |
number |
2.3.2 获取任务详情
Path: /api-task/tasks/task
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
taskIds |
query |
展开的任务 id |
Yes |
string[] |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
tasks |
任务列表 |
Yes |
TaskListItem [] |
TaskListItem
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
任务 id |
Yes |
string |
|
parentId |
sessionId |
Yes |
string | null |
|
loading |
是否加载中 |
No |
boolean |
|
userId |
用户名 |
No |
string |
|
userName |
用户姓名 |
No |
string |
2.3.3 获取任务数量
Path: /api-task/tasks/count
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
own |
query |
是否是自己的任务 |
Yes |
boolean |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
count |
任务数量 |
Yes |
number |
2.3.4 获取任务队列
Path: /api-task/tasks/queue
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
own |
query |
是否是自己的任务 |
Yes |
boolean |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
total |
任务总数 |
Yes |
number |
|
running |
运行任务数量 |
Yes |
number |
|
pending |
即将运行任务数量 |
Yes |
number |
|
waiting |
等待任务数量 |
Yes |
number |
|
finished |
结束任务数量 |
Yes |
number |
|
estimatedTaskDuration |
预计任务时间 |
Yes |
number |
2.3.5 清除全部任务(需要管理员权限)
Path: /api-task/tasks/clean
Method: POST
Headers: Headers
请求参数
无
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.6 获取指定 id 的任务
Path: /api-task/tasks/:id/task
Method: GET
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.7 创建任务
Path: /api-task/tasks/
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
caseIds |
body |
案例 id |
Yes |
string[] |
|
taskName |
body |
任务名称 |
Yes |
string |
|
vehicleConfig |
body |
WorldSim 车辆&算法配置 |
Yes |
|
|
algorithmName |
body |
LogSim 算法 id |
Yes |
string |
|
algorithmVersion |
body |
LogSim 算法版本 id |
Yes |
string |
|
overrideJudgementId |
body |
覆盖判定 id |
No |
string |
|
evaluationPresetId |
body |
评价 id |
No |
string |
|
withEvaluation |
body |
是否评价 |
No |
boolean |
|
enableStateMachine |
body |
状态机测试脚本 |
No |
boolean |
|
notification |
body |
运行结果通知配置 |
No |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
sessionId |
sessionId |
Yes |
string |
|
taskIds |
任务 id |
Yes |
string[] |
2.3.8 回放指定任务
Path: /api-task/tasks/:id/replay
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
|
RTC |
query |
是否 RTC 任务 |
No |
boolean |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
taskId |
任务 id |
Yes |
string |
2.3.9 查看任务运行可视化
Path: /api-task/tasks/:id/observe
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.10 dump 任务
Path: /api-task/tasks/:id/dump
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
|
vizConfig |
body |
每页数量 |
Yes |
|
|
outputConfig |
body |
每页数量 |
Yes |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.11 获取任务数据
Path: /api-task/tasks/:id/data
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
success |
是否成功 |
Yes |
boolean |
2.3.12 创建回放案例
Path: /api-task/tasks/convert2case
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
name |
path |
案例名 |
Yes |
string |
|
categoryId |
body |
保存目录 id |
Yes |
string |
|
opponent |
body |
保存类型,回放案例或标准案例 |
No |
“record” | “openscenario” |
|
ego2npc |
body |
选择保存为标准案例时,主车是否转换为对手车 |
No |
boolean |
|
tags |
body |
标签 |
No |
string[] |
|
notes |
body |
案例备注 |
No |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
|
404 |
Not Found |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
id |
Yes |
string |
2.3.12 停止任务
Path: /api-task/tasks/stop
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
all |
query |
是否停止全部任务 |
No |
boolean |
|
ids |
body |
任务 id |
Yes |
string[] |
|
isReplay |
body |
是否是回放 |
No |
boolean |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.13 停止回放任务
Path: /api-task/tasks/stopReplay
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
任务 id |
Yes |
string[] |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.14 删除任务
Path: /api-task/tasks/delete
Method: POST
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
taskIds |
body |
任务 id |
Yes |
string[] |
返回码
|
Code |
说明 |
|---|---|
|
202 |
Ok |
返回数据
无
2.3.15 获取任务是否结束
Path: /api-task/tasks/:id/hasFinished
Method: GET
Headers: Headers
请求参数
|
字段名 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务 id |
Yes |
string |
返回码
|
Code |
说明 |
|---|---|
|
200 |
Ok |
返回数据
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
hasFinished |
任务是否结束 |
Yes |
boolean |
2.4 测试计划相关接口
2.4.1 获取测试计划列表
Path: /api-task/testPlan
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
page |
query |
页码 |
Yes |
number |
|
pageSize |
query |
每页数量 |
Yes |
number |
|
options |
query |
筛选项,需要字符串化,并 url 编码,如:
|
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ list : TestPlan ; page : number; total : number} |
2.4.2 获取测试计划
Path: /api-task/testPlan/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试计划 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
2.4.3 创建测试计划
Path: /api-task/testPlan
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
data |
body |
创建测试计划 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ id : string} |
2.4.4 更新测试计划
Path: /api-task/testPlan/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试计划 id |
Yes |
string |
|
data |
body |
测试计划 data |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
2.4.5 删除测试计划
Path: /api-task/testPlan/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试计划 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ id : string} |
2.4.5 删除测试计划(可以同时删除多个)
Path: /api-task/testPlan/{id}
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
测试计划 id 列表 |
Yes |
string[] |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ deleted : string[]} |
2.4.6 执行测试计划
Path: /api-task/testPlan/execute
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
测试计划 id 列表 |
Yes |
string[] |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ sessionIds : string[]} |
2.4.7 复制测试计划
Path: /api-task/testPlan/{id}/clone
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试计划 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ id : string} |
2.4.8 测试计划名称是否已存在
Path: /api-task/testPlan/isrepeat
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
name |
query |
测试计划名称 |
Yes |
string |
|
type |
query |
测试计划案例类型 |
Yes |
Enum:
|
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ isRepeat : boolean} |
通用请求头
Headers
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
Authorization |
string |
用于权限验证的 token |
Yes |
|
projectId |
string |
默认值:
|
Yes |
相关类型
2.2 任务接口相关类型
ReplayTaskInfo
回放任务信息
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
status |
任务状态 |
Yes |
string |
|
mode |
任务模式 |
Yes |
“replay” | “dump” |
|
RTC |
是否 RTC 任务 |
No |
boolean |
VizConfig
可视化配置
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
duration |
开始时间,结束时间 |
Yes |
[number, number] |
|
sensors |
传感器 |
Yes |
{ [key: string]: boolean } |
OutputConfig
dump 输出配置
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
dumpHz |
dump 频率 |
Yes |
number |
|
h264 |
h264 |
Yes |
boolean |
|
bitrate |
比特率 |
Yes |
number |
|
bbox3D |
3d 包围盒 |
Yes |
boolean |
VehicleControl
主车控制输入信息
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
vehicleId |
主车 id |
No |
number |
|
throttlepercentage |
油门百分比 |
No |
number |
|
steeringpercentage |
转向百分比 |
No |
number |
|
brakepercentage |
刹车百分比 |
No |
number |
|
handBrake |
手刹状态 |
No |
boolean |
|
isManualGear |
是否手动挡 |
No |
boolean |
|
manualGear |
手动挡位 |
No |
number |
|
gearImmediate |
立即换挡 |
No |
boolean |
|
activeInput |
活跃输入 |
No |
number |
|
acceleration |
加速度 |
No |
number |
|
speed |
速度 |
No |
number |
|
signalLights |
信号灯 |
No |
number |
TaskListItem
任务项简要信息
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
任务 id |
Yes |
string |
|
parentId |
sessionId |
Yes |
string | null |
|
loading |
是否加载中 |
No |
boolean |
|
userId |
用户名 |
No |
string |
|
userName |
用户姓名 |
No |
string |
MainVehicleUIData
热区主车信息
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
id |
No |
number | null |
|
speed |
速度 |
No |
number | null |
|
throttle |
油门 |
No |
number | null |
|
steering |
转向 |
No |
number | null |
|
brake |
刹车 |
No |
number | null |
|
rpm |
转速 |
No |
number | null |
|
gear |
档位 |
No |
number | null |
|
velocityx |
速度 x 方向值 |
No |
number | null |
|
velocityy |
速度 y 方向值 |
No |
number | null |
|
velocityz |
速度 z 方向值 |
No |
number | null |
|
accelerationx |
加速度 x 方向值 |
No |
number | null |
|
accelerationy |
加速度 y 方向值 |
No |
number | null |
|
accelerationz |
加速度 z 方向值 |
No |
number | null |
|
posx |
位置 x 方向值 |
No |
number | null |
|
posy |
位置 y 方向值 |
No |
number | null |
|
posy |
位置 z 方向值 |
No |
number | null |
|
rotationRate |
旋转比率 |
No |
number | null |
2.3 任务时运行接口相关类型
AlgorithmSlot
控制器配置
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
占位控制器 id |
Yes |
string |
|
name |
占位控制器名称 |
Yes |
string |
|
algorithmId |
实际对应算法 id |
No |
string |
|
algorithmVId |
实际对应算法名称 |
No |
string |
2.4 测试计划接口相关类型
TestTypes
测试类型(支持自定义)
|
类型 |
值 |
|---|---|
|
冒烟测试 |
“1” |
|
回归测试 |
“2” |
|
单元测试 |
“3” |
|
功能测试 |
“4” |
|
系统测试 |
“5” |
AlgorithmConfig
WorldSim 算法配置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
用例内算法 Id |
Yes |
|
name |
string |
用例内算法名称 |
Yes |
|
algorithmId |
string |
算法资源 Id |
Yes |
|
algorithmVId |
string |
算法资源版本 Id |
No |
Algorithm
LogSim 算法配置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
用例内算法 Id |
Yes |
|
name |
string |
用例内算法名称 |
No |
|
version |
string |
算法版本 |
No |
|
vId |
string |
算法资源版本 Id |
No |
VehicleConfig
车辆配置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
主车资源 Id |
Yes |
|
classId |
string |
主车模型 Id |
Yes |
|
instanceId |
string |
用例内主车实例 Id,设置为 Ego |
Yes |
|
name |
string |
主车名称 |
No |
|
algorithms |
Array< AlgorithmConfig > |
用例内引用的算法配置 |
Yes |
Trigger
触发设置
// eg:
// 每天12:00
{type: "daily", at: "12:00"}
// 每周一12:00
{type: "weekly", at: "12:00", day: 1}
// 每月1号12:00
{type: "monthly", at: "12:00", date: 1}
// 每当其他测试计划结束后,且根据结果条件触发, any:任意结果 passed:通过 failed:未通过
{testplanId: "5051903e-6e52-43c6-b386-702a06c60cca", condition: "any"}
Notification
执行结果通知设置
// eg:
// 不通知
{type: "none", condition: "any"}
// groupId 钉钉配置Id condition any:任意结果 passed:通过 failed:未通过
{type: "dingtalk", condition: "any", groupId: "5a714bf6-7730-4470-ad82-f6d45d8c367d", groupName: "dev"}
FilterOptions
测试计划筛选项
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
category |
案例类型 |
Yes |
Enum:
|
|
search |
搜索关键字 |
No |
string |
|
types |
测试类型列表 |
No |
TestTypes [] |
|
vehicleIds |
主车 id 列表 |
No |
string[] |
|
algorithms |
算法配置&版本列表 |
No |
Array<{ type: string; groupIds?: string[] }> |
|
triggerTypes |
触发方式列表 |
No |
Array<
Enum:
|
|
notifications |
通知方式列表 |
No |
Array<{ type:
|
|
stateMachine |
状态机测试脚本列表 |
No |
string[] |
TestPlan
测试计划
|
字段名 |
说明 |
是否必填 |
类型 |
|---|---|---|---|
|
id |
测试计划 id (创建时不传) |
Yes |
string |
|
name |
测试计划名称 |
Yes |
string |
|
category |
案例类型 |
Yes |
Enum:
|
|
categoryIds |
测试用例文件夹 id 列表 |
No |
string[] |
|
caseSuiteIds |
测试集 id 列表 |
No |
string[] |
|
type |
测试类型 |
Yes |
|
|
Algorithm |
LogSim 算法配置 |
No |
|
|
vehicleConfig |
WorldSim 主车与算法配置 |
No |
|
|
overrideJudgementId |
判定集, "-1"代表无 |
No |
string |
|
withEvaluation |
是否自动评价 |
No |
boolean |
|
evaluationPresetId |
评价预设 Id, "-1"代表无 |
No |
string |
|
triggerType |
触发方式 |
No |
Enum:
|
|
trigger |
triggerType 值为
|
No |
|
|
notification |
运行结果通知配置 |
No |
|
|
enableStateMachine |
状态机测试脚本 |
No |
boolean |
3 评价服务接口文档
SimOne Web Evaluation Server
3.1 测试集接口
3.1.1 获取分页测试集
Path: /api-evaluation/suites
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
page |
query |
当前页码 |
No |
number |
|
pageSize |
query |
每页数量 |
No |
number |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.1.2 创建测试集
Path: /api-evaluation/suites
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
suite |
body |
包含id,name等测试集信息 |
Yes |
{ “suite” : Suite } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.1.3 获取单个测试集
Path: /api-evaluation/suites/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试集id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.1.4 更新单个测试集
Path: /api-evaluation/suites/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试集id |
Yes |
string |
|
data |
body |
需要更新的测试集信息 |
Yes |
{ “data” : Suite } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.1.5 批量删除测试集
Path: /api-evaluation/suites/remove
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
测试集id列表 |
Yes |
{ “ids” : [ string ] } |
返回数据
|
Code |
说明 |
|---|---|
|
204 |
No content |
3.2 任务接口
3.2.1 获取指定测试集下的任务列表
Path: /api-evaluation/tasks
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
suite |
query |
测试集id |
Yes |
string |
|
page |
query |
当前页码 |
No |
number |
|
pageSize |
query |
每页数量 |
No |
number |
|
sort |
query |
排序类型
|
No |
string |
|
order |
query |
升降序
|
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.2.2 创建任务
Path: /api-evaluation/tasks
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
task |
body |
包含id,name等任务信息 |
Yes |
{ “task” : Task } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.2.3 获取单个任务详情
Path: /api-evaluation/tasks/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.2.4 更新单个任务
Path: /api-evaluation/tasks/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
任务id |
Yes |
string |
|
data |
body |
需要更新的任务信息 |
Yes |
{ “data” : Task } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.2.5 批量删除任务
Path: /api-evaluation/tasks/remove
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
任务id列表 |
Yes |
{ “ids” : [ string ] } |
返回数据
|
Code |
说明 |
|---|---|
|
204 |
No content |
3.3 评价预设接口
3.3.1 获取所有预设
Path: /api-evaluation/presets/all
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
type |
query |
预设类型 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.2 获取分页预设
Path: /api-evaluation/presets
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
page |
query |
当前页码 |
No |
number |
|
pageSize |
query |
每页数量 |
No |
number |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.3 创建一个预设
Path: /api-evaluation/presets
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
preset |
body |
包含name,data等预设信息 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.4 获取单个预设
Path: /api-evaluation/presets/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
预设id |
Yes |
number |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.5 更新单个预设
Path: /api-evaluation/presets/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
预设id |
Yes |
number |
|
data |
body |
要更新的预设信息对象 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.6 删除单个预设
Path: /api-evaluation/presets/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
预设id |
Yes |
number |
返回数据
|
Code |
说明 |
|---|---|
|
204 |
No content |
3.3.7 克隆单个预设
Path: /api-evaluation/presets/clone
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
body |
预设id |
Yes |
number |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.8 导入单个预设
Path: /api-evaluation/presets/import
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
preset |
body |
要更新的预设信息 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.3.9 判断预设名是否重复
Path: /api-evaluation/presets/isrepeat
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
preset |
body |
预设信息 |
No |
{ “name” : string, “type?” : string, “id?” : string } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
{ “isNameRepeat” : boolean; “uniqueName” : string } |
3.4 评价报告接口
3.4.1 创建评价报告
Path: /api-evaluation/evaluations
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
evaluation |
body |
评价报告信息 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.4.2 获取单个评价报告
Path: /api-evaluation/evaluations
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
taskId |
query |
任务id,任务id和测试集id只能传一个 |
No |
string |
|
suiteId |
query |
测试集id |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
3.4.3 批量获取评价报告状态
Path: /api-evaluation/evaluations/status
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
taskIds |
query |
任务id字符串,taskIds和suiteId只能传一个 |
No |
string |
|
suiteIds |
query |
测试集id字符串 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
object |
3.4.4 删除单个评价报告
Path: /api-evaluation/evaluations/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
报告id |
Yes |
string |
返回数据
|
Code |
说明 |
|---|---|
|
204 |
No content |
3.4.5 触发规控评价
Path: /api-evaluation/evaluations/evaluate
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
config |
body |
包含测试集id和预设id |
Yes |
{ suiteId: string; presetId: number } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
object |
3.4.6 查看评价服务是否正常
Path: /api/health
Method: GET
Headers: Headers
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
OK |
{ “code” : number, “data” : { “message” : string } } |
通用请求头
Headers
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
Authorization |
string |
用于权限验证的token |
Yes |
相关类型
3.1 测试集接口相关类型
Suite
测试集
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
测试集id |
Yes |
|
name |
string |
测试集名称 |
Yes |
|
withEvaluation |
boolean |
是否能评价 |
Yes |
|
presetId |
number |
当前预设 |
No |
|
algorithmName |
string |
当前算法名称 |
No |
|
algorithmVersion |
string |
当前算法版本 |
No |
|
startTime |
number |
测试集开始时间 |
Yes |
|
endTime |
number |
测试集结束时间 |
No |
SuiteResponse
测试集响应
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
total |
number |
总数 |
Yes |
|
suites |
[ Suite ] |
测试集列表 |
Yes |
3.2 任务接口相关类型
Task
任务
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
任务id |
Yes |
|
name |
string |
任务名称 |
Yes |
|
suiteId |
string |
所属测试集id |
Yes |
|
map |
string |
地图id |
No |
|
mapName |
string |
地图名 |
No |
|
vehicle |
string |
主车id |
No |
|
controller |
string |
控制器id |
No |
|
algorithmName |
string |
算法名称 |
No |
|
algorithmVersion |
string |
算法版本 |
No |
|
presetId |
number |
当前预设id |
No |
|
startTime |
number |
任务开始时间 |
Yes |
|
endTime |
number |
任务结束时间 |
No |
TaskResponse
任务响应
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
total |
number |
总数 |
Yes |
|
tasks |
[ Task ] |
任务列表 |
Yes |
3.3 评价预设接口相关类型
Preset
评价预设
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
name |
string |
预设名称 |
Yes |
|
type |
string |
预设类型 |
No |
|
data |
[ object ] |
预设数据 |
Yes |
PresetResponse
评价预设响应
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
code |
number |
状态码 |
Yes |
|
data |
预设数据 |
Yes |
PresetsResponse
评价预设集响应
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
code |
number |
状态码 |
Yes |
|
data |
{ presets: [ Preset ] , total: number } |
预设数据 |
Yes |
PresetImportResponse
评价预设导入响应
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
code |
number |
状态码 |
Yes |
|
data |
{ reason: string } |
失败原因 |
Yes |
3.4 评价报告接口相关类型
Evaluation
评价报告
|
参数名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
name |
string |
报告名称 |
Yes |
|
type |
string |
报告枚举类型:
|
Yes |
|
status |
string |
报告状态 |
Yes |
|
suiteId |
string |
测试集id |
Yes |
|
taskId |
string |
任务id |
No |
|
presetId |
number |
预设id |
Yes |
|
presetName |
string |
预设名称 |
No |
|
presetVersionId |
number |
预设版本id |
Yes |
|
score |
number |
评价得分 |
No |
|
data |
object |
报告数据 |
Yes |
4 资源服务接口文档
SimOne Web Asset Server
4.1 资源接口
4.1.1 获取资源列表
Path: /api-asset/assets
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
schema |
query |
资源类型
Enum:
|
No |
string |
|
category |
query |
目录 id |
No |
string |
|
vehicleOnly |
query |
为"true"时,只获取主车编辑器页面使用的资源 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.2 创建资源
Path: /api-asset/assets
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
data
:资源数据;
|
No |
{ “data” : Asset , “sourceId” : string, “overwriteId” : string } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.3 获取指定资源
Path: /api-asset/assets/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
需要获取资源 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.4 修改资源
Path: /api-asset/assets/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
需要更新的资源 id |
Yes |
string |
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.5 删除资源
Path: /api-asset/assets/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
要删除的资源 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.6 资源判重
Path: /api-asset/assets/isrepeat
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.1.7 克隆资源
Path: /api-asset/assets/{id}/clone
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
要克隆资源的 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2 案例接口
4.2.1 创建案例
Path: /api-asset/cases
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
CaseCreateRequest extends PartialCaseDef |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.2 已完成任务另存为案例
Path: /api-asset/cases/vr
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.3 更新案例
Path: /api-asset/cases/update
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.4 克隆案例
Path: /api-asset/cases/clone
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.5 移动案例
Path: /api-asset/cases/move
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.6 导出案例
Path: /api-asset/cases/export
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.7 导入案例
Path: /api-asset/cases/import
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.2.8 获取传感器数量超载的案例
Path: /api-asset/cases/checkSensors
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
[ { “id” : string, “name” : string } ] |
4.2.9 删除案例
Path: /api-case/cases/trash
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
{ “ids” : [string] } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
204 or 200 |
Ok |
{} |
4.3 地图接口
4.3.1 创建地图 / 更新地图
Path: /api-asset/maps
Method: POST
Headers: FormDataHeaders
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
formdata |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
202 |
Ok |
object |
4.4 文件接口
4.4.1 上传文件
Path: /api-asset/files/{md5}/upload
Method: POST
Headers: FormDataHeaders
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
md5 |
path |
文件 md5 |
Yes |
string |
|
raw |
query |
为"true"时表示上传的是数据驱动源 |
Yes |
string |
|
formData |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “code” : double } |
4.4.2 替换指定目录下的文件
Path: /api-asset/files/replace
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
sourceId |
query |
文件名称 |
Yes |
string |
|
targetId |
query |
案例 id or 主车模型 id |
Yes |
string |
|
category |
query |
资源类型
Enum:
|
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “code” : double } |
4.5 主车接口
4.5.1 获取主车列表
Path: /api-asset/vehicles
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
page |
query |
页码 |
No |
string |
|
pageSize |
query |
每页数量 |
No |
string |
|
search |
query |
搜索关键字 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.2 创建主车
Path: /api-asset/vehicles
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.3 获取指定主车
Path: /api-asset/vehicles/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
主车 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.4 更新主车
Path: /api-asset/vehicles/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.5 删除主车
Path: /api-asset/vehicles/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
删除的主车 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
object |
4.5.6 判断主车是否重复
Path: /api-asset/vehicles/isrepeat
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.7 克隆主车
Path: /api-asset/vehicles/{id}/clone
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
主车 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.8 更新主车资源文件
Path: /api-asset/vehicles/{vehicleId}/files
Method: POST
Headers: FormDataHeaders
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
vehicleId |
path |
主车 id |
Yes |
string |
|
formData |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.5.9 获取主车数量
Path: /api-asset/vehicles/count
Method: GET
Headers: Headers
请求参数
无
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “count” : double } |
4.5.10 导入主车
Path: /api-asset/vehicles/import
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6 测试集接口
4.6.1 获取测试集列表
Path: /api-asset/suites
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
opponent |
query |
案例类型
Enum:
|
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6.2 创建测试集
Path: /api-asset/suites
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6.3 获取测试集
Path: /api-asset/suites/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试集 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6.4 更新测试集
Path: /api-asset/suites/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试集 id |
Yes |
string |
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6.5 删除测试集
Path: /api-asset/suites/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
测试集 id |
Yes |
string |
|
opponent |
query |
案例类型
Enum:
|
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.6.6 移动测试集
Path: /api-asset/suites/move
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{} |
4.6.7 测试集判重
Path: /api-asset/suites/isrepeat
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.7 页面目录接口
4.7.1 获取目录列表
Path: /api-asset/categories
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
pageType |
query |
页面类型
Enum:
|
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.8 对手元素接口
4.8.1 获取对手元素列表
Path: /api-asset/obstacles
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
schema |
query |
Enum:
|
Yes |
string |
|
category |
query |
目录 id |
Yes |
string |
|
page |
query |
页码 |
No |
string |
|
pageSize |
query |
每页数量 |
No |
string |
|
search |
query |
搜索关键字 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.8.2 创建自定义对手元素
Path: /api-asset/obstacles
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “npc” : ObstacleNpc } |
4.8.3 获取指定对手元素
Path: /api-asset/obstacles/{id}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
对手元素 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “npc” : ObstacleNpc } |
4.8.4 更新对手元素
Path: /api-asset/obstacles/{id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
对手元素 id |
Yes |
string |
|
requestBody |
body |
请求体 |
Yes |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “npc” : ObstacleNpc } |
4.8.5 删除自定义元素
Path: /api-asset/obstacles/{id}
Method: DELETE
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
需要删除元素的 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “id” : string, “schema” : string } |
4.8.6 对手元素判重
Path: /api-asset/obstacles/isrepeat
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
requestBody |
body |
请求体 |
Yes |
{ “name” : string; “id” ?: string } |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.9 算法接口
4.9.1 获取算法列表
Path: /api-asset/algorithms
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
type |
query |
Enum:
|
Yes |
string |
|
clientId |
query |
客户端机器 UUID |
No |
string |
|
isWindows |
query |
算法运行系统是否是 windows |
No |
boolean |
|
projectId |
query |
项目 Id |
No |
string |
|
keyword |
query |
搜索关键字 |
No |
string |
|
page |
query |
页码 |
Yes |
string |
|
pageSize |
query |
每页数量 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.9.2 获取算法版本
Path: /api-asset/algorithms/${algorithmId}/versions/${versionId}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
algorithmId |
path |
算法 id |
Yes |
string |
|
versionId |
path |
算法版本 id |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
4.9.3 获取算法版本列表
Path: /api-asset/algorithms/${algorithmId}/versions
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
algorithmId |
path |
算法 id |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
[ AlgorithmVersion ] |
4.9.4 新增算法
Path: /api-asset/algorithms
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
data |
body |
算法及版本数据 |
Yes |
|
|
sourceId |
body |
上传的算法资源 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “name” : string; “id” : string } |
4.9.5 更新算法
Path: /api-asset/algorithms/${id}
Method: PUT
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
name |
body |
重名名时传入 |
No |
string |
|
activatedId |
body |
删除当前 activatedId 的算法版本时,需要重置一个 activatedId |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “name” : string; “id” : string } |
4.9.6 删除算法
Path: /api-asset/algorithms/delete
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
需要删除的算法 id |
No |
string[] |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
|
4.9.7 算法名称是否已经存在
Path: /api-asset/algorithms/exists/{name}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
name |
path |
名称 |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “exists” : string; “id” : string } |
4.9.8 添加算法版本
Path: /api-asset/algorithms/${id}/versions
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
id |
path |
算法 id |
Yes |
string |
|
data |
body |
算法版本数据 |
Yes |
Partial< AlgorithmVersion > |
|
sourceId |
body |
上传的算法资源 |
No |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “name” : string; “id” : string } |
4.9.9 删除版本
Path: /api-asset/algorithms/versions/delete
Method: POST
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
ids |
body |
算法版本 id 列表 |
Yes |
string[] |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
|
4.9.10 算法版本是否存在
Path: /api-asset/algorithms/${algorithmId}/exists/${version}
Method: GET
Headers: Headers
请求参数
|
参数名称 |
传参格式 |
说明 |
是否必填 |
类型 |
|---|---|---|---|---|
|
algorithmId |
path |
算法 id |
Yes |
string |
|
version |
path |
算法版本 |
Yes |
string |
返回数据
|
Code |
说明 |
类型 |
|---|---|---|
|
200 |
Ok |
{ “exists” : string; “id” : string } |
通用请求头
Headers
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
Authorization |
string |
用于权限验证的 token |
Yes |
|
projectId |
string |
默认值:
|
Yes |
|
accept |
application/json |
客户端接收 JSON 数据 |
No |
FormDataHeaders
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
Authorization |
string |
用于权限验证的 token |
Yes |
|
projectId |
string |
默认值:
|
Yes |
|
Content-Type |
multipart/form-data |
客户端发送的数据类型 |
Yes |
|
accept |
application/json |
客户端接收 JSON 数据 |
No |
相关类型
4.1 资源接口相关类型
AssetList
系统资源列表
Record<string, [ Asset ]>
Asset
资源
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
name |
string |
名称 |
Yes |
|
userId |
string |
用户 id |
Yes |
|
schema |
string |
类型 |
Yes |
|
category |
string |
目录 |
Yes |
|
thumbnail |
string |
缩略图文件路径 |
No |
|
builtIn |
boolean |
是否内置 |
No |
|
external |
boolean |
是否是外挂元素 |
No |
PartialAsset
Partial< Asset >
表示 Asset 的每个键值对都是可选的
AssetBaseResponse
返回资源的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
资源数据 |
Yes |
AssetSaveRequest
修改资源的请求体
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
更新的资源的数据 |
Yes |
|
|
sourceId |
string |
当资源包含文件时,已上传的文件名称 |
No |
|
overwrite |
boolean |
是否重新启用已删除的资源 |
No |
|
needRefresh |
boolean |
更新后是否刷新页面列表 |
No |
IsRepeatResponse
是否重复的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
isRepeat |
boolean |
是否重复 |
Yes |
AssetIsRepeatRequest
资源是否重复的请求体
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
schema |
string |
资源类型
Enum:
|
Yes |
|
name |
string |
资源名称 |
Yes |
GeneralResponse
返回 id 的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
被操作对象的 id |
Yes |
4.2 案例接口相关类型
Environment
环境
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
timeOfDay |
double |
当前时间 |
Yes |
|
lightIntensity |
double |
光照强度 |
Yes |
|
ambientLightIntensity |
double |
环境光 |
Yes |
|
artificialLightIntensity |
double |
人造光 |
Yes |
|
heightAngle |
double |
高度角 |
Yes |
|
cloudDensity |
double |
云密度 |
Yes |
|
rainDensity |
double |
雨密度 |
Yes |
|
fogDensity |
double |
雾密度 |
Yes |
|
snowDensity |
double |
雪密度 |
Yes |
|
ground |
{ “enable” : boolean, “humidityLevel” : double, “dirtyLevel” : double, “adhesionCoefficient” : double } |
地面参数 |
Yes |
|
id |
string |
环境 id |
Yes |
|
name |
string |
环境名称 |
Yes |
|
schema |
string |
资源类型
Enum:
|
Yes |
|
thumbnail |
string |
缩略图路径 |
No |
|
builtIn |
boolean |
是否为内置 |
No |
|
classId |
string |
类型 |
Yes |
|
time |
string |
时间 |
Yes |
EnvironmentList
案例环境列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
{ [id]: Environment } |
环境实例 id 和环境数据作为键值对的对象 |
Yes |
|
allIds |
[ string ] |
环境实例 id 列表 |
Yes |
CaseSensorList
案例路测传感器列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
{ [id]: Sensor } |
传感器实例 id 和传感器数据作为键值对的对象 |
Yes |
|
allIds |
[ string ] |
传感器实例 id 列表 |
Yes |
JudgementList
案例判定列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
object |
判定实例 id 和数据作为键值对的对象 |
Yes |
|
allIds |
[ string ] |
判定实例 id |
Yes |
SpecialAreaList
案例特殊区域列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
object |
特殊区域实例 id 和数据作为键值对的对象 |
Yes |
|
allIds |
[ string ] |
特殊区域实例 id |
Yes |
MapGenConfigItem
案例地图配置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
enable |
boolean |
是否自动生成道路周边场景 |
Yes |
|
distance |
double |
间距 |
No |
|
distanceToRoadVerge |
double |
距路边的距离 |
No |
MapGenConfig
案例地图配置列表(键值对)
Record<string, MapGenConfigItem >
CommunicationConfig
通信公共参数设置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
frequencyBand |
double |
频段 |
Yes |
|
bandwidth |
double |
带宽 |
Yes |
|
maxRadiu |
double |
最大覆盖范围半径 |
Yes |
|
protocol |
string |
协议
Enum:
|
Yes |
|
model |
string |
无线通信传输模型
Enum:
|
Yes |
|
psSwitch |
boolean |
是否启用无线通信性能仿真 |
Yes |
CaseData
案例数据
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
environments |
环境配置 |
Yes |
|
|
sensors |
路侧传感器配置 |
Yes |
|
|
judgements |
判定配置 |
Yes |
|
|
specialAreas |
特殊区域配置 |
Yes |
|
|
mapGenConfig |
地图配置 |
No |
|
|
communicationParams |
通信公共参数设置 |
No |
|
|
schema |
string |
类型
Enum:
|
Yes |
|
caseId |
string |
案例 id |
Yes |
CaseCreateOptions
创建案例选项
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
envId |
string |
指定环境 id |
No |
|
mapGenConfig |
地图配置 |
No |
|
|
autoMapScene |
boolean |
省略 |
No |
|
scenario |
{ “vehicleId” : string, “content” : string } |
省略 |
No |
|
taskId |
string |
已完成任务存为案例时使用,任务 id |
No |
|
changeType |
boolean |
已完成任务存为案例时使用,表示是否把主车转换为对手车 |
No |
CaseCreateRequest
创建案例请求体
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
casedata |
案例数据 |
No |
|
|
options |
创建案例选项 |
No |
|
|
needRefresh |
boolean |
创建完成后是否更新页面 |
No |
CaseSaveResponse
更新案例的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
code |
double |
成功时为 0 |
No |
|
msg |
string |
返回信息 |
No |
CaseDefVehicle
案例主车配置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
案例主车资源 id |
Yes |
|
name |
string |
主车名称 |
Yes |
|
classId |
string |
主车模型 id |
Yes |
|
physicalGradeSensor |
double |
物理传感器数量 |
Yes |
|
category |
string |
省略 |
No |
|
instanceId |
string |
案例配置主车实例 id |
No |
|
instanceName |
string |
案例中的实例名称 |
No |
|
instanceColor |
string |
实例配色 |
No |
CaseDef
案例
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
schema |
string |
类型
Enum:
|
Yes |
|
id |
string |
案例 id |
Yes |
|
name |
string |
案例名称 |
Yes |
|
userId |
string |
用户名称 |
Yes |
|
created |
double |
创建时间 |
Yes |
|
lastModified |
double |
修改时间 |
Yes |
|
opponent |
object |
案例类型 |
Yes |
|
categoryId |
string |
目录 id |
No |
|
mapId |
string |
地图 id |
Yes |
|
mapName |
string |
地图名称 |
No |
|
vehicles |
[ CaseDefVehicle ] |
主车信息列表 |
No |
|
vehicleId |
[ string ] |
主车 id 列表 |
No |
|
tags |
[ string ] |
标签列表 |
No |
|
notes |
string |
备注 |
No |
|
builtIn |
boolean |
是否内置的 |
No |
|
joinway |
string |
省略 |
No |
|
thumbnail |
string |
缩略图 |
No |
|
roadSidePhysicalGradeSensor |
double |
路侧物理传感器数量 |
No |
PartialCaseDef
Partial< CaseDef >
表示 CaseDef 的每个键值对都是可选的
CaseSaveRequest
更新案例请求体
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
casedef |
案例信息 |
No |
|
|
casedata |
案例配置数据 |
Yes |
|
|
needRefresh |
boolean |
更新后是否更新页面 |
No |
CaseCloneResponse
案例克隆响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
clonedIds |
[ string ] |
复制成功后案例 id |
Yes |
CaseCloneRequest
案例克隆请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
ids |
[ string ] |
需要复制的案例的 id |
Yes |
|
categoryId |
string |
复制进文件夹的 id |
Yes |
CaseMoveResponse
移动案例响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
movedIds |
[ string ] |
案例 id 列表 |
Yes |
CaseMoveRequest
移动案例请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
ids |
[ string ] |
需要移动的案例的 id |
Yes |
|
categoryId |
string |
目的文件夹的 id |
Yes |
IRow
案例目录
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
目录 id |
Yes |
|
parentId |
string |
父目录 id |
No |
CaseExportRequest
导出案例请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
caseIds |
[ string ] |
案例 id 列表 |
Yes |
|
includesVehicle |
boolean |
是否包含主车 |
Yes |
|
includesMap |
boolean |
是否包含地图 |
Yes |
|
format |
string |
导出的案例格式
Enum:
|
Yes |
|
pathinfo |
[ IRow ] |
导出案例的目录信息 |
Yes |
CaseImportResponse
导入案例响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
导入文件的 md5 码 |
Yes |
|
isFixed |
boolean |
是否修复格式错误的案例 |
No |
|
reasons |
[ [ string ] ] |
错误原因 |
No |
Recordstringstring
键值对(值的类型是字符串)
Reacord<string, string>
CaseOverrideInfo
导入案例时的主车和地图信息
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
上传文件内包含的案例(包含相对路径) |
Yes |
|
name |
string |
名称 |
Yes |
|
replaceMap |
boolean |
是否替换地图 |
Yes |
|
replaceVehicle |
boolean |
是否替换主车 |
Yes |
|
missingMap |
boolean |
是否缺失地图 |
Yes |
|
missingVehicle |
boolean |
是否缺失主车 |
Yes |
|
overrideMapId |
string |
要替换为的地图 id |
Yes |
|
overrideVehicleId |
string |
要替换为的主车 id |
Yes |
|
mapId |
string |
可忽略 |
No |
|
mapName |
string |
可忽略 |
No |
|
vehicleIds |
[ string ] |
可忽略 |
No |
|
path |
string |
可忽略 上传文件内包含的案例(包含相对路径)+ ext |
No |
CaseImportRequest
导入案例的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
上传 file 文件时的 uploadId(uuid) |
Yes |
|
file |
string |
file 的 md5 (在服务端用作临时文件名称) |
Yes |
|
category |
string |
目录文件夹 |
Yes |
|
includesVehicle |
boolean |
是否包含主车 |
Yes |
|
includesMap |
boolean |
是否包含地图 |
Yes |
|
includes |
[ string ] |
上传文件内包含哪些案例(包含相对路径) |
Yes |
|
needRemoveCases |
传空对象就可以{} |
Yes |
|
|
overrides |
[ CaseOverrideInfo ] |
传空数组就可以[] |
Yes |
|
categoryInfo |
传空对象就可以{} |
Yes |
|
|
includesStopTrigger |
boolean |
添加默认案例结束条件(仿真时间>60s) |
No |
|
excludeVehicleIds |
[ string ] |
传空数组就可以[] |
No |
|
excludeMapIds |
[ string ] |
传空数组就可以[] |
No |
|
replaceVehiclesMap |
被替换的主车 |
No |
|
|
replaceMapIds |
[ string ] |
被替换的地图(从资源库删除) |
No |
|
name |
string |
上传文件的名称 |
Yes |
|
ext |
string |
file 后缀 (zip、sim、xosc) |
Yes |
|
ignoreNameChecking |
boolean |
标签列表 |
No |
|
tags |
[ string ] |
标签列表 |
No |
|
notes |
string |
备注 |
No |
|
needFix |
boolean |
是否需要验证失败的案例 |
No |
|
needFixCases |
[ string ] |
验证失败并需要修复的案例 |
No |
CheckSensorsRequest
检测案例配置的传感器是否过载的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
caseIds |
[ string ] |
需要运行的案例 id |
Yes |
|
maxWay |
double |
系统支持的传感器数量 |
Yes |
|
vehicleId |
string |
运行案例使用的主车 id, 不指定主车传"-1" |
Yes |
4.3 地图接口相关类型
CreateMapParams
创建地图参数
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
category |
string |
地图类型(目录)
Enum:
|
Yes |
|
id |
string |
默认是“” |
Yes |
|
name |
string |
名称 |
Yes |
|
size |
double |
从 xodr 解析获取 |
Yes |
|
ppm |
double |
从 xodr 解析获取 |
Yes |
|
bgColor |
string |
从 xodr 解析获取 |
Yes |
|
reproject |
boolean |
从 xodr 解析获取 |
Yes |
|
reprojectOrigin |
boolean |
从 xodr 解析获取 |
Yes |
|
reprojectOriginLat |
double |
从 xodr 解析获取 |
Yes |
|
reprojectOriginLng |
double |
从 xodr 解析获取 |
Yes |
|
tags |
[ string ] |
标签列表 |
No |
|
notes |
string |
备注 |
No |
MapCreateRequest
创建地图请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
params |
JSON 需要字符化 |
Yes |
|
|
xodr |
File |
xodr 文件 |
Yes |
|
thumbnail |
File |
地图缩略图文件 |
Yes |
4.4 文件接口相关类型
UploadFileParams
上传文件参数
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
uploadId |
string |
uuid |
Yes |
|
category |
string |
业务类型 |
Yes |
|
filename |
string |
文件名称 |
Yes |
|
index |
double |
chunks 序号 |
Yes |
|
chunks |
double |
分几次上传 |
Yes |
|
filesize |
double |
当前 chunk 大小 |
Yes |
FileUploadRequest
上传文件请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
params |
JSON 需要字符化 |
Yes |
|
|
file |
File |
文件 |
Yes |
4.5 主车接口相关类型
VehicleList
主车列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
{[id]: VehicleItem } |
主车 id 和数据作为键值对的对象 |
Yes |
|
allIds |
[ string ] |
主车资源 id |
Yes |
BasePageResponseVehicleList
获取主车列表的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
list |
主车列表 |
Yes |
|
|
page |
double |
当前页码 |
Yes |
|
total |
double |
主车总数 |
Yes |
VehicleCreateRequest
创建主车的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
name |
string |
主车名称 |
Yes |
|
classId |
string |
主车模型 id |
Yes |
|
overwriteId |
string |
要覆盖的主车 id |
No |
DataBlock
键值对
Reacord<string, any>
VehicleDynamics
主车动力学
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
name |
string |
名称 |
Yes |
|
schema |
string |
资源类型
|
Yes |
|
builtIn |
boolean |
是否内置 |
No |
|
type |
string |
动力学类型
Enum:
|
Yes |
|
params |
动力学参数 |
Yes |
VehicleCtl
主车控制器
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
type |
string |
类型 |
Yes |
|
name |
string |
名称 |
Yes |
|
params |
控制器参数 |
Yes |
|
|
aideId |
string |
辅助控制器 id |
No |
|
builtIn |
boolean |
是否内置 |
No |
SensorOutput
传感器输出设置
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byType |
{[selected]: any} |
输出配置 |
Yes |
|
selected |
string |
输出格式 |
Yes |
Sensor
传感器
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
name |
string |
名称 |
Yes |
|
schema |
string |
资源类型
Enum:
|
Yes |
|
category |
string |
目录 id |
Yes |
|
thumbnail |
string |
缩略图路径 |
No |
|
builtIn |
boolean |
是否内置 |
No |
|
classId |
string |
类型 |
Yes |
|
x |
double |
x 方向位置 |
Yes |
|
y |
double |
y 方向位置 |
Yes |
|
z |
double |
z 方向位置 |
Yes |
|
roll |
double |
倾斜角 |
Yes |
|
pitch |
double |
倾斜角 |
Yes |
|
yaw |
double |
倾斜角 |
Yes |
|
params |
传感器参数 |
Yes |
|
|
includeIds |
[ string ] |
融合传感器时,融合了哪些传感器 |
No |
|
output |
传感器输出设置 |
No |
|
|
disabled |
boolean |
是否禁用 |
No |
|
presetId |
string |
非内置时,表示原始传感器 id |
No |
VehicleItem
主车
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
name |
string |
名称 |
Yes |
|
thumbnail |
string |
缩略图路径 |
No |
|
builtIn |
boolean |
是否是内置 |
No |
|
schema |
string |
类型
Enum:
|
Yes |
|
classId |
string |
模型 id |
Yes |
|
driver |
string |
忽略
Enum:
|
Yes |
|
dynamics |
动力学参数 |
Yes |
|
|
controller |
控制器 |
Yes |
|
|
category |
string |
主车类型
Enum:
|
Yes |
|
sensors |
[ Sensor ] |
传感器配置 |
Yes |
PartialVehicleItem
Partial< VehicleItem >
表示 VehicleItem 的每个键值对都是可选的
VehicleSaveResponse
更新主车的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
更新后的数据 |
Yes |
VehicleSaveRequest
更新主车的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
主车信息 |
Yes |
|
|
overwrite |
boolean |
如果当前主车已删除,是否重新启用 |
No |
|
needRefresh |
boolean |
更新后是否刷新页面 |
No |
IsRepeatRequest
主车或测试集名称是否重复的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
name |
string |
名称 |
Yes |
VehiclesCreateRequest
导入主车的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
vehicleData |
导入主车的数据 |
Yes |
VehicleReplaceRequest
更新主车资源文件的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
params |
{ “type” : “controller” or “dynamics” } |
替换控制器或者动力学相关的资源,传参时需要字符串化 |
Yes |
|
file |
File |
要替换的资源文件 |
Yes |
4.6 测试集接口相关类型
SuiteList
测试集列表
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
byId |
{[id]: Suite } |
suiteid 和数据的键值对 |
Yes |
|
allIds |
[ string ] |
测试集 id 列表 |
Yes |
SuiteCreateRequest
创建测试集的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
parentId |
string |
父目录 id |
Yes |
|
name |
string |
名称 |
Yes |
Suite
测试集
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
schema |
string |
类型
Enum:
|
Yes |
|
id |
string |
ID |
Yes |
|
name |
string |
名称 |
Yes |
|
userId |
string |
用户 id |
Yes |
|
parentId |
string |
父目录 id |
Yes |
|
caseIds |
[ string ] |
包含哪些用例 |
No |
PartialSuite
Partial< Suite >
表示 Suite 的每个键值对都是可选的
SuiteSaveResponse
更新测试集的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
更新后的测试集 |
Yes |
SuiteSaveRequest
更新测试集的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
要更新的测试集 |
Yes |
|
|
caseIds |
[ string ] |
要操作的案例 id 列表 |
No |
|
delete |
boolean |
表示删除或者添加 caseIds |
No |
4.7 页面目录接口相关类型
CategoryMoveRequest
移动测试集的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
dragId |
string |
要移动的测试集 id |
Yes |
|
dropId |
string |
移动到相对这个测试集的某个位置 |
Yes |
|
state |
string |
相对 dropId 的位置
Enum:
|
Yes |
4.8 对手元素接口相关类型
ObstacleNpc
对手元素
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
ID |
Yes |
|
category |
string |
类型 |
Yes |
|
schema |
string |
元素分类
Enum:
|
Yes |
|
assetId |
double |
资源 id |
No |
|
name |
string |
名称 |
No |
|
uicategory |
string |
目录 id |
No |
|
oscSubCategory |
string |
osc 类型 |
No |
|
resourceType |
string |
元素资源的类型
Enum:
|
No |
|
resourceMd5 |
string |
资源文件 md5 |
No |
|
thumbnail |
string |
缩略图路径 |
Yes |
|
interpo |
string |
忽略
Enum:
|
Yes |
|
semantic |
string |
语义类型
Enum:
|
Yes |
|
builtIn |
boolean |
是否内置 |
No |
|
modelPath |
string |
外挂模型路径 |
No |
|
aniPath |
string |
外挂动画路径 |
No |
|
dimensions |
{ “length” : double, “width” : double, “height” : double } |
尺寸 |
No |
|
originToCenter |
{ “x” : double, “y” : double, “z” : double } |
原点位置 |
No |
PartialObstacleNpc
Partial< ObstacleNpc >
表示 ObstacleNpc 的每个键值对都是可选的
BasePageResponseObstacleNpcArray
获取对手元素列表的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
list |
[ ObstacleNpc ] |
对手元素列表 |
Yes |
|
page |
double |
当前页码 |
Yes |
|
total |
double |
总数 |
Yes |
ObstacleCreateRequest
创建对手元素的请求
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
data |
元素参数 |
Yes |
|
|
sourceId |
string |
已上传的文件 md5 |
Yes |
|
thumbnailId |
string |
已上传的缩略图的 md5 |
No |
4.9 算法接口相关类型
AlgorithmListResponse
获取算法列表的响应
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
list |
[ Algorithm ] |
算法列表 |
Yes |
|
page |
double |
当前页码 |
Yes |
|
total |
double |
总数 |
Yes |
Algorithm
算法
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
算法 id |
Yes |
|
name |
string |
名称 |
Yes |
|
type |
string |
类型
Enum:
|
Yes |
|
activatedId |
string |
最新算法版本 Id |
Yes |
|
activated |
最新算法版本 |
No |
|
|
clientId |
string |
所属客户端 UUID |
No |
AlgorithmVersion
算法版本
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
id |
string |
算法版本 id |
Yes |
|
algorithmId |
string |
所属算法 id |
Yes |
|
type |
string |
接入方式
Enum:
|
Yes |
|
params |
object |
算法参数 |
Yes |
|
notes |
string |
备注 |
No |
AlgorithmCreateData
算法创建参数
|
名称 |
类型 |
说明 |
是否必填 |
|---|---|---|---|
|
name |
string |
名称 |
Yes |
|
type |
string |
类型
Enum:
|
Yes |
|
versionData |
object |
Partial< AlgorithmVersion > |
Yes |
|
projectId |
string |
项目 id |
No |
|
notes |
string |
备注 |
No |
|
id |
string |
算法 id |
No |