Restful API 运行控制

提供基于 HTTP 的 Restful API,支持 Web 服务接口,控制 SimOne 界面的运行流程,比如可控制创建案例库,导入导出案例,运行停止案例等。

接口文档:

登录接口文档
任务接口文档
评价接口文档
资源接口文档

使用参考手册

1. 步骤描述

  1. 创建一个python文件 依次将接口路径、依赖、请求方法粘贴进去

  2. 顺序粘贴对应的 功能实现 模块代码

  3. 登录功能 必须要有并且在首位调用所有的操作都需要依赖登录功能携带的token

  4. 粘贴调用示例并稍微根据自己的环境做一些参数修改比如 请求路径修改 使用案例库案例名称修改 等,即可成功调用API

  5. 修改以下几处位置:

 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 默认值: "default"

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

VehicleControl

返回码

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

MainVehicleUIData


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

VehicleConfig

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

Notification

返回码

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

VizConfig

outputConfig

body

每页数量

Yes

OutputConfig

返回码

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 编码,如: encodeURIComponent(JSON.stringify(params.options))

Yes

FilterOptions

返回数据

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

TestPlan


2.4.3 创建测试计划

Path: /api-task/testPlan

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

data

body

创建测试计划

Yes

TestPlan

返回数据

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

TestPlan

返回数据

Code

说明

类型

200

Ok

TestPlan


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: "worldsim" , "logsim"

返回数据

Code

说明

类型

200

Ok

{ isRepeat : boolean}



通用请求头

Headers

参数名称

类型

说明

是否必填

Authorization

string

用于权限验证的 token

Yes

projectId

string

默认值: "default"

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: "worldsim" , "logsim"

search

搜索关键字

No

string

types

测试类型列表

No

TestTypes []

vehicleIds

主车 id 列表

No

string[]

algorithms

算法配置&版本列表

No

Array<{ type: string; groupIds?: string[] }>

triggerTypes

触发方式列表

No

Array< Enum: "manual" , "conditional" , "algorithm" , "timed" >

notifications

通知方式列表

No

Array<{ type: "dingtalk" , "none" ; groupIds?: string[] }>

stateMachine

状态机测试脚本列表

No

string[]

TestPlan

测试计划

字段名

说明

是否必填

类型

id

测试计划 id (创建时不传)

Yes

string

name

测试计划名称

Yes

string

category

案例类型

Yes

Enum: "worldsim" , "logsim"

categoryIds

测试用例文件夹 id 列表

No

string[]

caseSuiteIds

测试集 id 列表

No

string[]

type

测试类型

Yes

TestTypes a

Algorithm

LogSim 算法配置

No

Algorithm

vehicleConfig

WorldSim 主车与算法配置

No

VehicleConfig

overrideJudgementId

判定集, "-1"代表无

No

string

withEvaluation

是否自动评价

No

boolean

evaluationPresetId

评价预设 Id, "-1"代表无

No

string

triggerType

触发方式

No

Enum: "manual" , "conditional" , "algorithm" , "timed"

trigger

triggerType 值为 "conditional" , "timed" 时需要配置

No

Trigger

notification

运行结果通知配置

No

Notification

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

SuiteResponse


3.1.2 创建测试集

Path: /api-evaluation/suites

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

suite

body

包含id,name等测试集信息

Yes

{ “suite” : Suite }

返回数据

Code

说明

类型

200

OK

Suite



3.1.3 获取单个测试集

Path: /api-evaluation/suites/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

测试集id

Yes

string

返回数据

Code

说明

类型

200

OK

Suite


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

Suite



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

排序类型 "time" | "score"

No

string

order

query

升降序 "ASC" | "DESC"

No

string

返回数据

Code

说明

类型

200

OK

TaskResponse


3.2.2 创建任务

Path: /api-evaluation/tasks

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

task

body

包含id,name等任务信息

Yes

{ “task” : Task }

返回数据

Code

说明

类型

200

OK

Task



3.2.3 获取单个任务详情

