├── .gitignore
├── .idea
├── .gitignore
├── api_auto_test.iml
├── deployment.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── Report
└── html
│ └── data
│ ├── behaviors.csv
│ ├── behaviors.json
│ ├── categories.csv
│ ├── categories.json
│ ├── packages.json
│ ├── suites.csv
│ ├── suites.json
│ └── timeline.json
├── common
├── Init.py
├── __init__.py
├── assert_pro.py
├── check_json.py
├── check_result.py
├── config_http.py
├── consts.py
├── custom_fail.py
├── expected_manage.py
├── function_replace.py
├── get_relevance.py
├── host_manage.py
├── log.py
├── param_manage.py
├── read_param.py
├── request_send.py
├── send_email.py
├── shell.py
└── test_and_check.py
├── conf
├── __init__.py
├── cfg.ini
├── conf.py
└── conf_relevance.py
├── logdir
├── 2019-11-20.log
├── __init__.py
├── err.log
└── log.log
├── params
├── __init__.py
└── param
│ ├── __init__.py
│ ├── images
│ ├── __init__.py
│ └── image_create.yaml
│ ├── network
│ ├── __init__.py
│ ├── create_network.yaml
│ ├── delete_network.yaml
│ └── network_result.json
│ ├── os_volume_attach_detach
│ ├── __init__.py
│ ├── os_volume_attac_and_detach.yaml
│ └── os_volume_attach_adn_detach_result.json
│ ├── project
│ ├── __init__.py
│ ├── create_project.yaml
│ └── delete_project.yaml
│ ├── server
│ ├── __init__.py
│ ├── create_server.yaml
│ ├── delete_server.yaml
│ └── server_result.json
│ ├── server_snapshot
│ ├── __init__.py
│ ├── delete_server_snap.yaml
│ ├── get_server_snap.yaml
│ ├── get_server_snap_result.json
│ └── server_snap.yaml
│ ├── subnet
│ ├── Subnet.yaml
│ ├── __init__.py
│ ├── delete_subnet.yaml
│ └── subnet_result.json
│ ├── volume
│ ├── __init__.py
│ ├── delete_volume.yaml
│ ├── volume.yaml
│ └── volume_result.json
│ └── volume_snap
│ ├── delete_volume_snap.yaml
│ ├── volume_snap.yaml
│ └── volume_snap_result.json
├── pytest.ini
├── readme.md
├── report
├── __init__.py
└── html
│ └── data
│ ├── behaviors.csv
│ ├── behaviors.json
│ ├── categories.csv
│ ├── categories.json
│ ├── packages.json
│ ├── suites.csv
│ ├── suites.json
│ └── timeline.json
├── requirements.txt
├── run.py
├── testcase
├── __init__.py
├── conftest.py
├── test_01_project.py
├── test_02_network.py
├── test_03_subnet.py
├── test_04_server.py
├── test_05_volume.py
├── test_06_os_volume_attachments.py
├── test_07_volume_snap.py
├── test_08_server_snap.py
├── test_09_get_server_snap.py
├── test_10_delete_volume_snap.py
├── test_11_delete_server_snap.py
├── test_12_delete_server.py
├── test_13_delete_subnet.py
├── test_14_delete_network.py
├── test_15_delete_volume.py
└── test_16_delete_project.py
└── unit
├── __init__.py
├── add_role_admin.py
├── api_method.py
├── api_send.py
├── choice_data.py
├── get_time.py
├── initialize_env.py
├── load_yaml.py
├── md5_data.py
├── ports.py
├── rand_string.py
├── random_float.py
├── random_int.py
└── token.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | report
3 | params
4 | venv
5 | allure-report
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/.idea/api_auto_test.iml:
--------------------------------------------------------------------------------
1 |
2 |
本次接口自动化测试报告如下。
31 | # """ 32 | # mail_body = MIMEText(body, _subtype='html', _charset='utf-8') 33 | stress_body = consts.STRESS_LIST 34 | result_body = consts.RESULT_LIST 35 | body2 = 'Hi,all\n本次接口自动化测试报告如下:\n 接口响应时间集:%s\n 接口运行结果集:%s' % (stress_body, result_body) 36 | mail_body2 = MIMEText(body2, _subtype='plain', _charset='utf-8') 37 | tm = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) 38 | msg['Subject'] = Header("接口自动化测试报告"+"_"+tm, 'utf-8') 39 | msg['From'] = self.config.sender 40 | receivers = self.config.receiver 41 | toclause = receivers.split(',') 42 | msg['To'] = ",".join(toclause) 43 | # msg.attach(mail_body) 44 | msg.attach(mail_body2) 45 | try: 46 | smtp = smtplib.SMTP() 47 | smtp.connect(self.config.smtpserver) 48 | smtp.login(self.config.username, self.config.password) 49 | smtp.sendmail(self.config.sender, toclause, msg.as_string()) 50 | except Exception as e: 51 | print(e) 52 | print("发送失败") 53 | self.log.error("邮件发送失败,请检查邮件配置") 54 | 55 | else: 56 | print("发送成功") 57 | self.log.info("邮件发送成功") 58 | finally: 59 | smtp.quit() 60 | 61 | if __name__ == '__main__': 62 | try: 63 | mail = SendMail() 64 | mail.sendMail() 65 | except Exception as e: 66 | log.MyLog.error('发送邮件失败,请检查邮件配置') 67 | raise -------------------------------------------------------------------------------- /common/shell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env.ini python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/11 15:34 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : shell.py 7 | # @Software: PyCharm 8 | 9 | """ 10 | 封装执行shell语句方法 11 | 12 | """ 13 | 14 | import subprocess 15 | 16 | 17 | class Shell: 18 | @staticmethod 19 | def invoke(cmd): 20 | output, errors = subprocess.Popen( 21 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() 22 | o = output.decode("utf-8") 23 | return o 24 | -------------------------------------------------------------------------------- /conf/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:32 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /conf/cfg.ini: -------------------------------------------------------------------------------- 1 | [email] 2 | send = no 3 | smtpserver = smtp.qq.com 4 | port = 465 5 | sender = ******* 6 | psw = ***** 7 | receiver = **** 8 | username = ***** 9 | 10 | [env] 11 | tester = wuzushun 12 | environment = 192.168.54.103 13 | versioncode = V1.0 14 | host = 192.168.54.103 15 | logininfo = {"auth": {"scope": {"project": {"domain":{"id": "default"},"name": "${project_token_name}$"}}, "identity":{"password": {"user": {"domain":{"id": "default"},"password":"admin","name":"admin"}},"methods":["password"]}}} 16 | openstack_version = liberty 17 | virtual = VMware 18 | nova_api = V2.0 19 | cinder_api = V2.0 20 | neutron_api = V2.0 21 | glance_api = V2.0 22 | keystone_api = V3.0 23 | 24 | [test_data] 25 | name = $RandomInt(0,10)$ 26 | type = Web 27 | version = $RandomString(10)$ 28 | description = api_auto_$RandomString(10)$ 29 | project_id = deb02a9751a34c069a1ba0d433692983 30 | token_id = 86069a8ced2247f7a71a394ef126e98f 31 | project_name = $RandomString(20)$ 32 | network_name = $RandomString(20)$_netwrok 33 | subnet_name = $RandomString(20)$_subnet 34 | network_id = 2d2ed54b-b28a-4992-ac79-2a1556208ce2 35 | subnet_id = 91e29e60-51bf-4fcc-baf8-45ea93417165 36 | image_id = fce5d3b1-898d-44eb-80be-4b5025d53d2f 37 | flavor_id = d5a46f4d-6d28-465e-95be-bae0f0585488 38 | server_name = wuzs_$RandomString(20)$ 39 | server_id = 2ba5697e-ad6c-4328-a48c-edc24090a0ec 40 | project_token_name = 1GnvNTtEApkdLJ5Dw0VK 41 | admin_id = a757df739a5e492da79d525d4c7c5acf 42 | admin_role_id = afef96fbbcb944e8a36df7131abfe3ed 43 | volume_name = volume_$RandomString(20)$ 44 | volume_id = 81365616-725e-4d65-ac3c-b2e3691a762c 45 | server_snap_name = snap_8JkrX4yjSduLBPHcmTxC 46 | server_snap_id = 43af6b09-d047-4a87-a2c8-06bf8be91141 47 | volume_snapshot_id = 6976d7c6-fb93-4ff1-b5fa-859c37d7b6e3 48 | network_name_for_check = Gt9nkm3EiRaxjSyIVONZ_netwrok 49 | 50 | -------------------------------------------------------------------------------- /conf/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env.ini python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/9 16:35 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : conf.py 7 | # @Software: PyCharm 8 | 9 | from configparser import ConfigParser 10 | from common import log 11 | import os 12 | 13 | 14 | class Config: 15 | # titles: 16 | TITLE_ENV = "env" 17 | TITLE_EMAIL = "email" 18 | TITLE_TEST_DATA = "test_data" 19 | 20 | 21 | # values: 22 | # [env.ini] 23 | VALUE_TESTER = "tester" 24 | VALUE_ENVIRONMENT = "environment" 25 | VALUE_VERSION_CODE = "versionCode" 26 | VALUE_HOST = "host" 27 | VALUE_LOGIN_INFO = "loginInfo" 28 | # [mail] 29 | VALUE_SEND = "send" 30 | VALUE_SMTP_SERVER = "smtpserver" 31 | VALUE_SENDER = "sender" 32 | VALUE_RECEIVER = "receiver" 33 | VALUE_USERNAME = "username" 34 | VALUE_PASSWORD = "psw" 35 | #[test_data] 36 | VALUE_TOKEN = "token_id" 37 | 38 | # path 39 | path_dir = str(os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))) 40 | 41 | def __init__(self): 42 | """ 43 | 初始化 44 | """ 45 | self.config = ConfigParser() 46 | self.log = log.MyLog() 47 | self.conf_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cfg.ini') 48 | self.xml_report_path = Config.path_dir+'/report/xml' 49 | self.html_report_path = Config.path_dir+'/report/html' 50 | 51 | if not os.path.exists(self.conf_path): 52 | raise FileNotFoundError("请确保配置文件存在!") 53 | 54 | self.config.read(self.conf_path, encoding='utf-8') 55 | 56 | self.tester = self.get_conf(Config.TITLE_ENV, Config.VALUE_TESTER) 57 | self.environment = self.get_conf(Config.TITLE_ENV, Config.VALUE_ENVIRONMENT) 58 | self.versionCode = self.get_conf(Config.TITLE_ENV, Config.VALUE_VERSION_CODE) 59 | self.host = self.get_conf(Config.TITLE_ENV, Config.VALUE_HOST) 60 | self.loginInfo = self.get_conf(Config.TITLE_ENV, Config.VALUE_LOGIN_INFO) 61 | 62 | self.smtpserver = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_SMTP_SERVER) 63 | self.sender = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_SENDER) 64 | self.receiver = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_RECEIVER) 65 | self.username = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_USERNAME) 66 | self.password = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_PASSWORD) 67 | self.send = self.get_conf(Config.TITLE_EMAIL, Config.VALUE_SEND) 68 | self.token = self.get_conf(Config.TITLE_TEST_DATA,Config.VALUE_TOKEN) 69 | 70 | def get_conf(self, title, value): 71 | """ 72 | 配置文件读取 73 | :param title: 74 | :param value: 75 | :return: 76 | """ 77 | return self.config.get(title, value) 78 | 79 | def set_conf(self, title, value, text): 80 | """ 81 | 配置文件修改 82 | :param title: 83 | :param value: 84 | :param text: 85 | :return: 86 | """ 87 | self.config.set(title, value, text) 88 | with open(self.conf_path, "w+") as f: 89 | return self.config.write(f) 90 | 91 | def add_conf(self, title): 92 | """ 93 | 配置文件添加 94 | :param title: 95 | :return: 96 | """ 97 | self.config.add_section(title) 98 | with open(self.conf_path, "w+") as f: 99 | return self.config.write(f) 100 | 101 | 102 | if __name__ == "__main__": 103 | cnf = Config() 104 | cnf.set_conf("test_data","project_id","23456787654321") -------------------------------------------------------------------------------- /conf/conf_relevance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/9 22:37 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : conf_relevance.py 7 | # @Software: PyCharm 8 | 9 | 10 | import configparser 11 | 12 | from common.log import MyLog as logging 13 | from common.function_replace import function_replace 14 | 15 | 16 | class ConfRelevance: 17 | # 关联文件读取配置 18 | def __init__(self, _path, title): 19 | 20 | logging.info("初始化关联文件") 21 | config = configparser.ConfigParser() 22 | config.read(_path, encoding="utf-8") 23 | self.host = config[title] 24 | 25 | def get_relevance_conf(self): 26 | relevance = dict() 27 | logging.debug("读取初始关联文件内容: %s" % self.host.items()) 28 | for key, value in self.host.items(): 29 | relevance[key] = function_replace(value) 30 | logging.debug("初始关联内容数据处理后: %s" % relevance) 31 | return relevance 32 | 33 | 34 | if __name__ == "__main__": 35 | host = ConfRelevance("D:\\4_code\\os_l_test\\conf\\cfg.ini", "test_data") 36 | print(host.get_relevance_conf()) 37 | -------------------------------------------------------------------------------- /logdir/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:32 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /logdir/err.log: -------------------------------------------------------------------------------- 1 | [ERROR 2019-10-22 17:30:12]statusCode error, expected_code is 202, statusCode is 400 2 | [ERROR 2019-10-22 18:45:40]statusCode error, expected_code is 200, statusCode is 400 3 | [ERROR 2019-10-22 18:45:40]statusCode error, expected_code is 202, statusCode is 400 4 | [ERROR 2019-10-22 19:21:11]statusCode error, expected_code is 202, statusCode is 400 5 | [ERROR 2019-10-22 20:04:07]statusCode error, expected_code is 202, statusCode is 400 6 | [ERROR 2019-10-22 20:25:04]statusCode error, expected_code is 200, statusCode is 409 7 | [ERROR 2019-10-22 20:25:04]statusCode error, expected_code is 202, statusCode is 404 8 | [ERROR 2019-10-22 20:32:16]statusCode error, expected_code is 200, statusCode is 409 9 | [ERROR 2019-10-22 20:32:16]statusCode error, expected_code is 202, statusCode is 404 10 | [ERROR 2019-10-29 16:35:03]statusCode error, expected_code is 200, statusCode is 409 11 | [ERROR 2019-10-29 16:35:04]statusCode error, expected_code is 202, statusCode is 404 12 | [ERROR 2019-10-29 16:35:05]statusCode error, expected_code is 202, statusCode is 409 13 | [ERROR 2019-11-01 16:32:17]statusCode error, expected_code is 200, statusCode is 409 14 | [ERROR 2019-11-01 16:32:18]statusCode error, expected_code is 202, statusCode is 404 15 | [ERROR 2019-11-03 20:22:26]statusCode error, expected_code is 200, statusCode is 409 16 | [ERROR 2019-11-03 20:22:27]statusCode error, expected_code is 202, statusCode is 404 17 | [ERROR 2019-11-03 20:22:30]statusCode error, expected_code is 202, statusCode is 409 18 | [ERROR 2019-11-03 20:31:26]statusCode error, expected_code is 200, statusCode is 409 19 | [ERROR 2019-11-03 20:31:27]statusCode error, expected_code is 202, statusCode is 404 20 | [ERROR 2019-11-03 20:31:28]statusCode error, expected_code is 202, statusCode is 409 21 | [ERROR 2019-11-05 19:14:19]statusCode error, expected_code is 200, statusCode is 404 22 | [ERROR 2019-11-05 19:14:19]statusCode error, expected_code is 200, statusCode is 404 23 | [ERROR 2019-11-05 19:14:19]statusCode error, expected_code is 202, statusCode is 404 24 | [ERROR 2019-11-05 19:17:43]statusCode error, expected_code is 200, statusCode is 404 25 | [ERROR 2019-11-05 19:38:06]This is error 26 | [ERROR 2019-11-05 19:43:00]This is error 27 | [ERROR 2019-11-05 19:43:30]This is error 28 | [ERROR 2019-11-05 19:45:26]This is error 29 | [ERROR 2019-11-05 20:46:18]statusCode error, expected_code is 202, statusCode is 400 30 | [ERROR 2019-11-05 20:46:19]statusCode error, expected_code is 202, statusCode is 400 31 | [ERROR 2019-11-05 20:46:20]statusCode error, expected_code is 202, statusCode is 400 32 | [ERROR 2019-11-05 22:57:50]statusCode error, expected_code is 202, statusCode is 400 33 | [ERROR 2019-11-05 22:57:50]statusCode error, expected_code is 202, statusCode is 400 34 | [ERROR 2019-11-05 23:11:07]statusCode error, expected_code is 202, statusCode is 200 35 | [ERROR 2019-11-05 23:11:07]statusCode error, expected_code is 202, statusCode is 200 36 | [ERROR 2019-11-05 23:11:07]statusCode error, expected_code is 202, statusCode is 200 37 | [ERROR 2019-11-05 23:11:08]statusCode error, expected_code is 202, statusCode is 200 38 | [ERROR 2019-11-05 23:25:38]statusCode error, expected_code is 202, statusCode is 400 39 | [ERROR 2019-11-05 23:25:39]statusCode error, expected_code is 202, statusCode is 400 40 | [ERROR 2019-11-05 23:25:40]statusCode error, expected_code is 202, statusCode is 400 41 | [ERROR 2019-11-06 08:47:08]statusCode error, expected_code is 202, statusCode is 400 42 | [ERROR 2019-11-06 14:16:08]statusCode error, expected_code is 202, statusCode is 400 43 | [ERROR 2019-11-07 09:06:57]statusCode error, expected_code is 202, statusCode is 400 44 | [ERROR 2019-11-07 09:06:58]statusCode error, expected_code is 202, statusCode is 400 45 | [ERROR 2019-11-20 09:55:02]statusCode error, expected_code is 202, statusCode is 400 46 | [ERROR 2019-11-20 11:30:17]statusCode error, expected_code is 202, statusCode is 400 47 | [ERROR 2019-11-20 11:30:18]statusCode error, expected_code is 202, statusCode is 400 48 | [ERROR 2019-11-20 11:30:29]statusCode error, expected_code is 202, statusCode is 400 49 | [ERROR 2019-11-20 11:30:39]statusCode error, expected_code is 202, statusCode is 400 50 | -------------------------------------------------------------------------------- /params/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:32 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:33 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/images/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2019/11/21 15:48 3 | # @Author : mrwuzs 4 | # @Email : mrwuzs@outlook.com 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | 8 | -------------------------------------------------------------------------------- /params/param/images/image_create.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_17_delete_server_snap 3 | title: 虚拟机快照 4 | port: 9292 5 | address: /v2 6 | 7 | premise: 8 | 9 | # 测试用例 10 | test_case: 11 | # 第一条case,info可不填 12 | - test_name: 删除虚拟机快照 # 必填,parameter为文件路径时 13 | info: 删除虚拟机快照 14 | http_type: http # 请求协议 15 | request_type: post # 请求类型 16 | parameter_type: raw # 参数类型 17 | address: /v2/images/${server_snap_id}$ 18 | headers: # 请求头 19 | Content-Type: application/json 20 | X-Auth-Token: ${token_id}$ 21 | timeout: 20 22 | sleep_time: 0 23 | parameter: 24 | volume: 25 | size: 1 26 | name: ${volume_name}$ 27 | file: false 28 | check: 29 | - check_type: only_check_status 30 | datebase: 31 | expected_code: 204 32 | expected_request: {} 33 | relevance: 34 | 35 | - test_name: 删除虚拟机快照后查看询 36 | info: 删除虚拟机快照后查看询 37 | http_type: http 38 | request_type: get 39 | parameter_type: raw 40 | address: /v2/images/${server_snap_id}$ 41 | headers: 42 | Content-Type: application/json 43 | X-Auth-Token: ${token_id}$ 44 | timeout: 20 45 | sleep_time: 20 46 | parameter: 47 | volume: 48 | size: 1 49 | file: false 50 | check: 51 | - check_type: only_check_status 52 | datebase: 53 | expected_code: 404 54 | expected_request: {} 55 | relevance: -------------------------------------------------------------------------------- /params/param/network/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:54 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/network/create_network.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_02_create_network 3 | title: 网络 4 | port: 9696 5 | address: /v2.0/networks # 请求地址 选填(此处不填,每条用例必填) string 6 | premise: 7 | 8 | test_case: 9 | - test_name: 创建网络 10 | info: 创建网络 11 | http_type: http 12 | request_type: post 13 | parameter_type: raw 14 | address: /v2.0/networks 15 | headers: 16 | Content-Type: application/json 17 | X-Auth-Token: ${token_id}$ 18 | timeout: 20 19 | parameter: 20 | network: 21 | admin_state_up: true 22 | # dns_domain: 23 | # mtu: 1500 24 | name: ${network_name}$ 25 | # port_security_enabled: 26 | # project_id: ${project_id}$ 27 | provider:network_type: "vlan" 28 | provider:physical_network: "physnet2" 29 | # provider:segmentation_id: 30 | # qos_policy_id: 31 | # router:external: 32 | # segments: 33 | # shared: Flase 34 | tenant_id: ${project_id}$ 35 | # vlan_transparent: 36 | # description: "auto_wuzs" 37 | # is_default: 38 | # availability_zone_hints: 39 | file: false 40 | check: 41 | - check_type: json 42 | datebase: 43 | expected_code: 201 44 | expected_request: network_result.json 45 | relevance: 46 | 47 | - test_name: 查看网络 48 | info: 查询网络 49 | http_type: http 50 | request_type: get 51 | parameter_type: raw 52 | address: /v2.0/networks/${network_id}$ 53 | headers: 54 | Content-Type: application/json 55 | X-Auth-Token: ${token_id}$ 56 | timeout: 20 57 | parameter: 58 | network: 59 | admin_state_up: true 60 | name: ${network_name}$ 61 | tenant_id: ${project_id}$ 62 | file: false 63 | check: 64 | - check_type: json 65 | datebase: 66 | expected_code: 200 67 | expected_request: {} 68 | relevance: 69 | 70 | 71 | -------------------------------------------------------------------------------- /params/param/network/delete_network.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | testinfo: 4 | id: test_13_delete_network # 用例ID, 用于识别 string 5 | title: 网络 # 用例标题,在报告中作为一级目录显示 必填 string 6 | port: 9696 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 7 | address: /v2.0/networks # 请求地址 选填(此处不填,每条用例必填) string 8 | 9 | # 前置条件,case之前需关联的接口 10 | premise: 11 | 12 | # 测试用例 13 | test_case: 14 | # 第一条case,info可不填 15 | - test_name: 删除网络 # 必填,parameter为文件路径时 16 | info: 删除网络 17 | http_type: http # 请求协议 18 | request_type: delete # 请求类型 19 | parameter_type: raw # 参数类型 20 | address: /v2.0/networks/${network_id}$ 21 | headers: # 请求头 22 | Content-Type: application/json 23 | X-Auth-Token: ${token_id}$ 24 | timeout: 20 25 | sleep_time: 0 26 | parameter: 27 | subnet: 28 | network_id: ${network_id}$ 29 | 30 | file: false 31 | check: # 校验列表 list or dict 32 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 33 | datebase: 34 | expected_code: 204 35 | expected_request: 36 | relevance: # 关联键 37 | 38 | - test_name: 删除网络后查看网络 39 | info: 删除网络后查询网络 40 | http_type: http # 请求协议 41 | request_type: get # 请求类型 42 | parameter_type: raw # 参数类型 43 | address: /v2.0/networks/${network_id}$ 44 | headers: # 请求头 45 | Content-Type: application/json 46 | X-Auth-Token: ${token_id}$ 47 | timeout: 20 48 | sleep_time: 2 49 | parameter: 50 | subnet: 51 | admin_state_up: true 52 | 53 | file: false 54 | check: # 校验列表 list or dict 55 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 56 | datebase: 57 | expected_code: 404 58 | expected_request: {} 59 | relevance: # 关联键 60 | 61 | 62 | -------------------------------------------------------------------------------- /params/param/network/network_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [{ 3 | "network": { 4 | "status": "ACTIVE", 5 | "subnets": [], 6 | "provider:physical_network": "physnet2", 7 | "admin_state_up": true, 8 | "router:external": false, 9 | "qos_policy_id": null, 10 | "shared": false, 11 | "provider:network_type": "vlan" 12 | } 13 | } 14 | ], 15 | 16 | "test_name": "创建网络" 17 | }, 18 | { 19 | "json": [{ 20 | "network": { 21 | "status": "ACTIVE", 22 | "subnets": [], 23 | "provider:physical_network": "physnet2", 24 | "admin_state_up": true, 25 | "router:external": false, 26 | "qos_policy_id": null, 27 | "shared": false, 28 | "provider:network_type": "vlan" 29 | } 30 | } 31 | ], 32 | 33 | "test_name": "查看网络" 34 | } 35 | ] -------------------------------------------------------------------------------- /params/param/os_volume_attach_detach/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:58 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/os_volume_attach_detach/os_volume_attac_and_detach.yaml: -------------------------------------------------------------------------------- 1 | #os_volume_attac_and_detach.yaml 2 | testinfo: 3 | id: test_09_os-volume_attachments # 用例ID, 用于识别 string 4 | title: 云主机与磁盘挂载 # 用例标题,在报告中作为一级目录显示 必填 string 5 | port: 8774 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 6 | address: /v2/${project_id}$/servers/${server_id}$/os-volume_attachments # 请求地址 选填(此处不填,每条用例必填) string 7 | 8 | premise: 9 | 10 | # 测试用例 11 | test_case: 12 | # 第一条case,info可不填 13 | - test_name: 云主机与磁盘挂载 # 必填,parameter为文件路径时 14 | info: 云主机与磁盘挂载 15 | http_type: http # 请求协议 16 | request_type: post # 请求类型 17 | parameter_type: raw # 参数类型 18 | address: /v2/${project_id}$/servers/${server_id}$/os-volume_attachments 19 | headers: # 请求头 20 | Content-Type: application/json 21 | X-Auth-Token: ${token_id}$ 22 | timeout: 20 23 | sleep_time: 30 24 | parameter: 25 | volumeAttachment: 26 | volumeId: ${volume_id}$ 27 | file: false 28 | check: # 校验列表 list or dict 29 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 30 | datebase: 31 | expected_code: 200 32 | expected_request: os_volume_attach_adn_detach_result.json 33 | relevance: # 关联键 34 | 35 | - test_name: 挂载后查看虚拟机 # 必填,parameter为文件路径时 36 | info: 挂载后查看虚拟机 37 | http_type: http # 请求协议 38 | request_type: get # 请求类型 39 | parameter_type: raw # 参数类型 40 | address: /v2/${project_id}$/servers/${server_id}$ 41 | headers: # 请求头 42 | Content-Type: application/json 43 | X-Auth-Token: ${token_id}$ 44 | timeout: 20 45 | sleep_time: 10 46 | parameter: 47 | volumeId: ${volume_id}$ 48 | file: false 49 | check: # 校验列表 list or dict 50 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 51 | datebase: 52 | expected_code: 200 53 | expected_request: os_volume_attach_adn_detach_result.json 54 | relevance: # 关联键 55 | 56 | - test_name: 云主机与磁盘卸载 # 必填,parameter为文件路径时 57 | info: 云主机与磁盘卸载 58 | http_type: http # 请求协议 59 | request_type: delete # 请求类型 60 | parameter_type: raw # 参数类型 61 | address: /v2/${project_id}$/servers/${server_id}$/os-volume_attachments/${volume_id}$ 62 | headers: # 请求头 63 | Content-Type: application/json 64 | X-Auth-Token: ${token_id}$ 65 | timeout: 20 66 | sleep_time: 10 67 | parameter: 68 | volumeAttachment: 69 | volumeId: ${volume_id}$ 70 | file: false 71 | check: # 校验列表 list or dict 72 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 73 | datebase: 74 | expected_code: 202 75 | expected_request: {} 76 | relevance: # 关联键 -------------------------------------------------------------------------------- /params/param/os_volume_attach_detach/os_volume_attach_adn_detach_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [ 3 | { 4 | "volumeAttachment": { 5 | "serverId": "${server_id}$", 6 | "volumeId": "${volume_id}$" 7 | } 8 | } 9 | ], 10 | 11 | "test_name": "云主机与磁盘挂载" 12 | }, 13 | { 14 | "json": [{ 15 | "server": { 16 | "os-extended-volumes:volumes_attached": [ 17 | { 18 | "id": "${volume_id}$" 19 | } 20 | ]}} 21 | ], 22 | "test_name": "挂载后查看虚拟机" 23 | } 24 | ] -------------------------------------------------------------------------------- /params/param/project/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:55 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/project/create_project.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_01_create_project # 用例ID, 用于识别 string 3 | title: 项目 # 用例标题,在报告中作为一级目录显示 必填 string 4 | port: 5000 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 5 | address: # 请求地址 选填(此处不填,每条用例必填) string 6 | 7 | # 前置条件,case之前需关联的接口 8 | premise: 9 | 10 | # 测试用例 11 | test_case: 12 | # 第一条case,info可不填 13 | - test_name: 创建项目 # 必填,parameter为文件路径时 14 | info: 正常参数创建项目 15 | http_type: http # 请求协议 16 | request_type: post # 请求类型 17 | parameter_type: raw # 参数类型 18 | address: /v3/projects 19 | headers: # 请求头 20 | Content-Type: application/json 21 | X-Auth-Token: ${token_id}$ 22 | timeout: 20 23 | parameter: 24 | project: 25 | description: Automation_wuzs 26 | domain_id: default 27 | enabled: true 28 | is_domain: false 29 | name: ${project_name}$ 30 | file: false 31 | check: # 校验列表 list or dict 32 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 33 | datebase: 34 | expected_code: 200 35 | expected_request: {} 36 | relevance: # 关联键 37 | 38 | 39 | -------------------------------------------------------------------------------- /params/param/project/delete_project.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_16_delete_project 3 | title: 项目 4 | port: 5000 5 | address: 6 | premise: 7 | test_case: 8 | 9 | - test_name: 删除项目 10 | info: 删除项目 11 | http_type: http 12 | request_type: delete 13 | parameter_type: raw 14 | address: /v3/projects/${project_id}$ 15 | headers: 16 | Content-Type: application/json 17 | X-Auth-Token: ${token_id}$ 18 | timeout: 20 19 | parameter: 20 | project: 21 | description: Automation_wuzs 22 | file: false 23 | check: 24 | - check_type: only_check_status 25 | datebase: 26 | expected_code: 204 27 | expected_request: {} 28 | relevance: 29 | 30 | - test_name: 删除项目 31 | info: 删除项目后查看已删除 32 | http_type: http 33 | request_type: get 34 | parameter_type: raw 35 | address: /v3/projects/${project_id}$ 36 | headers: 37 | Content-Type: application/json 38 | X-Auth-Token: ${token_id}$ 39 | timeout: 20 40 | parameter: 41 | project: 42 | description: Automation_wuzs 43 | file: false 44 | check: 45 | - check_type: only_check_status 46 | datebase: 47 | expected_code: 401 48 | expected_request: {} 49 | relevance: -------------------------------------------------------------------------------- /params/param/server/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:55 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/server/create_server.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | testinfo: 4 | id: test_04_create_server # 用例ID, 用于识别 string 5 | title: 虚拟机 # 用例标题,在报告中作为一级目录显示 必填 string 6 | port: 8774 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 7 | address: /v2/${project_id}$/servers # 请求地址 选填(此处不填,每条用例必填) string 8 | 9 | premise: 10 | 11 | # 测试用例 12 | test_case: 13 | - test_name: 创建虚拟机 14 | info: 创建虚拟机 15 | sleep_time: 1 16 | http_type: http 17 | request_type: post 18 | parameter_type: raw 19 | address: /v2/${project_id}$/servers 20 | headers: 21 | Content-Type: application/json 22 | X-Auth-Token: ${token_id}$ 23 | timeout: 20 24 | parameter: 25 | server: 26 | imageRef: ${image_id}$ 27 | flavorRef: ${flavor_id}$ 28 | name: ${server_name}$ 29 | networks: 30 | - uuid: ${network_id}$ 31 | file: false 32 | check: 33 | - check_type: only_check_status 34 | datebase: 35 | expected_code: 202 36 | expected_request: server_result.json 37 | relevance: 38 | 39 | - test_name: 查看虚拟机 40 | sleep_time: 40 41 | info: 创建后查询虚拟机 42 | http_type: http 43 | request_type: get 44 | parameter_type: raw 45 | address: /v2/${project_id}$/servers/${server_id}$ 46 | headers: 47 | Content-Type: application/json 48 | X-Auth-Token: ${token_id}$ 49 | timeout: 20 50 | parameter: 51 | server: 52 | admin_state_up: true 53 | name: ${network_name}$ 54 | tenant_id: ${project_id}$ 55 | file: false 56 | check: 57 | - check_type: json 58 | datebase: 59 | expected_code: 200 60 | expected_request: server_result.json 61 | relevance: 62 | 63 | 64 | -------------------------------------------------------------------------------- /params/param/server/delete_server.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_12_delete_server # 用例ID, 用于识别 string 3 | title: 虚拟机 # 用例标题,在报告中作为一级目录显示 必填 string 4 | port: 8774 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 5 | address: /v2/${project_id}$/servers/${server_id}$ # 请求地址 选填(此处不填,每条用例必填) string 6 | 7 | # 前置条件,case之前需关联的接口 8 | premise: 9 | 10 | # 测试用例 11 | test_case: 12 | # 第一条case,info可不填 13 | - test_name: 删除虚拟机 # 必填,parameter为文件路径时 14 | info: 删除虚拟机 15 | sleep_time: 1 16 | http_type: http # 请求协议 17 | request_type: delete # 请求类型 18 | parameter_type: raw # 参数类型 19 | address: /v2/${project_id}$/servers/${server_id}$ 20 | headers: # 请求头 21 | Content-Type: application/json 22 | X-Auth-Token: ${token_id}$ 23 | timeout: 20 24 | parameter: 25 | server: 26 | 27 | file: false 28 | check: # 校验列表 list or dict 29 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 30 | datebase: 31 | expected_code: 204 32 | expected_request: server_result.json 33 | relevance: # 关联键 34 | 35 | - test_name: 删除后查看虚拟机 36 | sleep_time: 10 37 | info: 删除后查看查询虚拟机 38 | http_type: http # 请求协议 39 | request_type: get # 请求类型 40 | parameter_type: raw # 参数类型 41 | address: /v2/${project_id}$/servers/${server_id}$ 42 | headers: # 请求头 43 | Content-Type: application/json 44 | X-Auth-Token: ${token_id}$ 45 | timeout: 20 46 | parameter: 47 | server: 48 | admin_state_up: true 49 | name: ${network_name}$ 50 | tenant_id: ${project_id}$ 51 | file: false 52 | check: # 校验列表 list or dict 53 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 54 | datebase: 55 | expected_code: 404 56 | expected_request: server_result.json 57 | relevance: # 关联键 58 | -------------------------------------------------------------------------------- /params/param/server/server_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [{ 3 | 4 | }], 5 | 6 | "test_name": "创建虚拟机" 7 | }, 8 | { 9 | "json": [{ 10 | "server": { 11 | "status": "ACTIVE", 12 | "image": { 13 | "id": "${image_id}$" 14 | }, 15 | "OS-EXT-STS:vm_state": "active", 16 | "flavor": { 17 | "id": "${flavor_id}$" 18 | }, 19 | "tenant_id": "${project_id}$" 20 | } 21 | }], 22 | "test_name": "查看虚拟机" 23 | } 24 | ] -------------------------------------------------------------------------------- /params/param/server_snapshot/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:57 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/server_snapshot/delete_server_snap.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_11_delete_server_snap 3 | title: 虚拟机快照 4 | port: 9292 5 | address: /v2/${project_id}$/snapshots/${volume_id}$ 6 | 7 | premise: 8 | 9 | # 测试用例 10 | test_case: 11 | # 第一条case,info可不填 12 | - test_name: 删除虚拟机快照 # 必填,parameter为文件路径时 13 | info: 删除虚拟机快照 14 | http_type: http # 请求协议 15 | request_type: delete # 请求类型 16 | parameter_type: raw # 参数类型 17 | address: /v2/images/${server_snap_id}$ 18 | headers: # 请求头 19 | Content-Type: application/json 20 | X-Auth-Token: ${token_id}$ 21 | timeout: 20 22 | sleep_time: 0 23 | parameter: 24 | volume: 25 | size: 1 26 | name: ${volume_name}$ 27 | file: false 28 | check: 29 | - check_type: only_check_status 30 | datebase: 31 | expected_code: 204 32 | expected_request: {} 33 | relevance: 34 | 35 | - test_name: 删除虚拟机快照后查看询 36 | info: 删除虚拟机快照后查看询 37 | http_type: http 38 | request_type: get 39 | parameter_type: raw 40 | address: /v2/images/${server_snap_id}$ 41 | headers: 42 | Content-Type: application/json 43 | X-Auth-Token: ${token_id}$ 44 | timeout: 20 45 | sleep_time: 20 46 | parameter: 47 | volume: 48 | size: 1 49 | file: false 50 | check: 51 | - check_type: only_check_status 52 | datebase: 53 | expected_code: 404 54 | expected_request: {} 55 | relevance: -------------------------------------------------------------------------------- /params/param/server_snapshot/get_server_snap.yaml: -------------------------------------------------------------------------------- 1 | 2 | testinfo: 3 | id: test_07_server_snap_get # 用例ID, 用于识别 string 4 | title: 虚拟机快照 # 用例标题,在报告中作为一级目录显示 必填 string 5 | port: 9292 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 6 | address: /v2/${project_id}$/servers/${server_id}$/action # 请求地址 选填(此处不填,每条用例必填) string 7 | 8 | # 前置条件,case之前需关联的接口 9 | premise: 10 | 11 | # 测试用例 12 | test_case: 13 | # 第一条case,info可不填 14 | - test_name: 查看云主机快照 # 必填,parameter为文件路径时 15 | info: 查看云主机快照 16 | http_type: http # 请求协议 17 | request_type: get # 请求类型 18 | parameter_type: raw # 参数类型 19 | address: /v1/images/detail?sort_key=created_at&sort_dir=desc&limit=1000&image_type=snapshot&name=${server_snap_name}$ 20 | headers: # 请求头 21 | Content-Type: application/json 22 | X-Auth-Token: ${token_id}$ 23 | timeout: 20 24 | sleep_time: 30 25 | parameter: 26 | createImage: 27 | name: snap_$RandomString(20)$ 28 | 29 | file: false 30 | check: # 校验列表 list or dict 31 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 32 | datebase: 33 | expected_code: 200 34 | expected_request: get_server_snap_result.json 35 | relevance: # 关联键 36 | 37 | -------------------------------------------------------------------------------- /params/param/server_snapshot/get_server_snap_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [ 3 | { 4 | "images": 5 | { 6 | "status": "active", 7 | "name": "snap", 8 | "deleted": false, 9 | "disk_format": "vmdk", 10 | "is_public": false, 11 | "properties": { 12 | "instance_uuid": "${server_id}$", 13 | "image_type": "snapshot", 14 | "hypervisor_type": "vmware", 15 | "vmware_disktype": "streamOptimized", 16 | "vmware_image_version": "1", 17 | "vmware_adaptertype": "ide", 18 | "vmware_ostype": "centos64Guest" 19 | } 20 | } 21 | 22 | }], 23 | 24 | "test_name": "查看云主机快照" 25 | },{ 26 | "json": [ 27 | { 28 | "images": [ 29 | { 30 | "status": "active", 31 | "name": "snap", 32 | "deleted": false, 33 | "disk_format": "vmdk", 34 | "is_public": false, 35 | "properties": { 36 | "instance_uuid": "${server_id}$", 37 | "image_type": "snapshot", 38 | "hypervisor_type": "vmware", 39 | "vmware_disktype": "streamOptimized", 40 | "vmware_image_version": "1", 41 | "vmware_adaptertype": "ide", 42 | "vmware_ostype": "centos64Guest" 43 | } 44 | } 45 | ] 46 | }], 47 | 48 | "test_name": "查看云主机快照0001" 49 | } 50 | 51 | ] -------------------------------------------------------------------------------- /params/param/server_snapshot/server_snap.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_06_server_snap # 用例ID, 用于识别 string 3 | title: 虚拟机快照 # 用例标题,在报告中作为一级目录显示 必填 string 4 | port: 8774 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 5 | address: /v2/${project_id}$/servers/${server_id}$/action # 请求地址 选填(此处不填,每条用例必填) string 6 | # 前置条件,case之前需关联的接口 7 | premise: 8 | 9 | # 测试用例 10 | test_case: 11 | # 第一条case,info可不填 12 | - test_name: 创建云主机快照 # 必填,parameter为文件路径时 13 | info: 创建云主机快照 14 | http_type: http # 请求协议 15 | request_type: post # 请求类型 16 | parameter_type: raw # 参数类型 17 | address: /v2/${project_id}$/servers/${server_id}$/action 18 | headers: # 请求头 19 | Content-Type: application/json 20 | X-Auth-Token: ${token_id}$ 21 | timeout: 20 22 | parameter: 23 | createImage: 24 | name: ${server_snap_name}$ 25 | file: false 26 | check: # 校验列表 list or dict 27 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 28 | datebase: 29 | expected_code: 202 30 | expected_request: {} 31 | relevance: # 关联键 32 | -------------------------------------------------------------------------------- /params/param/subnet/Subnet.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | testinfo: 4 | id: test_03_create_subnet # 用例ID, 用于识别 string 5 | title: 子网 # 用例标题,在报告中作为一级目录显示 必填 string 6 | port: 9696 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 7 | address: /v2.0/subnets # 请求地址 选填(此处不填,每条用例必填) string 8 | 9 | # 前置条件,case之前需关联的接口 10 | premise: 11 | 12 | # 测试用例 13 | test_case: 14 | # 第一条case,info可不填 15 | - test_name: 创建子网 # 必填,parameter为文件路径时 16 | info: 创建子网 17 | http_type: http # 请求协议 18 | request_type: post # 请求类型 19 | parameter_type: raw # 参数类型 20 | address: /v2.0/subnets 21 | headers: # 请求头 22 | Content-Type: application/json 23 | X-Auth-Token: ${token_id}$ 24 | timeout: 20 25 | parameter: 26 | subnet: 27 | network_id: ${network_id}$ 28 | ip_version: 4 29 | name: ${subnet_name}$ 30 | tenant_id: ${project_id}$ 31 | cidr: "192.168.224.0/24" 32 | gateway_ip: "192.168.224.1" 33 | enable_dhcp: true 34 | 35 | 36 | file: false 37 | check: # 校验列表 list or dict 38 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 39 | datebase: 40 | expected_code: 201 41 | expected_request: subnet_result.json 42 | relevance: # 关联键 43 | 44 | - test_name: 查看子网 45 | info: 查询子网 46 | http_type: http # 请求协议 47 | request_type: get # 请求类型 48 | parameter_type: raw # 参数类型 49 | address: /v2.0/subnets/${subnet_id}$ 50 | headers: # 请求头 51 | Content-Type: application/json 52 | X-Auth-Token: ${token_id}$ 53 | timeout: 20 54 | parameter: 55 | subnet: 56 | admin_state_up: true 57 | name: ${subnet_name}$ 58 | tenant_id: ${project_id}$ 59 | 60 | file: false 61 | check: # 校验列表 list or dict 62 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 63 | datebase: 64 | expected_code: 200 65 | expected_request: subnet_result.json 66 | relevance: # 关联键 67 | 68 | 69 | -------------------------------------------------------------------------------- /params/param/subnet/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:55 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/subnet/delete_subnet.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | testinfo: 4 | id: test_13_delete_subnet # 用例ID, 用于识别 string 5 | title: 子网 # 用例标题,在报告中作为一级目录显示 必填 string 6 | port: 9696 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 7 | address: /v2.0/subnets # 请求地址 选填(此处不填,每条用例必填) string 8 | 9 | # 前置条件,case之前需关联的接口 10 | premise: 11 | 12 | # 测试用例 13 | test_case: 14 | # 第一条case,info可不填 15 | - test_name: 删除子网 # 必填,parameter为文件路径时 16 | info: 删除子网 17 | http_type: http # 请求协议 18 | request_type: delete # 请求类型 19 | parameter_type: raw # 参数类型 20 | address: /v2.0/subnets/${subnet_id}$ 21 | headers: # 请求头 22 | Content-Type: application/json 23 | X-Auth-Token: ${token_id}$ 24 | timeout: 20 25 | sleep_time: 0 26 | parameter: 27 | subnet: 28 | network_id: ${network_id}$ 29 | 30 | file: false 31 | check: # 校验列表 list or dict 32 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 33 | datebase: 34 | expected_code: 204 35 | expected_request: 36 | relevance: # 关联键 37 | 38 | - test_name: 删除子网后查看子网 39 | info: 删除子网后查询子网 40 | http_type: http # 请求协议 41 | request_type: get # 请求类型 42 | parameter_type: raw # 参数类型 43 | address: /v2.0/subnets/${subnet_id}$ 44 | headers: # 请求头 45 | Content-Type: application/json 46 | X-Auth-Token: ${token_id}$ 47 | timeout: 20 48 | sleep_time: 2 49 | parameter: 50 | subnet: 51 | admin_state_up: true 52 | 53 | file: false 54 | check: # 校验列表 list or dict 55 | - check_type: only_check_status # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 56 | datebase: 57 | expected_code: 404 58 | expected_request: {} 59 | relevance: # 关联键 60 | 61 | 62 | -------------------------------------------------------------------------------- /params/param/subnet/subnet_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [{ 3 | "subnet": { 4 | "enable_dhcp": true, 5 | "cidr": "192.168.224.0/24", 6 | "tenant_id": "${project_id}$", 7 | "gateway_ip": "192.168.224.1", 8 | "network_id": "${network_id}$", 9 | "ip_version": 4 10 | } 11 | } 12 | ], 13 | "test_name": "创建子网" 14 | }, 15 | { 16 | "json": [{ 17 | "subnet": { 18 | "enable_dhcp": true, 19 | "cidr": "192.168.224.0/24", 20 | "tenant_id": "${project_id}$", 21 | "gateway_ip": "192.168.224.1", 22 | "network_id": "${network_id}$", 23 | "ip_version": 4 24 | }}], 25 | 26 | "test_name": "查看子网" 27 | } 28 | ] -------------------------------------------------------------------------------- /params/param/volume/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/11/5 17:56 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /params/param/volume/delete_volume.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_15_delete_volume 3 | title: 卷 4 | port: 8776 5 | address: /v2/${project_id}$/volumes/${volume_id}$ 6 | 7 | premise: 8 | 9 | # 测试用例 10 | test_case: 11 | # 第一条case,info可不填 12 | - test_name: 删除卷 # 必填,parameter为文件路径时 13 | info: 删除卷 14 | http_type: http # 请求协议 15 | request_type: delete # 请求类型 16 | parameter_type: raw # 参数类型 17 | address: /v2/${project_id}$/volumes/${volume_id}$ 18 | headers: # 请求头 19 | Content-Type: application/json 20 | X-Auth-Token: ${token_id}$ 21 | timeout: 20 22 | sleep_time: 0 23 | parameter: 24 | volume: 25 | size: 1 26 | name: ${volume_name}$ 27 | 28 | file: false 29 | check: 30 | - check_type: only_check_status 31 | datebase: 32 | expected_code: 202 33 | expected_request: {} 34 | relevance: 35 | 36 | - test_name: 删除卷后查看询 37 | info: 删除卷后查看询 38 | http_type: http 39 | request_type: get 40 | parameter_type: raw 41 | address: /v2/${project_id}$/volumes/${volume_id}$ 42 | headers: 43 | Content-Type: application/json 44 | X-Auth-Token: ${token_id}$ 45 | timeout: 20 46 | sleep_time: 10 47 | parameter: 48 | volume: 49 | size: 1 50 | file: false 51 | check: 52 | - check_type: only_check_status 53 | datebase: 54 | expected_code: 404 55 | expected_request: {} 56 | relevance: -------------------------------------------------------------------------------- /params/param/volume/volume.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_05_create_volume # 用例ID, 用于识别 string 3 | title: 卷 # 用例标题,在报告中作为一级目录显示 必填 string 4 | port: 8776 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 5 | address: /v2/${project_id}$/volumes # 请求地址 选填(此处不填,每条用例必填) string 6 | 7 | # 前置条件,case之前需关联的接口 8 | premise: 9 | 10 | # 测试用例 11 | test_case: 12 | # 第一条case,info可不填 13 | - test_name: 创建卷 # 必填,parameter为文件路径时 14 | info: 创建卷 15 | http_type: http # 请求协议 16 | request_type: post # 请求类型 17 | parameter_type: raw # 参数类型 18 | address: /v2/${project_id}$/volumes 19 | headers: # 请求头 20 | Content-Type: application/json 21 | X-Auth-Token: ${token_id}$ 22 | timeout: 20 23 | sleep_time: 0 24 | parameter: 25 | volume: 26 | size: 1 27 | name: ${volume_name}$ 28 | 29 | file: false 30 | check: # 校验列表 list or dict 31 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 32 | datebase: 33 | expected_code: 202 34 | expected_request: {} 35 | relevance: # 关联键 36 | 37 | - test_name: 查看卷 38 | info: 查询卷 39 | http_type: http # 请求协议 40 | request_type: get # 请求类型 41 | parameter_type: raw # 参数类型 42 | address: /v2/${project_id}$/volumes/${volume_id}$ 43 | sleep_time: 20 44 | headers: # 请求头 45 | Content-Type: application/json 46 | X-Auth-Token: ${token_id}$ 47 | timeout: 20 48 | parameter: 49 | server: 50 | admin_state_up: true 51 | name: ${network_name}$ 52 | tenant_id: ${project_id}$ 53 | file: false 54 | check: # 校验列表 list or dict 55 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 56 | datebase: 57 | expected_code: 200 58 | expected_request: volume_result.json 59 | relevance: # 关联键 60 | 61 | 62 | -------------------------------------------------------------------------------- /params/param/volume/volume_result.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "json": [{ 3 | 4 | 5 | }], 6 | 7 | "test_name": "创建卷" 8 | }, 9 | { 10 | "json": [{ 11 | "volume": { 12 | "replication_status": "disabled", 13 | "id": "${volume_id}$", 14 | "size": 1, 15 | "user_id": "${admin_id}$", 16 | "os-vol-tenant-attr:tenant_id": "${project_id}$", 17 | "status": "available" 18 | } 19 | }], 20 | "test_name": "查看卷" 21 | } 22 | ] -------------------------------------------------------------------------------- /params/param/volume_snap/delete_volume_snap.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_10_delete_volume_snap 3 | title: 卷快照 4 | port: 8776 5 | address: /v2/${project_id}$/snapshots/${volume_snapshot_id}$ 6 | 7 | premise: 8 | 9 | # 测试用例 10 | test_case: 11 | - test_name: 删除卷快照 12 | info: 删除卷快照前查看询 13 | http_type: http 14 | request_type: get 15 | parameter_type: raw 16 | address: /v2/${project_id}$/snapshots/${volume_snapshot_id}$ 17 | headers: 18 | Content-Type: application/json 19 | X-Auth-Token: ${token_id}$ 20 | timeout: 20 21 | sleep_time: 60 22 | parameter: 23 | volume: 24 | size: 1 25 | file: false 26 | check: 27 | - check_type: json 28 | datebase: 29 | expected_code: 200 30 | expected_request: {"snapshot": {"status": "available"}} 31 | relevance: 32 | 33 | # 第一条case,info可不填 34 | - test_name: 删除卷快照 # 必填,parameter为文件路径时 35 | info: 删除卷快照 36 | http_type: http # 请求协议 37 | request_type: delete # 请求类型 38 | parameter_type: raw # 参数类型 39 | address: /v2/${project_id}$/snapshots/${volume_snapshot_id}$ 40 | headers: # 请求头 41 | Content-Type: application/json 42 | X-Auth-Token: ${token_id}$ 43 | timeout: 20 44 | sleep_time: 0 45 | parameter: 46 | volume: 47 | size: 1 48 | name: ${volume_name}$ 49 | file: false 50 | check: 51 | - check_type: only_check_status 52 | datebase: 53 | expected_code: 202 54 | expected_request: {} 55 | relevance: 56 | 57 | - test_name: 删除卷快照 58 | info: 删除卷快照后查看询 59 | http_type: http 60 | request_type: get 61 | parameter_type: raw 62 | address: /v2/${project_id}$/snapshots/${volume_snapshot_id}$ 63 | headers: 64 | Content-Type: application/json 65 | X-Auth-Token: ${token_id}$ 66 | timeout: 20 67 | sleep_time: 10 68 | parameter: 69 | volume: 70 | size: 1 71 | file: false 72 | check: 73 | - check_type: only_check_status 74 | datebase: 75 | expected_code: 404 76 | expected_request: {} 77 | relevance: -------------------------------------------------------------------------------- /params/param/volume_snap/volume_snap.yaml: -------------------------------------------------------------------------------- 1 | testinfo: 2 | id: test_07_volume_snap_get # 用例ID, 用于识别 string 3 | title: 卷快照 # 用例标题,在报告中作为一级目录显示 必填 string 4 | port: 8776 # 请求的域名,可写死,也可写成模板关联host配置文件 选填(此处不填,每条用例必填) string 5 | address: /v2/${project_id}$/snapshots # 请求地址 选填(此处不填,每条用例必填) string 6 | 7 | # 前置条件,case之前需关联的接口 8 | premise: 9 | 10 | # 测试用例 11 | test_case: 12 | 13 | - test_name: 创建卷快照前查询 # 必填,parameter为文件路径时 14 | info: 创建卷快照前查询 15 | http_type: http # 请求协议 16 | request_type: get # 请求类型 17 | parameter_type: raw # 参数类型 18 | address: /v2/${project_id}$/volumes/${volume_id}$ 19 | headers: # 请求头 20 | Content-Type: application/json 21 | X-Auth-Token: ${token_id}$ 22 | timeout: 20 23 | sleep_time: 30 24 | parameter: 25 | snapshot: 26 | name: Volume_$RandomString(20)$ 27 | file: false 28 | check: # 校验列表 list or dict 29 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 30 | datebase: 31 | expected_code: 200 32 | expected_request: volume_snap_result.json 33 | 34 | - test_name: 创建卷快照 # 必填,parameter为文件路径时 35 | info: 创建卷快照 36 | http_type: http # 请求协议 37 | request_type: post # 请求类型 38 | parameter_type: raw # 参数类型 39 | address: /v2/${project_id}$/snapshots 40 | headers: # 请求头 41 | Content-Type: application/json 42 | X-Auth-Token: ${token_id}$ 43 | timeout: 20 44 | sleep_time: 0 45 | parameter: 46 | snapshot: 47 | name: Volume_$RandomString(20)$ 48 | description: Daily backup 49 | volume_id: ${volume_id}$ 50 | force: true 51 | file: false 52 | check: # 校验列表 list or dict 53 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 54 | datebase: 55 | expected_code: 202 56 | expected_request: volume_snap_result.json 57 | relevance: # 关联键 58 | 59 | - test_name: 查询卷快照 # 必填,parameter为文件路径时 60 | info: 创建后查询卷快照 61 | http_type: http # 请求协议 62 | request_type: get # 请求类型 63 | parameter_type: raw # 参数类型 64 | address: /v2/${project_id}$/snapshots/${volume_snapshot_id}$ 65 | headers: # 请求头 66 | Content-Type: application/json 67 | X-Auth-Token: ${token_id}$ 68 | timeout: 20 69 | sleep_time: 60 70 | parameter: 71 | snapshot: 72 | name: Volume_$RandomString(20)$ 73 | file: false 74 | check: # 校验列表 list or dict 75 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 76 | datebase: 77 | expected_code: 200 78 | expected_request: volume_snap_result.json 79 | relevance: # 关联键 -------------------------------------------------------------------------------- /params/param/volume_snap/volume_snap_result.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "json": [{ 4 | "volume": { 5 | "status": "available" 6 | } 7 | }], 8 | "test_name": "创建卷快照前查询" 9 | }, 10 | { 11 | "json": [{ 12 | "snapshot": { 13 | "volume_id": "${volume_id}$" 14 | } 15 | }], 16 | 17 | "test_name": "创建卷快照" 18 | }, 19 | { 20 | "json": [{ 21 | "snapshot": { 22 | "status": "available", 23 | "volume_id": "${volume_id}$", 24 | "size": 1, 25 | "id": "${volume_snapshot_id}$" 26 | } 27 | }], 28 | "test_name": "查询卷快照" 29 | } 30 | ] -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = -p no:warnings 3 | filterwarnings = ignore:.*U.*mode is deprecated: RemovedInPytest4Warning 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 环境要求: 2 | 3 | ``` 4 | requests_toolbelt==0.9.1 5 | requests==2.20.0 6 | allure_python_commons==2.8.5 7 | pytest==5.2.1 8 | simplejson==3.16.0 9 | config==0.4.2 10 | PyYAML==5.1.2 11 | ``` 12 | 13 | # 安装allure 14 | 15 | XQwindows下安装 Allure工具 16 | 环境 17 | 1、安装JDK1.8+ 18 | 2、安装Allure 19 | 下载Allure的zip安装包,点击此处 20 | 解压到allure-commandline目录 21 | 进入bin目录,运行allure.bat 22 | 添加allure到环境变量PATH(\安装路径\allure-commandline\bin) 23 | 24 | # 测试框架介绍 25 | 26 |  27 | 28 | # 配置文件 29 | 30 | ```ini 31 | [email]#配置邮件发送和接受 32 | send = yes 33 | smtpserver = smtp.qq.com 34 | port = 465 35 | sender = xxxxxxxx 36 | psw = xxxxx 37 | receiver = 627383987@qq.com,mrwuzs@ctsi.com.cn 38 | username = 627383987@qq.com 39 | 40 | [env] 41 | #定义环境信息,用于报告展示和接口数据 42 | tester = wuzushun 43 | environment = 192.168.54.120 44 | versioncode = 1.0 45 | host = 192.168.54.120 46 | logininfo = {"auth": {"scope": {"project": {"domain":{"id": "default"},"name": "${project_token_name}$"}}, "identity":{"password": {"user": {"domain":{"id": "default"},"password":"admin","name":"admin"}},"methods":["password"]}}} 47 | openstack_version = liberty 48 | virtual = VMware 49 | nova_api = v2 50 | cinder_api = v2 51 | neutron_api = v2 52 | glance_api = v2 53 | keystone_api = v3 54 | 55 | [test_data] 56 | #测试数据,用于解决环境资源依赖问题 57 | name = $RandomInt(0,10)$ 58 | type = Web 59 | version = $RandomString(10)$ 60 | description = api_auto_$RandomString(10)$ 61 | project_id = 693fff2b334d48eeb3921e4dd1d4a592 62 | token_id = 49aa0e8a330c4c2d9e12121b4bd280e3 63 | project_name = $RandomString(20)$ 64 | network_name = $RandomString(20)$_netwrok 65 | subnet_name = $RandomString(20)$_subnet 66 | network_id = 83723762-af39-4fdc-ae5b-28b0ef04496e 67 | subnet_id = 8a57ec3c-dc96-4d57-9368-c5d922f2b387 68 | image_id = b4e9e907-686e-440d-bc1a-d73a8decfa54 69 | #必须配置,用于创建虚拟机 70 | flavor_id = flavor-1-1-1 #必须配置,用于创建虚拟机 71 | server_name = wuzs_$RandomString(20)$ 72 | server_id = d0a3a6b4-6f6b-4a7c-89b8-379e5dfef7b3 73 | project_token_name = admin 74 | admin_id = 0ec82b7380cb4d0c80058501938cdf48 75 | #必须配置,用户授权用 76 | admin_role_id = cc33f2c3a47247329d0ee7043c4f475f 77 | #必须配置,给用户授权用 78 | volume_name = volume_$RandomString(20)$ 79 | volume_id = e0404b30-8d58-4d2c-a087-6317844d79dd 80 | server_snap_name = snap_8JkrX4yjSduLBPHcmTxC 81 | volume_snapshot_id = 603eeb61-49fc-4b3e-9655-cfe1e099886a 82 | 83 | ``` 84 | 85 | 1,需要现在opentack获取 86 | 87 | image_id,flavor_id,admin_id,role_id 88 | 89 | ``` 90 | admin_id = `openstack user list | awk '/admin/{print$2}'` 91 | role_id = `openstack role list | awk '/admin/{print$2}'` 92 | image_id= glance images-list#选择合适的镜像 93 | flavor_id = 获取合适的镜像 94 | ``` 95 | 96 | # 测试用例示例 97 | 98 | 如创建网络,测试用例为yaml文件,按照示例增加用例 99 | 100 | ```yaml 101 | testinfo: 102 | id: test_02_create_network # 用例ID, 用于识别 103 | title: 创建网络 # 用例标题,在报告中作为一级目录显示 必填 string 104 | port: 9696 # 请求的端口号 105 | address: /v2.0/networks # 请求地址 选填(此处不填,每条用例必填) string 106 | # 前置条件,case之前需关联的接口 107 | premise: 108 | # 测试用例 109 | test_case: 110 | # 第一条case,info可不填 111 | - test_name: 创建网络 # 必填,parameter为文件路径时 112 | info: 创建网络 113 | http_type: http # 请求协议 114 | request_type: post # 请求类型 115 | parameter_type: raw # 参数类型 116 | address: /v2.0/networks 117 | headers: # 请求头 118 | Content-Type: application/json 119 | X-Auth-Token: ${token_id}$ 120 | timeout: 20 121 | parameter: 122 | network: 123 | admin_state_up: true 124 | # dns_domain: 125 | # mtu: 1500 126 | name: ${network_name}$ 127 | # port_security_enabled: 128 | # project_id: ${project_id}$ 129 | # provider:network_type: 130 | # provider:physical_network: 131 | # provider:segmentation_id: 132 | # qos_policy_id: 133 | # router:external: 134 | # segments: 135 | # shared: Flase 136 | tenant_id: ${project_id}$ 137 | # vlan_transparent: 138 | # description: "auto_wuzs" 139 | # is_default: 140 | # availability_zone_hints: 141 | file: false 142 | check: # 校验列表 list or dict 143 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 144 | datebase: 145 | expected_code: 201 146 | expected_request: network_result.json #result,用于校验 147 | relevance: # 关联键 148 | - test_name: 查看网络 149 | info: 查询网络 150 | http_type: http # 请求协议 151 | request_type: get # 请求类型 152 | parameter_type: raw # 参数类型 153 | address: /v2.0/networks/${network_id}$ 154 | headers: # 请求头 155 | Content-Type: application/json 156 | X-Auth-Token: ${token_id}$ 157 | timeout: 20 158 | parameter: 159 | network: 160 | admin_state_up: true 161 | name: ${network_name}$ 162 | tenant_id: ${project_id}$ 163 | file: false 164 | check: # 校验列表 list or dict 165 | - check_type: json # 校验类型 string 不校验时 datebase, expected_code, expected_request 均可不填 166 | datebase: 167 | expected_code: 200 168 | expected_request: {} 169 | relevance: # 关联键 170 | 171 | ``` 172 | 173 | 需要json的文件校验,可以把json文件名写到expected_request,用于校验,如:用于校验json文件,按照示例更改,根据需要可以添加需要校验内容 174 | 175 | ```json 176 | [{ 177 | "json": [{ 178 | "network": { 179 | "status": "ACTIVE", 180 | "subnets": [], 181 | "provider:physical_network": "physnet2", 182 | "admin_state_up": true, 183 | "mtu": 0, 184 | "router:external": false, 185 | "qos_policy_id": null, 186 | "shared": false, 187 | "provider:network_type": "vlan"}}], 188 | "test_name": "创建网络"}, 189 | { 190 | "json": [{ 191 | "network": { 192 | "status": "ACTIVE", 193 | "subnets": [], 194 | "provider:physical_network": "physnet2", 195 | "admin_state_up": true, 196 | "mtu": 0, 197 | "router:external": false, 198 | "qos_policy_id": null, 199 | "shared": false, 200 | "provider:network_type": "vlan"}}], 201 | "test_name": "查看网络"} 202 | ] 203 | ``` 204 | 205 | 206 | 207 | # 用例执行 208 | 209 | 用到的插件 210 | 211 | ``` 212 | @pytest.mark.flaky(reruns=3)#失败重跑,尝试重跑3次 213 | @allure.feature # 用于定义被测试的功能,被测产品的需求点 214 | @allure.story # 用于定义被测功能的用户场景,即子功能点 215 | @allure.attach # 用于向测试报告中输入一些附加的信息,通常是一些测试数据信息 216 | @pytest.mark.parametrize #参数化 217 | ``` 218 | 219 | # 测试报告查看 220 | 221 |  222 | 223 |  224 | 225 | -------------------------------------------------------------------------------- /report/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:39 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /report/html/data/behaviors.csv: -------------------------------------------------------------------------------- 1 | "Epic","Feature","Story","FAILED","BROKEN","PASSED","SKIPPED","UNKNOWN" 2 | "","子网","删除子网","0","0","2","0","0" 3 | "","虚拟机","创建和查询虚拟机","0","0","2","0","0" 4 | "","卷","删除卷","0","0","2","0","0" 5 | "","虚拟机","删除虚拟机","0","0","2","0","0" 6 | "","虚拟机快照","删除虚拟机快照","0","0","2","0","0" 7 | "","网络","删除网络","0","0","2","0","0" 8 | "","卷","卷","0","0","2","0","0" 9 | "","卷快照","创建卷快照","0","0","3","0","0" 10 | "","项目","删除项目","0","0","4","0","0" 11 | "","云主机与磁盘挂载","虚拟机挂载和卸载","0","0","3","0","0" 12 | "","子网","创建和查询子网","0","0","2","0","0" 13 | "","项目","创建项目","0","0","1","0","0" 14 | "","卷快照","删除卷快照","0","0","3","0","0" 15 | "","网络","网络创建和查询","0","0","2","0","0" 16 | "","虚拟机快照","查看虚拟机快照","0","0","1","0","0" 17 | "","虚拟机快照","虚拟机快照","0","0","1","0","0" 18 | -------------------------------------------------------------------------------- /report/html/data/categories.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woozs/api_auto_test/a95f8495f95cefcd2314d54d90079551d6b85206/report/html/data/categories.csv -------------------------------------------------------------------------------- /report/html/data/categories.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid" : "4b4757e66a1912dae1a509f688f20b0f", 3 | "name" : "categories", 4 | "children" : [ ] 5 | } -------------------------------------------------------------------------------- /report/html/data/suites.csv: -------------------------------------------------------------------------------- 1 | "Status","Start Time","Stop Time","Duration in ms","Parent Suite","Suite","Sub Suite","Test Class","Test Method","Name","Description" 2 | "passed","Wed Nov 06 14:19:58 CST 2019","Wed Nov 06 14:20:00 CST 2019","2117","testcase","test_13_delete_subnet","Test_Delete_Subnet","","","test_delete_subnet[case_data1]","删除子网后查询子网" 3 | "passed","Wed Nov 06 14:14:12 CST 2019","Wed Nov 06 14:14:14 CST 2019","2464","testcase","test_04_server","Test_Server","","","test_server[case_data0]","" 4 | "passed","Wed Nov 06 14:20:05 CST 2019","Wed Nov 06 14:20:16 CST 2019","10209","testcase","test_15_delete_volume","Test_Delete_volume","","","test_delete_volume[case_data1]","删除卷后查看询" 5 | "passed","Wed Nov 06 14:19:46 CST 2019","Wed Nov 06 14:19:57 CST 2019","10154","testcase","test_12_delete_server","Test_Server","","","test_server[case_data1]","删除后查看查询虚拟机" 6 | "passed","Wed Nov 06 14:19:24 CST 2019","Wed Nov 06 14:19:45 CST 2019","20236","testcase","test_11_delete_server_snap","Test_Server_Snap","","","test_server_snap[case_data1]","删除虚拟机快照后查看询" 7 | "passed","Wed Nov 06 14:20:00 CST 2019","Wed Nov 06 14:20:02 CST 2019","2259","testcase","test_14_delete_network","Test_Delete_network","","","test_delete_network[case_data0]","" 8 | "passed","Wed Nov 06 14:15:36 CST 2019","Wed Nov 06 14:15:57 CST 2019","20469","testcase","test_05_volume","Test_Volume","","","test_volume[case_data1]","查询卷" 9 | "passed","Wed Nov 06 14:16:41 CST 2019","Wed Nov 06 14:17:41 CST 2019","60089","testcase","test_07_volume_snap","Test_Volume_Snap","","","test_volume_snap[case_data2]","创建后查询卷快照" 10 | "passed","Wed Nov 06 08:51:16 CST 2019","Wed Nov 06 08:51:16 CST 2019","31","testcase","test_16_delete_project","Test_Delete_project","","","test_delete_project[case_data1]","删除项目后查看已删除" 11 | "passed","Wed Nov 06 14:16:40 CST 2019","Wed Nov 06 14:16:41 CST 2019","232","testcase","test_07_volume_snap","Test_Volume_Snap","","","test_volume_snap[case_data1]","创建卷快照" 12 | "passed","Wed Nov 06 08:51:15 CST 2019","Wed Nov 06 08:51:16 CST 2019","698","testcase","test_16_delete_project","Test_Delete_project","","","test_delete_project[case_data0]","" 13 | "passed","Wed Nov 06 14:16:09 CST 2019","Wed Nov 06 14:16:10 CST 2019","1110","testcase","test_06_os_volume_attachments","Test_Os_Volume_Attachments","","","test_os_volume_attachments[case_data2]","云主机与磁盘卸载" 14 | "passed","Wed Nov 06 14:15:36 CST 2019","Wed Nov 06 14:15:36 CST 2019","493","testcase","test_05_volume","Test_Volume","","","test_volume[case_data0]","" 15 | "passed","Wed Nov 06 14:15:58 CST 2019","Wed Nov 06 14:16:08 CST 2019","10295","testcase","test_06_os_volume_attachments","Test_Os_Volume_Attachments","","","test_os_volume_attachments[case_data1]","挂载后查看虚拟机" 16 | "passed","Wed Nov 06 14:14:11 CST 2019","Wed Nov 06 14:14:12 CST 2019","293","testcase","test_03_subnet","Test_Subnet","","","test_subnet[case_data0]","" 17 | "passed","Wed Nov 06 14:15:57 CST 2019","Wed Nov 06 14:15:58 CST 2019","838","testcase","test_06_os_volume_attachments","Test_Os_Volume_Attachments","","","test_os_volume_attachments[case_data0]","" 18 | "passed","Wed Nov 06 14:14:08 CST 2019","Wed Nov 06 14:14:08 CST 2019","69","testcase","test_01_project","TestAddProject","","","test_project_crate[case_data0]","" 19 | "passed","Wed Nov 06 14:20:16 CST 2019","Wed Nov 06 14:20:16 CST 2019","35","testcase","test_16_delete_project","Test_Delete_Project","","","test_delete_project[case_data1]","删除项目后查看已删除" 20 | "passed","Wed Nov 06 14:18:12 CST 2019","Wed Nov 06 14:19:12 CST 2019","60111","testcase","test_10_delete_volume_snap","Test_Volume_Snap_Delete","","","test_volume_snap_delete[case_data0]","" 21 | "passed","Wed Nov 06 14:19:45 CST 2019","Wed Nov 06 14:19:46 CST 2019","1517","testcase","test_12_delete_server","Test_Server","","","test_server[case_data0]","" 22 | "passed","Wed Nov 06 14:14:12 CST 2019","Wed Nov 06 14:14:12 CST 2019","148","testcase","test_03_subnet","Test_Subnet","","","test_subnet[case_data1]","查询子网" 23 | "passed","Wed Nov 06 14:20:05 CST 2019","Wed Nov 06 14:20:05 CST 2019","452","testcase","test_15_delete_volume","Test_Delete_volume","","","test_delete_volume[case_data0]","" 24 | "passed","Wed Nov 06 14:19:12 CST 2019","Wed Nov 06 14:19:13 CST 2019","400","testcase","test_10_delete_volume_snap","Test_Volume_Snap_Delete","","","test_volume_snap_delete[case_data1]","删除卷快照" 25 | "passed","Wed Nov 06 14:19:23 CST 2019","Wed Nov 06 14:19:24 CST 2019","1031","testcase","test_11_delete_server_snap","Test_Server_Snap","","","test_server_snap[case_data0]","" 26 | "passed","Wed Nov 06 14:19:57 CST 2019","Wed Nov 06 14:19:58 CST 2019","972","testcase","test_13_delete_subnet","Test_Delete_Subnet","","","test_delete_subnet[case_data0]","" 27 | "passed","Wed Nov 06 14:16:10 CST 2019","Wed Nov 06 14:16:40 CST 2019","30420","testcase","test_07_volume_snap","Test_Volume_Snap","","","test_volume_snap[case_data0]","" 28 | "passed","Wed Nov 06 14:14:11 CST 2019","Wed Nov 06 14:14:11 CST 2019","116","testcase","test_02_network","Test_Network","","","test_network[case_data1]","查询网络" 29 | "passed","Wed Nov 06 14:17:42 CST 2019","Wed Nov 06 14:18:12 CST 2019","30263","testcase","test_09_get_server_snap","Test_Get_Server_Snap","","","test_get_server_snap[case_data0]","" 30 | "passed","Wed Nov 06 14:17:41 CST 2019","Wed Nov 06 14:17:42 CST 2019","766","testcase","test_08_server_snap","Test_Server_Snap","","","test_server_snap[case_data0]","" 31 | "passed","Wed Nov 06 14:20:16 CST 2019","Wed Nov 06 14:20:16 CST 2019","643","testcase","test_16_delete_project","Test_Delete_Project","","","test_delete_project[case_data0]","" 32 | "passed","Wed Nov 06 14:14:55 CST 2019","Wed Nov 06 14:15:35 CST 2019","40249","testcase","test_04_server","Test_Server","","","test_server[case_data1]","创建后查询虚拟机" 33 | "passed","Wed Nov 06 14:19:13 CST 2019","Wed Nov 06 14:19:23 CST 2019","10302","testcase","test_10_delete_volume_snap","Test_Volume_Snap_Delete","","","test_volume_snap_delete[case_data2]","删除卷快照后查看询" 34 | "passed","Wed Nov 06 14:14:09 CST 2019","Wed Nov 06 14:14:11 CST 2019","2253","testcase","test_02_network","Test_Network","","","test_network[case_data0]","" 35 | "passed","Wed Nov 06 14:20:02 CST 2019","Wed Nov 06 14:20:05 CST 2019","2144","testcase","test_14_delete_network","Test_Delete_network","","","test_delete_network[case_data1]","删除网络后查询网络" 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests_toolbelt==0.9.1 2 | requests==2.20.0 3 | allure_python_commons==2.8.5 4 | pytest==5.2.1 5 | simplejson==3.16.0 6 | config==0.4.2 7 | PyYAML==5.1.2 8 | pytest-rerunfailures==8.0 9 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env.ini python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/11 15:34 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : run.py 7 | # @Software: PyCharm 8 | 9 | 10 | """ 11 | 运行用例集: 12 | python3 run.py 13 | 14 | # '--allure_severities=critical, blocker' 15 | # '--allure_stories=测试模块_demo1, 测试模块_demo2' 16 | # '--allure_features=测试features' 17 | 18 | """ 19 | 20 | import pytest 21 | 22 | from common import log 23 | from common import shell 24 | from conf import conf 25 | from common import send_email 26 | from unit import initialize_env 27 | 28 | 29 | failureException = AssertionError 30 | 31 | if __name__ == '__main__': 32 | 33 | conf = conf.Config() 34 | log = log.MyLog() 35 | log.info('初始化配置文件, path=' + conf.conf_path) 36 | shell = shell.Shell() 37 | xml_report_path = conf.xml_report_path 38 | html_report_path = conf.html_report_path 39 | 40 | # 初始化allure环境配置文件environment.xml 41 | initialize_env.Init_Env().init() 42 | 43 | # 定义测试集 44 | args = ['-s', '-q', '--alluredir', xml_report_path] 45 | # args = ['-s', '-q', '--alluredir', "H:\\api_auto_test\\report\xml"] 46 | pytest.main(args) 47 | cmd = 'allure generate %s -o %s --clean' % ( 48 | xml_report_path, html_report_path) 49 | log.info("执行allure,生成测试报告") 50 | log.debug(cmd) 51 | try: 52 | shell.invoke(cmd) 53 | except Exception: 54 | log.error('执行用例失败,请检查环境配置') 55 | raise 56 | if conf.send == "yes": 57 | try: 58 | mail = send_email.SendMail() 59 | mail.sendMail() 60 | except Exception as e: 61 | log.error('发送邮件失败,请检查邮件配置') 62 | raise 63 | elif conf.send == "no": 64 | log.info("配置为发送邮件") 65 | else: 66 | raise RuntimeError('配置文件错误:send只能为"yes" or "no"') 67 | -------------------------------------------------------------------------------- /testcase/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:40 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /testcase/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env.ini python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/11 15:22 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : conftest.py 7 | # @Software: PyCharm 8 | 9 | """ 10 | 11 | # @allure.feature # 用于定义被测试的功能,被测产品的需求点 12 | # @allure.story # 用于定义被测功能的用户场景,即子功能点 13 | # @allure.severity #用于定义用例优先级 14 | # @allure.issue #用于定义问题表识,关联标识已有的问题,可为一个url链接地址 15 | # @allure.testcase #用于用例标识,关联标识用例,可为一个url链接地址 16 | # @allure.attach # 用于向测试报告中输入一些附加的信息,通常是一些测试数据信息 17 | # @pytest.allure.step # 用于将一些通用的函数作为测试步骤输出到报告,调用此函数的地方会向报告中输出步骤 18 | # allure.environment(environment=env.ini) #用于定义environment 19 | 20 | """ 21 | 22 | 23 | 24 | import pytest 25 | 26 | def pytest_collection_modifyitems(config, items): 27 | """ 根据指定的mark参数场景,动态选择case的执行顺序""" 28 | for item in items: 29 | scenarios = [ 30 | marker for marker in item.own_markers 31 | if marker.name.startswith('scenarios') 32 | and marker.name in config.option.markexpr 33 | ] 34 | if len(scenarios) == 1 and not item.get_closest_marker('run'): 35 | item.add_marker(pytest.mark.run(order=scenarios[0].args[0])) 36 | 37 | 38 | -------------------------------------------------------------------------------- /testcase/test_01_project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/10 22:17 4 | # @Author : wuzushun 5 | # @Site : 6 | # @File : test_01_project.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | 13 | from conf.conf import Config 14 | from common import assert_pro 15 | from unit import load_yaml, token, add_role_admin 16 | from common import request_send 17 | from conf import conf_relevance 18 | from common import log 19 | 20 | 21 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 22 | CASE_PATH = BASE_PATH + "\\params\\param\\project" 23 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 24 | 25 | case_dict = load_yaml.load_case(CASE_PATH + "\\create_project.yaml") 26 | 27 | 28 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 29 | class TestAddProject: 30 | 31 | @classmethod 32 | def setup_class(cls): 33 | # 初始化用例参数,将全局变量替换成配置文件中得变量 34 | # cls.rel = ini_rel 35 | with allure.step("初始化环境变量"): 36 | cls.log = log.MyLog() 37 | cls.Assert = assert_pro.Assertions() 38 | cls.log.info("设置project_token_name为amdin") 39 | conf = Config() 40 | conf.set_conf("test_data", "project_token_name", "admin") 41 | cls.result = {"result": True} 42 | # 更新配置文件中的token 43 | cls.token = token.Token() 44 | cls.token.save_token() 45 | 46 | def setup(self): 47 | self.relevance = conf_relevance.ConfRelevance( 48 | CONF_PATH, "test_data").get_relevance_conf() 49 | 50 | @classmethod 51 | def teardown_class(cls): 52 | with allure.step("新建项目赋权"): 53 | cls.log.info("给新建项目赋权") 54 | role = add_role_admin.Project_Add_Rule() 55 | role.project_add_role() 56 | 57 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 58 | @allure.story("创建项目") 59 | def test_project_crate(self, case_data): 60 | # 参数化修改test_project_crate注释 61 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 62 | try: 63 | if case_data == v: 64 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 65 | TestAddProject.test_add_project.__doc__ = case_dict["test_case"][k + 1]["info"] 66 | except IndexError: 67 | pass 68 | 69 | if not self.result["result"]: 70 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 71 | pytest.xfail("前置接口测试失败,此接口标记为失败") 72 | 73 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 74 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 75 | case_dict["testinfo"].get("address"), 76 | str(case_dict["testinfo"].get("port")), 77 | self.relevance, CASE_PATH, self.result) 78 | project_id = data["project"]["id"] 79 | project_name = data["project"]["name"] 80 | self.Assert.assert_code(code, 201) 81 | with allure.step("保存项目信息到全局配置文件"): 82 | allure.attach("项目id:%s" % project_id) 83 | allure.attach("项目名称:%s" % project_name) 84 | self.log.info("保存project_id到全局配置文件") 85 | conf = Config() 86 | conf.set_conf("test_data", "project_id", project_id) 87 | self.log.info("保存项目名称为project_token_name到全局配置文件") 88 | conf.set_conf("test_data", "project_token_name", project_name) 89 | 90 | 91 | if __name__ == "__main__": 92 | pytest.main(["-s", "test_01_project.py"]) 93 | -------------------------------------------------------------------------------- /testcase/test_02_network.py: -------------------------------------------------------------------------------- 1 | # #!/usr/bin/env.ini python 2 | # # -*- coding: utf-8 -*- 3 | # # @Time : 2019/9/20 11:06 4 | # # @Author : mrwuzs 5 | # # @Site : 6 | # # @File : test_02_network.py 7 | # # @Software: PyCharm 8 | # 9 | # 10 | # 11 | import allure 12 | import pytest 13 | import os 14 | 15 | from conf.conf import Config 16 | from common import assert_pro 17 | from unit import load_yaml, token 18 | from common import request_send 19 | from conf import conf_relevance 20 | from common import log 21 | from common import check_result 22 | 23 | 24 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 25 | CASE_PATH = BASE_PATH + "\\params\\param\\network" 26 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 27 | case_dict = load_yaml.load_case(CASE_PATH + "\\create_network.yaml") 28 | 29 | 30 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 31 | class Test_Network: 32 | 33 | @classmethod 34 | def setup_class(cls): 35 | """ 36 | 初始化用例参数,将全局变量替换成配置文件中得变量 37 | :return: 38 | """ 39 | cls.result = {"result": True} 40 | cls.token = token.Token() 41 | cls.token.save_token() 42 | cls.log = log.MyLog() 43 | cls.Assert = assert_pro.Assertions() 44 | 45 | def setup(self): 46 | self.relevance = conf_relevance.ConfRelevance( 47 | CONF_PATH, "test_data").get_relevance_conf() 48 | 49 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 50 | @allure.story("网络创建和查询") 51 | def test_network(self, case_data): 52 | # 参数化修改test_network注释 53 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 54 | try: 55 | if case_data == v: 56 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 57 | Test_Network.test_network.__doc__ = case_dict["test_case"][k + 1]["info"] 58 | except IndexError: 59 | pass 60 | 61 | if not self.result["result"]: 62 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 63 | pytest.xfail("前置接口测试失败,此接口标记为失败") 64 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 65 | case_dict["testinfo"].get("address"), 66 | str(case_dict["testinfo"].get("port")), 67 | self.relevance, CASE_PATH, self.result) 68 | expected_code = case_data["check"][0]["expected_code"] 69 | network_id = data["network"]["id"] 70 | network_name = data["network"]["name"] 71 | self.log.debug("data:%s" % data) 72 | self.Assert.assert_code(code, expected_code) 73 | # 保存创建的网络id和网络名称 74 | if case_data["request_type"] == "post": 75 | self.log.info("保存network_id到全局配置文件") 76 | conf = Config() 77 | conf.set_conf("test_data", "network_id", network_id) 78 | conf.set_conf("test_data", "network_name_for_check", network_name) 79 | 80 | self.log.debug("保存network_name到全局配置文件,用于虚拟校验") 81 | check_result.check(case_data["test_name"], case_data["check"][0], 82 | code, data, self.relevance, CASE_PATH, self.result) 83 | 84 | 85 | if __name__ == "__main__": 86 | pytest.main(["-s", "test_02_network.py"]) 87 | -------------------------------------------------------------------------------- /testcase/test_03_subnet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env.ini python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/20 11:06 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_03_subnet.py 7 | # @Software: PyCharm 8 | 9 | import os 10 | import allure 11 | import pytest 12 | from conf.conf import Config 13 | from conf import conf_relevance 14 | from unit import load_yaml, token 15 | from common import request_send, check_result, log, assert_pro 16 | 17 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 18 | CASE_PATH = BASE_PATH + "\\params\\param\\subnet" 19 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 20 | case_dict = load_yaml.load_case(CASE_PATH + "\\Subnet.yaml") 21 | 22 | 23 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 24 | class Test_Subnet: 25 | @classmethod 26 | def setup_class(cls): 27 | # 初始化用例参数,将全局变量替换成配置文件中得变量 28 | # cls.rel = ini_rel 29 | cls.result = {"result": True} 30 | # 更新配置文件中的token 31 | cls.token = token.Token() 32 | cls.token.save_token() 33 | cls.log = log.MyLog() 34 | cls.Assert = assert_pro.Assertions() 35 | 36 | def setup(self): 37 | self.relevance = conf_relevance.ConfRelevance( 38 | CONF_PATH, "test_data").get_relevance_conf() 39 | 40 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 41 | @allure.story("创建和查询子网") 42 | # @pytest.mark.scenarios_3(1) 43 | def test_subnet(self, case_data): 44 | 45 | # 参数化修改test_subnet注释 46 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 47 | try: 48 | if case_data == v: 49 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 50 | Test_Subnet.test_subnet.__doc__ = case_dict["test_case"][k + 1]["info"] 51 | except IndexError: 52 | pass 53 | 54 | if not self.result["result"]: 55 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 56 | pytest.xfail("前置接口测试失败,此接口标记为失败") 57 | 58 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 59 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 60 | case_dict["testinfo"].get("address"), 61 | str(case_dict["testinfo"].get("port")), 62 | self.relevance, CASE_PATH, self.result) 63 | expected_code = case_data["check"][0]["expected_code"] 64 | subnet_id = data["subnet"]["id"] 65 | self.Assert.assert_code(code, expected_code) 66 | self.log.info("保存subnet_id到全局配置文件") 67 | conf = Config() 68 | conf.set_conf("test_data", "subnet_id", subnet_id) 69 | check_result.check( 70 | case_data["test_name"], 71 | case_data["check"][0], 72 | code, 73 | data, 74 | self.relevance, 75 | CASE_PATH, 76 | self.result) 77 | 78 | 79 | if __name__ == "__main__": 80 | pytest.main(["-s", "test_03_subnet.py"]) 81 | -------------------------------------------------------------------------------- /testcase/test_04_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/18 11:32 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_04_server.py 7 | # @Software: PyCharm 8 | 9 | import os 10 | import time 11 | import allure 12 | import pytest 13 | from conf.conf import Config 14 | from conf import conf_relevance 15 | from unit import load_yaml, token 16 | from common import request_send, log, check_result, assert_pro 17 | 18 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 19 | CASE_PATH = BASE_PATH + "\\params\\param\\server" 20 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 21 | case_dict = load_yaml.load_case(CASE_PATH + "\\create_server.yaml") 22 | 23 | 24 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 25 | class Test_Server: 26 | @classmethod 27 | def setup_class(cls): 28 | # 初始化用例参数,将全局变量替换成配置文件中得变量 29 | cls.result = {"result": True} 30 | # 更新配置文件中的token 31 | cls.token = token.Token() 32 | cls.token.save_token() 33 | cls.log = log.MyLog() 34 | cls.Assert = assert_pro.Assertions() 35 | # 36 | 37 | def setup(self): 38 | self.relevance = conf_relevance.ConfRelevance( 39 | CONF_PATH, "test_data").get_relevance_conf() 40 | 41 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 42 | @allure.story("创建和查询虚拟机") 43 | @pytest.mark.flaky(reruns=3) 44 | def test_server(self, case_data): 45 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 46 | try: 47 | if case_data == v: 48 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 49 | Test_Server.test_server.__doc__ = case_dict["test_case"][k + 1]["info"] 50 | except IndexError: 51 | pass 52 | 53 | if not self.result["result"]: 54 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 55 | pytest.xfail("前置接口测试失败,此接口标记为失败") 56 | 57 | code, data = request_send.send_request( 58 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 59 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 60 | expected_code = case_data["check"][0]["expected_code"] 61 | server_id = data["server"]["id"] 62 | self.Assert.assert_code(code, expected_code) 63 | 64 | if case_data["request_type"] == "post": 65 | self.log.info("保存server_id到全局配置文件") 66 | conf = Config() 67 | conf.set_conf("test_data", "server_id", server_id) 68 | if case_data["sleep_time"]: 69 | self.log.info("虚拟机已创建,等待创建........") 70 | time.sleep(case_data["sleep_time"]) 71 | 72 | check_result.check( 73 | case_data["test_name"], 74 | case_data["check"][0], 75 | code, 76 | data, 77 | self.relevance, 78 | CASE_PATH, 79 | self.result) 80 | 81 | 82 | if __name__ == "__main__": 83 | pytest.main(["-s", "test_04_server.py"]) 84 | -------------------------------------------------------------------------------- /testcase/test_05_volume.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/18 21:34 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_05_volume.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | import time 13 | 14 | from conf.conf import Config 15 | from common import assert_pro 16 | from unit import load_yaml, token 17 | from common import request_send 18 | from conf import conf_relevance 19 | from common import log 20 | from common import check_result 21 | 22 | 23 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 24 | CASE_PATH = BASE_PATH + "\\params\\param\\volume" 25 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 26 | case_dict = load_yaml.load_case(CASE_PATH + "\\volume.yaml") 27 | 28 | 29 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 30 | class Test_Volume: 31 | 32 | @classmethod 33 | def setup_class(cls): 34 | # 初始化用例参数,将全局变量替换成配置文件中得变量 35 | # cls.rel = ini_rel 36 | cls.result = {"result": True} 37 | # 更新配置文件中的token 38 | cls.token = token.Token() 39 | cls.token.save_token() 40 | cls.log = log.MyLog() 41 | cls.Assert = assert_pro.Assertions() 42 | 43 | def setup(self): 44 | self.relevance = conf_relevance.ConfRelevance( 45 | CONF_PATH, "test_data").get_relevance_conf() 46 | 47 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 48 | @allure.story("卷") 49 | # @pytest.mark.scenarios_6(1) 50 | @pytest.mark.flaky(reruns=3) 51 | def test_volume(self, case_data): 52 | 53 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 54 | try: 55 | if case_data == v: 56 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 57 | Test_Volume.test_volume.__doc__ = case_dict["test_case"][k + 1]["info"] 58 | except IndexError: 59 | pass 60 | 61 | if not self.result["result"]: 62 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 63 | pytest.xfail("前置接口测试失败,此接口标记为失败") 64 | time.sleep(case_data["sleep_time"]) 65 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 66 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 67 | case_dict["testinfo"].get("address"), 68 | str(case_dict["testinfo"].get("port")), 69 | self.relevance, CASE_PATH, self.result) 70 | expected_code = case_data["check"][0]["expected_code"] 71 | volume_id = data["volume"]["id"] 72 | self.Assert.assert_code(code, expected_code) 73 | if case_data["request_type"] == "post": 74 | self.log.info("保存Volume_id到全局配置文件") 75 | conf = Config() 76 | conf.set_conf("test_data", "volume_id", volume_id) 77 | # 完整校验 78 | check_result.check( 79 | case_data["test_name"], 80 | case_data["check"][0], 81 | code, 82 | data, 83 | self.relevance, 84 | CASE_PATH, 85 | self.result) 86 | 87 | 88 | if __name__ == "__main__": 89 | pytest.main(["-s", "test_05_volume.py"]) 90 | -------------------------------------------------------------------------------- /testcase/test_06_os_volume_attachments.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/19 17:46 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_06_os_volume_attachments.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | import time 13 | 14 | from common import assert_pro 15 | from unit import load_yaml, token 16 | from common import request_send 17 | from conf import conf_relevance 18 | from common import log 19 | from common import check_result 20 | 21 | 22 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 23 | CASE_PATH = BASE_PATH + "\\params\\param\\os_volume_attach_detach" 24 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 25 | case_dict = load_yaml.load_case(CASE_PATH + "\\os_volume_attac_and_detach.yaml") 26 | 27 | 28 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 29 | class Test_Os_Volume_Attachments: 30 | @classmethod 31 | def setup_class(cls): 32 | # 初始化用例参数,将全局变量替换成配置文件中得变量 33 | # cls.rel = ini_rel 34 | cls.result = {"result": True} 35 | # 更新配置文件中的token 36 | cls.token = token.Token() 37 | cls.token.save_token() 38 | cls.log = log.MyLog() 39 | cls.Assert = assert_pro.Assertions() 40 | 41 | def setup(self): 42 | self.relevance = conf_relevance.ConfRelevance( 43 | CONF_PATH, "test_data").get_relevance_conf() 44 | 45 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 46 | @allure.story("虚拟机挂载和卸载") 47 | @pytest.mark.flaky(reruns=3) 48 | def test_os_volume_attachments(self, case_data): 49 | # 参数化修改test_os_volume_attachments注释 50 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 51 | try: 52 | if case_data == v: 53 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 54 | Test_Os_Volume_Attachments.test_os_volume_attachments.__doc__ = case_dict[ 55 | "test_case"][k + 1]["info"] 56 | except IndexError: 57 | pass 58 | 59 | if not self.result["result"]: 60 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 61 | pytest.xfail("前置接口测试失败,此接口标记为失败") 62 | 63 | if case_data["request_type"] == "get": 64 | time.sleep(case_data["sleep_time"]) 65 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 66 | code, data = request_send.send_request( 67 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 68 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 69 | expected_code = case_data["check"][0]["expected_code"] 70 | 71 | self.Assert.assert_code(code, expected_code) 72 | # 完整校验 73 | check_result.check( 74 | case_data["test_name"], 75 | case_data["check"][0], 76 | code, 77 | data, 78 | self.relevance, 79 | CASE_PATH, 80 | self.result) 81 | 82 | 83 | if __name__ == "__main__": 84 | pytest.main(["-s", "test_06_os_volume_attachments.py"]) 85 | -------------------------------------------------------------------------------- /testcase/test_07_volume_snap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/19 17:12 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_07_volume_snap.py 7 | # @Software: PyCharm 8 | 9 | import os 10 | import time 11 | import allure 12 | import pytest 13 | from conf.conf import Config 14 | from conf import conf_relevance 15 | from unit import load_yaml, token 16 | from common import request_send, assert_pro, log, check_result 17 | 18 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 19 | CASE_PATH = BASE_PATH + "\\params\\param\\volume_snap" 20 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 21 | case_dict = load_yaml.load_case(CASE_PATH + "\\volume_snap.yaml") 22 | 23 | 24 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 25 | class Test_Volume_Snap: 26 | 27 | @classmethod 28 | def setup_class(cls): 29 | # 初始化用例参数,将全局变量替换成配置文件中得变量 30 | # cls.rel = ini_rel 31 | cls.result = {"result": True} 32 | # 更新配置文件中的token 33 | cls.token = token.Token() 34 | cls.token.save_token() 35 | cls.log = log.MyLog() 36 | cls.Assert = assert_pro.Assertions() 37 | 38 | def setup(self): 39 | self.relevance = conf_relevance.ConfRelevance( 40 | CONF_PATH, "test_data").get_relevance_conf() 41 | 42 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 43 | @allure.story("创建卷快照") 44 | @pytest.mark.flaky(reruns=3) 45 | def test_volume_snap(self, case_data): 46 | # 参数化修改test_add_project 注释 47 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 48 | try: 49 | if case_data == v: 50 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 51 | Test_Volume_Snap.test_volume_snap.__doc__ = case_dict["test_case"][k + 1]["info"] 52 | except IndexError: 53 | pass 54 | 55 | if not self.result["result"]: 56 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 57 | pytest.xfail("前置接口测试失败,此接口标记为失败") 58 | if case_data["request_type"] == "get": 59 | time.sleep(case_data["sleep_time"]) 60 | 61 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 62 | case_dict["testinfo"].get("address"), 63 | str(case_dict["testinfo"].get("port")), 64 | self.relevance, CASE_PATH, self.result) 65 | expected_code = case_data["check"][0]["expected_code"] 66 | if case_data["request_type"] == "post": 67 | snapshot_id = data["snapshot"]["id"] 68 | self.log.info("保存volume_snapshot_id到全局配置文件") 69 | conf = Config() 70 | conf.set_conf("test_data", "volume_snapshot_id", snapshot_id) 71 | self.Assert.assert_code(code, expected_code) 72 | check_result.check(case_data["test_name"], case_data["check"][0], 73 | code, data, self.relevance, CASE_PATH, self.result) 74 | 75 | 76 | if __name__ == "__main__": 77 | pytest.main(["-s", "test_07_volume_snap.py"]) 78 | -------------------------------------------------------------------------------- /testcase/test_08_server_snap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/19 16:10 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_server_snap_snap.py 7 | # @Software: PyCharm 8 | import os 9 | import allure 10 | import pytest 11 | 12 | from unit import load_yaml, token 13 | from common import request_send, log, assert_pro 14 | from conf import conf_relevance 15 | 16 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 17 | CASE_PATH = BASE_PATH + "\\params\\param\\server_snapshot" 18 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 19 | case_dict = load_yaml.load_case(CASE_PATH + "\\server_snap.yaml") 20 | 21 | 22 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 23 | class Test_Server_Snap: 24 | @classmethod 25 | def setup_class(cls): 26 | # 初始化用例参数,将全局变量替换成配置文件中得变量 27 | # cls.rel = ini_rel 28 | cls.result = {"result": True} 29 | # 更新配置文件中的token 30 | cls.token = token.Token() 31 | cls.token.save_token() 32 | cls.log = log.MyLog() 33 | cls.Assert = assert_pro.Assertions() 34 | 35 | def setup(self): 36 | self.relevance = conf_relevance.ConfRelevance( 37 | CONF_PATH, "test_data").get_relevance_conf() 38 | 39 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 40 | @allure.story("虚拟机快照") 41 | def test_server_snap(self, case_data): 42 | 43 | # 参数化修改test_add_project 注释 44 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 45 | try: 46 | if case_data == v: 47 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 48 | Test_Server_Snap.test_server_snap.__doc__ = case_dict["test_case"][k + 1]["info"] 49 | except IndexError: 50 | pass 51 | 52 | if not self.result["result"]: 53 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 54 | pytest.xfail("前置接口测试失败,此接口标记为失败") 55 | 56 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 57 | code, data = request_send.send_request( 58 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 59 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 60 | expected_code = case_data["check"][0]["expected_code"] 61 | self.Assert.assert_code(code, expected_code) 62 | 63 | 64 | if __name__ == "__main__": 65 | pytest.main(["-s", "test_08_server_snap.py"]) 66 | -------------------------------------------------------------------------------- /testcase/test_09_get_server_snap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/19 16:52 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_09_get_server_snap.py 7 | # @Software: PyCharm 8 | 9 | import os 10 | import time 11 | import allure 12 | import pytest 13 | from common import assert_pro 14 | from unit import load_yaml, token 15 | from common import request_send 16 | from conf.conf import Config 17 | from conf import conf_relevance 18 | from common import log 19 | from common import check_result 20 | 21 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 22 | CASE_PATH = BASE_PATH + "\\params\\param\\server_snapshot" 23 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 24 | case_dict = load_yaml.load_case(CASE_PATH + "\\get_server_snap.yaml") 25 | 26 | 27 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 28 | class Test_Get_Server_Snap: 29 | 30 | @classmethod 31 | def setup_class(cls): 32 | # 初始化用例参数,将全局变量替换成配置文件中得变量 33 | # cls.rel = ini_rel 34 | cls.result = {"result": True} 35 | # 更新配置文件中的token 36 | cls.token = token.Token() 37 | cls.token.save_token() 38 | cls.log = log.MyLog() 39 | cls.Assert = assert_pro.Assertions() 40 | 41 | def setup(self): 42 | self.relevance = conf_relevance.ConfRelevance( 43 | CONF_PATH, "test_data").get_relevance_conf() 44 | 45 | # self.relevance = init.ini_request(case_dict, self.relevance, PATH, self.result) 46 | 47 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 48 | @allure.story("查看虚拟机快照") 49 | @pytest.mark.flaky(reruns=3) 50 | def test_get_server_snap(self, case_data): 51 | # 参数化修改test_add_project 注释 52 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 53 | try: 54 | if case_data == v: 55 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 56 | Test_Get_Server_Snap.test_get_server_snap.__doc__ = case_dict[ 57 | "test_case"][k + 1]["info"] 58 | except IndexError: 59 | pass 60 | 61 | if not self.result["result"]: 62 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 63 | pytest.xfail("前置接口测试失败,此接口标记为失败") 64 | 65 | if case_data["request_type"] == "get": 66 | time.sleep(case_data["sleep_time"]) 67 | 68 | # send_request(_data, _host, _address,_port, _relevance, path, _success) 69 | code, data = request_send.send_request( 70 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 71 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 72 | expected_code = case_data["check"][0]["expected_code"] 73 | self.Assert.assert_code(code, expected_code) 74 | # 完整校验 75 | check_result.check( 76 | case_data["test_name"], 77 | case_data["check"][0], 78 | code, 79 | data, 80 | self.relevance, 81 | CASE_PATH, 82 | self.result) 83 | server_snap_id = data["images"][0]["id"] 84 | self.log.info("保存Volume_id到全局配置文件") 85 | conf = Config() 86 | conf.set_conf("test_data", "server_snap_id", server_snap_id) 87 | 88 | 89 | if __name__ == "__main__": 90 | pytest.main(["-s", "test_09_get_server_snap.py"]) 91 | -------------------------------------------------------------------------------- /testcase/test_10_delete_volume_snap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:55 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_10_delete_volume_snap.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | 13 | from time import sleep 14 | from common import check_result 15 | from common import assert_pro 16 | from unit import load_yaml, token 17 | from common import request_send 18 | from conf import conf_relevance 19 | from common import log 20 | 21 | 22 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 23 | CASE_PATH = BASE_PATH + "\\params\\param\\volume_snap" 24 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 25 | 26 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_volume_snap.yaml") 27 | 28 | 29 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 30 | class Test_Volume_Snap_Delete: 31 | 32 | @classmethod 33 | def setup_class(cls): 34 | # 初始化用例参数,将全局变量替换成配置文件中得变量 35 | # cls.rel = ini_rel 36 | cls.result = {"result": True} 37 | # 更新配置文件中的token 38 | cls.token = token.Token() 39 | cls.token.save_token() 40 | cls.log = log.MyLog() 41 | cls.Assert = assert_pro.Assertions() 42 | # 43 | 44 | def setup(self): 45 | self.relevance = conf_relevance.ConfRelevance( 46 | CONF_PATH, "test_data").get_relevance_conf() 47 | 48 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 49 | @allure.story("删除卷快照") 50 | @pytest.mark.flaky(reruns=3) 51 | def test_volume_snap_delete(self, case_data): 52 | 53 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 54 | try: 55 | if case_data == v: 56 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 57 | Test_Volume_Snap_Delete.test_volume_snap_delete.__doc__ = case_dict[ 58 | "test_case"][k + 1]["info"] 59 | except IndexError: 60 | pass 61 | 62 | if not self.result["result"]: 63 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 64 | pytest.xfail("前置接口测试失败,此接口标记为失败") 65 | 66 | # 设置延时,等待快照删除完成 67 | if case_data["request_type"] == "get": 68 | sleep(case_data["sleep_time"]) 69 | 70 | code, data = request_send.send_request( 71 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 72 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 73 | 74 | # 结果校验 75 | check_result.check( 76 | case_data["test_name"], 77 | case_data["check"][0], 78 | code, 79 | data, 80 | self.relevance, 81 | CASE_PATH, 82 | self.result) 83 | 84 | 85 | if __name__ == "__main__": 86 | pytest.main(["-s", "test_10_delete_volume_snap.py"]) 87 | -------------------------------------------------------------------------------- /testcase/test_11_delete_server_snap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:56 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_11_delete_server_snap.py 7 | # @Software: PyCharm 8 | import allure 9 | import pytest 10 | import os 11 | import time 12 | 13 | from conf.conf import Config 14 | from common import assert_pro 15 | from unit import load_yaml, token 16 | from common import request_send 17 | from conf import conf_relevance 18 | from common import log 19 | from common import check_result 20 | 21 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 22 | CASE_PATH = BASE_PATH + "\\params\\param\\server_snapshot" 23 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 24 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_server_snap.yaml") 25 | 26 | 27 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 28 | class Test_Server_Snap: 29 | @classmethod 30 | def setup_class(cls): 31 | # 初始化用例参数,将全局变量替换成配置文件中得变量 32 | cls.result = {"result": True} 33 | # 更新配置文件中的token 34 | cls.token = token.Token() 35 | cls.token.save_token() 36 | cls.log = log.MyLog() 37 | cls.Assert = assert_pro.Assertions() 38 | 39 | def setup(self): 40 | self.relevance = conf_relevance.ConfRelevance( 41 | CONF_PATH, "test_data").get_relevance_conf() 42 | 43 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 44 | @allure.story("删除虚拟机快照") 45 | @pytest.mark.flaky(reruns=3) 46 | def test_server_snap(self, case_data): 47 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 48 | try: 49 | if case_data == v: 50 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 51 | Test_Server_Snap.test_server_snap.__doc__ = case_dict["test_case"][k + 1]["info"] 52 | except IndexError: 53 | pass 54 | if not self.result["result"]: 55 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 56 | pytest.xfail("前置接口测试失败,此接口标记为失败") 57 | if case_data["request_type"] == "get": 58 | time.sleep(case_data["sleep_time"]) 59 | 60 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 61 | case_dict["testinfo"].get("address"), 62 | str(case_dict["testinfo"].get("port")), 63 | self.relevance, CASE_PATH, self.result) 64 | check_result.check( 65 | case_data["test_name"], 66 | case_data["check"][0], 67 | code, 68 | data, 69 | self.relevance, 70 | CASE_PATH, 71 | self.result) 72 | 73 | 74 | if __name__ == "__main__": 75 | pytest.main(["-s", "test_11_delete_server_snap.py"]) 76 | -------------------------------------------------------------------------------- /testcase/test_12_delete_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:56 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_12_delete_server.py 7 | # @Software: PyCharm 8 | import allure 9 | import pytest 10 | import os 11 | import time 12 | 13 | from conf.conf import Config 14 | from common import assert_pro 15 | from unit import load_yaml, token 16 | from common import request_send 17 | from conf import conf_relevance 18 | from common import log 19 | from common import check_result 20 | 21 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 22 | CASE_PATH = BASE_PATH + "\\params\\param\\server" 23 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 24 | 25 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_server.yaml") 26 | 27 | 28 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 29 | class Test_Server: 30 | 31 | @classmethod 32 | def setup_class(cls): 33 | # 初始化用例参数,将全局变量替换成配置文件中得变量 34 | cls.result = {"result": True} 35 | # 更新配置文件中的token 36 | cls.token = token.Token() 37 | cls.token.save_token() 38 | cls.log = log.MyLog() 39 | cls.Assert = assert_pro.Assertions() 40 | # 41 | 42 | def setup(self): 43 | self.relevance = conf_relevance.ConfRelevance( 44 | CONF_PATH, "test_data").get_relevance_conf() 45 | 46 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 47 | @allure.story("删除虚拟机") 48 | @pytest.mark.flaky(reruns=3) 49 | def test_server(self, case_data): 50 | 51 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 52 | try: 53 | if case_data == v: 54 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 55 | Test_Server.test_server.__doc__ = case_dict["test_case"][k + 1]["info"] 56 | except IndexError: 57 | pass 58 | 59 | # if not self.result["result"]: 60 | # # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 61 | # pytest.xfail("前置接口测试失败,此接口标记为失败") 62 | 63 | time.sleep(case_data["sleep_time"]) 64 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 65 | code, data = request_send.send_request(case_data, case_dict["testinfo"].get("host"), 66 | case_dict["testinfo"].get("address"), 67 | str(case_dict["testinfo"].get("port")), 68 | self.relevance, CASE_PATH, self.result) 69 | check_result.check( 70 | case_data["test_name"], 71 | case_data["check"][0], 72 | code, 73 | data, 74 | self.relevance, 75 | CASE_PATH, 76 | self.result) 77 | 78 | 79 | if __name__ == "__main__": 80 | pytest.main(["-s", "test_12_delete_server.py"]) 81 | -------------------------------------------------------------------------------- /testcase/test_13_delete_subnet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:57 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_13_delete_subnet.py 7 | # @Software: PyCharm 8 | 9 | 10 | import allure 11 | import pytest 12 | import os 13 | import time 14 | 15 | 16 | from common import assert_pro 17 | from unit import load_yaml, token, ports 18 | from common import request_send 19 | from conf import conf_relevance 20 | from common import log 21 | from common import check_result 22 | 23 | 24 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 25 | CASE_PATH = BASE_PATH + "\\params\\param\\subnet" 26 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 27 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_subnet.yaml") 28 | 29 | 30 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 31 | class Test_Delete_Subnet: 32 | 33 | @classmethod 34 | def setup_class(cls): 35 | # 初始化用例参数,将全局变量替换成配置文件中得变量 36 | # cls.rel = ini_rel 37 | cls.result = {"result": True} 38 | # 更新配置文件中的token 39 | cls.token = token.Token() 40 | cls.token.save_token() 41 | cls.log = log.MyLog() 42 | cls.Assert = assert_pro.Assertions() 43 | 44 | def setup(self): 45 | self.relevance = conf_relevance.ConfRelevance( 46 | CONF_PATH, "test_data").get_relevance_conf() 47 | 48 | # self.relevance = init.ini_request(case_dict, self.relevance, PATH, self.result) 49 | 50 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 51 | @allure.story("删除子网") 52 | # @pytest.mark.scenarios_3(1) 53 | def test_delete_subnet(self, case_data): 54 | 55 | if case_data["request_type"] == "delete": 56 | ports.Ports().delete_all_port() 57 | 58 | # 参数化修改test_add_project 注释 59 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 60 | try: 61 | if case_data == v: 62 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 63 | Test_Delete_Subnet.test_delete_subnet.__doc__ = case_dict[ 64 | "test_case"][k + 1]["info"] 65 | except IndexError: 66 | pass 67 | 68 | if not self.result["result"]: 69 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 70 | pytest.xfail("前置接口测试失败,此接口标记为失败") 71 | 72 | time.sleep(case_data["sleep_time"]) 73 | 74 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 75 | code, data = request_send.send_request( 76 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 77 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 78 | 79 | check_result.check( 80 | case_data["test_name"], 81 | case_data["check"][0], 82 | code, 83 | data, 84 | self.relevance, 85 | CASE_PATH, 86 | self.result) 87 | 88 | 89 | if __name__ == "__main__": 90 | pytest.main(["-s", "test_13_delete_subnet.py"]) 91 | -------------------------------------------------------------------------------- /testcase/test_14_delete_network.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:57 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_14_delete_network.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | import time 13 | 14 | 15 | from common import assert_pro 16 | from unit import load_yaml, token 17 | from common import request_send 18 | from conf import conf_relevance 19 | from common import log 20 | from common import check_result 21 | 22 | 23 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 24 | CASE_PATH = BASE_PATH + "\\params\\param\\network" 25 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 26 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_network.yaml") 27 | 28 | 29 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 30 | class Test_Delete_network: 31 | @classmethod 32 | def setup_class(cls): 33 | # 初始化用例参数,将全局变量替换成配置文件中得变量 34 | # cls.rel = ini_rel 35 | cls.result = {"result": True} 36 | # 更新配置文件中的token 37 | cls.token = token.Token() 38 | cls.token.save_token() 39 | cls.log = log.MyLog() 40 | cls.Assert = assert_pro.Assertions() 41 | 42 | def setup(self): 43 | self.relevance = conf_relevance.ConfRelevance( 44 | CONF_PATH, "test_data").get_relevance_conf() 45 | 46 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 47 | @allure.story("删除网络") 48 | # @pytest.mark.scenarios_3(1) 49 | def test_delete_network(self, case_data): 50 | 51 | # 参数化修改test_add_project 注释 52 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 53 | try: 54 | if case_data == v: 55 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 56 | Test_Delete_network.test_delete_network.__doc__ = case_dict[ 57 | "test_case"][k + 1]["info"] 58 | except IndexError: 59 | pass 60 | 61 | if not self.result["result"]: 62 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 63 | pytest.xfail("前置接口测试失败,此接口标记为失败") 64 | 65 | time.sleep(case_data["sleep_time"]) 66 | 67 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 68 | code, data = request_send.send_request( 69 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 70 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 71 | 72 | check_result.check( 73 | case_data["test_name"], 74 | case_data["check"][0], 75 | code, 76 | data, 77 | self.relevance, 78 | CASE_PATH, 79 | self.result) 80 | 81 | 82 | if __name__ == "__main__": 83 | pytest.main(["-s", "test_14_delete_network.py"]) 84 | -------------------------------------------------------------------------------- /testcase/test_15_delete_volume.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 11:39 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_15_delete_volume.py 7 | # @Software: PyCharm 8 | 9 | import os, time 10 | import allure, pytest 11 | 12 | from unit import load_yaml, token 13 | from conf import conf_relevance 14 | from common import assert_pro, request_send, check_result, log 15 | 16 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 17 | CASE_PATH = BASE_PATH + "\\params\\param\\volume" 18 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 19 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_volume.yaml") 20 | 21 | @allure.feature(case_dict["testinfo"]["title"]) # feature定义功能 22 | class Test_Delete_volume: 23 | 24 | 25 | @classmethod 26 | def setup_class(cls): 27 | #初始化用例参数,将全局变量替换成配置文件中得变量 28 | # cls.rel = ini_rel 29 | cls.result = {"result": True} 30 | #更新配置文件中的token 31 | cls.token = token.Token() 32 | cls.token.save_token() 33 | cls.log = log.MyLog() 34 | cls.Assert = assert_pro.Assertions() 35 | # 36 | 37 | def setup(self): 38 | self.relevance = conf_relevance.ConfRelevance(CONF_PATH, "test_data").get_relevance_conf() 39 | 40 | 41 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 42 | @allure.story("删除卷") 43 | @pytest.mark.flaky(reruns=3) 44 | def test_delete_volume(self,case_data): 45 | 46 | # 参数化修改test_add_project 注释 47 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 48 | try: 49 | if case_data == v: 50 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 51 | Test_Delete_volume.test_delete_volume.__doc__ = case_dict["test_case"][k + 1]["info"] 52 | except IndexError: 53 | pass 54 | 55 | if not self.result["result"]: 56 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 57 | pytest.xfail("前置接口测试失败,此接口标记为失败") 58 | if case_data["request_type"] == "get": 59 | time.sleep(case_data["sleep_time"]) 60 | #send_request(_data, _host, _address,_port, _relevance, path, _success) 61 | code, data = request_send.send_request(case_data, 62 | case_dict["testinfo"].get("host"), 63 | case_dict["testinfo"].get("address"), 64 | str(case_dict["testinfo"].get("port")), 65 | self.relevance, CASE_PATH, self.result) 66 | check_result.check(case_data["test_name"], 67 | case_data["check"][0], 68 | code, data, 69 | self.relevance, CASE_PATH, 70 | self.result) 71 | 72 | 73 | if __name__ == "__main__": 74 | pytest.main(["-s", "test_15_delete_volume.py"]) 75 | -------------------------------------------------------------------------------- /testcase/test_16_delete_project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/29 9:58 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : test_16_delete_project.py 7 | # @Software: PyCharm 8 | 9 | import allure 10 | import pytest 11 | import os 12 | 13 | from common import assert_pro 14 | from unit import load_yaml, token 15 | from common import request_send 16 | from conf import conf_relevance 17 | from common import log 18 | from common import check_result 19 | 20 | 21 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 22 | CASE_PATH = BASE_PATH + "\\params\\param\\project" 23 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 24 | case_dict = load_yaml.load_case(CASE_PATH + "\\delete_project.yaml") 25 | 26 | 27 | @allure.feature(case_dict["testinfo"]["title"]) 28 | class Test_Delete_Project: 29 | @classmethod 30 | def setup_class(cls): 31 | # 初始化用例参数,将全局变量替换成配置文件中得变量 32 | cls.result = {"result": True} 33 | # 更新配置文件中的token 34 | cls.token = token.Token() 35 | cls.token.save_token() 36 | cls.log = log.MyLog() 37 | cls.Assert = assert_pro.Assertions() 38 | 39 | def setup(self): 40 | self.relevance = conf_relevance.ConfRelevance( 41 | CONF_PATH, "test_data").get_relevance_conf() 42 | 43 | @pytest.mark.parametrize("case_data", case_dict["test_case"]) 44 | @allure.story("删除项目") 45 | # @pytest.mark.scenarios_3(1) 46 | def test_delete_project(self, case_data): 47 | # 参数化修改test_add_project 注释 48 | for k, v in enumerate(case_dict["test_case"]): # 遍历用例文件中所有用例的索引和值 49 | try: 50 | if case_data == v: 51 | # 修改方法的__doc__在下一次调用时生效,此为展示在报告中的用例描述 52 | Test_Delete_Project.test_delete_project.__doc__ = case_dict[ 53 | "test_case"][k + 1]["info"] 54 | except IndexError: 55 | pass 56 | if not self.result["result"]: 57 | # 查看类变量result的值,如果未False,则前一接口校验错误,此接口标记未失败,节约测试时间 58 | pytest.xfail("前置接口测试失败,此接口标记为失败") 59 | code, data = request_send.send_request( 60 | case_data, case_dict["testinfo"].get("host"), case_dict["testinfo"].get("address"), str( 61 | case_dict["testinfo"].get("port")), self.relevance, CASE_PATH, self.result) 62 | check_result.check( 63 | case_data["test_name"], 64 | case_data["check"][0], 65 | code, 66 | data, 67 | self.relevance, 68 | CASE_PATH, 69 | self.result) 70 | 71 | 72 | if __name__ == "__main__": 73 | pytest.main(["-s", "test_16_delete_project.py"]) 74 | -------------------------------------------------------------------------------- /unit/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/21 20:40 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : __init__.py.py 7 | # @Software: PyCharm -------------------------------------------------------------------------------- /unit/add_role_admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/18 17:22 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : add_role_admin.py 7 | # @Software: PyCharm 8 | import requests 9 | import os 10 | import allure 11 | 12 | from common import log 13 | from common import param_manage 14 | from conf import conf 15 | from conf import conf_relevance 16 | 17 | 18 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 19 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 20 | 21 | 22 | class Project_Add_Rule: 23 | """给项目添加admin权限""" 24 | 25 | def __init__(self): 26 | self.config = conf.Config() 27 | self.log = log.MyLog() 28 | self.relevance = conf_relevance.ConfRelevance( 29 | CONF_PATH, "test_data").get_relevance_conf() 30 | self.headers = { 31 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", 32 | "Content-Type": "application/json", 33 | "X-Auth-Token": "${token_id}$"} 34 | 35 | self.address = { 36 | "address": "/v3/projects/${project_id}$/users/${admin_id}$/roles/${admin_role_id}$"} 37 | 38 | def project_add_role(self): 39 | """ 40 | 给项目添加权限 41 | :return: 42 | """ 43 | self.log.debug("处理header") 44 | headers = param_manage.manage(self.headers, self.relevance) 45 | self.log.debug("Headers:%s" % headers) 46 | self.log.debug("处理address") 47 | address = param_manage.manage(self.address, self.relevance) 48 | self.log.debug("address:%s" % address) 49 | login_url = "http://" + self.config.host + ":5000" + address["address"] 50 | self.log.debug("login_url:%s" % login_url) 51 | self.log.info("给项目添加admin权限") 52 | with allure.step("给项目添加权限"): 53 | allure.attach("address:%s" % address["address"]) 54 | response = requests.put(login_url, headers=headers) 55 | if response.status_code == 204: 56 | self.log.info("项目成功添加admin权限") 57 | return 58 | else: 59 | raise Exception("项目添加admin权限失败,请确认参数") 60 | 61 | 62 | if __name__ == '__main__': 63 | add_role_test = Project_Add_Rule() 64 | add_role_test.project_add_role() 65 | -------------------------------------------------------------------------------- /unit/api_method.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/9 16:25 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : api_method.py 7 | # @Software: PyCharm 8 | 9 | import json 10 | import os 11 | import requests 12 | import random 13 | import simplejson 14 | import setupMain 15 | from requests_toolbelt import MultipartEncoder 16 | from common.log import MyLog as logging 17 | 18 | def post(header, address, request_parameter_type, timeout=8, data=None, files=None): 19 | """ 20 | post请求 21 | :param header: 请求头 22 | :param address: 请求地址 23 | :param request_parameter_type: 请求参数格式(form_data,raw) 24 | :param timeout: 超时时间 25 | :param data: 请求参数 26 | :param files: 文件路径 27 | :return: 28 | """ 29 | if 'form_data' in request_parameter_type: 30 | for i in files: 31 | value = files[i] 32 | if '/' in value: 33 | file_parm = i 34 | files[file_parm] = (os.path.basename(value), open(value, 'rb')) 35 | enc = MultipartEncoder( 36 | fields=files, 37 | boundary='--------------' + str(random.randint(1e28, 1e29 - 1)) 38 | ) 39 | header['Content-Type'] = enc.content_type 40 | 41 | response = requests.post(url=address, data=enc, headers=header, timeout=timeout) 42 | else: 43 | response = requests.post(url=address, data=data, headers=header, timeout=timeout, files=files) 44 | try: 45 | if response.status_code != 200: 46 | return response.status_code, response.text 47 | else: 48 | return response.status_code, response.json() 49 | except json.decoder.JSONDecodeError: 50 | return response.status_code, '' 51 | except simplejson.errors.JSONDecodeError: 52 | return response.status_code, '' 53 | except Exception as e: 54 | logging.exception('ERROR') 55 | logging.error(e) 56 | raise 57 | 58 | 59 | def get(header, address, data, timeout=8): 60 | """ 61 | get请求 62 | :param header: 请求头 63 | :param address: 请求地址 64 | :param data: 请求参数 65 | :param timeout: 超时时间 66 | :return: 67 | """ 68 | response = requests.get(url=address, params=data, headers=header, timeout=timeout) 69 | if response.status_code == 301: 70 | response = requests.get(url=response.headers["location"]) 71 | try: 72 | return response.status_code, response.json() 73 | except json.decoder.JSONDecodeError: 74 | return response.status_code, '' 75 | except simplejson.errors.JSONDecodeError: 76 | return response.status_code, '' 77 | except Exception as e: 78 | logging.exception('ERROR') 79 | logging.error(e) 80 | raise 81 | 82 | 83 | def put(header, address, request_parameter_type, timeout=8, data=None, files=None): 84 | """ 85 | post请求 86 | :param header: 请求头 87 | :param address: 请求地址 88 | :param request_parameter_type: 请求参数格式(form_data,raw) 89 | :param timeout: 超时时间 90 | :param data: 请求参数 91 | :param files: 文件路径 92 | :return: 93 | """ 94 | if request_parameter_type == 'raw': 95 | data = json.dumps(data) 96 | response = requests.put(url=address, data=data, headers=header, timeout=timeout, files=files) 97 | try: 98 | return response.status_code, response.json() 99 | except json.decoder.JSONDecodeError: 100 | return response.status_code, '' 101 | except simplejson.errors.JSONDecodeError: 102 | return response.status_code, '' 103 | except Exception as e: 104 | logging.exception('ERROR') 105 | logging.error(e) 106 | raise 107 | 108 | 109 | def delete(header, address, data, timeout=8): 110 | """ 111 | get请求 112 | :param header: 请求头 113 | :param address: 请求地址 114 | :param data: 请求参数 115 | :param timeout: 超时时间 116 | :return: 117 | """ 118 | response = requests.delete(url=address, params=data, headers=header, timeout=timeout) 119 | 120 | try: 121 | return response.status_code, response.json() 122 | except json.decoder.JSONDecodeError: 123 | return response.status_code, '' 124 | except simplejson.errors.JSONDecodeError: 125 | return response.status_code, '' 126 | except Exception as e: 127 | logging.exception('ERROR') 128 | logging.error(e) 129 | raise 130 | 131 | 132 | def save_cookie(header, address, timeout=8, data=None, files=None): 133 | """ 134 | 保存cookie信息 135 | :param header: 请求头 136 | :param address: 请求地址 137 | :param timeout: 超时时间 138 | :param data: 请求参数 139 | :param files: 文件路径 140 | :return: 141 | """ 142 | cookie_path = setupMain.PATH + '/aff/data/cookie.txt' 143 | response = requests.post(url=address, data=data, headers=header, timeout=timeout, files=files) 144 | try: 145 | cookie = response.cookies.get_dict() 146 | for i in cookie: 147 | values = cookie[i] 148 | with open(cookie_path, 'w+', encoding='utf-8')as f: 149 | f.write(i+"="+values) 150 | logging.debug("cookies已保存,结果为:%s" % (i+"="+values)) 151 | except json.decoder.JSONDecodeError: 152 | return response.status_code, '' 153 | except simplejson.errors.JSONDecodeError: 154 | return response.status_code, '' 155 | except Exception as e: 156 | logging.exception('ERROR') 157 | logging.error(e) 158 | raise -------------------------------------------------------------------------------- /unit/api_send.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/9 16:24 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : api_send.py 7 | # @Software: PyCharm 8 | 9 | from common.log import MyLog as logging 10 | import allure 11 | 12 | from unit import api_method, replaceRelevance 13 | from unit import initializeCookie 14 | from config import confManage 15 | from unit import readParameter 16 | 17 | 18 | def send_request(data, host, address, _path, relevance=None): 19 | """ 20 | 封装请求 21 | :param data: 测试用例 22 | :param host: 测试host 23 | :param address: 接口地址 24 | :param relevance: 关联对象 25 | :param _path: case路径 26 | :return: 27 | """ 28 | logging.info("=" * 100) 29 | header = readParameter.read_param( 30 | data["test_name"], data["headers"], _path, relevance) 31 | if data["cookies"] is True: 32 | header["Cookie"] = initializeCookie.ini_cookie() 33 | logging.debug("请求头处理结果:%s" % header) 34 | parameter = readParameter.read_param( 35 | data["test_name"], data["parameter"], _path, relevance) 36 | logging.debug("请求参数处理结果:%s" % parameter) 37 | try: 38 | host = data["host"] 39 | except KeyError: 40 | pass 41 | try: 42 | address = data["address"] 43 | except KeyError: 44 | pass 45 | host = confManage.host_manage(host) 46 | address = replaceRelevance.replace(address, relevance) 47 | logging.debug("host处理结果: %s" % host) 48 | if not host: 49 | raise Exception("接口请求地址为空 %s" % data["headers"]) 50 | logging.info("请求接口:%s" % str(data["test_name"])) 51 | logging.info("请求地址:%s" % data["http_type"] + "://" + host + address) 52 | logging.info("请求头: %s" % str(header)) 53 | logging.info("请求参数: %s" % str(parameter)) 54 | if data["test_name"] == 'password正确': 55 | with allure.step("保存cookie信息"): 56 | allure.attach("请求接口:", str(data["test_name"])) 57 | allure.attach("请求地址", data["http_type"] + "://" + host + address) 58 | allure.attach("请求头", str(header)) 59 | allure.attach("请求参数", str(parameter)) 60 | api_method.save_cookie( 61 | header=header, 62 | address=data["http_type"] + 63 | "://" + 64 | host + 65 | address, 66 | data=parameter) 67 | 68 | if data["request_type"].lower() == 'post': 69 | logging.info("请求方法: POST") 70 | if data["file"]: 71 | with allure.step("POST上传文件"): 72 | allure.attach("请求接口:", str(data["test_name"])) 73 | allure.attach( 74 | "请求地址", 75 | data["http_type"] + 76 | "://" + 77 | host + 78 | address) 79 | allure.attach("请求头", str(header)) 80 | allure.attach("请求参数", str(parameter)) 81 | 82 | result = api_method.post( 83 | header=header, 84 | address=data["http_type"] + "://" + host + address, 85 | request_parameter_type=data["parameter_type"], 86 | files=parameter, 87 | timeout=data["timeout"]) 88 | else: 89 | with allure.step("POST请求接口"): 90 | allure.attach("请求接口:", str(data["test_name"])) 91 | allure.attach( 92 | "请求地址", 93 | data["http_type"] + 94 | "://" + 95 | host + 96 | address) 97 | allure.attach("请求头", str(header)) 98 | allure.attach("请求参数", str(parameter)) 99 | result = api_method.post( 100 | header=header, 101 | address=data["http_type"] + "://" + host + address, 102 | request_parameter_type=data["parameter_type"], 103 | data=parameter, 104 | timeout=data["timeout"]) 105 | elif data["request_type"].lower() == 'get': 106 | with allure.step("GET请求接口"): 107 | allure.attach("请求接口:", str(data["test_name"])) 108 | allure.attach("请求地址", data["http_type"] + "://" + host + address) 109 | allure.attach("请求头", str(header)) 110 | allure.attach("请求参数", str(parameter)) 111 | logging.info("请求方法: GET") 112 | result = api_method.get( 113 | header=header, 114 | address=data["http_type"] + 115 | "://" + 116 | host + 117 | address, 118 | data=parameter, 119 | timeout=data["timeout"]) 120 | elif data["request_type"].lower() == 'put': 121 | logging.info("请求方法: PUT") 122 | if data["file"]: 123 | with allure.step("PUT上传文件"): 124 | allure.attach("请求接口:", str(data["test_name"])) 125 | allure.attach( 126 | "请求地址", 127 | data["http_type"] + 128 | "://" + 129 | host + 130 | address) 131 | allure.attach("请求头", str(header)) 132 | allure.attach("请求参数", str(parameter)) 133 | result = api_method.post( 134 | header=header, 135 | address=data["http_type"] + "://" + host + address, 136 | request_parameter_type=data["parameter_type"], 137 | files=parameter, 138 | timeout=data["timeout"]) 139 | else: 140 | with allure.step("PUT请求接口"): 141 | allure.attach("请求接口:", str(data["test_name"])) 142 | allure.attach( 143 | "请求地址", 144 | data["http_type"] + 145 | "://" + 146 | host + 147 | address) 148 | allure.attach("请求头", str(header)) 149 | allure.attach("请求参数", str(parameter)) 150 | result = api_method.post( 151 | header=header, 152 | address=data["http_type"] + "://" + host + address, 153 | request_parameter_type=data["parameter_type"], 154 | data=parameter, 155 | timeout=data["timeout"]) 156 | elif data["request_type"].lower() == 'delete': 157 | with allure.step("DELETE请求接口"): 158 | allure.attach("请求接口:", str(data["test_name"])) 159 | allure.attach("请求地址", data["http_type"] + "://" + host + address) 160 | allure.attach("请求头", str(header)) 161 | allure.attach("请求参数", str(parameter)) 162 | logging.info("请求方法: DELETE") 163 | result = api_method.get( 164 | header=header, 165 | address=data["http_type"] + 166 | "://" + 167 | host + 168 | address, 169 | data=parameter, 170 | timeout=data["timeout"]) 171 | else: 172 | result = {"code": False, "data": False} 173 | logging.info("请求接口结果:\n %s" % str(result)) 174 | return result 175 | -------------------------------------------------------------------------------- /unit/choice_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/26 8:50 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : choice_data.py 7 | # @Software: PyCharm 8 | 9 | import random 10 | 11 | 12 | def choice_data(data): 13 | """ 14 | 获取随机整型数据 15 | :param data: 16 | :return: 17 | """ 18 | _list = data.split(",") 19 | num = random.choice(_list) 20 | return num 21 | 22 | 23 | if __name__ == "__main__": 24 | print(choice_data("200, 100, 5")) 25 | -------------------------------------------------------------------------------- /unit/get_time.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/9/26 8:50 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : get_time.py 7 | # @Software: PyCharm 8 | import datetime 9 | import time 10 | 11 | 12 | 13 | def get_time(time_type, layout, unit="0,0,0,0,0"): 14 | """ 15 | 获取时间 16 | :param time_type: 现在的时间now, 其他时间else_time 17 | :param layout: 10timestamp, 13timestamp, else 时间类型 18 | :param unit: 时间单位: [seconds, minutes, hours, days, weeks] 秒,分,时,天,周 19 | :return: 20 | """ 21 | tim = datetime.datetime.now() 22 | if time_type != "now": 23 | lag = unit.split(",") 24 | try: 25 | tim = tim + datetime.timedelta(seconds=int(lag[0]), minutes=int(lag[1]), 26 | hours=int(lag[2]), days=int(lag[3]), weeks=int(lag[4])) 27 | except ValueError: 28 | raise AssertionError("获取时间错误,时间单位%s" % unit) 29 | # 获取10位时间戳 30 | if layout == "10timestamp": 31 | tim = tim.strftime('%Y-%m-%d %H:%M:%S') 32 | tim = int(time.mktime(time.strptime(tim, "%Y-%m-%d %H:%M:%S"))) 33 | return tim 34 | # 获取13位时间戳 35 | elif layout == "13timestamp": 36 | tim = tim.strftime('%Y-%m-%d %H:%M:%S') 37 | tim = int(time.mktime(time.strptime(tim, "%Y-%m-%d %H:%M:%S"))) 38 | tim = int(round(tim * 1000)) 39 | return tim 40 | # 按传入格式获取时间 41 | else: 42 | tim = tim.strftime(layout) 43 | return tim 44 | 45 | 46 | if __name__ == "__main__": 47 | print(get_time("else_time", "%Y-%m-%d %H:%M:%S", "5,5,5,5,5")) 48 | print(get_time("now", "%Y-%m-%d %H:%M:%S", "5,5,5,5,5")) 49 | 50 | -------------------------------------------------------------------------------- /unit/initialize_env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2019/10/20 19:36 4 | # @Author : mrwuzs 5 | # @Site : 6 | # @File : initialize_env.py 7 | # @Software: PyCharm 8 | 9 | import os 10 | from common.log import MyLog as logging 11 | from conf.conf_relevance import ConfRelevance 12 | 13 | 14 | 15 | 16 | BASE_PATH = str(os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) 17 | CONF_PATH = BASE_PATH + "\\conf\\cfg.ini" 18 | ENV_PATH = BASE_PATH + "\\report\\xml\\environment.xml" 19 | 20 | 21 | class Init_Env: 22 | """初始化环境信息,更新xml文件""" 23 | 24 | def __init__(self): 25 | logging.info("初始化关联文件") 26 | self.data = ConfRelevance(CONF_PATH,"env").get_relevance_conf() 27 | 28 | 29 | 30 | 31 | def dict_to_xml(self): 32 | parameter = [] 33 | for k in sorted(self.data.keys()): 34 | xml = [] 35 | v = self.data.get(k) 36 | if k == 'detail' and not v.startswith(''.format(v) 38 | xml.append('