Path: /api-evaluation/tasks/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

任务id

Yes

string

返回数据

Code

说明

类型

200

OK

Task


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

Task



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

PresetsResponse



3.3.2 获取分页预设

Path: /api-evaluation/presets

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

page

query

当前页码

No

number

pageSize

query

每页数量

No

number

返回数据

Code

说明

类型

200

OK

PresetsResponse


3.3.3 创建一个预设

Path: /api-evaluation/presets

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

preset

body

包含name,data等预设信息

Yes

Preset

返回数据

Code

说明

类型

200

OK

Preset



3.3.4 获取单个预设

Path: /api-evaluation/presets/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

预设id

Yes

number

返回数据

Code

说明

类型

200

OK

PresetResponse


3.3.5 更新单个预设

Path: /api-evaluation/presets/{id}

Method: PUT

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

预设id

Yes

number

data

body

要更新的预设信息对象

Yes

Preset

返回数据

Code

说明

类型

200

OK

Preset


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

Preset



3.3.8 导入单个预设

Path: /api-evaluation/presets/import

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

preset

body

要更新的预设信息

Yes

Preset

返回数据

Code

说明

类型

200

OK

PresetImportResponse



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

Evaluation

返回数据

Code

说明

类型

200

OK

Evaluation


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

Evaluation



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

Preset

预设数据

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

报告枚举类型: "task" , "suite"

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: "vehicleModel" , "trafficflow" , "sensor" , "judgement" , "dynamics" , "controller"

No

string

category

query

目录 id

No

string

vehicleOnly

query

为"true"时,只获取主车编辑器页面使用的资源

No

string

返回数据

Code

说明

类型

200

Ok

AssetList


4.1.2 创建资源

Path: /api-asset/assets

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

data :资源数据;
sourceId :当资源包含文件时,已上传的文件名称(md5);
overwriteId :如果传值将覆盖这个已存在的资源

No

{ “data” : Asset , “sourceId” : string, “overwriteId” : string }

返回数据

Code

说明

类型

200

Ok

AssetBaseResponse



4.1.3 获取指定资源

Path: /api-asset/assets/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

需要获取资源 id

Yes

string

返回数据

Code

说明

类型

200

Ok

Asset


4.1.4 修改资源

Path: /api-asset/assets/{id}

Method: PUT

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

需要更新的资源 id

Yes

string

requestBody

body

请求体

Yes

AssetSaveRequest

返回数据

Code

说明

类型

200

Ok

AssetBaseResponse


4.1.5 删除资源

Path: /api-asset/assets/{id}

Method: DELETE

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

要删除的资源 id

Yes

string

返回数据

Code

说明

类型

200

Ok

AssetBaseResponse



4.1.6 资源判重

Path: /api-asset/assets/isrepeat

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

AssetIsRepeatRequest

返回数据

Code

说明

类型

200

Ok

IsRepeatResponse



4.1.7 克隆资源

Path: /api-asset/assets/{id}/clone

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

要克隆资源的 id

Yes

string

返回数据

Code

说明

类型

200

Ok

AssetBaseResponse



4.2 案例接口

4.2.1 创建案例

Path: /api-asset/cases

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseCreateRequest extends PartialCaseDef

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.2.2 已完成任务另存为案例

Path: /api-asset/cases/vr

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseCreateRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.2.3 更新案例

Path: /api-asset/cases/update

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseSaveRequest

返回数据

Code

说明

类型

200

Ok

CaseSaveResponse



4.2.4 克隆案例

Path: /api-asset/cases/clone

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseCloneRequest

返回数据

Code

说明

类型

200

Ok

CaseCloneResponse



4.2.5 移动案例

Path: /api-asset/cases/move

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseMoveRequest

返回数据

Code

说明

类型

200

Ok

CaseMoveResponse



4.2.6 导出案例

Path: /api-asset/cases/export

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseExportRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.2.7 导入案例

Path: /api-asset/cases/import

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CaseImportRequest

返回数据

Code

说明

类型

200

Ok

CaseImportResponse



4.2.8 获取传感器数量超载的案例

Path: /api-asset/cases/checkSensors

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CheckSensorsRequest

返回数据

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

MapCreateRequest

返回数据

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

FileUploadRequest

返回数据

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: "case" , "vehicleModel"

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

BasePageResponseVehicleList


4.5.2 创建主车

Path: /api-asset/vehicles

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

VehicleCreateRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.5.3 获取指定主车

Path: /api-asset/vehicles/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

主车 id

Yes

string

返回数据

Code

说明

类型

200

Ok

VehicleItem



4.5.4 更新主车

Path: /api-asset/vehicles/{id}

Method: PUT

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

VehicleSaveRequest

返回数据

Code

说明

类型

200

Ok

VehicleSaveResponse


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

IsRepeatRequest

返回数据

Code

说明

类型

200

Ok

IsRepeatResponse



4.5.7 克隆主车

Path: /api-asset/vehicles/{id}/clone

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

主车 id

Yes

string

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.5.8 更新主车资源文件

Path: /api-asset/vehicles/{vehicleId}/files

Method: POST

Headers: FormDataHeaders

请求参数

参数名称

传参格式

说明

是否必填

类型

vehicleId

path

主车 id

Yes

string

formData

body

请求体

Yes

VehicleReplaceRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse

Header



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

VehiclesCreateRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.6 测试集接口

4.6.1 获取测试集列表

Path: /api-asset/suites

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

opponent

query

案例类型 Enum: "openscenario"

Yes

string

返回数据

Code

说明

类型

200

Ok

SuiteList


4.6.2 创建测试集

Path: /api-asset/suites

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

SuiteCreateRequest

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.6.3 获取测试集

Path: /api-asset/suites/{id}

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

测试集 id

Yes

string

返回数据

Code

说明

类型

200

Ok

Suite


4.6.4 更新测试集

Path: /api-asset/suites/{id}

Method: PUT

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

测试集 id

Yes

string

requestBody

body

请求体

Yes

SuiteSaveRequest

返回数据

Code

说明

类型

200

Ok

SuiteSaveResponse


4.6.5 删除测试集

Path: /api-asset/suites/{id}

Method: DELETE

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

id

path

测试集 id

Yes

string

opponent

query

案例类型 Enum: "openscenario"

No

string

返回数据

Code

说明

类型

200

Ok

GeneralResponse



4.6.6 移动测试集

Path: /api-asset/suites/move

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

CategoryMoveRequest

返回数据

Code

说明

类型

200

Ok

{}



4.6.7 测试集判重

Path: /api-asset/suites/isrepeat

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

IsRepeatRequest

返回数据

Code

说明

类型

200

Ok

IsRepeatResponse



4.7 页面目录接口

4.7.1 获取目录列表

Path: /api-asset/categories

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

pageType

query

页面类型 Enum: "assets" , "case" , "vehicle" , "judgeAsset"

Yes

string

返回数据

Code

说明

类型

200

Ok

AssetList



4.8 对手元素接口

4.8.1 获取对手元素列表

Path: /api-asset/obstacles

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

schema

query

Enum: "dynamic" , "static"
障碍物类型,指定 category 时可以不传

Yes

string

category

query

目录 id

Yes

string

page

query

页码

No

string

pageSize

query

每页数量

No

string

search

query

搜索关键字

No

string

返回数据

Code

说明

类型

200

Ok

BasePageResponseObstacleNpcArray


4.8.2 创建自定义对手元素

Path: /api-asset/obstacles

Method: POST

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

requestBody

body

请求体

Yes

ObstacleCreateRequest

返回数据

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

ObstacleCreateRequest

返回数据

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

IsRepeatResponse



4.9 算法接口

4.9.1 获取算法列表

Path: /api-asset/algorithms

Method: GET

Headers: Headers

请求参数

参数名称

传参格式

说明

是否必填

类型

type

query

Enum: "client" , "cloud" , ""

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

AlgorithmListResponse




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

AlgorithmVersion




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

AlgorithmCreateData

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

默认值: "default"

Yes

accept

application/json

客户端接收 JSON 数据

No

FormDataHeaders

名称

类型

说明

是否必填

Authorization

string

用于权限验证的 token

Yes

projectId

string

默认值: "default"

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

Asset

资源数据

Yes

AssetSaveRequest

修改资源的请求体

名称

类型

说明

是否必填

data

PartialAsset

更新的资源的数据

Yes

sourceId

string

当资源包含文件时,已上传的文件名称

No

overwrite

boolean

是否重新启用已删除的资源

No

needRefresh

boolean

更新后是否刷新页面列表

No

IsRepeatResponse

是否重复的响应

名称

类型

说明

是否必填

isRepeat

boolean

是否重复

Yes

AssetIsRepeatRequest

资源是否重复的请求体

名称

类型

说明

是否必填

schema

string

资源类型 Enum: "vehicleModel" , "trafficflow" , "sensor" , "judgement" , "dynamics" , "controller"

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: "environment"

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: "LTE-V"

Yes

model

string

无线通信传输模型 Enum: "Urban" , "Rural"

Yes

psSwitch

boolean

是否启用无线通信性能仿真

Yes

CaseData

案例数据

名称

类型

说明

是否必填

environments

EnvironmentList

环境配置

Yes

sensors

CaseSensorList

路侧传感器配置

Yes

judgements

JudgementList

判定配置

Yes

specialAreas

SpecialAreaList

特殊区域配置

Yes

mapGenConfig

MapGenConfig

地图配置

No

communicationParams

CommunicationConfig

通信公共参数设置

No

schema

string

类型 Enum: "casedata"

Yes

caseId

string

案例 id

Yes

CaseCreateOptions

创建案例选项

名称

类型

说明

是否必填

envId

string

指定环境 id

No

mapGenConfig

MapGenConfig

地图配置

No

autoMapScene

boolean

省略

No

scenario

{ “vehicleId” : string, “content” : string }

省略

No

taskId

string

已完成任务存为案例时使用,任务 id

No

changeType

boolean

已完成任务存为案例时使用,表示是否把主车转换为对手车

No

CaseCreateRequest

创建案例请求体

名称

类型

说明

是否必填

casedata

CaseData

案例数据

No

options

CaseCreateOptions

创建案例选项

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: "casedef"

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

PartialCaseDef

案例信息

No

casedata

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: "simone" , "xosc"

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

Recordstringstring

传空对象就可以{}

Yes

overrides

[ CaseOverrideInfo ]

传空数组就可以[]

Yes

categoryInfo

Recordstringstring

传空对象就可以{}

Yes

includesStopTrigger

boolean

添加默认案例结束条件(仿真时间>60s)

No

excludeVehicleIds

[ string ]

传空数组就可以[]

No

excludeMapIds

[ string ]

传空数组就可以[]

No

replaceVehiclesMap

Recordstringstring

被替换的主车

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: "integrated" , "atomic" , "customized" , "city" , "city_viaduct" , "city_parking" , "city_integrated" , "i_highway" , "i_highway_integrated" , "straightway" , "turn" , "crossroads" , "T_junction" , "roundabout" , "a_highway"

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

CreateMapParams

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

UploadFileParams

JSON 需要字符化

Yes

file

File

文件

Yes

4.5 主车接口相关类型

VehicleList

主车列表

名称

类型

说明

是否必填

byId

{[id]: VehicleItem }

主车 id 和数据作为键值对的对象

Yes

allIds

[ string ]

主车资源 id

Yes

BasePageResponseVehicleList

获取主车列表的响应

名称

类型

说明

是否必填

list

VehicleList

主车列表

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

资源类型 "dynamics"

Yes

builtIn

boolean

是否内置

No

type

string

动力学类型 Enum: "srvehicles" , "srvehicle-truck" , "srvehicle-bus" , "carsim" , "carmaker" , "vigrade" , "none"

Yes

params

DataBlock

动力学参数

Yes

VehicleCtl

主车控制器

名称

类型

说明

是否必填

id

string

ID

Yes

type

string

类型

Yes

name

string

名称

Yes

params

DataBlock

控制器参数

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: "sensor"

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

DataBlock

传感器参数

Yes

includeIds

[ string ]

融合传感器时,融合了哪些传感器

No

output

SensorOutput

传感器输出设置

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: "vehicle"

Yes

classId

string

模型 id

Yes

driver

string

忽略 Enum: "ai" , "human"

Yes

dynamics

VehicleDynamics

动力学参数

Yes

controller

VehicleCtl

控制器

Yes

category

string

主车类型 Enum: "Bike" , "Vehicle" , "Pedestrian"

Yes

sensors

[ Sensor ]

传感器配置

Yes

PartialVehicleItem

Partial< VehicleItem >

表示 VehicleItem 的每个键值对都是可选的

VehicleSaveResponse

更新主车的响应

名称

类型

说明

是否必填

data

PartialVehicleItem

更新后的数据

Yes

VehicleSaveRequest

更新主车的请求

名称

类型

说明

是否必填

data

PartialVehicleItem

主车信息

Yes

overwrite

boolean

如果当前主车已删除,是否重新启用

No

needRefresh

boolean

更新后是否刷新页面

No

IsRepeatRequest

主车或测试集名称是否重复的请求

名称

类型

说明

是否必填

name

string

名称

Yes

VehiclesCreateRequest

导入主车的请求

名称

类型

说明

是否必填

vehicleData

VehicleList

导入主车的数据

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: "suite"

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

PartialSuite

更新后的测试集

Yes

SuiteSaveRequest

更新测试集的请求

名称

类型

说明

是否必填

data

PartialSuite

要更新的测试集

Yes

caseIds

[ string ]

要操作的案例 id 列表

No

delete

boolean

表示删除或者添加 caseIds

No

4.7 页面目录接口相关类型

CategoryMoveRequest

移动测试集的请求

名称

类型

说明

是否必填

dragId

string

要移动的测试集 id

Yes

dropId

string

移动到相对这个测试集的某个位置

Yes

state

string

相对 dropId 的位置 Enum: "up" , "down" , "inside"

Yes

4.8 对手元素接口相关类型

ObstacleNpc

对手元素

名称

类型

说明

是否必填

id

string

ID

Yes

category

string

类型

Yes

schema

string

元素分类 Enum: "dynamic" , "static"

Yes

assetId

double

资源 id

No

name

string

名称

No

uicategory

string

目录 id

No

oscSubCategory

string

osc 类型

No

resourceType

string

元素资源的类型 Enum: "model" , "chartlet" , "external"

No

resourceMd5

string

资源文件 md5

No

thumbnail

string

缩略图路径

Yes

interpo

string

忽略 Enum: "clothoid" , "legacy"

Yes

semantic

string

语义类型 Enum: "vehicle" , "none"

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

PartialObstacleNpc

元素参数

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: "client" , "cloud" , "builtIn"

Yes

activatedId

string

最新算法版本 Id

Yes

activated

AlgorithmVersion

最新算法版本

No

clientId

string

所属客户端 UUID

No

AlgorithmVersion

算法版本

名称

类型

说明

是否必填

id

string

算法版本 id

Yes

algorithmId

string

所属算法 id

Yes

type

string

接入方式 Enum: "Manual" , "SM" , "SimOneDriver" , "Simulator , "Simulink"

Yes

params

object

算法参数

Yes

notes

string

备注

No

AlgorithmCreateData

算法创建参数

名称

类型

说明

是否必填

name

string

名称

Yes

type

string

类型 Enum: "client" , "cloud" , ""

Yes

versionData

object

Partial< AlgorithmVersion >

Yes

projectId

string

项目 id

No

notes

string

备注

No

id

string

算法 id

No