summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhaokun <[email protected]>2023-11-08 13:44:25 +0800
committerzhaokun <[email protected]>2023-11-08 13:44:25 +0800
commit4e683d5703daf29810097b9961b5ce02420202ea (patch)
tree4ad01d46a7417a14a8c8a9045e95d0387cf24388
parent44ed57c3f0b5f83e2836aadeea34003f08867b08 (diff)
updatemain
-rw-r--r--.idea/aoto_selenium.iml14
-rw-r--r--.idea/auto_tsg.iml8
-rw-r--r--.idea/inspectionProfiles/Project_Default.xml14
-rw-r--r--.idea/inspectionProfiles/profiles_settings.xml6
-rw-r--r--.idea/modules.xml8
-rw-r--r--cases/__init__.py0
-rw-r--r--cases/__pycache__/__init__.cpython-38.pycbin0 -> 129 bytes
-rw-r--r--cases/__pycache__/conftest.cpython-38-pytest-7.4.0.pycbin0 -> 2274 bytes
-rw-r--r--cases/__pycache__/conftest.cpython-38.pycbin0 -> 2161 bytes
-rw-r--r--cases/__pycache__/test_1_demo.cpython-38-pytest-7.4.0.pycbin0 -> 1845 bytes
-rw-r--r--cases/conftest.py96
-rw-r--r--cases/ui/__init__.py0
-rw-r--r--cases/ui/__pycache__/__init__.cpython-38.pycbin0 -> 132 bytes
-rw-r--r--cases/ui/fast_test/__init__.py0
-rw-r--r--cases/ui/fast_test/__pycache__/__init__.cpython-38.pycbin0 -> 137 bytes
-rw-r--r--cases/ui/fast_test/__pycache__/test_fast.cpython-38-pytest-7.4.0.pycbin0 -> 5942 bytes
-rw-r--r--cases/ui/fast_test/test_fast.py217
-rw-r--r--cases/ui/profiles/__init__.py0
-rw-r--r--cases/ui/profiles/__pycache__/__init__.cpython-38.pycbin0 -> 141 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_dns_records.cpython-38-pytest-7.4.0.pycbin0 -> 1856 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_hijack_files.cpython-38-pytest-7.4.0.pycbin0 -> 1824 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_response_pages.cpython-38-pytest-7.4.0.pycbin0 -> 1738 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_shaping_profile_records.cpython-38-pytest-7.4.0.pycbin0 -> 2263 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_shaping_profiles.cpython-38-pytest-7.4.0.pycbin0 -> 2263 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_ssl_decryption_keyrings.cpython-38-pytest-7.4.0.pycbin0 -> 2258 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_ssl_decryption_profiles.cpython-38-pytest-7.4.0.pycbin0 -> 2328 bytes
-rw-r--r--cases/ui/profiles/__pycache__/test_traffic_mirroring_profiles.cpython-38-pytest-7.4.0.pycbin0 -> 1932 bytes
-rw-r--r--cases/ui/profiles/test_Dos_detection_profiles.py68
-rw-r--r--cases/ui/profiles/test_dns_records.py60
-rw-r--r--cases/ui/profiles/test_hijack_files.py55
-rw-r--r--cases/ui/profiles/test_response_pages.py53
-rw-r--r--cases/ui/profiles/test_shaping_profiles.py79
-rw-r--r--cases/ui/profiles/test_ssl_decryption_keyrings.py59
-rw-r--r--cases/ui/profiles/test_ssl_decryption_profiles.py67
-rw-r--r--cases/ui/profiles/test_traffic_mirroring_profiles.py60
-rw-r--r--common/__init__.py0
-rw-r--r--common/__pycache__/__init__.cpython-38.pycbin0 -> 130 bytes
-rw-r--r--common/__pycache__/demo_1.cpython-38.pycbin0 -> 1095 bytes
-rw-r--r--common/__pycache__/read_data.cpython-38.pycbin0 -> 776 bytes
-rw-r--r--common/demo_1.py23
-rw-r--r--common/driver_common/__init__.py0
-rw-r--r--common/driver_common/__pycache__/__init__.cpython-38.pycbin0 -> 144 bytes
-rw-r--r--common/driver_common/__pycache__/mywebdriver.cpython-38.pycbin0 -> 1879 bytes
-rw-r--r--common/driver_common/__pycache__/random_name.cpython-38.pycbin0 -> 1699 bytes
-rw-r--r--common/driver_common/__pycache__/screenshot.cpython-38.pycbin0 -> 1564 bytes
-rw-r--r--common/driver_common/mywebdriver.py58
-rw-r--r--common/driver_common/random_name.py48
-rw-r--r--common/driver_common/recovery.py25
-rw-r--r--common/driver_common/screenshot.py39
-rw-r--r--common/read_data.py16
-rw-r--r--common/ui_common/__init__.py0
-rw-r--r--common/ui_common/__pycache__/__init__.cpython-38.pycbin0 -> 140 bytes
-rw-r--r--common/ui_common/login_logout/__init__.py0
-rw-r--r--common/ui_common/login_logout/__pycache__/__init__.cpython-38.pycbin0 -> 153 bytes
-rw-r--r--common/ui_common/login_logout/__pycache__/loginout.cpython-38.pycbin0 -> 1495 bytes
-rw-r--r--common/ui_common/login_logout/loginout.py26
-rw-r--r--common/ui_common/profiles/Dos_detection.py248
-rw-r--r--common/ui_common/profiles/__init__.py0
-rw-r--r--common/ui_common/profiles/__pycache__/__init__.cpython-38.pycbin0 -> 152 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/dns_records.cpython-38.pycbin0 -> 10203 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/hijack_files.cpython-38.pycbin0 -> 8714 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/profiles_public_operations.cpython-38.pycbin0 -> 3817 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/response_pages.cpython-38.pycbin0 -> 5919 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/shaping_profiles.cpython-38.pycbin0 -> 8361 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/ssl_decryption_keyrings.cpython-38.pycbin0 -> 9127 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/ssl_decryption_profiles.cpython-38.pycbin0 -> 10455 bytes
-rw-r--r--common/ui_common/profiles/__pycache__/traffic_mirroring_profiles.cpython-38.pycbin0 -> 7244 bytes
-rw-r--r--common/ui_common/profiles/dns_records.py288
-rw-r--r--common/ui_common/profiles/hijack_files.py224
-rw-r--r--common/ui_common/profiles/profiles_public_operations.py78
-rw-r--r--common/ui_common/profiles/response_pages.py141
-rw-r--r--common/ui_common/profiles/shaping_profiles.py248
-rw-r--r--common/ui_common/profiles/ssl_decryption_keyrings.py219
-rw-r--r--common/ui_common/profiles/ssl_decryption_profiles.py252
-rw-r--r--common/ui_common/profiles/traffic_mirroring_profiles.py195
-rw-r--r--common/ui_read_data/__init__.py0
-rw-r--r--common/ui_read_data/__pycache__/__init__.cpython-38.pycbin0 -> 143 bytes
-rw-r--r--common/ui_read_data/__pycache__/read_data.cpython-38.pycbin0 -> 2424 bytes
-rw-r--r--common/ui_read_data/read_data.py72
-rw-r--r--config/__pycache__/workpath.cpython-38.pycbin0 -> 200 bytes
-rw-r--r--config/ui_conf/__init__.py0
-rw-r--r--config/ui_conf/importfile.ini13
-rw-r--r--config/ui_conf/loginout.ini12
-rw-r--r--config/workpath.py5
-rw-r--r--main.py24
-rw-r--r--page_element/element_position.py278
-rw-r--r--results/screenshot/2023-11-02-19-27-12.pngbin0 -> 110866 bytes
-rw-r--r--results/screenshot/2023-11-03-09-45-41.pngbin0 -> 161181 bytes
-rw-r--r--results/screenshot/2023-11-03-09-47-56.pngbin0 -> 88681 bytes
-rw-r--r--results/screenshot/2023-11-03-09-47-58.pngbin0 -> 183799 bytes
-rw-r--r--results/screenshot/2023-11-03-09-49-25.pngbin0 -> 130221 bytes
-rw-r--r--results/screenshot/2023-11-03-09-49-28.pngbin0 -> 179813 bytes
-rw-r--r--results/screenshot/2023-11-03-11-48-06.pngbin0 -> 88513 bytes
-rw-r--r--results/screenshot/2023-11-03-14-27-31.pngbin0 -> 100446 bytes
-rw-r--r--results/screenshot/2023-11-03-14-47-01.pngbin0 -> 93189 bytes
-rw-r--r--results/screenshot/2023-11-03-18-09-46.pngbin0 -> 137544 bytes
-rw-r--r--results/screenshot/2023-11-03-18-10-48.pngbin0 -> 118024 bytes
-rw-r--r--temp/tess1.py16
-rw-r--r--temp/test4.py124
-rw-r--r--testdata/demo1_data.json15
-rw-r--r--testdata/json_data.json31
-rw-r--r--testdata/ui_data/__init__.py0
-rw-r--r--testdata/ui_data/profiles_data/DoS_detection_profiles.json16
-rw-r--r--testdata/ui_data/profiles_data/__init__.py0
-rw-r--r--testdata/ui_data/profiles_data/dns_records.json184
-rw-r--r--testdata/ui_data/profiles_data/hijack_files.json49
-rw-r--r--testdata/ui_data/profiles_data/insert_scripts.json21
-rw-r--r--testdata/ui_data/profiles_data/response_pages.json17
-rw-r--r--testdata/ui_data/profiles_data/shaping_profiles.json69
-rw-r--r--testdata/ui_data/profiles_data/ssl_decryption_keyrings.json63
-rw-r--r--testdata/ui_data/profiles_data/ssl_decryption_profiles.json64
-rw-r--r--testdata/ui_data/profiles_data/traffic_mirroring_profiles.json44
-rw-r--r--testdata/ui_file/__init__.py0
-rw-r--r--testdata/ui_file/profiles/__init__.py0
-rw-r--r--testdata/ui_file/profiles/hijack_files/__init__.py0
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_apk_1.apkbin0 -> 178037 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_exe_1.exebin0 -> 76664 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_gif_1.gifbin0 -> 103503 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_gif_2.gifbin0 -> 511062 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_html_1.html185
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_jpeg_1.jpegbin0 -> 178037 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_png_1.pngbin0 -> 59948 bytes
-rw-r--r--testdata/ui_file/profiles/hijack_files/test_svg_1.svgbin0 -> 76664 bytes
-rw-r--r--testdata/ui_file/profiles/insert_scripts/__init__.py0
-rw-r--r--testdata/ui_file/profiles/insert_scripts/test_css_1.css27
-rw-r--r--testdata/ui_file/profiles/insert_scripts/test_css_2.css3
-rw-r--r--testdata/ui_file/profiles/insert_scripts/test_js_1.js1
-rw-r--r--testdata/ui_file/profiles/insert_scripts/test_js_2.js1
-rw-r--r--testdata/ui_file/profiles/response_pages/__init__.py0
-rw-r--r--testdata/ui_file/profiles/response_pages/testa.html56
-rw-r--r--testdata/ui_file/profiles/response_pages/testb.html56
-rw-r--r--testdata/ui_file/profiles/response_pages/testc.html56
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/__init__.py0
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_cert_caentitytest.chain.pem93
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_keycaentitytest.key27
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_cert_camiddletest.chain.pem100
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_key_camiddletest.key27
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_cert_catest.cer21
-rw-r--r--testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_key_catest.key27
139 files changed, 4789 insertions, 0 deletions
diff --git a/.idea/aoto_selenium.iml b/.idea/aoto_selenium.iml
new file mode 100644
index 00000000..dfd71bfe
--- /dev/null
+++ b/.idea/aoto_selenium.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+ <component name="NewModuleRootManager">
+ <content url="file://$MODULE_DIR$" />
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+ <component name="PackageRequirementsSettings">
+ <option name="requirementsPath" value="" />
+ </component>
+ <component name="TestRunnerService">
+ <option name="PROJECT_TEST_RUNNER" value="py.test" />
+ </component>
+</module> \ No newline at end of file
diff --git a/.idea/auto_tsg.iml b/.idea/auto_tsg.iml
new file mode 100644
index 00000000..d0876a78
--- /dev/null
+++ b/.idea/auto_tsg.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+ <component name="NewModuleRootManager">
+ <content url="file://$MODULE_DIR$" />
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000..79f1fc39
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,14 @@
+<component name="InspectionProjectProfileManager">
+ <profile version="1.0">
+ <option name="myName" value="Project Default" />
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoredPackages">
+ <value>
+ <list size="1">
+ <item index="0" class="java.lang.String" itemvalue="cryptography" />
+ </list>
+ </value>
+ </option>
+ </inspection_tool>
+ </profile>
+</component> \ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 00000000..105ce2da
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+ <settings>
+ <option name="USE_PROJECT_PROFILE" value="false" />
+ <version value="1.0" />
+ </settings>
+</component> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..5aa62326
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/.idea/aoto_selenium.iml" filepath="$PROJECT_DIR$/.idea/aoto_selenium.iml" />
+ </modules>
+ </component>
+</project> \ No newline at end of file
diff --git a/cases/__init__.py b/cases/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/cases/__init__.py
diff --git a/cases/__pycache__/__init__.cpython-38.pyc b/cases/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..0124b67f
--- /dev/null
+++ b/cases/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/cases/__pycache__/conftest.cpython-38-pytest-7.4.0.pyc b/cases/__pycache__/conftest.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..ec51f6f1
--- /dev/null
+++ b/cases/__pycache__/conftest.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/__pycache__/conftest.cpython-38.pyc b/cases/__pycache__/conftest.cpython-38.pyc
new file mode 100644
index 00000000..60126bc1
--- /dev/null
+++ b/cases/__pycache__/conftest.cpython-38.pyc
Binary files differ
diff --git a/cases/__pycache__/test_1_demo.cpython-38-pytest-7.4.0.pyc b/cases/__pycache__/test_1_demo.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..b0c9ad87
--- /dev/null
+++ b/cases/__pycache__/test_1_demo.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/conftest.py b/cases/conftest.py
new file mode 100644
index 00000000..567aee1d
--- /dev/null
+++ b/cases/conftest.py
@@ -0,0 +1,96 @@
+import time
+import pytest
+from common.ui_common.login_logout.loginout import LogInOut
+import time
+import atexit
+import sys
+import os
+import signal
+import configparser
+from config.workpath import workdir
+from selenium import webdriver
+from common.driver_common.mywebdriver import MyWebDriver
+driver = None #全局变量用户保存webdirver实例
+
+def my_driver():
+ print("\n用例开始时执行。。。")
+ global driver
+ # 初始化,负责远程用户登录
+ loginout_parse = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(workdir, "config", "ui_conf", "loginout.ini")
+ loginout_parse.read(loginout_parse_dir, encoding="utf-8")
+ remote_url = loginout_parse.get("remote_url", "url")
+ chrome_option = webdriver.ChromeOptions()
+ driver = MyWebDriver(
+ command_executor=remote_url,
+ options=chrome_option
+ )
+ #driver.implicitly_wait(2)
+ driver.maximize_window()
+ return driver
+
+def setup():
+ global driver
+ driver = my_driver()
+ loginout = LogInOut(driver)
+ loginout.login()
+
+def teardown():
+ global driver
+ if driver:
+ print("\n用例结束时执行。。。")
+ driver.quit()
+ time.sleep(1)
+
+def demo_fixture():
+ global driver
+ setup()
+ yield driver
+ teardown()
+
+def pytest_collection_modifyitems(items):
+ """
+ 测试用例收集完成时,将收集到的name和nodeid的中文显示在控制台上,中文转换
+ https://www.cnblogs.com/canglongdao/p/13418305.html
+ """
+ for i in items:
+ i.name = i.name.encode("utf-8").decode("unicode_escape")
+ i._nodeid = i.nodeid.encode("utf-8").decode("unicode_escape")
+
+#处理ctrl+c中断
+def handle_interrupt(sinnum, frame):
+ global driver
+ print(driver, "主动中断")
+ if driver:
+ driver.close()
+ exit(1)
+
+#注册 Ctrl+C中断处理函数
+signal.signal(signal.SIGINT, handle_interrupt)
+
+
+"""
+# 自定义插件
+class CtrlCPlugin:
+ def __init__(self):
+ self.interrupted = False
+
+ def pytest_runtest_protocol(self, item, nextitem):
+ if self.interrupted:
+ pytest.skip("Ctrl+C 中断")
+
+ctrl_c_plugin = CtrlCPlugin()
+
+# 注册插件
+def pytest_configure(config):
+ config.pluginmanager.register(ctrl_c_plugin)
+
+# 注册 Ctrl+C 中断处理函数
+def handle_interrupt(signum, frame):
+ ctrl_c_plugin.interrupted = True
+ signal.signal(signal.SIGINT, signal.SIG_DFL) # 恢复默认 Ctrl+C 处理
+
+# 注册 Ctrl+C 中断处理函数
+signal.signal(signal.SIGINT, handle_interrupt)
+""" \ No newline at end of file
diff --git a/cases/ui/__init__.py b/cases/ui/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/cases/ui/__init__.py
diff --git a/cases/ui/__pycache__/__init__.cpython-38.pyc b/cases/ui/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..abb59e52
--- /dev/null
+++ b/cases/ui/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/cases/ui/fast_test/__init__.py b/cases/ui/fast_test/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/cases/ui/fast_test/__init__.py
diff --git a/cases/ui/fast_test/__pycache__/__init__.cpython-38.pyc b/cases/ui/fast_test/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..d1ac4718
--- /dev/null
+++ b/cases/ui/fast_test/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/cases/ui/fast_test/__pycache__/test_fast.cpython-38-pytest-7.4.0.pyc b/cases/ui/fast_test/__pycache__/test_fast.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..b7739ef8
--- /dev/null
+++ b/cases/ui/fast_test/__pycache__/test_fast.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/fast_test/test_fast.py b/cases/ui/fast_test/test_fast.py
new file mode 100644
index 00000000..2522d5b9
--- /dev/null
+++ b/cases/ui/fast_test/test_fast.py
@@ -0,0 +1,217 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.response_pages import ResponsePages
+from common.ui_common.profiles.dns_records import DnsRecords
+from common.ui_common.profiles.shaping_profiles import ShapingProfiles
+from common.ui_common.profiles.traffic_mirroring_profiles import TrafficMirroringProfiles
+from common.ui_common.profiles.ssl_decryption_keyrings import SSLDecryptionKeyrings
+from common.ui_common.profiles.ssl_decryption_profiles import SSLDecryptionProfiles
+from common.ui_common.profiles.hijack_files import HijackFiles
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+
+#data = ReadData()
+"""
+1.快速用例已包含:
+profiles:dns records、shaping profiles
+"""
+
+class TestFast:
+ # response pages 快速测试
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建respose_page文件再修改",
+ "model": "modify",
+ "file": "testa.html->testb.html"
+ }
+ ],
+ ids=["创建respose_page文件再修改"]
+ )
+ def test_responsePages_modify(self, demo_fixture, data):
+ responsePages = ResponsePages(demo_fixture)
+ responsePage_name = responsePages.create(data)
+ responsePage_id = responsePages.query(data, require_assertion=1, Name=responsePage_name)
+ responsePages.modify(data)
+ responsePages.query(data, require_assertion=2, ID=responsePage_id)
+ responsePages.delete()
+
+ # dns records 快速测试
+ @pytest.mark.parametrize(
+ "data", [
+ {
+ "ids": "创建多类型A,再修改为CNAME用例",
+ "model": "modify",
+ "type": "A->CNAME",
+ "values":
+ [
+ "112.12.32.12->test.sdgoc.sdwa.caom.com",
+ "53.23.234.21->",
+ "12.12.33.45->test.sodmao.asdo.com",
+ "->test.sddsg.sdsd.fco.cn"
+ ],
+ "description": "12.12.33.45->test.sodmao.asdo.com"
+ }
+ ],
+ ids=["创建多类型A,再修改为CNAME用例"]
+ )
+ def test_dnsRecords_modify(self, demo_fixture, data): #外部方法调用测试(增、查、改、删)
+ dnsRecords = DnsRecords(demo_fixture)
+ dnsRecord_name = dnsRecords.create(data)
+ dnsRecord_id = dnsRecords.query(data, require_assertion=1, Name=dnsRecord_name)
+ dnsRecords.modify(data)
+ dnsRecords.query(data, require_assertion=2, ID=dnsRecord_id)
+ dnsRecords.delete()
+
+ # trafficMirroringProfiles 快速测试
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建vlanid再修改",
+ "model": "modify",
+ "vlan_id":
+ [
+ "16->7",
+ "18->",
+ "->23",
+ "25->45",
+ "55->55"
+ ]
+ }
+ ],
+ ids=["创建vlanid再修改"]
+ )
+ def test_trafficMirroringProfiles_modify(self, demo_fixture, data):
+ trafficMirroringProfiles = TrafficMirroringProfiles(demo_fixture)
+ trafficMirroringProfiles_name = trafficMirroringProfiles.create(data)
+ trafficMirroringProfiles_id = trafficMirroringProfiles.query(data, require_assertion=1, Name=trafficMirroringProfiles_name)
+ trafficMirroringProfiles.modify(data)
+ trafficMirroringProfiles.query(data, require_assertion=2, ID=trafficMirroringProfiles_id)
+ trafficMirroringProfiles.delete()
+
+ #shaping profiles 快速测试
+ @pytest.mark.parametrize(
+ "data", [
+ {
+ "ids": "创建Fair_Share_bps再修改为Gps带宽",
+ "model": "modify",
+ "type": "Fair Share",
+ "argument": "Max Min Host Fairness",
+ "unit": "bps->Gbps",
+ "incoming": "670->856",
+ "outgoing": "550->543"
+ }
+ ],
+ ids=["创建Fair_Share_bps再修改为Gps带宽"]
+ )
+ def test_shapingProfiles_modify(self, demo_fixture, data): #外部方法调用测试(增、查、改、删)
+ shapingProfiles = ShapingProfiles(demo_fixture)
+ shapingProfile_name = shapingProfiles.create(data)
+ shapingProfile_id = shapingProfiles.query(data, require_assertion=1, Name=shapingProfile_name)
+ shapingProfiles.modify(data) #修改
+ shapingProfiles.query(data, require_assertion=2, ID=shapingProfile_id)
+ shapingProfiles.delete()
+
+ #sslDecryptionKeyrings快速测试
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建root_根证书PKA设置为RSA-2048再修改为中间证书PKA设置为RSA-1024",
+ "model": "modify",
+ "certificate": "test_root_cert_catest.cer->test_mid_cert_camiddletest.chain.pem",
+ "private_key": "PKF-test_root_key_catest.key->PKF-test_mid_key_camiddletest.key",
+ "reissue_expiry_hours": "MSC->C-120",
+ "type": "Root-Certificate->Intermediate-Certificate",
+ "public_key_algorithm": "RSA-2048->RSA-1024",
+ "certificate_revocation_list": "->不修改",
+ "include_root": "on->off"
+ }
+ ],
+ ids=["创建root_根证书PKA设置为RSA-2048再修改为中间证书PKA设置为RSA-1024"]
+ )
+ def test_sslDecryptionKeyrings_modify(self, demo_fixture, data):
+ sslDecryptionKeyrings = SSLDecryptionKeyrings(demo_fixture)
+ sslDecryptionKeyrings_name = sslDecryptionKeyrings.create(data)
+ sslDecryptionKeyrings_id = sslDecryptionKeyrings.query(data, require_assertion=1, Name=sslDecryptionKeyrings_name)
+ sslDecryptionKeyrings.modify(data)
+ sslDecryptionKeyrings.query(data, require_assertion=2, ID=sslDecryptionKeyrings_id)
+ sslDecryptionKeyrings.delete()
+
+ # sslDecryptionProfiles快速测试
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on再修改common_name_off22",
+ "model": "modify",
+ "common_name": "on->off",
+ "issuer": "on-off>",
+ "self_signed": "on->不修改",
+ "expiry_date": "on->不修改",
+ "fail_action": "Pass-through->Fail-close",
+ "ev_certificate": "on->off",
+ "certificate_transparency": "on->不修改",
+ "mutual_authentication": "on->不修改",
+ "protocol_errors": "on->不修改",
+ "certificate_pinning": "on->off",
+ "certificate_not_installed": "on->",
+ "mirror_client_versions": "off->on",
+ "min_client_version": "TLSv1.2->不修改",
+ "max_client_version": "TLSv1.3->不修改",
+ "allow_HTTP2": "off->on"
+ }
+ ],
+ ids=["创建ssl_decryption_profiles_fail_action_on再修改common_name_off22"]
+ )
+ def test_sslDecryptionProfiles_modify(self, demo_fixture, data):
+ sslDecryptionProfiles = SSLDecryptionProfiles(demo_fixture)
+ sslDecryptionProfiles_name = sslDecryptionProfiles.create(data)
+ sslDecryptionProfiles_id = sslDecryptionProfiles.query(data, require_assertion=1, Name=sslDecryptionProfiles_name)
+ sslDecryptionProfiles.modify(data)
+ sslDecryptionProfiles.query(data, require_assertion=2, ID=sslDecryptionProfiles_id)
+ sslDecryptionProfiles.delete()
+
+ # HijackFiles 快速测试
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建gif类型hijack_files数据再修改数据gif数据",
+ "model": "modify",
+ "file": "test_gif_1.gif->test_gif_2.gif",
+ "download_name": "test_gif_1.gif->Mirror Server Response",
+ "file_type": "gif->不修改"
+ }
+ ],
+ ids=["创建gif类型hijack_files数据再修改数据gif数据"]
+ )
+ def test_hijackFiles_modify(self, demo_fixture, data):
+ hijackFiles = HijackFiles(demo_fixture)
+ hijackFiles_name = hijackFiles.create(data)
+ hijackFiles_id = hijackFiles.query(data, require_assertion=1, Name=hijackFiles_name)
+ hijackFiles.modify(data)
+ hijackFiles.query(data, require_assertion=2, ID=hijackFiles_id)
+ hijackFiles.delete()
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_fast.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/__init__.py b/cases/ui/profiles/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/cases/ui/profiles/__init__.py
diff --git a/cases/ui/profiles/__pycache__/__init__.cpython-38.pyc b/cases/ui/profiles/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..c950d3a9
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_dns_records.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_dns_records.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..dcd7460d
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_dns_records.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_hijack_files.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_hijack_files.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..73e33734
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_hijack_files.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_response_pages.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_response_pages.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..9353cd88
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_response_pages.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_shaping_profile_records.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_shaping_profile_records.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..4730eaef
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_shaping_profile_records.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_shaping_profiles.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_shaping_profiles.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..738b3a89
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_shaping_profiles.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_ssl_decryption_keyrings.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_ssl_decryption_keyrings.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..cd532f89
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_ssl_decryption_keyrings.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_ssl_decryption_profiles.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_ssl_decryption_profiles.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..7c8294d5
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_ssl_decryption_profiles.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/__pycache__/test_traffic_mirroring_profiles.cpython-38-pytest-7.4.0.pyc b/cases/ui/profiles/__pycache__/test_traffic_mirroring_profiles.cpython-38-pytest-7.4.0.pyc
new file mode 100644
index 00000000..d1c6904f
--- /dev/null
+++ b/cases/ui/profiles/__pycache__/test_traffic_mirroring_profiles.cpython-38-pytest-7.4.0.pyc
Binary files differ
diff --git a/cases/ui/profiles/test_Dos_detection_profiles.py b/cases/ui/profiles/test_Dos_detection_profiles.py
new file mode 100644
index 00000000..4c84ac62
--- /dev/null
+++ b/cases/ui/profiles/test_Dos_detection_profiles.py
@@ -0,0 +1,68 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.Dos_detection import Dos_detection
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestSSLDecryptionProfiles:
+ @pytest.mark.parametrize("data", data.read_data_profiles("ssl_decryption_profiles.json"), ids=data.generate_id)
+ def test_sslDecryptionProfiles(self, demo_fixture, data):
+ dos_detection = Dos_detection(demo_fixture)
+ dos_detection.Dos_detection_case(data)
+
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on再修改common_name_off22",
+ "model": "modify",
+ "common_name": "on->off",
+ "issuer": "on-off>",
+ "self_signed": "on->不修改",
+ "expiry_date": "on->不修改",
+ "fail_action": "Pass-through->不修改",
+ "ev_certificate": "on->off",
+ "certificate_transparency": "on->不修改",
+ "mutual_authentication": "on->不修改",
+ "protocol_errors": "on->不修改",
+ "certificate_pinning": "on->off",
+ "certificate_not_installed": "on->",
+ "mirror_client_versions": "off->off",
+ "min_client_version": "TLSv1.2->不修改",
+ "max_client_version": "TLSv1.3->不修改",
+ "allow_HTTP2": "off->on"
+ }
+ ],
+ ids=["创建ssl_decryption_profiles_fail_action_on再修改common_name_off22"]
+ )
+ def test_sslDecryptionProfiles_modify(self, demo_fixture, data):
+ sslDecryptionProfiles = SSLDecryptionProfiles(demo_fixture)
+ sslDecryptionProfiles_name = sslDecryptionProfiles.create(data)
+ sslDecryptionProfiles_id = sslDecryptionProfiles.query(data, require_assertion=1, Name=sslDecryptionProfiles_name)
+ sslDecryptionProfiles.modify(data)
+ sslDecryptionProfiles.query(data, require_assertion=2, ID=sslDecryptionProfiles_id)
+ sslDecryptionProfiles.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_ssl_decryption_profiles.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_dns_records.py b/cases/ui/profiles/test_dns_records.py
new file mode 100644
index 00000000..8cc3040b
--- /dev/null
+++ b/cases/ui/profiles/test_dns_records.py
@@ -0,0 +1,60 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.dns_records import DnsRecords
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestDnsRecords:
+ @pytest.mark.parametrize("data", data.read_data_profiles("dns_records.json"), ids=data.generate_id)
+ def test_dnsRecords(self, demo_fixture, data):
+ dnsRecords = DnsRecords(demo_fixture)
+ dnsRecords.dns_records_case(data)
+
+ @pytest.mark.parametrize(
+ "data", [
+ {
+ "ids": "创建多类型A,再修改为CNAME用例",
+ "model": "modify",
+ "type": "A->CNAME",
+ "values":
+ [
+ "112.12.32.12->test.sdgoc.sdwa.caom.com",
+ "53.23.234.21->",
+ "12.12.33.45->test.sodmao.asdo.com",
+ "->test.sddsg.sdsd.fco.cn"
+ ],
+ "description": "12.12.33.45->test.sodmao.asdo.com"
+ }
+ ]
+ )
+ def test_dnsRecords_modify(self, demo_fixture, data): #外部方法调用测试(增、查、改、删)
+ dnsRecords = DnsRecords(demo_fixture)
+ dnsRecord_name = dnsRecords.create(data)
+ dnsRecord_id = dnsRecords.query(data, require_assertion=1, Name=dnsRecord_name)
+ dnsRecords.modify(data)
+ dnsRecords.query(data, require_assertion=2, ID=dnsRecord_id)
+ print(dnsRecord_name)
+ print(dnsRecord_id)
+ dnsRecords.delete()
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_dns_records.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_hijack_files.py b/cases/ui/profiles/test_hijack_files.py
new file mode 100644
index 00000000..d92e7146
--- /dev/null
+++ b/cases/ui/profiles/test_hijack_files.py
@@ -0,0 +1,55 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.hijack_files import HijackFiles
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestHijackFiles:
+ @pytest.mark.parametrize("data", data.read_data_profiles("hijack_files.json"), ids=data.generate_id)
+ def test_hijackFiles(self, demo_fixture, data):
+ hijackFiles = HijackFiles(demo_fixture)
+ hijackFiles.hijackFiles_case(data)
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建gif类型hijack_files数据再修改数据gif数据",
+ "model": "modify",
+ "file": "test_gif_1.gif->test_gif_2.gif",
+ "download_name": "test_gif_1.gif->Mirror Server Response",
+ "file_type": "gif->不修改"
+ }
+ ],
+ ids=["创建gif类型hijack_files数据再修改数据gif数据"]
+ )
+ def test_hijackFiles_modify(self, demo_fixture, data):
+ hijackFiles = HijackFiles(demo_fixture)
+ hijackFiles_name = hijackFiles.create(data)
+ hijackFiles_id = hijackFiles.query(data, require_assertion=1, Name=hijackFiles_name)
+ hijackFiles.modify(data)
+ hijackFiles.query(data, require_assertion=2, ID=hijackFiles_id)
+ hijackFiles.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_hijack_files.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_response_pages.py b/cases/ui/profiles/test_response_pages.py
new file mode 100644
index 00000000..935f3849
--- /dev/null
+++ b/cases/ui/profiles/test_response_pages.py
@@ -0,0 +1,53 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.response_pages import ResponsePages
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestResponsePages:
+ @pytest.mark.parametrize("data", data.read_data_profiles("response_pages.json"), ids=data.generate_id)
+ def test_resposnePages(self, demo_fixture, data):
+ responsePages = ResponsePages(demo_fixture)
+ responsePages.response_page_case(data)
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建respose_page文件再修改",
+ "model": "modify",
+ "file": "testa.html->testb.html"
+ }
+ ]
+ )
+ def test_responsePages_modify(self, demo_fixture, data):
+ responsePages = ResponsePages(demo_fixture)
+ responsePage_name = responsePages.create(data)
+ responsePage_id = responsePages.query(data, require_assertion=1, Name=responsePage_name)
+ responsePages.modify(data)
+ responsePages.query(data, require_assertion=2, ID=responsePage_id)
+ print(responsePage_id, responsePage_name)
+ responsePages.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_response_pages.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_shaping_profiles.py b/cases/ui/profiles/test_shaping_profiles.py
new file mode 100644
index 00000000..08104d9f
--- /dev/null
+++ b/cases/ui/profiles/test_shaping_profiles.py
@@ -0,0 +1,79 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.shaping_profiles import ShapingProfiles
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestShapingProfiles:
+ @pytest.mark.parametrize("data", data.read_data_profiles("shaping_profiles.json"), ids=data.generate_id)
+ def test_shapingProfiles(self, demo_fixture, data):
+ shapingProfiles = ShapingProfiles(demo_fixture)
+ shapingProfiles.shaping_profiles_case(data)
+
+ @pytest.mark.parametrize(
+ "data", [
+ {
+ "ids": "创建Generic_bps用例",
+ "model": "create",
+ "type": "Generic",
+ "argument": "",
+ "unit": "bps->",
+ "incoming": "876->",
+ "outgoing": "543->"
+ }
+ ]
+ )
+ def test_shapingProfiles_create(self, demo_fixture, data): #外部方法调用测试(增、查、删)
+ shapingProfiles = ShapingProfiles(demo_fixture)
+ shapingProfile_name = shapingProfiles.create(data)
+ shapingProfile_id = shapingProfiles.query(data, Name=shapingProfile_name)
+ print(shapingProfile_name)
+ print(shapingProfile_id)
+ shapingProfiles.delete()
+
+ @pytest.mark.parametrize(
+ "data", [
+ {
+ "ids": "创建Fair_Share_bps再修改为Gps带宽",
+ "model": "modify",
+ "type": "Fair Share",
+ "argument": "Max Min Host Fairness",
+ "unit": "bps->Gbps",
+ "incoming": "670->856",
+ "outgoing": "550->543"
+ }
+ ]
+ )
+ def test_shapingProfiles_modify(self, demo_fixture, data): #外部方法调用测试(增、查、改、删)
+ shapingProfiles = ShapingProfiles(demo_fixture)
+ shapingProfile_name = shapingProfiles.create(data)
+ shapingProfile_id = shapingProfiles.query(data, require_assertion=1, Name=shapingProfile_name)
+ shapingProfiles.modify(data) #修改
+ shapingProfiles.query(data, require_assertion=2, ID=shapingProfile_id)
+ print(shapingProfile_name)
+ print(shapingProfile_id)
+ shapingProfiles.delete()
+
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_shaping_profiles.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_ssl_decryption_keyrings.py b/cases/ui/profiles/test_ssl_decryption_keyrings.py
new file mode 100644
index 00000000..f069034d
--- /dev/null
+++ b/cases/ui/profiles/test_ssl_decryption_keyrings.py
@@ -0,0 +1,59 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.ssl_decryption_keyrings import SSLDecryptionKeyrings
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestSSLDecryptionKeyrings:
+ @pytest.mark.parametrize("data", data.read_data_profiles("ssl_decryption_keyrings.json"), ids=data.generate_id)
+ def test_sslDecryptionKeyrings(self, demo_fixture, data):
+ sslDecryptionKeyrings = SSLDecryptionKeyrings(demo_fixture)
+ sslDecryptionKeyrings.sslDecryptionKeyrings_case(data)
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建root_根证书PKA设置为RSA-2048再修改为中间证书PKA设置为RSA-1024",
+ "model": "modify",
+ "certificate": "test_root_cert_catest.cer->test_mid_cert_camiddletest.chain.pem",
+ "private_key": "PKF-test_root_key_catest.key->PKF-test_mid_key_camiddletest.key",
+ "reissue_expiry_hours": "MSC->C-120",
+ "type": "Root-Certificate->Intermediate-Certificate",
+ "public_key_algorithm": "RSA-2048->RSA-1024",
+ "certificate_revocation_list": "->不修改",
+ "include_root": "on->off"
+ }
+ ],
+ ids=["创建root_根证书PKA设置为RSA-2048再修改为中间证书PKA设置为RSA-1024"]
+ )
+ def test_sslDecryptionKeyrings_modify(self, demo_fixture, data):
+ sslDecryptionKeyrings = SSLDecryptionKeyrings(demo_fixture)
+ sslDecryptionKeyrings_name = sslDecryptionKeyrings.create(data)
+ sslDecryptionKeyrings_id = sslDecryptionKeyrings.query(data, require_assertion=1, Name=sslDecryptionKeyrings_name)
+ sslDecryptionKeyrings.modify(data)
+ sslDecryptionKeyrings.query(data, require_assertion=2, ID=sslDecryptionKeyrings_id)
+ sslDecryptionKeyrings.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_ssl_decryption_keyrings.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_ssl_decryption_profiles.py b/cases/ui/profiles/test_ssl_decryption_profiles.py
new file mode 100644
index 00000000..0e50b461
--- /dev/null
+++ b/cases/ui/profiles/test_ssl_decryption_profiles.py
@@ -0,0 +1,67 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.ssl_decryption_profiles import SSLDecryptionProfiles
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestSSLDecryptionProfiles:
+ @pytest.mark.parametrize("data", data.read_data_profiles("ssl_decryption_profiles.json"), ids=data.generate_id)
+ def test_sslDecryptionProfiles(self, demo_fixture, data):
+ sslDecryptionProfiles = SSLDecryptionProfiles(demo_fixture)
+ sslDecryptionProfiles.sslDecryptionProfiles_case(data)
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on再修改common_name_off22",
+ "model": "modify",
+ "common_name": "on->off",
+ "issuer": "on-off>",
+ "self_signed": "on->不修改",
+ "expiry_date": "on->不修改",
+ "fail_action": "Pass-through->不修改",
+ "ev_certificate": "on->off",
+ "certificate_transparency": "on->不修改",
+ "mutual_authentication": "on->不修改",
+ "protocol_errors": "on->不修改",
+ "certificate_pinning": "on->off",
+ "certificate_not_installed": "on->",
+ "mirror_client_versions": "off->off",
+ "min_client_version": "TLSv1.2->不修改",
+ "max_client_version": "TLSv1.3->不修改",
+ "allow_HTTP2": "off->on"
+ }
+ ],
+ ids=["创建ssl_decryption_profiles_fail_action_on再修改common_name_off22"]
+ )
+ def test_sslDecryptionProfiles_modify(self, demo_fixture, data):
+ sslDecryptionProfiles = SSLDecryptionProfiles(demo_fixture)
+ sslDecryptionProfiles_name = sslDecryptionProfiles.create(data)
+ sslDecryptionProfiles_id = sslDecryptionProfiles.query(data, require_assertion=1, Name=sslDecryptionProfiles_name)
+ sslDecryptionProfiles.modify(data)
+ sslDecryptionProfiles.query(data, require_assertion=2, ID=sslDecryptionProfiles_id)
+ sslDecryptionProfiles.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_ssl_decryption_profiles.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/cases/ui/profiles/test_traffic_mirroring_profiles.py b/cases/ui/profiles/test_traffic_mirroring_profiles.py
new file mode 100644
index 00000000..17076a65
--- /dev/null
+++ b/cases/ui/profiles/test_traffic_mirroring_profiles.py
@@ -0,0 +1,60 @@
+# -*- coding: UTF-8 -*-
+import time
+import pytest
+from common.ui_common.profiles.traffic_mirroring_profiles import TrafficMirroringProfiles
+from common.ui_read_data.read_data import ReadData
+from cases.conftest import demo_fixture
+
+data = ReadData()
+
+
+class TestTrafficMirroringProfiles:
+ @pytest.mark.parametrize("data", data.read_data_profiles("traffic_mirroring_profiles.json"), ids=data.generate_id)
+ def test_trafficMirroringProfiles(self, demo_fixture, data):
+ trafficMirroringProfiles = TrafficMirroringProfiles(demo_fixture)
+ trafficMirroringProfiles.traffic_morroring_profiles_case(data)
+
+ @pytest.mark.parametrize(
+ "data",
+ [
+ {
+ "ids": "创建vlanid再修改",
+ "model": "modify",
+ "vlan_id":
+ [
+ "16->7",
+ "18->",
+ "->23",
+ "25->45",
+ "55->55"
+ ]
+ }
+ ]
+ )
+ def test_trafficMirroringProfiles_modify(self, demo_fixture, data):
+ trafficMirroringProfiles = TrafficMirroringProfiles(demo_fixture)
+ trafficMirroringProfiles_name = trafficMirroringProfiles.create(data)
+ trafficMirroringProfiles_id = trafficMirroringProfiles.query(data, require_assertion=1, Name=trafficMirroringProfiles_name)
+ trafficMirroringProfiles.modify(data)
+ trafficMirroringProfiles.query(data, require_assertion=2, ID=trafficMirroringProfiles_id)
+ print(trafficMirroringProfiles_id, trafficMirroringProfiles_name)
+ trafficMirroringProfiles.delete()
+
+
+if __name__ == '__main__':
+ a = time.time()
+ print(111111111111)
+ pytest.main(['-sv', 'test_response_pages.py', '--check-max-tb=60000'])
+
+ b = time.time()
+ c = b - a
+ print("用时:::", c)
+ print(3333333333333)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/common/__init__.py b/common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/__init__.py
diff --git a/common/__pycache__/__init__.cpython-38.pyc b/common/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..13af0213
--- /dev/null
+++ b/common/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/__pycache__/demo_1.cpython-38.pyc b/common/__pycache__/demo_1.cpython-38.pyc
new file mode 100644
index 00000000..b74fe3a6
--- /dev/null
+++ b/common/__pycache__/demo_1.cpython-38.pyc
Binary files differ
diff --git a/common/__pycache__/read_data.cpython-38.pyc b/common/__pycache__/read_data.cpython-38.pyc
new file mode 100644
index 00000000..22ea7626
--- /dev/null
+++ b/common/__pycache__/read_data.cpython-38.pyc
Binary files differ
diff --git a/common/demo_1.py b/common/demo_1.py
new file mode 100644
index 00000000..e5fcd4f7
--- /dev/null
+++ b/common/demo_1.py
@@ -0,0 +1,23 @@
+import pytest
+import requests
+import time
+
+
+def demo1():
+ assert 1 == 11
+
+def demo2(data):
+ print(f"demo2使用数据{data}")
+ assert 2 == 2
+
+class DemoA:
+ def __init__(self):
+ self.n = 1
+
+ def demo3(self, data):
+ print(f"demo3使用数据{data}")
+ assert 3 == 3
+
+ def demo4(self, data):
+ print(f"demo4使用数据{data}")
+ assert 4 == 4 \ No newline at end of file
diff --git a/common/driver_common/__init__.py b/common/driver_common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/driver_common/__init__.py
diff --git a/common/driver_common/__pycache__/__init__.cpython-38.pyc b/common/driver_common/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..38bc323b
--- /dev/null
+++ b/common/driver_common/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/driver_common/__pycache__/mywebdriver.cpython-38.pyc b/common/driver_common/__pycache__/mywebdriver.cpython-38.pyc
new file mode 100644
index 00000000..8e258f8b
--- /dev/null
+++ b/common/driver_common/__pycache__/mywebdriver.cpython-38.pyc
Binary files differ
diff --git a/common/driver_common/__pycache__/random_name.cpython-38.pyc b/common/driver_common/__pycache__/random_name.cpython-38.pyc
new file mode 100644
index 00000000..ce517551
--- /dev/null
+++ b/common/driver_common/__pycache__/random_name.cpython-38.pyc
Binary files differ
diff --git a/common/driver_common/__pycache__/screenshot.cpython-38.pyc b/common/driver_common/__pycache__/screenshot.cpython-38.pyc
new file mode 100644
index 00000000..1c1f63c7
--- /dev/null
+++ b/common/driver_common/__pycache__/screenshot.cpython-38.pyc
Binary files differ
diff --git a/common/driver_common/mywebdriver.py b/common/driver_common/mywebdriver.py
new file mode 100644
index 00000000..cb8dadaf
--- /dev/null
+++ b/common/driver_common/mywebdriver.py
@@ -0,0 +1,58 @@
+import time
+import traceback
+import inspect
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+from typing import Optional
+
+
+class MyWebDriver(webdriver.Remote):
+ def find_element(self, by=By.ID, value: Optional[str] = None,
+ find_before_wait_time=0.3, find_after_wait_time=0.3, wait_timeout=10):
+ if wait_timeout > 60:
+ wait_timeout = 60
+ while wait_timeout > 0:
+ time.sleep(find_before_wait_time)
+ wait_timeout = wait_timeout - (find_before_wait_time if find_before_wait_time > 0 else 2.5)
+ try:
+ self.element = super().find_element(by, value)
+ except:
+ caller_info = inspect.stack()[1]
+ caller_filename = caller_info.filename
+ caller_line_number = caller_info.frame
+ caller_code_context = caller_info.code_context
+ print(caller_filename, caller_line_number, caller_code_context)
+ print(f"查找方法:{by};-->>", f"查找元素:{value}\n")
+ throw_assert = 1
+ assert_info = traceback.format_exc()
+ continue
+ else:
+ time.sleep(find_after_wait_time)
+ throw_assert = 0
+ break #找到则退出循环
+ if throw_assert == 1:
+ print(assert_info)
+ raise
+ return self.element
+
+
+
+if __name__ == '__main__':
+ chrome_option = webdriver.ChromeOptions()
+ driver = MyWebDriver(
+ command_executor="http://192.168.64.34:4444",
+ options=chrome_option
+ )
+ driver.implicitly_wait(5)
+ driver.get("http://192.168.44.72")
+ driver.find_element(By.NAME, "username1").send_keys("zcw3")
+ driver.find_element(By.NAME, "username").send_keys("zcw3")
+ driver.find_element(By.NAME, "username").send_keys("zcw3")
+ driver.find_element(By.NAME, "username").send_keys("zcw3")
+ driver.find_element(By.NAME, "password").send_keys("111111")
+ driver.find_element(By.NAME, "password").send_keys("111111")
+ driver.find_element(By.NAME, "password").send_keys("111111")
+ driver.find_element(By.NAME, "password").send_keys("111111")
+
+ driver.quit()
diff --git a/common/driver_common/random_name.py b/common/driver_common/random_name.py
new file mode 100644
index 00000000..8f5327f0
--- /dev/null
+++ b/common/driver_common/random_name.py
@@ -0,0 +1,48 @@
+import random
+import string
+import time
+import datetime
+
+class RandomName:
+ """
+ 生成随机使用名称
+ """
+ def __init__(self, pro_name="test_uitemp", r_letter_count=8, r_number_count=8):
+ self.pro_name = pro_name
+ self.r_letter_count = r_letter_count
+ self.r_number_count = r_number_count
+
+ def random_name(self):
+ letters = self.random_letter(self.r_letter_count)
+ numbers = self.random_number(self.r_number_count)
+ format_time = self.current_time()
+ r_name = f"{self.pro_name}_{letters}_{numbers}_{format_time}"
+ return r_name
+
+ def random_letter(self, count=8):
+ temp_list = []
+ for i in range(count):
+ temp_list.append(random.choice(string.ascii_letters))
+ r_letter = "".join(temp_list)
+ #print(r_letter)
+ return r_letter
+
+ def random_number(self, count=8):
+ temp_list = []
+ for i in range(count):
+ temp_list.append(random.choice(string.digits))
+ r_number = "".join(temp_list)
+ #print(r_number)
+ return r_number
+
+ def current_time(self):
+ c_time = time.time()
+ formatted_time = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d-%H-%M-%S')
+ return formatted_time
+
+# r = RandomName()
+# c = r.random_name()
+# print(c)
+# print(c)
+# print(c)
+
diff --git a/common/driver_common/recovery.py b/common/driver_common/recovery.py
new file mode 100644
index 00000000..b982faa9
--- /dev/null
+++ b/common/driver_common/recovery.py
@@ -0,0 +1,25 @@
+import configparser
+from config.workpath import *
+import requests
+
+
+class Recovery:
+ """
+ 自动回收异常时,产生的创建对象
+ 从接口来删除对象
+ """
+ def __init__(self):
+ #初始化,负载远程用户登录
+ self.loginout_parse = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(workdir, "config", "ui_conf", "loginout.ini")
+ self.loginout_parse.read(loginout_parse_dir, encoding="utf-8")
+ self.username = self.loginout_parse.get("ui_account_1", "username")
+ self.passwd = self.loginout_parse.get("ui_account_1", "passwd")
+
+ def login_by_interface(self):
+ #todo
+ pass
+
+ def del_profile(self):
+ # todo
+ pass
diff --git a/common/driver_common/screenshot.py b/common/driver_common/screenshot.py
new file mode 100644
index 00000000..84c00968
--- /dev/null
+++ b/common/driver_common/screenshot.py
@@ -0,0 +1,39 @@
+from selenium import webdriver
+import shutil
+import time, datetime
+import os
+import functools
+from config.workpath import workdir
+
+#截图装饰器
+def screenshot_on_failure(func):
+ @functools.wraps(func)
+ def warpper(self, *args, **kwargs):
+ try:
+ return func(self, *args, **kwargs)
+ except:
+ driver = self.driver
+ if driver:
+ formatted_time = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d-%H-%M-%S')
+ file = "{}.png".format(formatted_time)
+ file_path = os.path.join(workdir, "results", "screenshot", file)
+ print(f"截图保存于:{file_path}")
+ driver.save_screenshot(file_path)
+ #删除历史7天前数据
+ try:
+ clear_history(file_path)
+ except:
+ print("删除历史数据失败...")
+ raise
+ return warpper
+
+def clear_history(file_path, retain_time=3600*24*1):
+ time_now = time.time()
+ file_work = os.path.dirname(file_path)
+ data_list = [os.path.join(file_work, i) for i in os.listdir(file_work)]
+ for datapath in data_list:
+ if time_now - os.path.getctime(datapath) > retain_time:
+ try:
+ os.remove(datapath)
+ except:
+ shutil.rmtree(datapath)
diff --git a/common/read_data.py b/common/read_data.py
new file mode 100644
index 00000000..69d6478c
--- /dev/null
+++ b/common/read_data.py
@@ -0,0 +1,16 @@
+import json
+
+class ReadData:
+ def __init__(self):
+ print(__file__)
+
+ @property
+ def read_from_json(self):
+ with open("C:/zcw/aoto_selenium/testdata/demo1_data.json", "r") as f:
+ data = json.load(f)["item"]
+ data = list(data)
+ return data
+
+
+if __name__ == '__main__':
+ ReadData().read_from_json \ No newline at end of file
diff --git a/common/ui_common/__init__.py b/common/ui_common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/ui_common/__init__.py
diff --git a/common/ui_common/__pycache__/__init__.cpython-38.pyc b/common/ui_common/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..3c247a2f
--- /dev/null
+++ b/common/ui_common/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/login_logout/__init__.py b/common/ui_common/login_logout/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/ui_common/login_logout/__init__.py
diff --git a/common/ui_common/login_logout/__pycache__/__init__.cpython-38.pyc b/common/ui_common/login_logout/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..d7ef9377
--- /dev/null
+++ b/common/ui_common/login_logout/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/login_logout/__pycache__/loginout.cpython-38.pyc b/common/ui_common/login_logout/__pycache__/loginout.cpython-38.pyc
new file mode 100644
index 00000000..56aba1be
--- /dev/null
+++ b/common/ui_common/login_logout/__pycache__/loginout.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/login_logout/loginout.py b/common/ui_common/login_logout/loginout.py
new file mode 100644
index 00000000..f09ddcb2
--- /dev/null
+++ b/common/ui_common/login_logout/loginout.py
@@ -0,0 +1,26 @@
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+import configparser
+from config.workpath import *
+from page_element.element_position import *
+
+class LogInOut:
+ def __init__(self, driver: MyWebDriver):
+ self.driver = driver
+ #初始化,负载远程用户登录
+ self.loginout_parse = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(workdir, "config", "ui_conf", "loginout.ini")
+ self.loginout_parse.read(loginout_parse_dir, encoding="utf-8")
+ self.tsglogin_url = self.loginout_parse.get("tsg_url", "login_url")
+
+ def login(self):
+ self.driver.get(self.tsglogin_url)
+ #输入账户和密码
+ self.driver.find_element(By.NAME, loginPage_userName_posName).send_keys(self.loginout_parse.get("ui_account_1", "username"))
+ self.driver.find_element(By.NAME, loginPage_passwd_posName).send_keys(self.loginout_parse.get("ui_account_1", "passwd"))
+ self.driver.find_element(By.ID, loginPage_signIn_posId).click()
+
+ def logout(self):
+ pass
+
+
diff --git a/common/ui_common/profiles/Dos_detection.py b/common/ui_common/profiles/Dos_detection.py
new file mode 100644
index 00000000..ada88436
--- /dev/null
+++ b/common/ui_common/profiles/Dos_detection.py
@@ -0,0 +1,248 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+
+
+class Dos_detection:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def Dos_detection_case(self, data: {}):
+ """
+ 测试用例调用函数,
+ :param demo_fixture: 传入driver
+ :param data: 测试数据。
+
+ :return:
+ """
+ #self.driver = demo_fixture
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content) # 修改后查询
+ self._del() #删除数据
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到shapingProfiles列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_shapingProfiles_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建shapingProfiles
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_shapingProfiles_createButton_posId).click()
+ #在create dns shapingProfiles操作
+ self.driver.find_element(By.ID, shapingProfilePage_input_Name_posId).send_keys(self.random_name) #输入名字
+ #判断点击哪种类型
+ self._select_type(data)
+ self._select_limits(data, model=0)
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ @screenshot_on_failure
+ def _a(self, data: {}):
+ print(__name__)
+ 1 == 1
+ return 444
+
+ @screenshot_on_failure
+ def _select_type(self, data: {}):
+ """
+ 选择type类型点击
+ :param data:
+ :return:
+ """
+ type: str = data["type"].strip().lower()
+ argument: str = data["argument"].strip().lower()
+ if type == "generic":
+ element_type_pos = shapingProfilePage_radioButton_generic_posXpath
+ elif type == "fair share":
+ element_type_pos = shapingProfilePage_radioButton_fairShare_posXpath
+ if argument == "Max Min Host Fairness".lower():
+ element_argument_pos = shapingProfilePage_radioButton_maxMinHostFairness_posXpath
+ else:
+ raise ValueError(f"用例参数argument:{argument}")
+ else:
+ element_type_pos = shapingProfilePage_radioButton_splitBy_posXpath
+ if argument == "Local Host".lower():
+ element_argument_pos = shapingProfilePage_radioButton_localHost_posXpath
+ else:
+ raise ValueError(f"用例参数argument:{argument}")
+ #点击type类型
+ self.driver.find_element(By.XPATH, element_type_pos).click()
+ #判断是否点击Argument
+ if type != "generic":
+ self.driver.find_element(By.XPATH, element_argument_pos).click()
+
+ @screenshot_on_failure
+ def _select_limits(self, data: {}, model=0):
+ """
+ 输入limits
+ :param data:
+ :param model: =0表示创建时调用。-1表示修改时调用
+ :return:
+ """
+ unitItem = data["unit"].strip().split("->")[model]
+ element_dropDown_unitItem = shapingProfilePage_drowDown_unitItem_posXpath.format(replaceName=unitItem)
+ #点击Unit并选择单位
+ self.driver.find_element(By.ID, shapingProfilePage_inputSelect_unit_posId).click()
+ self.driver.find_element(By.XPATH, element_dropDown_unitItem).click()
+ #输入incoming、outgoing
+ input_incoming = data["incoming"].strip().split("->")[model]
+ input_outgoing = data["outgoing"].strip().split("->")[model]
+ self.driver.find_element(By.ID, shapingProfilePage_input_incoming_posId).clear()
+ self.driver.find_element(By.ID, shapingProfilePage_input_incoming_posId).send_keys(input_incoming)
+ self.driver.find_element(By.ID, shapingProfilePage_input_outgoing_posId).clear()
+ self.driver.find_element(By.ID, shapingProfilePage_input_outgoing_posId).send_keys(input_outgoing)
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_shapingProfiles_selectLabel_posId, listPage_profileSearch_shapingProfiles_dropDown_item_posXpath,
+ listPage_profileSearch_shapingProfiles_input_itemContent_posXpath, listPage_profileSearch_shapingProfiles_buttonSearch_posId,
+ listPage_profilTable_shapingProfiles_tableTbody_posXpath, listPage_profilTable_shapingProfiles_tableHeader_posXpath, **kwargs)
+ """
+ #点击search查询框
+ self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_selectLabel_posId).click()
+ #循环输入查询内容
+ for key, value in kwargs.items():
+ dropdown_item_posXpath = listPage_profileSearch_shapingProfiles_dropDown_item_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, dropdown_item_posXpath).click() #点击下拉item
+ if key != "type":
+ input_item_posXpath = listPage_profileSearch_shapingProfiles_input_itemContent_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, input_item_posXpath).send_keys(value.strip()) #输入查询值
+ else:
+ pass
+ # dropdown_typeItem_posXpath = listPage_profileSearch_dnsRecords_dropDown_typeItem_posXpath.format(replaceName=value.split("->")[0])
+ # self.driver.find_element(By.XPATH, dropdown_typeItem_posXpath).click() #点击type的下拉item
+ #点击查询按钮
+ element_search = self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_buttonSearch_posId)
+ self.driver.execute_script("arguments[0].click()", element_search) #强制点击
+ element_tbody = self.driver.find_element(By.XPATH, listPage_profilTable_shapingProfiles_tableTbody_posXpath) #找到所有的行,table的body
+ element_header = self.driver.find_element(By.XPATH, listPage_profilTable_shapingProfiles_tableHeader_posXpath) #查询table的header
+ #获取table header的text、th.class
+ headers = element_header.find_elements(By.XPATH, "th") #table header
+ rows = element_tbody.find_elements(By.XPATH, "tr") #table body
+ map_header_className = {} #表头名称和th.class的映射,为了从表body中取对应列的值{"ID":"33"}
+ for th in headers:
+ header_content = th.text.strip()
+ classNames = th.get_attribute("class").split()
+ for c_name in classNames:
+ if "el-table" in c_name:
+ tableBodyRowClassName = c_name
+ if header_content and tableBodyRowClassName:
+ map_header_className[header_content] = tableBodyRowClassName
+ #从第一行查询的结果中,取出需要断言的值、name、Type、Values
+ first_row = rows[0]
+ """
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Type_class = map_header_className["Type"]
+ first_row_Type_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Type_class}')]//span").text.strip()
+ first_row_IncomingOutgoing_class = map_header_className["Incoming/Outgoing"]
+ first_row_IncomingOutgoing_contents = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_IncomingOutgoing_class}')]//span").text.strip()
+
+ print(first_row_id_content, first_row_Name_content, first_row_Type_content, first_row_IncomingOutgoing_contents)
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].strip(), msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["outgoing"].strip().split("->")[0] == "0": #为0时,直接断言Unlimit
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["outgoing"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["incoming"].strip().split("->")[0] == "0":
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["incoming"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].split("->")[-1], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["outgoing"].strip().split("->")[-1] == "0": #为0时,直接断言Unlimit
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["outgoing"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["incoming"].strip().split("->")[-1] == "0":
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["incoming"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_shapingProfiles_editButton_posId).click()
+ #根据修改数据,重新输入limits
+ self._select_limits(data, model=-1)
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_shapingProfiles_delButton_posId, listPage_dialogTips_shapingProfiles_button_yes_posCss,
+ listPage_dialogTips_shapingProfiles_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del
diff --git a/common/ui_common/profiles/__init__.py b/common/ui_common/profiles/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/ui_common/profiles/__init__.py
diff --git a/common/ui_common/profiles/__pycache__/__init__.cpython-38.pyc b/common/ui_common/profiles/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..12f4a2fb
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/dns_records.cpython-38.pyc b/common/ui_common/profiles/__pycache__/dns_records.cpython-38.pyc
new file mode 100644
index 00000000..5a164705
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/dns_records.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/hijack_files.cpython-38.pyc b/common/ui_common/profiles/__pycache__/hijack_files.cpython-38.pyc
new file mode 100644
index 00000000..687f3e13
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/hijack_files.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/profiles_public_operations.cpython-38.pyc b/common/ui_common/profiles/__pycache__/profiles_public_operations.cpython-38.pyc
new file mode 100644
index 00000000..ae34623c
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/profiles_public_operations.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/response_pages.cpython-38.pyc b/common/ui_common/profiles/__pycache__/response_pages.cpython-38.pyc
new file mode 100644
index 00000000..f8f10cef
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/response_pages.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/shaping_profiles.cpython-38.pyc b/common/ui_common/profiles/__pycache__/shaping_profiles.cpython-38.pyc
new file mode 100644
index 00000000..beae1dcf
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/shaping_profiles.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/ssl_decryption_keyrings.cpython-38.pyc b/common/ui_common/profiles/__pycache__/ssl_decryption_keyrings.cpython-38.pyc
new file mode 100644
index 00000000..11cf401b
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/ssl_decryption_keyrings.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/ssl_decryption_profiles.cpython-38.pyc b/common/ui_common/profiles/__pycache__/ssl_decryption_profiles.cpython-38.pyc
new file mode 100644
index 00000000..e26b49a4
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/ssl_decryption_profiles.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/__pycache__/traffic_mirroring_profiles.cpython-38.pyc b/common/ui_common/profiles/__pycache__/traffic_mirroring_profiles.cpython-38.pyc
new file mode 100644
index 00000000..6a9287a9
--- /dev/null
+++ b/common/ui_common/profiles/__pycache__/traffic_mirroring_profiles.cpython-38.pyc
Binary files differ
diff --git a/common/ui_common/profiles/dns_records.py b/common/ui_common/profiles/dns_records.py
new file mode 100644
index 00000000..f07116c3
--- /dev/null
+++ b/common/ui_common/profiles/dns_records.py
@@ -0,0 +1,288 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+
+
+class DnsRecords:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def dns_records_case(self, data: {}):
+ """
+ 测试用例调用函数,
+ :param demo_fixture: 传入driver
+ :param data: 测试数据。
+ 例如:create.
+ {
+ "model":"create",
+ "type":"A",
+ "values":
+ [
+ "2.2.2.2",
+ "3.3.3.3",
+ "4.4.4.4"
+ ]
+ }
+ 例如:modify."12.12.12.12->34.45.67.54"表示修改前后数据,'->'为前后数据分隔符。在修改中,分隔符前为空表示新增数据。分隔符后为空表示删除数据。其它同理
+ {
+ "ids": "创建多个类型A,再修改为多个类型A用例",
+ "model": "modify",
+ "type": "A->A",
+ "values":
+ [
+ "12.12.12.12->34.45.67.54",
+ "13.13.31.13->",
+ "->65.123.34.56",
+ "14.14.14.41->56.43.46.64",
+ "->165.123.134.56"
+ ],
+ "description": "test-description->tesst modify desc"
+ }
+ :return:
+ """
+ self._create(data) #创建
+ self._search(data, require_assertion=1, Name=self.random_name) #创建后查询
+ self._modify(data)
+ self._search(data, require_assertion=2, ID=self.first_row_ID_content) # 修改后查询
+ self._del() #删除数据
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到dnsRecords列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_dnsRecords_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #goto dnsRecords列表页
+ self._goto_subProfilePage() #跳转页面
+ #创建dns record
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_dnsRecords_createButton_posId).click()
+ #在create dns record profile操作
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_input_Name_posId).send_keys(self.random_name) #输入名字
+ #判断点击哪种类型
+ self._select_type(data, model=0)
+ #创建time操作
+ self._ceate_item(data, model=0)
+ #输入description内容
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_textArea_Description_posId).send_keys(data["description"].split("->")[0])
+ self.driver.find_element(By.CSS_SELECTOR, dnsRecordsProfilePage_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, dnsRecordsProfilePage_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ def _select_type(self, data, model=0):
+ """
+ 根据model参数,选择点击那种类型,0为创建函数使用,-1为编辑修改函数使用
+ :param data:
+ :param model:
+ :return:
+ """
+ type: str = data["type"].split("->")[model] #因为modify时,有->表示
+ type = type.strip().lower()
+ if type == "a":
+ type_posId = dnsRecordsProfilePage_radioButton_typeA_posId
+ elif type == "aaaa":
+ type_posId = dnsRecordsProfilePage_radioButton_typeAAAA_posId
+ else:
+ type_posId = dnsRecordsProfilePage_radioButton_typeCNAME_posId
+ self.driver.find_element(By.ID, type_posId).click()
+
+ def _ceate_item(self, data, model=0):
+ """
+ 根据参数,选择创建item的方式,0为创建函数使用。-1为编辑修改函数使用且当type类型和创建时不一样。
+ :param data:
+ :param model:
+ :return:
+ """
+ items: list = data["values"]
+ flags = 0 #当一个非空数据时,不点击添加按钮
+ for i in range(len(items)):
+ if items[i].split("->")[model] == "": #modify数据中->左侧为空(创建侧)
+ continue
+ #判断是否需要点击添加按钮
+ if items[i].split("->")[model] != "":
+ flags += 1 #第一个非空标志
+ if flags == 1: #遇到第一个分空数据,不用点击
+ pass
+ else: #第二个后续的非空数据,点击添加
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_button_addItem_posId).click()
+ #添加item时,text()=空,xpath可以定位到
+ if "replaceName" in dnsRecordsProfilePage_input_inputItemName_posXpath:
+ item_input_posCss = dnsRecordsProfilePage_input_inputItemName_posXpath.replace("replaceName", "")
+ else:
+ raise ValueError(f"replaceName not found in {dnsRecordsProfilePage_input_inputItemName_posXpath}")
+ if "replaceName" in dnsRecordsProfilePage_button_saveItemByName_posXpath:
+ item_save_posCss = dnsRecordsProfilePage_button_saveItemByName_posXpath.replace("replaceName", items[i].split("->")[model]) #->修改中会此表标识
+ else:
+ raise ValueError(f"replaceName not found in {dnsRecordsProfilePage_button_saveItemByName_posXpath}")
+ #输出item、保存、添加下一个
+ self.driver.find_element(By.XPATH, item_input_posCss).send_keys(items[i].split("->")[model])
+ self.driver.find_element(By.XPATH, item_save_posCss).click()
+
+ def _modify_item(self, data):
+ """
+ 修改的item数据,type类型前后一样
+ :param data:
+ :return:
+ """
+ items: list = data["values"]
+ for i in range(len(items)):
+ if items[i].split("->")[-1] == "": #modify数据中->右侧为空(删除此数据)
+ element_item_del = dnsRecordsProfilePage_button_delItemByName_posXpath.replace("replaceName", items[i].split("->")[0])
+ self.driver.find_element(By.XPATH, element_item_del).click()
+ continue
+ if items[i].split("->")[0] == "": #modify数据中->做侧为空(创建的数据为空,直接添加item)
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_button_addItem_posId).click() #点击添加按钮
+ # 添加item时,text()=空,xpath可以定位到
+ item_input_posCss = dnsRecordsProfilePage_input_inputItemName_posXpath.replace("replaceName", "")
+ item_save_posCss = dnsRecordsProfilePage_button_saveItemByName_posXpath.replace("replaceName", items[i].split("->")[-1]) # ->修改中会此表标识
+ # 输入item,保存
+ self.driver.find_element(By.XPATH, item_input_posCss).send_keys(items[i].split("->")[-1])
+ self.driver.find_element(By.XPATH, item_save_posCss).click()
+ continue
+ #直接编辑item项内容,在原有的item中编辑值
+ item_edit_posCss = dnsRecordsProfilePage_button_editItemByName_posXpath.replace("replaceName", items[i].split("->")[0])
+ item_input_posCss = dnsRecordsProfilePage_input_inputItemName_posXpath.replace("replaceName", items[i].split("->")[0])
+ self.driver.find_element(By.XPATH, item_edit_posCss).click()
+ self.driver.find_element(By.XPATH, item_input_posCss).clear()
+ self.driver.find_element(By.XPATH, dnsRecordsProfilePage_input_inputItemName_posXpath.replace("replaceName", "")).send_keys(items[i].split("->")[-1])
+ self.driver.find_element(By.XPATH, dnsRecordsProfilePage_button_saveItemByName_posXpath.replace("replaceName", items[i].split("->")[-1])).click()
+
+ @screenshot_on_failure
+ def _search(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,Type=None("A")
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_dnsRecords_selectLabel_posId, listPage_profileSearch_dnsRecords_dropDown_item_posXpath,
+ listPage_profileSearch_dnsRecords_input_itemContent_posXpath, listPage_profileSearch_dnsRecords_buttonSearch_posId,
+ listPage_profilTable_dnsRecords_tableTbody_posXpath, listPage_profilTable_dnsRecords_tableHeader_posXpath,
+ listPage_profileSearch_subProfiles_dropDown_typeItem_posXpath=listPage_profileSearch_dnsRecords_dropDown_typeItem_posXpath, **kwargs)
+ """
+ #点击search查询框
+ self.driver.find_element(By.ID, listPage_profileSearch_dnsRecords_selectLabel_posId).click()
+ #循环输入查询内容
+ for key, value in kwargs.items():
+ dropdown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, dropdown_item_posXpath).click() #点击下拉item
+ if key != "type":
+ input_item_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, input_item_posXpath).send_keys(value.split("->")[0]) #输入查询值
+ else:
+ dropdown_typeItem_posXpath = listPage_profileSearch_dnsRecords_dropDown_typeItem_posXpath.format(replaceName=value.split("->")[0])
+ self.driver.find_element(By.XPATH, dropdown_typeItem_posXpath).click() #点击type的下拉item
+ #点击查询按钮
+ element_search = self.driver.find_element(By.ID, listPage_profileSearch_dnsRecords_buttonSearch_posId)
+ self.driver.execute_script("arguments[0].click()", element_search) #强制点击
+ element_tbody = self.driver.find_element(By.XPATH, listPage_profilTable_dnsRecords_tableTbody_posXpath) #找到所有的行,table的body
+ element_header = self.driver.find_element(By.XPATH, listPage_profilTable_dnsRecords_tableHeader_posXpath) #查询table的header
+ #获取table header的text、th.class
+ headers = element_header.find_elements(By.XPATH, "th") #table header
+ rows = element_tbody.find_elements(By.XPATH, "tr") #table body
+ map_header_className = {} #表头名称和th.class的映射,为了从表body中去对应列的值{"ID":"33"}
+ for th in headers:
+ header_content = th.text.strip()
+ classNames = th.get_attribute("class").split()
+ for c_name in classNames:
+ if "el-table" in c_name:
+ tableBodyRowClassName = c_name
+ if header_content and tableBodyRowClassName:
+ map_header_className[header_content] = tableBodyRowClassName
+ #从第一行查询的结果中,取出需要断言的值、name、Type、Values
+ first_row = rows[0]
+ """
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Type_class = map_header_className["Type"]
+ first_row_Type_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Type_class}')]//span").text.strip()
+ first_row_Values_class = map_header_className["Values"]
+ first_row_Values_contents = first_row.find_elements(By.XPATH, f"//td[contains(@class, '{first_row_Values_class}')]//span//span")
+ values_list = []
+ for value in first_row_Values_contents:
+ values_list.append(value.text.strip())
+ print(first_row_id_content, first_row_Name_content, first_row_Type_content, values_list)
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ create_values_list = [i.split("->")[0] for i in data["values"] if i.split("->")[0] != ""] # 兼容modify中->的标识值
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].split("->")[0], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ for i in range(len(values_list)):
+ pytest_check.is_in(values_list[i], create_values_list, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ create_values_list = [i.split("->")[-1] for i in data["values"] if i.split("->")[-1] != ""] # modify中修改的数据->的右侧
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].split("->")[-1], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ for i in range(len(values_list)):
+ pytest_check.is_in(values_list[i], create_values_list, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_dnsRecords_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_dnsRecords_editButton_posId).click()
+ #根据修改数据,判断type类型
+ self._select_type(data, model=-1)
+ if data["type"].split("->")[0].lower() != data["type"].split("->")[1].lower(): #创建和修改参数的type类型不一致
+ self._ceate_item(data, model=-1)
+ else:
+ self._modify_item(data)
+ #修改description内容
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_textArea_Description_posId).clear()
+ self.driver.find_element(By.ID, dnsRecordsProfilePage_textArea_Description_posId).send_keys(data["description"].split("->")[-1])
+ self.driver.find_element(By.CSS_SELECTOR, dnsRecordsProfilePage_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, dnsRecordsProfilePage_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, dnsRecordsProfilePage_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_dnsRecords_delButton_posId, listPage_dialogTips_dnsRecords_button_yes_posCss,
+ listPage_dialogTips_dnsRecords_button_no_posCss)
+
+ create = _create
+ query = _search
+ modify = _modify
+ delete = _del
diff --git a/common/ui_common/profiles/hijack_files.py b/common/ui_common/profiles/hijack_files.py
new file mode 100644
index 00000000..82a031c5
--- /dev/null
+++ b/common/ui_common/profiles/hijack_files.py
@@ -0,0 +1,224 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+import configparser
+import os
+
+
+class HijackFiles:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def hijackFiles_case(self, data: {}):
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content)
+ self._del()
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到ssl_decryption_keyrings列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_hijackFiles_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_hijackFiles_createButton_posId).click()
+ #在打开页面操作:输入name
+ self.driver.find_element(By.ID, hijackFiles_input_Name_posId).send_keys(self.random_name)
+ #页面其它选项操作
+ self._operate_page(data, operation_type="create")
+ #点击OK
+ self.driver.find_element(By.CSS_SELECTOR, hijackFiles_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, hijackFiles_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ def _operate_page(self, data: {}, operation_type="create"):
+ """
+ 除name的其它选项操作,共创建、修改逻辑调用
+ :param data:
+ :param operation_type: create modify。创建 修改时调用
+ :return:
+ """
+ if operation_type == "create":
+ data_index = 0 #新增数据索引
+ else:
+ data_index = -1 #编辑数据索引
+ no_modify = "不修改"
+ #解析输入data数据的数据
+ #File文件上传操作
+ file = self._get_value_from_data(data, key="file", data_index=data_index) #解析file文件名称
+ if file != no_modify: #判断修改时不修改时跳过操作。
+ file_abspath = self._abs_path(file)
+ #上传文件
+ self.driver.find_element(By.XPATH, hijackFiles_input_fileUpLoad_posXpath).send_keys(file_abspath)
+ #download name 下载文件名称操作
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="download_name", element_position=hijackFiles_switch_downLoadName_posXpath)
+ #file type 文件类型操作
+ file_type = self._get_value_from_data(data, key="file_type", data_index=data_index)
+ if file_type != no_modify: #修改时不用修改数据直接跳过
+ #点击type添加按钮
+ self.driver.find_element(By.XPATH, hijackFiles_button_fileType_posXpath).click()
+ element_type_replace_name = {'gif': 'image/gif', 'jpeg': 'image/jpeg', 'png': 'image/png', 'svg+xml': 'image/svg+xml',
+ 'exe': 'application/x-msdos-program', 'apk': 'application/vnd.android.package-archive', 'html': 'text/html'}
+ if file_type not in element_type_replace_name.keys():
+ raise f"文件类型错误。用例数据类型为:{file_type}, 可选择文件类型为:{list(element_type_replace_name.keys())}"
+ element_tablist_type = self.driver.find_element(By.XPATH, hijackFiles_tablist_fileType_posXpath.format(replaceName=element_type_replace_name[file_type]))
+ self.driver.execute_script("arguments[0].click()", element_tablist_type) # 强制点击
+
+ def _abs_path(self, file_name):
+ # 以下是要读取数据的名称
+ conf = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(self.workdir, "config", "ui_conf", "importfile.ini")
+ conf.read(loginout_parse_dir, encoding="utf-8")
+ testdata = conf.get("profiles", "testdata")
+ ui_file = conf.get("profiles", "ui_file")
+ profiles = conf.get("profiles", "profiles")
+ hijack_files = conf.get("profiles", "hijack_files")
+ import_file_abs = os.path.join(self.workdir, testdata, ui_file, profiles, hijack_files, file_name)
+ import_file_abs = os.path.abspath(import_file_abs)
+ return import_file_abs
+
+ def _get_value_from_data(self, data: {}, key="", data_index=0):
+ """
+ 从data数据中,根据key提取值
+ :param data:
+ :param key:
+ :param data_index: 0 -1
+ :return:
+ """
+ try:
+ switch_value: str = data[key].split("->")[data_index].strip().lower() #用例数据
+ except Exception as e:
+ print(e)
+ return switch_value
+
+ def _operate_switch(self, data: {}, data_index=0, no_modify="不修改", switch_name="", element_position=""):
+ """
+ 页面中,开关状态操作,。
+ :param data:
+ :param data_index: 0 -1来自上层
+ :param no_modify:"不修改" 来自上次调用
+ :param operation_type: create modify两个状态,
+ :param switch_name: 数据中开关名称
+ :param elementPosition: 开关的定位
+ :return:
+ """
+ #解析输入data数据的数据
+ switch_value: str = self._get_value_from_data(data, key=switch_name, data_index=data_index) #提取数据 Mirror Server Response
+ if switch_value != no_modify: #编辑时,有不修改则不用执行
+ #先获取当前页面中开关状态 include_root_current_class : class="el-switch is-checked" 有is-checked当前状态为开,没有is-chedked当前状态为关
+ swith_current_class = self.driver.find_element(By.XPATH, element_position).get_attribute("class")
+ if ("mirror" in switch_value) and ("server" in switch_value) and ("response" in switch_value): #数据中为Mirror Server Response,使用默认名称,不修改
+ if "is-checked" in swith_current_class: #页面当前为开,不用点击开关
+ pass
+ else: #页面当前为关,需要点击开关
+ self.driver.find_element(By.XPATH, f"{element_position}/span[2]").click()
+ else: ##数据中为其它名称,则需要修改默认名称
+ if "is-checked" in swith_current_class: #页面当前为开,需要先关闭开关,在输入值
+ self.driver.find_element(By.XPATH, f"{element_position}/span[2]").click()
+ #输入修改名称值
+ self.driver.find_element(By.XPATH, hijackFiles_input_downLoadName_posXpath).clear()
+ self.driver.find_element(By.XPATH, hijackFiles_input_downLoadName_posXpath).send_keys(switch_value)
+
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_hijackFiles_selectLabel_posId, listPage_profileSearch_hijackFiles_dropDown_item_posXpath,
+ listPage_profileSearch_hijackFiles_input_itemContent_posXpath, listPage_profileSearch_hijackFiles_buttonSearch_posId,
+ listPage_profilTable_hijackFiles_tableTbody_posXpath, listPage_profilTable_hijackFiles_tableHeader_posXpath, **kwargs)
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ #print(map_header_className)
+ # 需要提取ID Name、Type 信息
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Type_class = map_header_className["Type"]
+ first_row_Type_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Type_class}')]//span").text
+
+ print(first_row_id_content, first_row_Name_content, first_row_Type_content)
+ element_type_replace_name = {'gif': 'image/gif', 'jpeg': 'image/jpeg', 'png': 'image/png', 'svg+xml': 'image/svg+xml',
+ 'exe': 'application/x-msdos-program', 'apk': 'application/vnd.android.package-archive', 'html': 'text/html'}
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ file_type = self._get_value_from_data(data, key="file_type", data_index=0)
+ pytest_check.equal(first_row_Type_content, element_type_replace_name[file_type], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ file_type = self._get_value_from_data(data, key="file_type", data_index=-1)
+ if file_type != "不修改":
+ pytest_check.equal(first_row_Type_content, element_type_replace_name[file_type], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_hijackFiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_hijackFiles_editButton_posId).click()
+ #解析修改数据
+ self._operate_page(data, operation_type="edit")
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, hijackFiles_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, hijackFiles_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, hijackFiles_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_hijackFiles_delButton_posId, listPage_dialogTips_hijackFiles_button_yes_posCss,
+ listPage_dialogTips_hijackFiles_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del \ No newline at end of file
diff --git a/common/ui_common/profiles/profiles_public_operations.py b/common/ui_common/profiles/profiles_public_operations.py
new file mode 100644
index 00000000..914f418d
--- /dev/null
+++ b/common/ui_common/profiles/profiles_public_operations.py
@@ -0,0 +1,78 @@
+import time
+
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+import random
+
+
+class ProfilesPublicOperations:
+ def __init__(self, driver):
+ self.driver = driver
+
+ def query(self, mainPage_profileSearch_selectLabel_posId, listPage_profileSearch_subProfiles_dropDown_item_posXpath,
+ listPage_profileSearch_subProfiles_input_itemContent_posXpath, mainPage_profileSearch_buttonSearch_posId,
+ listPage_profilTable_subProfiles_tableTbody_posXpath, listPage_profilTable_subProfiles_tableHeader_posXpath,
+ listPage_profileSearch_subProfiles_dropDown_typeItem_posXpath="", **kwargs):
+ """
+ profiles模块中从点击查询到查询到结果使用方法,并返回第一行数据和表头、class的字典
+ :param mainPage_profileSearch_selectLabel_posId: 查询框id
+ :param listPage_profileSearch_subProfiles_dropDown_item_posXpath: 下拉列表item的xpath
+ :param listPage_profileSearch_subProfiles_input_itemContent_posXpath: 选中item后,输入input的xpath
+ :param mainPage_profileSearch_buttonSearch_posId: 查询按钮id
+ :param listPage_profilTable_subProfiles_tableTbody_posXpath: 列表页body的部分xpath
+ :param listPage_profilTable_subProfiles_tableHeader_posXpath: 列表页header的部分xpath
+ :param listPage_profileSearch_subProfiles_dropDown_typeItem_posXpath: 如果有下拉列表item的枚举选项定位,需要增补
+ :param kwargs: 需要查询的内容,来自调用函数
+ :return: [first_row, map_header_className]
+ """
+ #点击search查询框
+ self.driver.find_element(By.ID, mainPage_profileSearch_selectLabel_posId).click()
+ #循环输入查询内容
+ for key, value in kwargs.items():
+ dropdown_item_posXpath = listPage_profileSearch_subProfiles_dropDown_item_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, dropdown_item_posXpath).click() #点击下拉item
+ if key != "type":
+ input_item_posXpath = listPage_profileSearch_subProfiles_input_itemContent_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, input_item_posXpath).send_keys(value.strip()) #输入查询值
+ else:
+ dropdown_typeItem_posXpath = listPage_profileSearch_subProfiles_dropDown_typeItem_posXpath.format(replaceName=value.split("->")[0])
+ self.driver.find_element(By.XPATH, dropdown_typeItem_posXpath).click() #点击type的下拉item
+ #点击查询按钮
+ element_search = self.driver.find_element(By.ID, mainPage_profileSearch_buttonSearch_posId)
+ self.driver.execute_script("arguments[0].click()", element_search) #强制点击
+ element_tbody = self.driver.find_element(By.XPATH, listPage_profilTable_subProfiles_tableTbody_posXpath) #找到所有的行,table的body
+ element_header = self.driver.find_element(By.XPATH, listPage_profilTable_subProfiles_tableHeader_posXpath) #查询table的header
+ #获取table header的text、th.class
+ headers = element_header.find_elements(By.XPATH, "th") #table header
+ rows = element_tbody.find_elements(By.XPATH, "tr") #table body
+ map_header_className = {} #表头名称和th.class的映射,为了从表body中取对应列的值{"ID":"33"}
+ for th in headers:
+ header_content = th.text.strip()
+ classNames = th.get_attribute("class").split()
+ for c_name in classNames:
+ if "el-table" in c_name:
+ tableBodyRowClassName = c_name
+ if header_content and tableBodyRowClassName:
+ map_header_className[header_content] = tableBodyRowClassName
+ #从第一行查询的结果中,取出需要断言的值、name
+ first_row = rows[0]
+ return [first_row, map_header_className]
+
+ def delete(self, listPage_profile_subProfiles_delButton_posId, listPage_dialogTips_subProfiles_button_yes_posCss,
+ listPage_dialogTips_subProfiles_button_no_posCss):
+ """
+ 直接删除函数,
+ :param listPage_profile_subProfiles_delButton_posId: 删除按钮id
+ :param listPage_dialogTips_subProfiles_button_yes_posCss: 提示删除框中yes定位css
+ :param listPage_dialogTips_subProfiles_button_no_posCss: 提示删除框中no定位css
+ :return:
+ """
+ self.driver.find_element(By.ID, listPage_profile_subProfiles_delButton_posId).click() #点击删除按钮
+ random_yes_or_no = random.randint(0, 1)
+ if random_yes_or_no == 0: #点击yes,删除
+ self.driver.find_element(By.CSS_SELECTOR, listPage_dialogTips_subProfiles_button_yes_posCss).click() #直接删除
+ else:
+ self.driver.find_element(By.CSS_SELECTOR, listPage_dialogTips_subProfiles_button_no_posCss).click() #先取消,再删除
+ self.driver.find_element(By.ID, listPage_profile_subProfiles_delButton_posId).click() # 点击删除按钮
+ self.driver.find_element(By.CSS_SELECTOR, listPage_dialogTips_subProfiles_button_yes_posCss).click()
+ time.sleep(0.5) \ No newline at end of file
diff --git a/common/ui_common/profiles/response_pages.py b/common/ui_common/profiles/response_pages.py
new file mode 100644
index 00000000..2492def9
--- /dev/null
+++ b/common/ui_common/profiles/response_pages.py
@@ -0,0 +1,141 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+import configparser
+import os
+
+
+class ResponsePages:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def response_page_case(self, data: {}):
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content)
+ self._del()
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到responsePages列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_responsePages_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建responsePages
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_responsePages_createButton_posId).click()
+ #在create resposne page页面操作
+ self.driver.find_element(By.ID, responsePage_input_Name_posId).send_keys(self.random_name)
+ #上传文件
+ create_file_ = data["file"].split("->")[0] #提取上传文件绝对路径
+ create_file_abs = self._abs_path(create_file_)
+ self.driver.find_element(By.XPATH, responsePage_input_file_posXpath).send_keys(create_file_abs)
+ #点击OK
+ self.driver.find_element(By.CSS_SELECTOR, responsePage_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, responsePage_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ def _abs_path(self, file_name):
+ # 以下是要读取数据的名称
+ conf = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(self.workdir, "config", "ui_conf", "importfile.ini")
+ conf.read(loginout_parse_dir, encoding="utf-8")
+ testdata = conf.get("profiles", "testdata")
+ ui_file = conf.get("profiles", "ui_file")
+ profiles = conf.get("profiles", "profiles")
+ response_pages = conf.get("profiles", "response_pages")
+ import_file_abs = os.path.join(self.workdir, testdata, ui_file, profiles, response_pages, file_name)
+ import_file_abs = os.path.abspath(import_file_abs)
+ return import_file_abs
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_responsePages_selectLabel_posId, listPage_profileSearch_responsePages_dropDown_item_posXpath,
+ listPage_profileSearch_responsePages_input_itemContent_posXpath, listPage_profileSearch_responsePages_buttonSearch_posId,
+ listPage_profilTable_responsePages_tableTbody_posXpath, listPage_profilTable_responsePages_tableHeader_posXpath, **kwargs)
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ print(first_row_id_content, first_row_Name_content)
+ #不同操作后的断言,创建后、修改后、无断言
+
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_responsePages_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_responsePages_editButton_posId).click()
+ #根据修改数据,修改上次文件
+ modify_file = data["file"].split("->")[-1] #提取上传文件绝对路径
+ modify_file_abs = self._abs_path(modify_file)
+ self.driver.find_element(By.XPATH, responsePage_input_file_posXpath).send_keys(modify_file_abs)
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, responsePage_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, responsePage_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, responsePage_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_responsePages_delButton_posId, listPage_dialogTips_responsePages_button_yes_posCss,
+ listPage_dialogTips_responsePages_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del \ No newline at end of file
diff --git a/common/ui_common/profiles/shaping_profiles.py b/common/ui_common/profiles/shaping_profiles.py
new file mode 100644
index 00000000..56a4d055
--- /dev/null
+++ b/common/ui_common/profiles/shaping_profiles.py
@@ -0,0 +1,248 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+
+
+class ShapingProfiles:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def shaping_profiles_case(self, data: {}):
+ """
+ 测试用例调用函数,
+ :param demo_fixture: 传入driver
+ :param data: 测试数据。
+
+ :return:
+ """
+ #self.driver = demo_fixture
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content) # 修改后查询
+ self._del() #删除数据
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到shapingProfiles列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_shapingProfiles_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建shapingProfiles
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_shapingProfiles_createButton_posId).click()
+ #在create dns shapingProfiles操作
+ self.driver.find_element(By.ID, shapingProfilePage_input_Name_posId).send_keys(self.random_name) #输入名字
+ #判断点击哪种类型
+ self._select_type(data)
+ self._select_limits(data, model=0)
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ @screenshot_on_failure
+ def _a(self, data: {}):
+ print(__name__)
+ 1 == 1
+ return 444
+
+ @screenshot_on_failure
+ def _select_type(self, data: {}):
+ """
+ 选择type类型点击
+ :param data:
+ :return:
+ """
+ type: str = data["type"].strip().lower()
+ argument: str = data["argument"].strip().lower()
+ if type == "generic":
+ element_type_pos = shapingProfilePage_radioButton_generic_posXpath
+ elif type == "fair share":
+ element_type_pos = shapingProfilePage_radioButton_fairShare_posXpath
+ if argument == "Max Min Host Fairness".lower():
+ element_argument_pos = shapingProfilePage_radioButton_maxMinHostFairness_posXpath
+ else:
+ raise ValueError(f"用例参数argument:{argument}")
+ else:
+ element_type_pos = shapingProfilePage_radioButton_splitBy_posXpath
+ if argument == "Local Host".lower():
+ element_argument_pos = shapingProfilePage_radioButton_localHost_posXpath
+ else:
+ raise ValueError(f"用例参数argument:{argument}")
+ #点击type类型
+ self.driver.find_element(By.XPATH, element_type_pos).click()
+ #判断是否点击Argument
+ if type != "generic":
+ self.driver.find_element(By.XPATH, element_argument_pos).click()
+
+ @screenshot_on_failure
+ def _select_limits(self, data: {}, model=0):
+ """
+ 输入limits
+ :param data:
+ :param model: =0表示创建时调用。-1表示修改时调用
+ :return:
+ """
+ unitItem = data["unit"].strip().split("->")[model]
+ element_dropDown_unitItem = shapingProfilePage_drowDown_unitItem_posXpath.format(replaceName=unitItem)
+ #点击Unit并选择单位
+ self.driver.find_element(By.ID, shapingProfilePage_inputSelect_unit_posId).click()
+ self.driver.find_element(By.XPATH, element_dropDown_unitItem).click()
+ #输入incoming、outgoing
+ input_incoming = data["incoming"].strip().split("->")[model]
+ input_outgoing = data["outgoing"].strip().split("->")[model]
+ self.driver.find_element(By.ID, shapingProfilePage_input_incoming_posId).clear()
+ self.driver.find_element(By.ID, shapingProfilePage_input_incoming_posId).send_keys(input_incoming)
+ self.driver.find_element(By.ID, shapingProfilePage_input_outgoing_posId).clear()
+ self.driver.find_element(By.ID, shapingProfilePage_input_outgoing_posId).send_keys(input_outgoing)
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_shapingProfiles_selectLabel_posId, listPage_profileSearch_shapingProfiles_dropDown_item_posXpath,
+ listPage_profileSearch_shapingProfiles_input_itemContent_posXpath, listPage_profileSearch_shapingProfiles_buttonSearch_posId,
+ listPage_profilTable_shapingProfiles_tableTbody_posXpath, listPage_profilTable_shapingProfiles_tableHeader_posXpath, **kwargs)
+ """
+ #点击search查询框
+ self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_selectLabel_posId).click()
+ #循环输入查询内容
+ for key, value in kwargs.items():
+ dropdown_item_posXpath = listPage_profileSearch_shapingProfiles_dropDown_item_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, dropdown_item_posXpath).click() #点击下拉item
+ if key != "type":
+ input_item_posXpath = listPage_profileSearch_shapingProfiles_input_itemContent_posXpath.format(replaceName=key)
+ self.driver.find_element(By.XPATH, input_item_posXpath).send_keys(value.strip()) #输入查询值
+ else:
+ pass
+ # dropdown_typeItem_posXpath = listPage_profileSearch_dnsRecords_dropDown_typeItem_posXpath.format(replaceName=value.split("->")[0])
+ # self.driver.find_element(By.XPATH, dropdown_typeItem_posXpath).click() #点击type的下拉item
+ #点击查询按钮
+ element_search = self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_buttonSearch_posId)
+ self.driver.execute_script("arguments[0].click()", element_search) #强制点击
+ element_tbody = self.driver.find_element(By.XPATH, listPage_profilTable_shapingProfiles_tableTbody_posXpath) #找到所有的行,table的body
+ element_header = self.driver.find_element(By.XPATH, listPage_profilTable_shapingProfiles_tableHeader_posXpath) #查询table的header
+ #获取table header的text、th.class
+ headers = element_header.find_elements(By.XPATH, "th") #table header
+ rows = element_tbody.find_elements(By.XPATH, "tr") #table body
+ map_header_className = {} #表头名称和th.class的映射,为了从表body中取对应列的值{"ID":"33"}
+ for th in headers:
+ header_content = th.text.strip()
+ classNames = th.get_attribute("class").split()
+ for c_name in classNames:
+ if "el-table" in c_name:
+ tableBodyRowClassName = c_name
+ if header_content and tableBodyRowClassName:
+ map_header_className[header_content] = tableBodyRowClassName
+ #从第一行查询的结果中,取出需要断言的值、name、Type、Values
+ first_row = rows[0]
+ """
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Type_class = map_header_className["Type"]
+ first_row_Type_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Type_class}')]//span").text.strip()
+ first_row_IncomingOutgoing_class = map_header_className["Incoming/Outgoing"]
+ first_row_IncomingOutgoing_contents = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_IncomingOutgoing_class}')]//span").text.strip()
+
+ print(first_row_id_content, first_row_Name_content, first_row_Type_content, first_row_IncomingOutgoing_contents)
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].strip(), msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["outgoing"].strip().split("->")[0] == "0": #为0时,直接断言Unlimit
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["outgoing"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["incoming"].strip().split("->")[0] == "0":
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["incoming"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[0], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.equal(first_row_Type_content, data["type"].split("->")[-1], msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["outgoing"].strip().split("->")[-1] == "0": #为0时,直接断言Unlimit
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["outgoing"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if data["incoming"].strip().split("->")[-1] == "0":
+ pytest_check.is_in("Unlimit", first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else:
+ pytest_check.is_in(data["incoming"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ pytest_check.is_in(data["unit"].strip().split("->")[-1], first_row_IncomingOutgoing_contents, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_shapingProfiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_shapingProfiles_editButton_posId).click()
+ #根据修改数据,重新输入limits
+ self._select_limits(data, model=-1)
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, shapingProfilePage_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_shapingProfiles_delButton_posId, listPage_dialogTips_shapingProfiles_button_yes_posCss,
+ listPage_dialogTips_shapingProfiles_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del
diff --git a/common/ui_common/profiles/ssl_decryption_keyrings.py b/common/ui_common/profiles/ssl_decryption_keyrings.py
new file mode 100644
index 00000000..5e81b7a4
--- /dev/null
+++ b/common/ui_common/profiles/ssl_decryption_keyrings.py
@@ -0,0 +1,219 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+import configparser
+import os
+
+
+class SSLDecryptionKeyrings:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def sslDecryptionKeyrings_case(self, data: {}):
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content)
+ self._del()
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到ssl_decryption_keyrings列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_sslDecryptionKeyrings_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_sslDecryptionKeyrings_createButton_posId).click()
+ #在create 创建页面操作
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_Name_posId).send_keys(self.random_name)
+ #页面其它项操作函数
+ self._operate_page(data, operation_type="create")
+ #点击OK
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionKeyrings_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionKeyrings_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ def _operate_page(self, data: {}, operation_type="create"):
+ """
+ 不包含name输入的其它操作,可以兼容新增、编辑使用
+ :param data:
+ :opration_type:可选择值为create edit
+ :return:
+ """
+ if operation_type == "create":
+ data_index = 0 #新增数据索引
+ else:
+ data_index = -1 #编辑数据索引
+ no_modify = "不修改"
+ #解析输入data数据、证书、私钥操作
+ cert_name = data["certificate"].split("->")[data_index].strip() #"test_root_cert_catest.cer->"
+ if cert_name != no_modify: #需改数据时,需要执行
+ cert_abspath = self._abs_path(cert_name)
+ self.driver.find_element(By.XPATH, sslDecryptionKeyrings_input_certificateFile_posXpath).send_keys(cert_abspath) #上传证书
+ #私钥
+ if data["private_key"].split("->")[data_index].strip() != no_modify: #修改私钥时执行
+ if data["private_key"].split("->")[data_index].strip().startswith("PKF-"): #如果已PKF-开始,则是私钥 "PKF-test_root_key_catest.key->"
+ key_name = data["private_key"].split("->")[data_index].strip().lstrip("PKF-")
+ key_abspath = self._abs_path(key_name)
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_radio_privateKeyFile_posId).click()
+ self.driver.find_element(By.XPATH, sslDecryptionKeyrings_input_privateKeyFile_posXpath).send_keys(key_abspath) #上传私钥
+ else: #私钥是HSM形式, 例如:HSM-345
+ slod_id = data["private_key"].split("->")[data_index].strip().lstrip("HSM-")
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_radio_hsm_posId).click()
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_slotIdHSM_posId).send_keys(slod_id) #输入slot id
+ #证书时间选择
+ reissue_expiry_hours: str = data["reissue_expiry_hours"].split("->")[data_index].strip()
+ if reissue_expiry_hours != no_modify:
+ if reissue_expiry_hours.startswith("MSC"): #'MSC'
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_radio_mirrorServerCertificate_poId).click()
+ else:
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_radio_customized_poId).click()
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_customized_poId).clear()
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_customized_poId).send_keys(reissue_expiry_hours.lstrip("C-")) #‘C-234'
+ #证书类型操作
+ type = data["type"].split("->")[data_index].strip()
+ if type != no_modify:
+ type_index_dict = {"Root-Certificate": 0, "Intermediate-Certificate": 1, "End-entity": 2}
+ if type not in type_index_dict.keys():
+ raise f"输入的证书类型参数错误。输出的参数:type={type}。可选择的输入参数值为:{list(type_index_dict.keys())}"
+ element_pos_type_droplist_item = sslDecryptionKeyrings_dropdown_certificateTypeSelect_poId.format(replaceIndex=type_index_dict[type])
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_certificateType_poId).click() #点击类型列表选择框
+ self.driver.find_element(By.ID, element_pos_type_droplist_item).click() #点击列表下拉参数具体选项
+ pka = data["public_key_algorithm"].split("->")[data_index].strip()
+ #公钥算法
+ if pka != no_modify:
+ pka_idex_dict = {"RSA-1024": 0, "RSA-2048": 1, "SECP-256r1": 2, "SECP-384r1": 3} #下拉列表定位索引
+ if pka not in pka_idex_dict.keys():
+ raise f"输入的公钥算法错误。输出的参数:pka={pka}。可选择的输入参数值为:{list(pka_idex_dict.keys())}"
+ element_pos_pka_droplist_item = sslDecryptionKeyrings_dropdown_publickKeyAlgorithmSelect_poId.format(replaceIndex=pka_idex_dict[pka])
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_publickKeyAlgorithm_poId).click()
+ self.driver.find_element(By.ID, element_pos_pka_droplist_item).click() #点击公钥算法下拉选项定位
+ #输入Certificate Revocation List
+ if data["certificate_revocation_list"].split("->")[data_index].strip() != no_modify:
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_certificateRevocationList_poId).clear()
+ self.driver.find_element(By.ID, sslDecryptionKeyrings_input_certificateRevocationList_poId).send_keys(data["certificate_revocation_list"].split("->")[data_index].strip())
+ include_root = data["include_root"].split("->")[data_index].strip().lower() #用例数据
+ if include_root != no_modify:
+ #先获取页面中包含根证书当前状态 include_root_current_class : class="el-switch is-checked" 有is-checked当前状态为开,没有is-chedked当前状态为关
+ include_root_current_class = self.driver.find_element(By.XPATH, sslDecryptionKeyrings_input_includeRoot_poXpath).find_element(By.XPATH, "parent::*").get_attribute("class")
+ if "on" == include_root: #开
+ if "is-checked" in include_root_current_class: #页面当前为开,不用点击开关
+ pass
+ else: #页面当前为关,需要点击开关
+ self.driver.find_element(By.XPATH, sslDecryptionKeyrings_input_includeRoot_poXpath).click()
+ self.include_root_statue = "on" #修改时会使用判断
+ else: #用例输入为关
+ if "is-checked" in include_root_current_class: #页面当前为开,需要点击开关
+ self.driver.find_element(By.XPATH, sslDecryptionKeyrings_input_includeRoot_poXpath).click()
+ self.include_root_statue = "on" # 修改时会使用判断
+ else: #页面当前为关,不用点击开关
+ pass
+
+ def _abs_path(self, file_name):
+ # 以下是要读取数据的名称
+ conf = configparser.ConfigParser()
+ loginout_parse_dir = os.path.join(self.workdir, "config", "ui_conf", "importfile.ini")
+ conf.read(loginout_parse_dir, encoding="utf-8")
+ testdata = conf.get("profiles", "testdata")
+ ui_file = conf.get("profiles", "ui_file")
+ profiles = conf.get("profiles", "profiles")
+ ssl_decryption_keyrings = conf.get("profiles", "ssl_decryption_keyrings")
+ import_file_abs = os.path.join(self.workdir, testdata, ui_file, profiles, ssl_decryption_keyrings, file_name)
+ import_file_abs = os.path.abspath(import_file_abs)
+ return import_file_abs
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_sslDecryptionKeyrings_selectLabel_posId, listPage_profileSearch_sslDecryptionKeyrings_dropDown_item_posXpath,
+ listPage_profileSearch_sslDecryptionKeyrings_input_itemContent_posXpath, listPage_profileSearch_sslDecryptionKeyrings_buttonSearch_posId,
+ listPage_profilTable_sslDecryptionKeyrings_tableTbody_posXpath, listPage_profilTable_sslDecryptionKeyrings_tableHeader_posXpath, **kwargs)
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ # 需要提取id、name、type、crl信息
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Type_class = map_header_className["Type"]
+ first_row_Type_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Type_class}')]//span").text.strip()
+ first_row_CRL_class = map_header_className["CRL"]
+ first_row_CRL_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_CRL_class}')]//span").text.strip()
+
+ print(first_row_id_content, first_row_Name_content, first_row_Type_content, first_row_CRL_content)
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_trafficMirroringProfiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_sslDecryptionKeyrings_editButton_posId).click()
+ #解析修改数据
+ self._operate_page(data, operation_type="edit")
+
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionKeyrings_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, sslDecryptionKeyrings_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionKeyrings_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_sslDecryptionKeyrings_delButton_posId, listPage_dialogTips_sslDecryptionKeyrings_button_yes_posCss,
+ listPage_dialogTips_sslDecryptionKeyrings_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del \ No newline at end of file
diff --git a/common/ui_common/profiles/ssl_decryption_profiles.py b/common/ui_common/profiles/ssl_decryption_profiles.py
new file mode 100644
index 00000000..3acb1160
--- /dev/null
+++ b/common/ui_common/profiles/ssl_decryption_profiles.py
@@ -0,0 +1,252 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+
+
+class SSLDecryptionProfiles:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+
+ def sslDecryptionProfiles_case(self, data: {}):
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content)
+ self._del()
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到ssl_decryption_keyrings列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_sslDecryptionProfiles_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_sslDecryptionProfiles_createButton_posId).click()
+ #在create 创建页面操作
+ self.driver.find_element(By.ID, sslDecryptionProfiles_input_Name_posId).send_keys(self.random_name)
+ #页面其它选项操作
+ self._operate_page(data, operation_type="create")
+ #点击OK
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionProfiles_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionProfiles_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ def _operate_page(self, data: {}, operation_type="create"):
+ """"""
+ if operation_type == "create":
+ data_index = 0 #新增数据索引
+ else:
+ data_index = -1 #编辑数据索引
+ no_modify = "不修改"
+ #解析输入data数据的数据
+ #页面开关操作 common name,issuer,selfSigned,expiryDate
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="common_name", element_position=sslDecryptionProfiles_switch_commonName_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="issuer", element_position=sslDecryptionProfiles_switch_issuer_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="self_signed", element_position=sslDecryptionProfiles_switch_selfSigned_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="expiry_date", element_position=sslDecryptionProfiles_switch_expiryDate_posXpath)
+ #Fail Action操作
+ fail_action = self._get_value_from_data(data, key="fail_action", data_index=data_index) #用例数据提取 Pass-through Fail-close
+ if fail_action != no_modify:
+ if "pass-through" == fail_action: #点击pass through
+ self.driver.find_element(By.XPATH, sslDecryptionProfiles_radio_passThrough_posXpath).click()
+ else: #点击fail close
+ self.driver.find_element(By.XPATH, sslDecryptionProfiles_radio_failClose_posXpath).click()
+ #页面开关操作ev_certificate certificate_transparency mutual_authentication protocol_errors certificate_pinning certificate_not_installed allow_HTTP2 mirror_client_versions
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="ev_certificate", element_position=sslDecryptionProfiles_switch_evCert_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="certificate_transparency", element_position=sslDecryptionProfiles_switch_certificateTransparency_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="mutual_authentication", element_position=sslDecryptionProfiles_switch_mutualAuthentication_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="protocol_errors", element_position=sslDecryptionProfiles_switch_onProtocolErrors_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="certificate_pinning", element_position=sslDecryptionProfiles_switch_certificatePinning_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="certificate_not_installed", element_position=sslDecryptionProfiles_switch_certificateNotInstalled_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="mirror_client_versions", element_position=sslDecryptionProfiles_switch_mirrorClientVersions_posXpath)
+ self._operate_switch(data, data_index=data_index, no_modify=no_modify, switch_name="allow_HTTP2", element_position=sslDecryptionProfiles_switch_allowHTTP2_posXpath)
+ #Min Max version操作
+ mirror_client_versions = self._get_value_from_data(data, key="mirror_client_versions", data_index=data_index) #提取数据
+ mirror_client_versions_class = self.driver.find_element(By.XPATH, sslDecryptionProfiles_switch_mirrorClientVersions_posXpath).get_attribute("class") #该开关当前属性状态
+ min_version = self._get_value_from_data(data, key="min_client_version", data_index=data_index)
+ max_version = self._get_value_from_data(data, key="max_client_version", data_index=data_index)
+ if "is-checked" not in mirror_client_versions_class: #只有 当前状态为关时,才可以操作版本大小。
+ version_index_list = ['sslv3.0', 'tlsv1.0', 'tlsv1.1', 'tlsv1.2', 'tlsv1.3']
+ if min_version != no_modify: #编辑时不修改,则不用操作
+ self.driver.find_element(By.XPATH, sslDecryptionProfiles_input_minVersion_posXpath).click()
+ element_pos_min_drop_down_item = sslDecryptionProfiles_dropDown_minVersion_posXpath.format(replaceIndex=version_index_list.index(min_version)) #组定位
+ self.driver.find_element(By.XPATH, element_pos_min_drop_down_item).click()
+ if max_version != no_modify: #编辑时不修改,则不用操作
+ self.driver.find_element(By.XPATH, sslDecryptionProfiles_input_maxVersion_posXpath).click()
+ element_pos_max_drop_down_item = sslDecryptionProfiles_dropDown_maxVersion_posXpath.format(replaceIndex=version_index_list.index(max_version)) #组定位
+ self.driver.find_element(By.XPATH, element_pos_max_drop_down_item).click()
+
+ def _get_value_from_data(self, data: {}, key="", data_index=0):
+ """
+ 从data数据中,根据key提取值
+ :param data:
+ :param key:
+ :param data_index: 0 -1
+ :return:
+ """
+ try:
+ switch_value: str = data[key].split("->")[data_index].strip().lower() #用例数据
+ except Exception as e:
+ print(e)
+ return switch_value
+
+ def _operate_switch(self, data: {}, data_index=0, no_modify="不修改", switch_name="", element_position=""):
+ """
+ 页面中,开关状态操作。
+ :param data:
+ :param data_index: 0 -1来自上层
+ :param no_modify:"不修改" 来自上次调用
+ :param operation_type: create modify两个状态,
+ :param switch_name: 数据中开关名称
+ :param elementPosition: 开关的定位
+ :return:
+ """
+ #解析输入data数据的数据
+ switch_value: str = self._get_value_from_data(data, key=switch_name, data_index=data_index) #提取数据
+ if switch_value != no_modify: #编辑时,有不修改则不用执行
+ #先获取当前页面中开关状态 include_root_current_class : class="el-switch is-checked" 有is-checked当前状态为开,没有is-chedked当前状态为关
+ swith_current_class = self.driver.find_element(By.XPATH, element_position).get_attribute("class")
+ if "on" == switch_value: #数据中为开
+ if "is-checked" in swith_current_class: #页面当前为开,不用点击开关
+ pass
+ else: #页面当前为关,需要点击开关
+ self.driver.find_element(By.XPATH, element_position).click()
+ else: #用例输入为关
+ if "is-checked" in swith_current_class: #页面当前为开,需要点击开关
+ self.driver.find_element(By.XPATH, element_position).click()
+ else: #页面当前为关,不用点击开关
+ pass
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_sslDecryptionProfiles_selectLabel_posId, listPage_profileSearch_sslDecryptionProfiles_dropDown_item_posXpath,
+ listPage_profileSearch_sslDecryptionProfiles_input_itemContent_posXpath, listPage_profileSearch_sslDecryptionProfiles_buttonSearch_posId,
+ listPage_profilTable_sslDecryptionProfiles_tableTbody_posXpath, listPage_profilTable_sslDecryptionProfiles_tableHeader_posXpath, **kwargs)
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ #print(map_header_className)
+ # 需要提取id、name、type、Certificate Checks、Fail Action、Dynamic Bypass、Allow HTTP/2信息
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_Certificate_Checks_class = map_header_className["Certificate Checks"]
+ first_row_Certificate_Checks_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Certificate_Checks_class}')]//span").text
+ first_row_Fail_Action_class = map_header_className["Fail Action"]
+ first_row_Fail_Action_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Fail_Action_class}')]//span").text
+ first_row_Dynamic_Bypass_class = map_header_className["Dynamic Bypass"]
+ first_row_Dynamic_Bypass_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Dynamic_Bypass_class}')]//span").text
+ first_row_Allow_HTTP2_class = map_header_className["Allow HTTP/2"]
+ first_row_Allow_HTTP2_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Allow_HTTP2_class}')]//span").text
+
+ print(first_row_id_content, first_row_Name_content, first_row_Certificate_Checks_content, first_row_Fail_Action_content, first_row_Dynamic_Bypass_content, first_row_Allow_HTTP2_content)
+ #不同操作后的断言,创建后、修改后、无断言
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ self_signed = self._get_value_from_data(data, key="self_signed", data_index=0)
+ common_name = self._get_value_from_data(data, key="common_name", data_index=0)
+ fail_action = self._get_value_from_data(data, key="fail_action", data_index=0)
+ allow_HTTP2 = self._get_value_from_data(data, key="fail_action", data_index=0)
+ certificate_pinning = self._get_value_from_data(data, key="certificate_pinning", data_index=0)
+ if self_signed == "on":
+ pytest_check.is_in("Self-signed", first_row_Certificate_Checks_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if common_name == "on":
+ pytest_check.is_in("Common Name", first_row_Certificate_Checks_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if fail_action == "pass-through":
+ pytest_check.is_in("Pass-through", first_row_Fail_Action_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif fail_action == "fail-close":
+ pytest_check.is_in("Fail-close", first_row_Fail_Action_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if certificate_pinning == "on":
+ pytest_check.is_in("Certificate Pinning", first_row_Dynamic_Bypass_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if allow_HTTP2 == "on":
+ pytest_check.is_in("Enabled", first_row_Allow_HTTP2_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ self_signed = self._get_value_from_data(data, key="self_signed", data_index=-1)
+ common_name = self._get_value_from_data(data, key="common_name", data_index=-1)
+ fail_action = self._get_value_from_data(data, key="fail_action", data_index=-1)
+ allow_HTTP2 = self._get_value_from_data(data, key="fail_action", data_index=-1)
+ certificate_pinning = self._get_value_from_data(data, key="certificate_pinning", data_index=-1)
+ if self_signed == "on":
+ pytest_check.is_in("Self-signed", first_row_Certificate_Checks_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if common_name == "on":
+ pytest_check.is_in("Common Name", first_row_Certificate_Checks_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if fail_action == "pass-through":
+ pytest_check.is_in("Pass-through", first_row_Fail_Action_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif fail_action == "fail-close":
+ pytest_check.is_in("Fail-close", first_row_Fail_Action_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if certificate_pinning == "on":
+ pytest_check.is_in("Certificate Pinning", first_row_Dynamic_Bypass_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ if allow_HTTP2 == "on":
+ pytest_check.is_in("Enabled", first_row_Allow_HTTP2_content, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_sslDecryptionProfiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_sslDecryptionProfiles_editButton_posId).click()
+ #解析修改数据
+ self._operate_page(data, operation_type="edit")
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionProfiles_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, sslDecryptionProfiles_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, sslDecryptionProfiles_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_sslDecryptionProfiles_delButton_posId, listPage_dialogTips_sslDecryptionProfiles_button_yes_posCss,
+ listPage_dialogTips_sslDecryptionProfiles_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del \ No newline at end of file
diff --git a/common/ui_common/profiles/traffic_mirroring_profiles.py b/common/ui_common/profiles/traffic_mirroring_profiles.py
new file mode 100644
index 00000000..22719f0e
--- /dev/null
+++ b/common/ui_common/profiles/traffic_mirroring_profiles.py
@@ -0,0 +1,195 @@
+# -*- coding: UTF-8 -*-
+from common.driver_common.mywebdriver import MyWebDriver
+from selenium.webdriver.common.by import By
+from config.workpath import workdir
+from page_element.element_position import *
+from common.driver_common.screenshot import screenshot_on_failure
+from common.driver_common.random_name import RandomName
+from common.ui_common.profiles.profiles_public_operations import ProfilesPublicOperations
+import pytest_check
+import inspect
+import time
+
+
+class TrafficMirroringProfiles:
+ def __init__(self, demo_fixture: MyWebDriver):
+ self.workdir = workdir
+ self.my_random = RandomName()
+ self.driver = demo_fixture
+ # 调用profiles公共方法操作、删除、查询,
+ self.profiles_po = ProfilesPublicOperations(self.driver)
+ #todo
+ def traffic_morroring_profiles_case(self, data: {}):
+ self._create(data) #创建
+ self._query(data, require_assertion=1, Name=self.random_name) #创建后查询
+ if data["model"].strip().lower() == "modify": #修改测试时,执行修改方法
+ self._modify(data)
+ self._query(data, require_assertion=2, ID=self.first_row_ID_content)
+ self._del()
+
+ @screenshot_on_failure
+ def _goto_subProfilePage(self):
+ # 菜单操作,定位到trafficMirroringProfiles列表页
+ self.driver.find_element(By.CSS_SELECTOR, mainPage_navigationBar_logo_posCss).click()
+ self.driver.find_element(By.ID, mainPage_firstLevelMenu_profiles_posId).click()
+ self.driver.find_element(By.ID, mainPage_secondLevelMenu_trafficMirroringProfiles_posId).click()
+
+ @screenshot_on_failure
+ def _create(self, data: {}):
+ #页面跳转
+ self._goto_subProfilePage()
+ #创建
+ #点击create
+ self.random_name = self.my_random.random_name()
+ self.driver.find_element(By.ID, listPage_profile_trafficMirroringProfiles_createButton_posId).click()
+ #在create 创建页面操作
+ self.driver.find_element(By.ID, trafficMirroringProfiles_input_Name_posId).send_keys(self.random_name)
+ #解析输入的vlan id数据
+ vlan_ids = data["vlan_id"]
+ vlan_ids_create = [] #创建的vlan id
+ for i in vlan_ids:
+ if i.strip().split("->")[0] != "":
+ vlan_ids_create.append(i.strip().split("->")[0])
+ #循环输入vlan id
+ for j in range(len(vlan_ids_create)):
+ #输入ipnut
+ elements_vlan_ids_input = self.driver.find_elements(By.XPATH, trafficMirroringProfiles_input_vlanIdsInput_posXpath)
+ for element_vlan_id in elements_vlan_ids_input:
+ if element_vlan_id.get_attribute("value") == "": #创建时,只是往input.value=none中键入数据
+ element_pos_by_id = element_vlan_id.get_attribute("id")
+ self.driver.find_element(By.ID, element_pos_by_id).send_keys(vlan_ids_create[j]) #输入vlan id的值
+ break
+ if (len(vlan_ids_create) - 1) - j > 0: #点击add按钮比数据个数少一次
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_vlanIdAdd_posCss).click() #点击add添加
+ #点击OK
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_oK_posCss).click()
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_warningSaveYes_posCss).click()
+ return self.random_name
+
+ @screenshot_on_failure
+ def _query(self, data: {}, require_assertion=0, **kwargs):
+ """
+ 查询函数,根据输入的类型查询
+ :param require_assertion: =0默认情况不需要断言,=1为创建后使用的断言预期,=2为编辑修改后使用的断言预期
+ :param kwargs: 例如 :可以查询使用的关键字,ID=None,Name=None,
+ :return:
+ """
+ #打开该列表
+ self._goto_subProfilePage
+ #first_row查询到的第一行内容。map_header_className为需要使用的到字典,用来提取第一行的结果。
+ first_row, map_header_className = \
+ self.profiles_po.query(listPage_profileSearch_trafficMirroringProfiles_selectLabel_posId, listPage_profileSearch_trafficMirroringProfiles_dropDown_item_posXpath,
+ listPage_profileSearch_trafficMirroringProfiles_input_itemContent_posXpath, listPage_profileSearch_trafficMirroringProfiles_buttonSearch_posId,
+ listPage_profilTable_trafficMirroringProfiles_tableTbody_posXpath, listPage_profilTable_trafficMirroringProfiles_tableHeader_posXpath, **kwargs)
+ #第一行的勾选定位,给修改、删除使用
+ self.first_row_checkBox_element = first_row.find_element(By.XPATH, "//span[@class='el-checkbox__input']")
+ self.first_row_ID_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']/span").text.strip()
+ first_row_id_content = first_row.find_element(By.XPATH, "//div[@class='table-status-item-id']//span").text.strip()
+ first_row_Name_class = map_header_className["Name"]
+ first_row_Name_content = first_row.find_element(By.XPATH, f"//td[contains(@class, '{first_row_Name_class}')]//span").text.strip()
+ first_row_VLAN_ID_class = map_header_className["VLAN ID"]
+ first_row_VLAN_IDs_content = first_row.find_elements(By.XPATH, f"//td[contains(@class, '{first_row_VLAN_ID_class}')]//span//span")
+ first_row_VLAN_IDS_list = []
+ for element_vlan_id in first_row_VLAN_IDs_content:
+ vlan_id_str = element_vlan_id.text.strip()
+ if "," in vlan_id_str and len(vlan_id_str) == 1: #跳过只是,的数据
+ continue
+ first_row_VLAN_IDS_list.append(vlan_id_str.strip(","))
+ print(first_row_id_content, first_row_Name_content, first_row_VLAN_IDS_list)
+ #不同操作后的断言,创建后、修改后、无断言
+
+ if require_assertion == 1: #直接创建后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ # 解析输入的vlan id数据,并断言使用
+ vlan_ids = data["vlan_id"]
+ vlan_ids_create = [] # 创建的vlan id
+ for i in vlan_ids:
+ if i.strip().split("->")[0] != "":
+ vlan_ids_create.append(i.strip().split("->")[0])
+ #断言vlan id
+ for vlan_id in first_row_VLAN_IDS_list:
+ pytest_check.is_in(vlan_id, vlan_ids_create, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ elif require_assertion == 2 and data["model"].strip().lower() == "modify": #修改数据后,使用的断言
+ pytest_check.equal(first_row_Name_content, self.random_name, msg="所在行数{}".format(inspect.currentframe().f_lineno))
+ else: #不适用断言
+ pass
+ #强制点击清空查询按钮
+ element_clear = self.driver.find_element(By.ID, listPage_profileSearch_trafficMirroringProfiles_buttonClear_posId)
+ self.driver.execute_script("arguments[0].click()", element_clear) # 强制点击
+ return self.first_row_ID_content
+
+ @screenshot_on_failure
+ def _modify(self, data: {}):
+ """
+ 修改数据,使用方法
+ :param data:
+ :return:
+ """
+ if data["model"].strip().lower() == "create": #如果是create参数用例,则不用执行修改方法
+ return 0
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ self.driver.find_element(By.ID, listPage_profile_trafficMirroringProfiles_editButton_posId).click()
+ #从data数据中解析出修改数据、删除输出、新增数据
+ modify_vlan_ids = []
+ del_vlan_ids = []
+ add_vlan_ids = []
+ raw_vlan_ids = data["vlan_id"] #用例中输入的数据,->前的数据为创建,标识符后的数据为修改的数据
+ for item in raw_vlan_ids:
+ if item.strip().split("->")[0] != "" and item.strip().split("->")[-1] != "": #提创建、取修改数据
+ modify_vlan_ids.append(item.strip())
+ elif item.strip().split("->")[-1] == "": #提取创建、删除数据
+ del_vlan_ids.append(item.strip())
+ else: #提取新增数据
+ add_vlan_ids.append(item.strip())
+ print(modify_vlan_ids, del_vlan_ids, add_vlan_ids)
+ #操作直接修改vlan id数据
+ if len(modify_vlan_ids) != 0:
+ for modify_item in modify_vlan_ids:
+ elements_vlan_ids_input = self.driver.find_elements(By.XPATH, trafficMirroringProfiles_input_vlanIdsInput_posXpath)
+ for element_vlan_id in elements_vlan_ids_input:
+ if element_vlan_id.get_attribute("value").strip() == modify_item.split("->")[0]: #有需要修改的vlan id
+ element_vlan_id.clear()
+ element_vlan_id.send_keys(modify_item.split("->")[-1]) #修改数据
+ time.sleep(0.2)
+ break
+ #操作直接删除vlan id数据
+ if len(del_vlan_ids) != 0:
+ for del_item in del_vlan_ids:
+ elements_vlan_ids_input = self.driver.find_elements(By.XPATH, trafficMirroringProfiles_input_vlanIdsInput_posXpath)
+ for element_vlan_id in elements_vlan_ids_input:
+ if element_vlan_id.get_attribute("value").strip() == del_item.split("->")[0]: #有需要删除的vlan id
+ element_vlan_id.find_element(By.XPATH, r"parent::*/parent::*//i").click() #点击删除按钮
+ time.sleep(0.2)
+ break
+ #操作新增vlan id数据
+ if len(add_vlan_ids) != 0:
+ for add_item in add_vlan_ids:
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_vlanIdAdd_posCss).click()
+ elements_vlan_ids_input = self.driver.find_elements(By.XPATH, trafficMirroringProfiles_input_vlanIdsInput_posXpath)
+ for element_vlan_id in elements_vlan_ids_input:
+ if element_vlan_id.get_attribute("value") == "": #创建时,只是往input.value=none中键入数据
+ element_vlan_id.send_keys(add_item.split("->")[-1])
+ time.sleep(0.2)
+ break
+ #点击ok
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_oK_posCss).click()
+ if self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_warningSaveYes_posCss).is_displayed():
+ self.driver.find_element(By.CSS_SELECTOR, trafficMirroringProfiles_button_warningSaveYes_posCss).click()
+
+ @screenshot_on_failure
+ def _del(self):
+ """
+ 默认删除查询到的第一个结果
+ :return:
+ """
+ #点击勾选第一行选择框
+ self.first_row_checkBox_element.click() #变量来自查询函数
+ #调用profiles的功能删除方法
+ self.profiles_po.delete(listPage_profile_trafficMirroringProfiles_delButton_posId, listPage_dialogTips_trafficMirroringProfiles_button_yes_posCss,
+ listPage_dialogTips_trafficMirroringProfiles_button_no_posCss)
+
+ create = _create
+ query = _query
+ modify = _modify
+ delete = _del \ No newline at end of file
diff --git a/common/ui_read_data/__init__.py b/common/ui_read_data/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/common/ui_read_data/__init__.py
diff --git a/common/ui_read_data/__pycache__/__init__.cpython-38.pyc b/common/ui_read_data/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000..29d8cfa5
--- /dev/null
+++ b/common/ui_read_data/__pycache__/__init__.cpython-38.pyc
Binary files differ
diff --git a/common/ui_read_data/__pycache__/read_data.cpython-38.pyc b/common/ui_read_data/__pycache__/read_data.cpython-38.pyc
new file mode 100644
index 00000000..8201539a
--- /dev/null
+++ b/common/ui_read_data/__pycache__/read_data.cpython-38.pyc
Binary files differ
diff --git a/common/ui_read_data/read_data.py b/common/ui_read_data/read_data.py
new file mode 100644
index 00000000..52dea141
--- /dev/null
+++ b/common/ui_read_data/read_data.py
@@ -0,0 +1,72 @@
+import json
+import os
+from config.workpath import workdir
+
+class ReadData:
+ def __init__(self):
+ #json文件和测试文件目录
+ self.workdir = workdir
+ self.testdata = "testdata"
+ self.ui_data = "ui_data"
+ self.profiles_data = "profiles_data"
+ # 以下是要读取数据的名称
+ self.response_pages_name = "response_pages.json"
+ self.dns_records_name = "dns_records.json"
+ self.shaping_profile_name = "shaping_profiles.json"
+
+ def _from_json(self, file):
+ """
+ 从json中读取数据函数
+ :param file:
+ :return:
+ """
+ with open(file, "r", encoding="utf-8") as f:
+ data = json.load(f)["item"]
+ data = list(data)
+ return data
+
+ def _abs_path(self, file_name):
+ """
+ 重组路径
+ :param file_name:
+ :return:
+ """
+ file = os.path.join(self.workdir, self.testdata, self.ui_data, self.profiles_data, file_name)
+ return file
+
+ @property
+ def read_response_pages(self):
+ file = self._abs_path(self.response_pages_name)
+ return self._from_json(file)
+
+ @property
+ def read_dns_records(self):
+ file = self._abs_path(self.dns_records_name)
+ return self._from_json(file)
+
+ @property
+ def read_shaping_profiles(self):
+ file = self._abs_path(self.shaping_profile_name)
+ return self._from_json(file)
+
+ def read_data_profiles(self, file_name):
+ """
+ 通用读取json数据方法
+ :param file_name:
+ :return:
+ """
+ file = self._abs_path(file_name)
+ return self._from_json(file)
+
+ def generate_id(self, param):
+ """
+ 测试用例中ids信息提取
+ :param param:
+ :return:
+ """
+ ids: str = param["ids"]
+ #print(ids)
+ return ids
+
+if __name__ == '__main__':
+ ReadData().read_dns_records \ No newline at end of file
diff --git a/config/__pycache__/workpath.cpython-38.pyc b/config/__pycache__/workpath.cpython-38.pyc
new file mode 100644
index 00000000..3fbd6862
--- /dev/null
+++ b/config/__pycache__/workpath.cpython-38.pyc
Binary files differ
diff --git a/config/ui_conf/__init__.py b/config/ui_conf/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/config/ui_conf/__init__.py
diff --git a/config/ui_conf/importfile.ini b/config/ui_conf/importfile.ini
new file mode 100644
index 00000000..71747f2a
--- /dev/null
+++ b/config/ui_conf/importfile.ini
@@ -0,0 +1,13 @@
+[profiles] #profiles中文件使用路径管理
+#profiles上传文件多层目录结构
+testdata = testdata
+ui_file = ui_file
+profiles = profiles
+#response_pages上传文件目录
+response_pages = response_pages
+#ssl_decryption_keyrings上传文件目录
+ssl_decryption_keyrings = ssl_decryption_keyrings
+#hijack_files上传文件目录
+hijack_files = hijack_files
+# insert_scripts 上传文件目录
+insert_scripts = insert_scripts \ No newline at end of file
diff --git a/config/ui_conf/loginout.ini b/config/ui_conf/loginout.ini
new file mode 100644
index 00000000..59d9f7e1
--- /dev/null
+++ b/config/ui_conf/loginout.ini
@@ -0,0 +1,12 @@
+[remote_url]
+url = http://192.168.64.34:4444
+#url = http://192.168.64.33:4444
+
+[tsg_url]
+login_url = http://192.168.44.72
+
+[ui_account_1]
+username = Auto_UI_Test_2
+passwd = Auto_UI_Test_2
+#username = admin
+#passwd = admin \ No newline at end of file
diff --git a/config/workpath.py b/config/workpath.py
new file mode 100644
index 00000000..48dd69a2
--- /dev/null
+++ b/config/workpath.py
@@ -0,0 +1,5 @@
+import os
+
+
+#获取工作目录
+workdir = os.path.dirname(os.path.dirname(__file__))
diff --git a/main.py b/main.py
new file mode 100644
index 00000000..c2a9aeb4
--- /dev/null
+++ b/main.py
@@ -0,0 +1,24 @@
+import pytest
+
+
+
+
+
+
+if __name__ == '__main__':
+ print(223333)
+ pytest.main(["-s", "-v", "cases/ui"])
+ print(55633)
+
+ """
+ # 在测试文件的当前路径执行如下命令执行测试用例:
+ --max
+ pytest –cache-clear -v pytest_json.py --alluredir ./allure
+ --check-max-tb 9000 #最大校验
+ --reruns=1 #失败重运行次数
+ pytest -cache-clear -sv ./cases/ui --check-max-tb 9000 --alluredir ./results/reports
+ pytest -cache-clear -sv ./cases/ui --check-max-tb 9000 --reruns=1 --alluredir ./results/reports
+ allure serve ./results/reports
+ # 执行如下命令生成测试报告(自动打开浏览器):
+ allure serve allure
+ """ \ No newline at end of file
diff --git a/page_element/element_position.py b/page_element/element_position.py
new file mode 100644
index 00000000..5312a561
--- /dev/null
+++ b/page_element/element_position.py
@@ -0,0 +1,278 @@
+#login page 登录页面
+loginPage_userName_posName = "username"
+loginPage_passwd_posName = "password"
+loginPage_signIn_posId = "login"
+
+#main页面
+##上导航栏
+mainPage_navigationBar_logo_posCss = ".tsg-img-logo"
+#菜单栏================================菜单栏===================================菜单栏================================菜单栏==================================菜单栏========================菜单栏
+##菜单栏
+mainPage_firstLevelMenu_profiles_posId = "Profiles" #一级菜单Profiles
+mainPage_secondLevelMenu_responsePages_posId = "Proxy_Profiles/Profile_ResponsePages" #二级菜单response pages
+mainPage_secondLevelMenu_dnsRecords_posId = "Proxy_Profiles/DNS_record_profile" #二级菜单dns records
+mainPage_secondLevelMenu_trafficMirroringProfiles_posId = "Proxy_Profiles/Profile_TrafficMirrorProfiles" #二级菜单traffic mirroring profiles
+mainPage_secondLevelMenu_sslDecryptionKeyrings_posId = "Proxy_CertificateManagement/Certificate_Keyrings" #二级菜单ssl decryption keyrings
+mainPage_secondLevelMenu_sslDecryptionProfiles_posId = "Proxy_Profiles/Profile_DecryptionProfile" #二级菜单ssl decryption Profiles
+mainPage_secondLevelMenu_hijackFiles_posId = "Proxy_Profiles/Profile_HijackFiles" #二级菜单hijack files
+mainPage_secondLevelMenu_insertScripts_posId = "Proxy_Profiles/Profile_Insert" #二级菜单insert scripts
+mainPage_secondLevelMenu_shapingProfiles_posId = "Proxy_Profiles/ShapingProfile" #二级菜单shaping profiles
+
+
+#Profiles 查询栏===================Profiles 查询栏=====================Profiles 查询栏=================Profiles 查询栏=======================Profiles 查询栏=================Profiles 查询栏
+##profiles模块查询栏
+mainPage_profileSearch_selectLabel_posId = "select-label" #查询框id
+mainPage_profileSearch_buttonSearch_posId = "searchQuery" #查询按钮id
+mainPage_profileSearch_buttonClear_posId = "searchClear" #清空查询按钮id
+
+
+#Profiles DNS Records===================Profiles DNS Records====================Profiles DNS Records=================Profiles DNS Records=======================Profiles DNS Records=================Profiles DNS Records
+#DNS Records list page 列表页
+listPage_profile_dnsRecords_createButton_posId = "app_create-_OperateBtns_ElRow_DNSRecordProfile_Home_App_anonymousComponent" #create按钮id
+listPage_profile_dnsRecords_editButton_posId = "appEdit-_OperateBtns_ElRow_DNSRecordProfile_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_dnsRecords_delButton_posId = "appDel-_OperateBtns_ElRow_DNSRecordProfile_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_dnsRecords_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id
+listPage_profileSearch_dnsRecords_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id
+listPage_profileSearch_dnsRecords_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id
+listPage_profileSearch_dnsRecords_dropDown_item_posXpath = "//div[contains(@class,'el-scrollbar')]//span[normalize-space(text())='{replaceName}']" #下拉菜单定位
+listPage_profileSearch_dnsRecords_input_itemContent_posXpath = "//div[contains(@class,'ListItem')]//span[normalize-space(text())='{replaceName}']/ancestor::div[contains(@class,'ListItem')]//input" #输入item的值,replaceName替换实际查询值
+listPage_profileSearch_dnsRecords_dropDown_typeItem_posXpath = "//div[contains(@class,'select-popper')]//span[normalize-space(text())='{replaceName}']" #查询中type的下拉item定位,replaceName替换实际查询值
+listPage_profilTable_dnsRecords_tableTbody_posXpath = "//div[contains(@class,'ly-table1')]//tbody" #列表tabel body xpath
+listPage_profilTable_dnsRecords_tableHeader_posXpath = "//div[contains(@class,'ly-table1')]//table[@class='el-table__header']//thead//tr" #列表table 表头xpath
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_dnsRecords_button_yes_posCss = ".delComponents-ok span" #删除提示的Tips的yes按钮
+listPage_dialogTips_dnsRecords_button_no_posCss = ".delComponents-close span" #删除提示的Tips的close按钮
+#Create DNS Record Profile 和 Edit DNS Record Profile 新增和编辑页
+dnsRecordsProfilePage_input_Name_posId = "DNSRecordPrfileadd_Home_App_anonymousComponent_objectAdd_name" #name输入框id
+dnsRecordsProfilePage_radioButton_typeA_posId = "objectAdd_ip0-_DNSRecordPrfileadd_Home_App_anonymousComponent" #A单选按钮id,
+dnsRecordsProfilePage_radioButton_typeAAAA_posId = "objectAdd_ip1-_DNSRecordPrfileadd_Home_App_anonymousComponent" #AAAA单选按钮id
+dnsRecordsProfilePage_radioButton_typeCNAME_posId = "objectAdd_ip2-_DNSRecordPrfileadd_Home_App_anonymousComponent" #CNAME单选按钮id
+dnsRecordsProfilePage_input_searchFor_posId = "object_ip_search" #search for 输入框id
+dnsRecordsProfilePage_button_addItem_posId = "temporary_form" #添加item按钮id
+dnsRecordsProfilePage_input_inputItemName_posXpath = "//span[normalize-space(text())='replaceName' and contains(@class,'content-show')]/ancestor::div[@class='item-row']//input[@class='el-input__inner']" #item的输入框xpath, replaceNamew为替换内容
+dnsRecordsProfilePage_button_saveItemByName_posXpath = "//span[normalize-space(text())='replaceName' and contains(@class, 'content-show')]/ancestor::div[@class='item-row']//i[contains(@class, 'icon-save')]" #item的保存xpath, replaceNamew为替换内容
+dnsRecordsProfilePage_button_editItemByName_posXpath = "//span[normalize-space(text())='replaceName' and contains(@class,'content-show')]/ancestor::div[@class='item-row']//i[contains(@class, 'icon-Edit')]" #item的编辑按钮xpath, replaceNamew为替换内容
+dnsRecordsProfilePage_button_delItemByName_posXpath = "//span[normalize-space(text())='replaceName' and contains(@class,'content-show')]/ancestor::div[@class='item-row']//i[contains(@class, 'icon-Delete_X')]" #item的删除按钮, replaceNamew为替换内容
+dnsRecordsProfilePage_textArea_Description_posId = "DNSRecordPrfileadd_Home_App_anonymousComponent_objectAdd_description" #description文本输入区id
+dnsRecordsProfilePage_button_warningSaveYes_posCss = ".el-message-box__btns .el-button--primary span" #提示保存ok按钮警告框
+dnsRecordsProfilePage_button_warningSaveCancel_posCss = ".el-message-box__btns .operation-cancel span" #提示保存取消按钮警告框
+dnsRecordsProfilePage_button_oK_posCss = "#dnsRecord_ok-_DNSRecordPrfileadd_Home_App_anonymousComponent span" #OK按钮css
+dnsRecordsProfilePage_button_cancel_posCss = "#dnsRecord_cancel-_DNSRecordPrfileadd_Home_App_anonymousComponent span" #Cancel
+
+
+#Profiles Response-Pages===================Profiles Response-Pages====================Profiles Response-Pages=================Profiles Response-Pages=======================Profiles Response-Pages=================Profiles Response-Pages
+#Response Pages list page 列表页
+listPage_profile_responsePages_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_ResponsePages_Home_App_anonymousComponent" #create按钮id
+listPage_profile_responsePages_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_ResponsePages_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_responsePages_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_ResponsePages_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_responsePages_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_responsePages_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_responsePages_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_responsePages_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_responsePages_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_responsePages_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_responsePages_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_responsePages_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_responsePages_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create Response Page 和 Edit Response Page 新增和编辑页
+responsePage_input_Name_posId = "responsepages_profileName" #name输入框id
+responsePage_input_file_posXpath = "//*[@id='responseAddUpload']/parent::*//input" #File上次输入按钮
+responsePage_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+responsePage_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+responsePage_button_oK_posCss = "#responseAddOk1 span" #OK按钮css
+responsePage_button_cancel_posCss = "#responseAddCancel1 span" #Cancel按钮
+
+
+#Profiles traffic mirroring profiles===================Profiles traffic mirroring profiles====================Profiles traffic mirroring profiles=================Profiles traffic mirroring profiles=======================Profiles traffic mirroring profiles=================Profiles traffic mirroring profiles
+#listPage->traffic mirroring profiles list page 列表页
+listPage_profile_trafficMirroringProfiles_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_TrafficMirrorProfiles_Home_App_anonymousComponent" #create按钮id
+listPage_profile_trafficMirroringProfiles_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_TrafficMirrorProfiles_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_trafficMirroringProfiles_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_TrafficMirrorProfiles_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_trafficMirroringProfiles_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_trafficMirroringProfiles_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_trafficMirroringProfiles_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_trafficMirroringProfiles_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_trafficMirroringProfiles_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_trafficMirroringProfiles_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_trafficMirroringProfiles_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_trafficMirroringProfiles_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_trafficMirroringProfiles_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create traffic mirroring profile page 和 Edit traffic mirroring profile page 新增和编辑页
+trafficMirroringProfiles_input_Name_posId = "trafficmirror_profileName" #name输入框id
+trafficMirroringProfiles_button_vlanIdAdd_posCss = "#addrTypeAdd i" #vlan id 添加按钮css
+trafficMirroringProfiles_input_vlanIdsInput_posXpath = "//form//div[contains(@class, 'addel-form')]//input" #所有显示的vlan id的所有input定位,需要通过value二次处理,css
+trafficMirroringProfiles_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+trafficMirroringProfiles_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+trafficMirroringProfiles_button_oK_posCss = "#trafficMirrorProfile_ok span" #OK按钮css
+trafficMirroringProfiles_button_cancel_posCss = "#trafficMirrorProfile_cancel span" #Cancel按钮
+
+
+#Profiles ssl decryption keyrings===================Profiles ssl decryption keyrings====================Profiles ssl decryption keyrings=================Profiles ssl decryption keyrings=======================Profiles ssl decryption keyrings
+#listPage->ssl decryption keyrings list page 列表页
+listPage_profile_sslDecryptionKeyrings_createButton_posId = "app_create-_OperateBtns_ElRow_Certificate_Keyrings_Home_App_anonymousComponent" #create按钮id
+listPage_profile_sslDecryptionKeyrings_editButton_posId = "appEdit-_OperateBtns_ElRow_Certificate_Keyrings_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_sslDecryptionKeyrings_delButton_posId = "appDel-_OperateBtns_ElRow_Certificate_Keyrings_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_sslDecryptionKeyrings_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_sslDecryptionKeyrings_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_sslDecryptionKeyrings_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_sslDecryptionKeyrings_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_sslDecryptionKeyrings_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_sslDecryptionKeyrings_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_sslDecryptionKeyrings_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_sslDecryptionKeyrings_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_sslDecryptionKeyrings_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create ssl decryption keyrings page 和 Edit ssl decryption keyrings page 新增和编辑页
+sslDecryptionKeyrings_input_Name_posId = "keyringsadd_name" #name输入框id
+sslDecryptionKeyrings_input_certificateFile_posXpath = "//*[@id='keyringsadd_file']/parent::*//input" #证书上传按钮xpath
+sslDecryptionKeyrings_radio_privateKeyFile_posId = "privateFile" #私钥单选按钮
+sslDecryptionKeyrings_radio_hsm_posId = "privateHSM" #私钥单选按钮
+sslDecryptionKeyrings_input_privateKeyFile_posXpath = "//*[@id='keyringsadd_file1']/parent::*//input" #证书上传按钮xpath
+sslDecryptionKeyrings_input_slotIdHSM_posId = "keyringsadd_slotid" #slot id输入框定位id
+sslDecryptionKeyrings_radio_mirrorServerCertificate_poId = "keyringsadd_default" #默认服务端证书时间单选按钮id
+sslDecryptionKeyrings_radio_customized_poId = "keyringsadd_customized" #自定义时间单选按钮id
+sslDecryptionKeyrings_input_customized_poId = "reissueExpiryDate" #自定义输入框id
+sslDecryptionKeyrings_input_certificateType_poId = "certificateType_input" #证书类型选择输入框id
+sslDecryptionKeyrings_dropdown_certificateTypeSelect_poId = "certificateType_select{replaceIndex}" #证书类型下拉列表item选择,replaceIndex为替换索引
+sslDecryptionKeyrings_input_publickKeyAlgorithm_poId = "keyringsadd_publicKeyAlgo" #公钥算法选择输入框id
+sslDecryptionKeyrings_dropdown_publickKeyAlgorithmSelect_poId = "keyringsadd_publicKeyAlgoSelet{replaceIndex}" #公钥算术下拉列表item选择,replaceIndex为替换索引
+sslDecryptionKeyrings_input_certificateRevocationList_poId = "keyringsadd_crl" #Certificate Revocation List输入框id
+sslDecryptionKeyrings_input_includeRoot_poXpath = "//*[@id='keyringsadd_includeRoot']/parent::*/span" #包含根证书输入框开关选择xpath
+sslDecryptionKeyrings_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+sslDecryptionKeyrings_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+sslDecryptionKeyrings_button_oK_posCss = "#keyringsadd_sub span" #OK按钮css
+sslDecryptionKeyrings_button_cancel_posCss = "#keyringsadd_info span" #Cancel按钮
+
+
+#Profiles ssl decryption profiles===================Profiles ssl decryption profiles====================Profiles ssl decryption profiles=================Profiles ssl decryption profiles=======================Profiles ssl decryption profiles
+#listPage->ssl decryption profiles list page 列表页
+listPage_profile_sslDecryptionProfiles_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_Decryption_Profile_Home_App_anonymousComponent" #create按钮id
+listPage_profile_sslDecryptionProfiles_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_Decryption_Profile_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_sslDecryptionProfiles_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_Decryption_Profile_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_sslDecryptionProfiles_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_sslDecryptionProfiles_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_sslDecryptionProfiles_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_sslDecryptionProfiles_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_sslDecryptionProfiles_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_sslDecryptionProfiles_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_sslDecryptionProfiles_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_sslDecryptionProfiles_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_sslDecryptionProfiles_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create ssl decryption profiles page 和 Edit ssl decryption profiles page 新增和编辑页
+sslDecryptionProfiles_input_Name_posId = "decrytion_profileName" #name输入框id
+sslDecryptionProfiles_switch_commonName_posXpath = "//*[@id='decryption-commenName']/parent::*" #common name 开关xpath
+sslDecryptionProfiles_switch_issuer_posXpath = "//*[@id='decryption-issuer']/parent::*" #issuer 开关xpath
+sslDecryptionProfiles_switch_selfSigned_posXpath = "//*[@id='decryption-signed']/parent::*" #decryption-signed 开关xpath
+sslDecryptionProfiles_switch_expiryDate_posXpath = "//*[@id='decryption-expiration']/parent::*" #ddecryption-expiration 开关xpath
+sslDecryptionProfiles_radio_failClose_posXpath = "//*[@id='decryptionfail-close']" #decryptionfail-close 点选按钮 Fail-close xpath
+sslDecryptionProfiles_radio_passThrough_posXpath = "//*[@id='decryptionpass-through']" #decryptionpass-through 点选按钮 Pass-through xpath
+sslDecryptionProfiles_switch_evCert_posXpath = "//*[@id='decryption-ev_cert']/parent::*" #ddecryption-expiration 开关xpath
+sslDecryptionProfiles_switch_certificateTransparency_posXpath = "//*[@id='decryption-cert_transparency']/parent::*" #Certificate Transparency 开关xpath
+sslDecryptionProfiles_switch_mutualAuthentication_posXpath = "//*[@id='decryption-client_cert_req']/parent::*" #Mutual Authentication 开关xpath
+sslDecryptionProfiles_switch_onProtocolErrors_posXpath = "//*[@id='decryption-protocol_errors']/parent::*" #On Protocol Errors 开关xpath
+sslDecryptionProfiles_switch_certificatePinning_posXpath = "//*[@id='decryption-pinning']/parent::*" #Certificate Pinning 开关xpath
+sslDecryptionProfiles_switch_certificateNotInstalled_posXpath = "//*[@id='decryption-Certificate_Not_Installed']/parent::*" #Certificate Not Installed 开关xpath
+sslDecryptionProfiles_switch_mirrorClientVersions_posXpath = "//*[@id='decryption-radio']/parent::*" #Mirror Client Versions 开关xpath
+sslDecryptionProfiles_input_minVersion_posXpath = "//*[@id='decryption-radio']/ancestor::div[@class='decryption_from']/div[2]//i" #Min Version 下拉菜单xpath
+sslDecryptionProfiles_dropDown_minVersion_posXpath = "//*[@id='pro_min{replaceIndex}']" #MMin Version 下拉列表中item选项定位 xpath。replaceIndex需要二次处理,替换为实际的索引。
+sslDecryptionProfiles_dropDown_maxVersion_posXpath = "//*[@id='pro_max{replaceIndex}']" #MMin Version 下拉列表中item选项定位 xpath。replaceIndex需要二次处理,替换为实际的索引。
+sslDecryptionProfiles_input_maxVersion_posXpath = "//*[@id='decryption-radio']/ancestor::div[@class='decryption_from']/div[3]//i" #Max Version 下拉菜单xpath
+sslDecryptionProfiles_switch_allowHTTP2_posXpath = "//*[@id='decryption-allow_http2']/parent::*" #Allow HTTP2 开关xpath
+sslDecryptionProfiles_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+slDecryptionProfiles_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+sslDecryptionProfiles_button_oK_posCss = "#decryption-ok span" #OK按钮css
+sslDecryptionProfiles_button_cancel_posCss = "#decryption-cancel span" #Cancel按钮
+
+
+#Profiles hijack files===================Profiles hijack files====================Profiles hijack files=================Profiles hijack files=======================Profiles hijack files
+#listPage->hijack files list page 列表页
+listPage_profile_hijackFiles_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_HijackFiles_Home_App_anonymousComponent" #create按钮id
+listPage_profile_hijackFiles_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_HijackFiles_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_hijackFiles_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_HijackFiles_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_hijackFiles_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_hijackFiles_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_hijackFiles_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_hijackFiles_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_hijackFiles_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_hijackFiles_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_hijackFiles_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_hijackFiles_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_hijackFiles_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create hijack files page 和 Edit hijack files page 新增和编辑页
+hijackFiles_input_Name_posId = "hijack_profileName" #name输入框id
+hijackFiles_input_fileUpLoad_posXpath = "//*[@id='uploadFile']/parent::*//input" #input 上传文件xpath
+hijackFiles_switch_downLoadName_posXpath = "//*[@id='contentNameChoose']/parent::*" #download name状态开关 xpath,点击操作其子元素改变状态
+hijackFiles_input_downLoadName_posXpath = "//*[@id='hijack_contentName']" #下载文件名称输入框 xpath
+hijackFiles_button_fileType_posXpath = "//*[@id='hijackAddContentType']" #添加文件类型按钮 xpath
+hijackFiles_tablist_fileType_posXpath = "//*[@class='right-show-edit']//span[normalize-space(text())='{replaceName}']" #右侧滑中type元素定位 xpath。需要二次处理,replaceName替换为类型名称
+hijackFiles_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+hijackFiles_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+hijackFiles_button_oK_posCss = "#hijackAddOk1 span" #OK按钮css
+hijackFiles_button_cancel_posCss = "#hijackAddCancel1 span" #Cancel按钮
+
+
+#Profiles insert scripts===================Profiles insert scripts====================Profiles insert scripts=================Profiles insert scripts=======================Profiles insert scripts
+#listPage->insert scripts list page 列表页
+listPage_profile_insertScripts_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_Insert_Home_App_anonymousComponent" #create按钮id
+listPage_profile_insertScripts_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_Insert_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_insertScripts_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_Insert_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_insertScripts_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_insertScripts_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_insertScripts_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_insertScripts_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_insertScripts_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_insertScripts_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_insertScripts_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_insertScripts_button_yes_posCss = listPage_dialogTips_dnsRecords_button_yes_posCss #删除提示的Tips的yes按钮
+listPage_dialogTips_insertScripts_button_no_posCss = listPage_dialogTips_dnsRecords_button_no_posCss #删除提示的Tips的close按钮
+#Create insert scripts page 和 Edit inserts script page 新增和编辑页
+insertScripts_input_Name_posId = "insert_profileName" #name输入框id
+hijackFiles_input_scriptUpLoad_posXpath = "/*[@id='insertAddUpload']//input" #input 上传文件xpath
+hijackFiles_input_scriptType_posXpath = "//*[@id='insert_select_format']" #input 文件类型选择xpath
+hijackFiles_dropdown_jsItem_posXpath = "//*[@id='insert_select_formatjs']" #下拉菜单 js选项 xpath
+hijackFiles_dropdown_cssItem_posXpath = "//*[@id='insert_select_formatcss']" #下拉菜单 js选项 xpath
+hijackFiles_input_insertPosition_posXpath = "//*[@id='insert_select_insertOn']" #input insert position xpath
+# todo
+hijackFiles_dropdown_cssItem_posXpath = "//*[@id='insert_select_formatcss']" #下拉菜单 js选项 xpath
+
+
+insertScripts_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存按钮警告框OK按钮
+insertScripts_button_warningSaveCancel_posCss = dnsRecordsProfilePage_button_warningSaveCancel_posCss #提示保存警告框Cancel按钮
+insertScripts_button_oK_posCss = "#hijackAddOk1 span" #OK按钮css
+insertScripts_button_cancel_posCss = "#hijackAddCancel1 span" #Cancel按钮
+
+
+#Profiles rofiles-Shaping=============Profiles rofiles-Shaping===================Profiles rofiles-Shaping====================Profiles rofiles-Shaping==================Profiles rofiles-Shaping==============Profiles rofiles-Shaping
+#Shaping Profiles list page 列表页
+listPage_profile_shapingProfiles_createButton_posId = "app_create-_OperateBtns_ElRow_Profile_ShapingProfile_Home_App_anonymousComponent" #create按钮id
+listPage_profile_shapingProfiles_editButton_posId = "appEdit-_OperateBtns_ElRow_Profile_ShapingProfile_Home_App_anonymousComponent" #edit按钮id
+listPage_profile_shapingProfiles_delButton_posId = "appDel-_OperateBtns_ElRow_Profile_ShapingProfile_Home_App_anonymousComponent" #del按钮id
+listPage_profileSearch_shapingProfiles_selectLabel_posId = mainPage_profileSearch_selectLabel_posId #查询框id 定位形式一样
+listPage_profileSearch_shapingProfiles_buttonSearch_posId = mainPage_profileSearch_buttonSearch_posId #查询按钮id 定位形式一样
+listPage_profileSearch_shapingProfiles_buttonClear_posId = mainPage_profileSearch_buttonClear_posId #清空查询按钮id 定位形式一样
+listPage_profileSearch_shapingProfiles_dropDown_item_posXpath = listPage_profileSearch_dnsRecords_dropDown_item_posXpath #下拉菜单定位 定位形式一样
+listPage_profileSearch_shapingProfiles_input_itemContent_posXpath = listPage_profileSearch_dnsRecords_input_itemContent_posXpath #输入item的值,replaceName替换实际查询值 定位形式一样
+listPage_profilTable_shapingProfiles_tableTbody_posXpath = listPage_profilTable_dnsRecords_tableTbody_posXpath #列表tabel body xpath 定位形式一样
+listPage_profilTable_shapingProfiles_tableHeader_posXpath = listPage_profilTable_dnsRecords_tableHeader_posXpath #列表table 表头xpath 定位形式一样
+#listPage->Tips dialog 列表页 tips对话框
+listPage_dialogTips_shapingProfiles_button_yes_posCss = "body>.el-dialog__wrapper .delComponents-ok span" #删除提示的Tips的yes按钮
+listPage_dialogTips_shapingProfiles_button_no_posCss = "body>.el-dialog__wrapper .delComponents-close span" #删除提示的Tips的close按钮
+#Create Shaping Profile 和 Edit Shaping Profile 新增和编辑页
+shapingProfilePage_input_Name_posId = "ShapingProfile_profileName" #name输入框id
+shapingProfilePage_radioButton_generic_posXpath = "//div[@id='shaping_Splitby-_ShapingProfile_write_Home_App_anonymousComponent']//span[normalize-space(text())='Generic']" #Generic单选按钮Xpath
+shapingProfilePage_radioButton_fairShare_posXpath = "//div[@id='shaping_Splitby-_ShapingProfile_write_Home_App_anonymousComponent']//span[normalize-space(text())='Fair Share']" #Fair Share单选按钮iXpath
+shapingProfilePage_radioButton_splitBy_posXpath = "//div[@id='shaping_Splitby-_ShapingProfile_write_Home_App_anonymousComponent']//span[normalize-space(text())='Split By']" #Split By单选按钮Xpath
+shapingProfilePage_radioButton_maxMinHostFairness_posXpath = "//div[@id='shaping_Splitby-_ShapingProfile_write_Home_App_anonymousComponent']//span[normalize-space(text())='Max Min Host Fairness']" #Max Min Host Fairness单选按钮Xpath
+shapingProfilePage_radioButton_localHost_posXpath = "//div[@id='shaping_Splitby-_ShapingProfile_write_Home_App_anonymousComponent']//span[normalize-space(text())='Local Host']" #Host Fairness单选按钮Xpath
+shapingProfilePage_inputSelect_unit_posId = "ShapingProfile-DirectionValue" #unit单位输入选择框id
+shapingProfilePage_drowDown_unitItem_posXpath = "//div[contains(@class, 'el-select-dropdown')]//li//span[normalize-space(text())='{replaceName}']" #unit的下拉item定位,replaceName替换实际查询值
+shapingProfilePage_input_incoming_posId = "ShapingProfile-Incoming" #incoming输入框 id
+shapingProfilePage_input_outgoing_posId = "ShapingProfile-Outgoing" #outgoing输入框 id
+shapingProfilePage_button_warningSaveYes_posCss = dnsRecordsProfilePage_button_warningSaveYes_posCss #提示保存警告框
+shapingProfilePage_button_oK_posCss = "#runScriptOk1 span" #OK按钮css
+shapingProfilePage_button_cancel_posCss = "#runScriptCancel1 span" #Cancel \ No newline at end of file
diff --git a/results/screenshot/2023-11-02-19-27-12.png b/results/screenshot/2023-11-02-19-27-12.png
new file mode 100644
index 00000000..f929d2e8
--- /dev/null
+++ b/results/screenshot/2023-11-02-19-27-12.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-09-45-41.png b/results/screenshot/2023-11-03-09-45-41.png
new file mode 100644
index 00000000..298ec851
--- /dev/null
+++ b/results/screenshot/2023-11-03-09-45-41.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-09-47-56.png b/results/screenshot/2023-11-03-09-47-56.png
new file mode 100644
index 00000000..64dd4db5
--- /dev/null
+++ b/results/screenshot/2023-11-03-09-47-56.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-09-47-58.png b/results/screenshot/2023-11-03-09-47-58.png
new file mode 100644
index 00000000..962524e6
--- /dev/null
+++ b/results/screenshot/2023-11-03-09-47-58.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-09-49-25.png b/results/screenshot/2023-11-03-09-49-25.png
new file mode 100644
index 00000000..3690ca17
--- /dev/null
+++ b/results/screenshot/2023-11-03-09-49-25.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-09-49-28.png b/results/screenshot/2023-11-03-09-49-28.png
new file mode 100644
index 00000000..95e244f3
--- /dev/null
+++ b/results/screenshot/2023-11-03-09-49-28.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-11-48-06.png b/results/screenshot/2023-11-03-11-48-06.png
new file mode 100644
index 00000000..8bdee02c
--- /dev/null
+++ b/results/screenshot/2023-11-03-11-48-06.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-14-27-31.png b/results/screenshot/2023-11-03-14-27-31.png
new file mode 100644
index 00000000..d733ddcd
--- /dev/null
+++ b/results/screenshot/2023-11-03-14-27-31.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-14-47-01.png b/results/screenshot/2023-11-03-14-47-01.png
new file mode 100644
index 00000000..6fb073ec
--- /dev/null
+++ b/results/screenshot/2023-11-03-14-47-01.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-18-09-46.png b/results/screenshot/2023-11-03-18-09-46.png
new file mode 100644
index 00000000..f6d63b71
--- /dev/null
+++ b/results/screenshot/2023-11-03-18-09-46.png
Binary files differ
diff --git a/results/screenshot/2023-11-03-18-10-48.png b/results/screenshot/2023-11-03-18-10-48.png
new file mode 100644
index 00000000..d7ff1286
--- /dev/null
+++ b/results/screenshot/2023-11-03-18-10-48.png
Binary files differ
diff --git a/temp/tess1.py b/temp/tess1.py
new file mode 100644
index 00000000..cc02472c
--- /dev/null
+++ b/temp/tess1.py
@@ -0,0 +1,16 @@
+a = "172.16.70.1"
+
+for i in range(1, 256):
+ a = "172.16.71.{}/index*".format(i)
+ print(a)
+
+
+b = "http://www.yumi.com/\n"
+#print(b*30)
+
+c = "kafka-operation.sh consumer-begin OBJECT-STATISTICS-METRIC"
+d = "kafka-operation.sh comsumer-begin OBJECT-STATISTICS-METRIC"
+
+print(c == d)
+
+print("ssds{}".format([12,233,44])) \ No newline at end of file
diff --git a/temp/test4.py b/temp/test4.py
new file mode 100644
index 00000000..d325049e
--- /dev/null
+++ b/temp/test4.py
@@ -0,0 +1,124 @@
+import requests
+import json
+a = """
+191053
+191053
+191061
+191061
+191069
+191069
+191077
+191077
+191101
+191101
+191109
+191109
+191117
+191117
+191125
+191125
+191133
+191133
+191141
+191141
+191149
+191149
+191157
+191157
+191165
+191165
+191173
+191173
+191181
+191181
+191189
+191189
+191197
+191197
+191205
+191205
+191213
+191213
+191221
+191221
+191229
+191229
+191237
+191237
+191245
+191245
+191253
+191253
+191261
+191261
+191269
+191269
+191277
+191277
+191293
+191293
+191301
+191301
+191311
+191311
+191317
+191317
+191325
+191325
+191333
+191333
+191341
+191341
+191349
+191349
+191357
+191357
+191365
+191365
+191373
+191373
+191381
+191381
+191391
+191391
+191409
+191409
+191413
+191413
+191421
+191421
+191429
+191429"""
+#print(a)
+b = a.split()
+c = ",".join(b)
+#print(b)
+#print(c)
+
+req_header = {
+ "Content-Type":"application/x-www-form-urlencoded"
+}
+data = {
+ "username": "zcw",
+ "password": "rmj7HMJYgTq9KlZyhOGj4Q=="
+}
+r_login = requests.post(url="http://192.168.44.72/v1/user/login", headers=req_header, data=data)
+
+token = r_login.json()["data"]["token"]
+print(token)
+
+del_header = {
+ "Content-Type": "application/json",
+ "Authorization": token
+}
+del_data_json = {
+ "refuseCode": "true",
+ "objectIds": b,
+ "objectType": "apn",
+ "vsysId": 1
+}
+del_data = json.dumps(del_data_json)
+
+r_del = requests.delete(url="http://192.168.44.72/v1/policy/object", headers=del_header, data=del_data)
+print(r_del.status_code)
+print(r_del.text) \ No newline at end of file
diff --git a/testdata/demo1_data.json b/testdata/demo1_data.json
new file mode 100644
index 00000000..0dfde25f
--- /dev/null
+++ b/testdata/demo1_data.json
@@ -0,0 +1,15 @@
+{
+ "item":
+ [
+ {
+ "a": 1,
+ "b": 2,
+ "expect": 3
+ },
+ {
+ "a": 3,
+ "b": 4,
+ "expect": 7
+ }
+ ]
+}
diff --git a/testdata/json_data.json b/testdata/json_data.json
new file mode 100644
index 00000000..ffdd918f
--- /dev/null
+++ b/testdata/json_data.json
@@ -0,0 +1,31 @@
+{
+ "item":
+ [
+ {
+ "request":
+ {
+ "url": "http://192.168.44.72/v1/user/login",
+ "body":
+ {
+ "id":"111",
+ "username": "zcw",
+ "password": "Gg1Etyh7fs1y/v/K2XOJDg=="
+ }
+ },
+ "response":"true"
+ },
+ {
+ "request":
+ {
+ "url": "http://192.168.44.72/v1/user/login",
+ "body":
+ {
+ "id":"222",
+ "username": "zcw3",
+ "password": "Gg1Etyh7fs1y/v/K2XOJDg=="
+ }
+ },
+ "response":"true"
+ }
+ ]
+} \ No newline at end of file
diff --git a/testdata/ui_data/__init__.py b/testdata/ui_data/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_data/__init__.py
diff --git a/testdata/ui_data/profiles_data/DoS_detection_profiles.json b/testdata/ui_data/profiles_data/DoS_detection_profiles.json
new file mode 100644
index 00000000..bc969470
--- /dev/null
+++ b/testdata/ui_data/profiles_data/DoS_detection_profiles.json
@@ -0,0 +1,16 @@
+{
+ "comment": "shaping_profiles参数注解:item中为参数驱动测试,model可选为modify。'->'为创建修改数据分隔符,前为创建数据,后为修改数据。unit分隔符后为空则只创建数据,例如’bps->‘、'543->'。unit分隔符后非空,修改数据。544->表示不修改、654->456表示修改前后数据。",
+ "item":
+ [
+ {
+ "ids": "创建Generic_bps用例",
+ "model": "create",
+ "attack_type": "DNS Flood->",
+ "target_IPs": [
+ "1.1.1.1->"
+ ],
+ "packet_second": "0->",
+ "bits_second": "0->"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/__init__.py b/testdata/ui_data/profiles_data/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_data/profiles_data/__init__.py
diff --git a/testdata/ui_data/profiles_data/dns_records.json b/testdata/ui_data/profiles_data/dns_records.json
new file mode 100644
index 00000000..801ac7b7
--- /dev/null
+++ b/testdata/ui_data/profiles_data/dns_records.json
@@ -0,0 +1,184 @@
+{
+ "comment": "dns_records参数注解:item中为参数驱动测试,model可选为create、modify。type可选为A、AAAA、CNAME 。如果model=modify,例如:modify.'12.12.12.12->34.45.67.54'表示修改前后数据,'->'为前后数据分隔符。在修改中,分隔符前为空表示新增数据。分隔符后为空表示删除数据。其它同理。",
+ "item":
+ [
+ {
+ "ids": "创建单个类型A用例",
+ "model": "create",
+ "type": "A",
+ "values":
+ [
+ "45.23.122.223"
+ ],
+ "description": "test-description45.23.122.223"
+ },
+ {
+ "ids": "创建单个类型A再修改为A用例",
+ "model": "modify",
+ "type": "A->A",
+ "values":
+ [
+ "145.223.172.243->32.124.176.43"
+ ],
+ "description": "test-description32.124.176.43"
+ },
+ {
+ "ids": "创建多个类型A用例",
+ "model": "create",
+ "type": "A",
+ "values":
+ [
+ "2.2.2.2",
+ "3.3.3.3",
+ "4.4.4.4"
+ ],
+ "description": "test-description"
+ },
+ {
+ "ids": "创建多个类型A,再修改为多个类型A用例",
+ "model": "modify",
+ "type": "A->A",
+ "values":
+ [
+ "12.12.12.12->34.45.67.54",
+ "13.13.31.13->",
+ "->65.123.34.56",
+ "14.14.14.41->56.43.46.64",
+ "->165.123.134.56"
+ ],
+ "description": "test-description->tesst modify desc"
+ },
+ {
+ "ids": "创建单个类型AAAA用例",
+ "model": "create",
+ "type": "AAAA",
+ "values":
+ [
+ "32:12aa::34cd"
+ ],
+ "description": "test-32:12aa::34cd"
+ },
+ {
+ "ids": "创建单个类型AAAA,再修改为AAAA用例",
+ "model": "modify",
+ "type": "AAAA->AAAA",
+ "values":
+ [
+ "32:12aa::34cd->1231:3452:5643::aa"
+ ],
+ "description": "test-1231:3452:5643::aa"
+ },
+ {
+ "ids": "创建多个类型AAAA用例",
+ "model": "create",
+ "type": "AAAA",
+ "values":
+ [
+ "32:12aa::34cd",
+ "4265:5688:3345::4325:4456",
+ "1234::3456:53aa"
+ ],
+ "description": "test-sa14265:5688:3345::4325:4456"
+ },
+ {
+
+ "ids": "创建多类型AAAA,再修改为AAAA用例",
+ "model": "modify",
+ "type": "AAAA->AAAA",
+ "values":
+ [
+ "3322:12aa::34cd->1231:3452:5643::aa",
+ "3252:123a::347d->",
+ "3352:127a::844d->1231:3752:9643::86aa",
+ "->1431:7652:5333::64aa"
+ ],
+ "description": "test-ssa1231:3752:9643::86aa"
+ },
+ {
+ "ids": "创建单个类型CNAME用例",
+ "model": "create",
+ "type": "CNAME",
+ "values":
+ [
+ "test.sds.asd.com"
+ ],
+ "description": "test-test.sds.asd.com"
+ },
+ {
+ "ids": "创建单个类型CNAME,再修改为CNAME用例",
+ "model": "modify",
+ "type": "CNAME->CNAME",
+ "values":
+ [
+ "test.sttds.adssd.com->test.sda.ddss.gec.cn"
+ ],
+ "description": "test-test.sda.ddss.gec.cn"
+ },
+ {
+ "ids": "创建多个类型CNAME用例",
+ "model": "create",
+ "type": "CNAME",
+ "values":
+ [
+ "test.sttds.adssd.com",
+ "test.sttsdssds.addfeessd.com",
+ "test.sttee2wads.adsssssd.com"
+ ],
+ "description": "test-sa1test.sttee2wads.adsssssd.com"
+ },
+ {
+ "ids": "创建多类型CNAME,再修改为CNAME用例",
+ "model": "modify",
+ "type": "CNAME->CNAME",
+ "values":
+ [
+ "->test.sddsg.sdsssdd.fco.cn",
+ "test.ssdsdssds.addsd.com->test.sdgoc.sdwa.caom.com",
+ "->test.sddsg.sdsd.fcfgo.cn",
+ "test.sassdo.caom.com->",
+ "test.sdoas.comada.com->test.sodmao.asdo.com",
+ "->test.sddsg.sdsd.fco.cn"
+ ],
+ "description": "test-est.sddsg.sdsd.fco.cn"
+ },
+ {
+ "ids": "创建多类型A,再修改为CNAME用例",
+ "model": "modify",
+ "type": "A->CNAME",
+ "values":
+ [
+ "112.12.32.12->test.sdgoc.sdwa.caom.com",
+ "53.23.234.21->",
+ "12.12.33.45->test.sodmao.asdo.com",
+ "->test.sddsg.sdsd.fco.cn"
+ ],
+ "description": "12.12.33.45->test.sodmao.asdo.com"
+ },
+ {
+ "ids": "创建多类型CNAME,再修改为CNAME用例",
+ "model": "modify",
+ "type": "AAAA->CNAME",
+ "values":
+ [
+ "42::4532:2234->test.sdgoc.sdwa.caom.com",
+ "5342:5322:3234::3213->",
+ "aa11:3214::4521->test.sodmao.asdo.com",
+ "->test.sddsg.sdsd.fco.cn"
+ ],
+ "description": "test-aa11:3214::4521->test.sodmao.asdo.com"
+ },
+ {
+ "ids": "创建多类型CNAME,再修改为A用例",
+ "model": "modify",
+ "type": "CNAME->A",
+ "values":
+ [
+ "test.ssdsdssds.addsd.com->23.42.234.12",
+ "test.sassdo.caom.com->",
+ "test.sdoas.comada.com->53.65.156.176",
+ "->12.45.168.123"
+ ],
+ "description": "test-est.test.sdoas.comada.com->53.65.156.176"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/hijack_files.json b/testdata/ui_data/profiles_data/hijack_files.json
new file mode 100644
index 00000000..d65f9b0c
--- /dev/null
+++ b/testdata/ui_data/profiles_data/hijack_files.json
@@ -0,0 +1,49 @@
+{
+ "comment": "标识符'->'参数注解:model可选参数create、modify。标识符'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:16->7:表示创建及修改;18->不修改:表示只创建不修改;18->删除:表示删除;->18:表示修改为新增(创建时不输入)",
+ "comment2": "1.file:文件名称。2.download_name in (Mirror Server Response, 或者其它输入内容)。3.file_type in (gif,jpeg,png,svg+xml,exe,apk,html)",
+ "item":
+ [
+ {
+ "ids": "创建gif类型hijack_files数据",
+ "model": "create",
+ "file": "test_gif_1.gif->",
+ "download_name": "Mirror Server Response->",
+ "file_type": "gif->"
+ },
+ {
+ "ids": "创建gif类型hijack_files数据再修改数据gif数据",
+ "model": "modify",
+ "file": "test_gif_1.gif->test_gif_2.gif",
+ "download_name": "test_gif_1.gif->Mirror Server Response",
+ "file_type": "gif->不修改"
+ },
+ {
+ "ids": "创建jpeg类型hijack_files数据",
+ "model": "create",
+ "file": "test_jpeg_1.jpeg->",
+ "download_name": "test_jpeg_1.jpeg->",
+ "file_type": "jpeg->"
+ },
+ {
+ "ids": "创建png类型hijack_files数据再修改数据svg+xml数据",
+ "model": "modify",
+ "file": "test_png_1.png->test_svg_1.svg",
+ "download_name": "test_png_1.gif->name_test_svg_1.svg",
+ "file_type": "png->svg+xml"
+ },
+ {
+ "ids": "创建exe类型hijack_files数据",
+ "model": "create",
+ "file": "test_exe_1.exe->",
+ "download_name": "test_name_exe_1.exe->",
+ "file_type": "exe->"
+ },
+ {
+ "ids": "创建apk类型hijack_files数据再修改数据html数据",
+ "model": "modify",
+ "file": "test_apk_1.apk->test_html_1.html",
+ "download_name": "Mirror Server Response->不修改",
+ "file_type": "apk->html"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/insert_scripts.json b/testdata/ui_data/profiles_data/insert_scripts.json
new file mode 100644
index 00000000..fab53d86
--- /dev/null
+++ b/testdata/ui_data/profiles_data/insert_scripts.json
@@ -0,0 +1,21 @@
+{
+ "comment": "标识符'->'参数注解:model可选参数create、modify。标识符'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:16->7:表示创建及修改;18->不修改:表示只创建不修改;18->删除:表示删除;->18:表示修改为新增(创建时不输入)",
+ "comment2": "1.script:文件名称。2.script_type in (js, css)。3.insert_position in (After Page Load, Before Page Load)",
+ "item":
+ [
+ {
+ "ids": "创建js类型insert_files数据11",
+ "model": "create",
+ "script": "test_js_1.js->",
+ "script_type": "js->",
+ "insert_position": "After Page Load->"
+ },
+ {
+ "ids": "创建css类型css数据22",
+ "model": "create",
+ "script": "test_css_1.css->",
+ "script_type": "css->",
+ "insert_position": "->"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/response_pages.json b/testdata/ui_data/profiles_data/response_pages.json
new file mode 100644
index 00000000..606a0f17
--- /dev/null
+++ b/testdata/ui_data/profiles_data/response_pages.json
@@ -0,0 +1,17 @@
+{
+ "comment": "Resposne_pages参数注解,model可选参数create、modify。file中'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:testa.html->表示只创建数据、testa.html->testb.html表示创建和修改数据。",
+
+ "item":
+ [
+ {
+ "ids": "创建respose_page文件11",
+ "model": "create",
+ "file": "testa.html->"
+ },
+ {
+ "ids": "创建respose_page文件再修改",
+ "model": "modify",
+ "file": "testa.html->testb.html"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/shaping_profiles.json b/testdata/ui_data/profiles_data/shaping_profiles.json
new file mode 100644
index 00000000..d94dc3fa
--- /dev/null
+++ b/testdata/ui_data/profiles_data/shaping_profiles.json
@@ -0,0 +1,69 @@
+{
+ "comment": "shaping_profiles参数注解:item中为参数驱动测试,model可选为modify。'->'为创建修改数据分隔符,前为创建数据,后为修改数据。unit分隔符后为空则只创建数据,例如’bps->‘、'543->'。unit分隔符后非空,修改数据。544->表示不修改、654->456表示修改前后数据。",
+ "item":
+ [
+ {
+ "ids": "创建Generic_bps用例",
+ "model": "create",
+ "type": "Generic",
+ "argument": "",
+ "unit": "bps->",
+ "incoming": "0->",
+ "outgoing": "0->"
+ },
+ {
+ "ids": "创建Generic_bps用例",
+ "model": "create",
+ "type": "Generic",
+ "argument": "",
+ "unit": "bps->",
+ "incoming": "876->",
+ "outgoing": "543->"
+ },
+ {
+ "ids": "创建Fair_Share_Kbps用例",
+ "model": "create",
+ "type": "Fair Share",
+ "argument": "Max Min Host Fairness",
+ "unit": "Kbps->",
+ "incoming": "345->",
+ "outgoing": "678->"
+ },
+ {
+ "ids": "创建Split_By_Mbps用例",
+ "model": "create",
+ "type": "Split By",
+ "argument": "Local Host",
+ "unit": "Mbps->",
+ "incoming": "678->",
+ "outgoing": "565->"
+ },
+ {
+ "ids": "创建Generic_Gbps再修改为bps带宽",
+ "model": "modify",
+ "type": "Generic",
+ "argument": "",
+ "unit": "Gbps->bps",
+ "incoming": "500->876",
+ "outgoing": "800->543"
+ },
+ {
+ "ids": "创建Fair_Share_bps再修改为Gps带宽",
+ "model": "modify",
+ "type": "Fair Share",
+ "argument": "Max Min Host Fairness",
+ "unit": "bps->Gbps",
+ "incoming": "670->856",
+ "outgoing": "550->543"
+ },
+ {
+ "ids": "创建Split_By_Mps再修改为Mps带宽",
+ "model": "modify",
+ "type": "Split By",
+ "argument": "Local Host",
+ "unit": "Mbps->Mbps",
+ "incoming": "640->576",
+ "outgoing": "250->533"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/ssl_decryption_keyrings.json b/testdata/ui_data/profiles_data/ssl_decryption_keyrings.json
new file mode 100644
index 00000000..01623df2
--- /dev/null
+++ b/testdata/ui_data/profiles_data/ssl_decryption_keyrings.json
@@ -0,0 +1,63 @@
+{
+ "comment": "标识符'->'参数注解:model可选参数create、modify。标识符'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:16->7:表示创建及修改;18->不修改:表示只创建不修改",
+ "comment2": "可选值参考certificate和private_key为文件名称。private_key=‘HSM-***’表示选择HSM格式,private_key=‘PKF-***’上次key文件名称。reissue_expiry_hours=‘MSC’表示默认时间,reissue_expiry_hours=‘C-***表示自定义时间’",
+ "comnent3": "可选值参考:type in (Root-Certificate,Intermediate-Certificate,End-entity)。 public_key_algorithm in (RSA-1024,RSA-2048,SECP-256r1,SECP-384r1)。 include_root in (on,off)",
+ "item":
+ [
+ {
+ "ids": "创建root_根证书PKA设置为RSA-20481",
+ "model": "create",
+ "certificate": "test_root_cert_catest.cer->",
+ "private_key": "PKF-test_root_key_catest.key->",
+ "reissue_expiry_hours": "MSC->",
+ "type": "Root-Certificate->",
+ "public_key_algorithm": "RSA-2048->",
+ "certificate_revocation_list": "http://www.example.ABCD.com->",
+ "include_root": "off->"
+ },
+ {
+ "ids": "创建root_根证书PKA设置为RSA-2048只修改PKA为SECP-384r1",
+ "model": "modify",
+ "certificate": "test_root_cert_catest.cer->不修改",
+ "private_key": "PKF-test_root_key_catest.key->不修改",
+ "reissue_expiry_hours": "MSC->不修改",
+ "type": "Root-Certificate->不修改",
+ "public_key_algorithm": "RSA-2048->SECP-384r1",
+ "certificate_revocation_list": "http://www.example.ABCD.com->不修改",
+ "include_root": "on->off"
+ },
+ {
+ "ids": "创建root_根证书PKA设置为RSA-2048再修改为中间证书PKA设置为RSA-10243",
+ "model": "modify",
+ "certificate": "test_root_cert_catest.cer->test_mid_cert_camiddletest.chain.pem",
+ "private_key": "PKF-test_root_key_catest.key->PKF-test_mid_key_camiddletest.key",
+ "reissue_expiry_hours": "MSC->C-120",
+ "type": "Root-Certificate->Intermediate-Certificate",
+ "public_key_algorithm": "RSA-2048->RSA-1024",
+ "certificate_revocation_list": "->不修改",
+ "include_root": "on->off"
+ },
+ {
+ "ids": "创建mid_中间书PKA设置为SECP-256r1再修改为实体证书PKA设置为SECP-384r1",
+ "model": "modify",
+ "certificate": "test_mid_cert_camiddletest.chain.pem->test_end_cert_caentitytest.chain.pem",
+ "private_key": "PKF-test_mid_key_camiddletest.key->PKF-test_end_keycaentitytest.key",
+ "reissue_expiry_hours": "C400->C-320",
+ "type": "Intermediate-Certificate->End-entity",
+ "public_key_algorithm": "SECP-256r1->SECP-384r1",
+ "certificate_revocation_list": "http://www.example.ABCD.cn.cmo->http://www.TESTAA.abcd.cn.cmo",
+ "include_root": "on->off"
+ },
+ {
+ "ids": "创建mid_中间证书PKA设置为SECP-256r1私钥为HSM",
+ "model": "create",
+ "certificate": "test_mid_cert_camiddletest.chain.pem->",
+ "private_key": "HSM-453->",
+ "reissue_expiry_hours": "MSC->",
+ "type": "Intermediate-Certificate->",
+ "public_key_algorithm": "RSA-2048->",
+ "certificate_revocation_list": "http://www.www.ww->",
+ "include_root": "off->"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/ssl_decryption_profiles.json b/testdata/ui_data/profiles_data/ssl_decryption_profiles.json
new file mode 100644
index 00000000..a8ab38ab
--- /dev/null
+++ b/testdata/ui_data/profiles_data/ssl_decryption_profiles.json
@@ -0,0 +1,64 @@
+{
+ "comment": "标识符'->'参数注解:model可选参数create、modify。标识符'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:16->7:表示创建及修改;18->不修改:表示只创建不修改;18->删除:表示删除;->18:表示修改为新增(创建时不输入)",
+ "comment2": "开关的取值为:1.on、off。2.fail_action in (Fail-close,Pass-through)。3.min_client_version、max_client_version in (SSLv3.0,TLSv1.0,TLSv1.1,TLSv1.2,TLSv1.3)",
+ "item":
+ [
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on11",
+ "model": "create",
+ "common_name":"on->",
+ "issuer":"off->",
+ "self_signed":"off->",
+ "expiry_date":"on->",
+ "fail_action":"Pass-through->",
+ "ev_certificate":"on->",
+ "certificate_transparency":"on->",
+ "mutual_authentication":"on->",
+ "protocol_errors":"on->",
+ "certificate_pinning":"on->",
+ "certificate_not_installed":"on->",
+ "mirror_client_versions":"off->",
+ "min_client_version":"TLSv1.0->",
+ "max_client_version":"TLSv1.2->",
+ "allow_HTTP2":"off->"
+ },
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on再修改common_name_off22",
+ "model": "modify",
+ "common_name":"on->off",
+ "issuer":"on-off>",
+ "self_signed":"on->不修改",
+ "expiry_date":"on->不修改",
+ "fail_action":"Pass-through->不修改",
+ "ev_certificate":"on->off",
+ "certificate_transparency":"on->不修改",
+ "mutual_authentication":"on->不修改",
+ "protocol_errors":"on->不修改",
+ "certificate_pinning":"on->off",
+ "certificate_not_installed":"on->",
+ "mirror_client_versions":"off->off",
+ "min_client_version":"TLSv1.2->不修改",
+ "max_client_version":"TLSv1.3->不修改",
+ "allow_HTTP2":"off->on"
+ },
+ {
+ "ids": "创建ssl_decryption_profiles_fail_action_on33",
+ "model": "create",
+ "common_name":"on->",
+ "issuer":"on->",
+ "self_signed":"on->",
+ "expiry_date":"on->",
+ "fail_action":"Pass-through->",
+ "ev_certificate":"off->",
+ "certificate_transparency":"off->",
+ "mutual_authentication":"on->",
+ "protocol_errors":"on->",
+ "certificate_pinning":"on->",
+ "certificate_not_installed":"off->",
+ "mirror_client_versions":"on->",
+ "min_client_version":"TLSv1.0->",
+ "max_client_version":"TLSv1.2->",
+ "allow_HTTP2":"on->"
+ }
+ ]
+}
diff --git a/testdata/ui_data/profiles_data/traffic_mirroring_profiles.json b/testdata/ui_data/profiles_data/traffic_mirroring_profiles.json
new file mode 100644
index 00000000..934c3a04
--- /dev/null
+++ b/testdata/ui_data/profiles_data/traffic_mirroring_profiles.json
@@ -0,0 +1,44 @@
+{
+ "comment": "traffic mirroring profiles参数注解,model可选参数create、modify。vlan_id为列表参数,标识符'->'为前后数据分隔符,分隔符前为创建数据,后为修改数据。例如:16->7:表示创建及修改;18->:表示只创建不修改;->23:表示修改中新增",
+
+ "item":
+ [
+ {
+ "ids": "创建traffic_mirroring_profiles_多vlanid",
+ "model": "create",
+ "vlan_id":
+ [
+ "6->",
+ "58->"
+ ]
+ },
+ {
+ "ids": "创建vlanid再修改",
+ "model": "modify",
+ "vlan_id":
+ [
+ "16->7",
+ "18->",
+ "->23",
+ "25->45",
+ "55->55"
+ ]
+ },
+ {
+ "ids": "创建一个vlanid",
+ "model": "create",
+ "vlan_id":
+ [
+ "35->"
+ ]
+ },
+ {
+ "ids": "创建一个vlanid再修改",
+ "model": "create",
+ "vlan_id":
+ [
+ "45->25"
+ ]
+ }
+ ]
+}
diff --git a/testdata/ui_file/__init__.py b/testdata/ui_file/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/__init__.py
diff --git a/testdata/ui_file/profiles/__init__.py b/testdata/ui_file/profiles/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/profiles/__init__.py
diff --git a/testdata/ui_file/profiles/hijack_files/__init__.py b/testdata/ui_file/profiles/hijack_files/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/__init__.py
diff --git a/testdata/ui_file/profiles/hijack_files/test_apk_1.apk b/testdata/ui_file/profiles/hijack_files/test_apk_1.apk
new file mode 100644
index 00000000..c96c8ce8
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_apk_1.apk
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_exe_1.exe b/testdata/ui_file/profiles/hijack_files/test_exe_1.exe
new file mode 100644
index 00000000..e33f7250
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_exe_1.exe
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_gif_1.gif b/testdata/ui_file/profiles/hijack_files/test_gif_1.gif
new file mode 100644
index 00000000..8a8d19e6
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_gif_1.gif
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_gif_2.gif b/testdata/ui_file/profiles/hijack_files/test_gif_2.gif
new file mode 100644
index 00000000..042ac791
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_gif_2.gif
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_html_1.html b/testdata/ui_file/profiles/hijack_files/test_html_1.html
new file mode 100644
index 00000000..9cee60cd
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_html_1.html
@@ -0,0 +1,185 @@
+<html>
+<head>
+ <title>新建网页</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta name="description" content=""/>
+ <meta name="keywords" content=""/>
+
+ <script type="text/javascript">
+ //① 绘制地图
+ function Map() {
+ //私有成员(不会随便发生变化)
+ var w = 800;
+ var h = 400;
+
+ //成员方法,绘制地图
+ this.showmap = function () {
+ //创建div、设置css样式、追加给body
+ var tu = document.createElement('div');
+
+ tu.style.width = w + "px";
+ tu.style.height = h + "px";
+ tu.style.backgroundImage = "url(./12.jpg)";
+
+ document.body.appendChild(tu);
+ }
+ }
+
+ //② 绘制食物
+ function Food() {
+ var len = 20;
+ //把食物(权值)坐标声明为公开的,以便在外部访问
+ this.xFood = 0;
+ this.yFood = 0;
+ this.piece = null; //页面上唯一的食物对象
+ //绘制
+ this.showfood = function () {
+ //创建div、设置css样式、追加给body
+ if (this.piece === null) {
+ this.piece = document.createElement('div');
+ this.piece.style.width = this.piece.style.height = len + "px";
+ this.piece.style.backgroundColor = "green";
+ this.piece.style.position = "absolute";
+
+ document.body.appendChild(this.piece);
+ }
+ //食物设置绝对定位(position/left/top)
+ //食物位置“随机”摆放
+ //移动步进值:20px
+ //食物“权值”坐标: X轴(0-39) Y轴(0-19)
+ //食物真实坐标:权值坐标 * 步进值
+ this.xFood = Math.floor(Math.random() * 40); //0-39的随机数
+ this.yFood = Math.floor(Math.random() * 20); //0-19的随机数
+
+ this.piece.style.left = this.xFood * len + "px";
+ this.piece.style.top = this.yFood * len + "px";
+
+ }
+ }
+
+ //③ 小蛇
+ function Snake() {
+ var len = 20;
+ this.redirect = "right"; //默认向右边移动
+ //后期snakebody要变化,因此声明为公开的(每个蛇节:[x坐标,y坐标,颜色,蛇节对象])
+ this.snakebody = [[0, 1, 'green', null], [1, 1, 'green', null], [2, 1, 'green', null], [3, 1, 'red', null]];
+ //a.绘制小蛇
+ this.showsnake = function () {
+ //遍历小蛇的各个蛇节,并依次创建即可
+ for (var i = 0; i < this.snakebody.length; i++) {
+ //this.snakebody[i]//代表每个蛇节
+ //创建蛇节div
+ if (this.snakebody[i][3] === null) {//判断没有创建对应的蛇节
+ this.snakebody[i][3] = document.createElement('div');
+ //设置css样式(宽度、高度、颜色)
+ this.snakebody[i][3].style.width = this.snakebody[i][3].style.height = len + "px";
+ this.snakebody[i][3].style.backgroundColor = this.snakebody[i][2];
+ //绝对定位及位置
+ this.snakebody[i][3].style.position = "absolute";
+ //把蛇节追加给body
+ document.body.appendChild(this.snakebody[i][3]);
+ }
+ this.snakebody[i][3].style.left = this.snakebody[i][0] * len + "px";
+ this.snakebody[i][3].style.top = this.snakebody[i][1] * len + "px";
+ }
+ }
+
+ //b.移动小蛇
+ this.movesnake = function () {
+ //非蛇头蛇节(当前蛇节的新坐标 是"下个蛇节"的旧坐标)
+ for (var i = 0; i < this.snakebody.length - 1; i++) {
+ this.snakebody[i][0] = this.snakebody[i + 1][0];
+ this.snakebody[i][1] = this.snakebody[i + 1][1];
+ }
+ if (this.redirect == "right") {
+ //蛇头x坐标递增
+ this.snakebody[this.snakebody.length - 1][0] += 1;
+ }
+ if (this.redirect == "left") {
+ //蛇头x坐标递减
+ this.snakebody[this.snakebody.length - 1][0] -= 1;
+ }
+ if (this.redirect == "up") {
+ //蛇头y坐标递减
+ this.snakebody[this.snakebody.length - 1][1] -= 1;
+ }
+ if (this.redirect == "down") {
+ //蛇头y坐标递增
+ this.snakebody[this.snakebody.length - 1][1] += 1;
+ }
+
+ //判断蛇头碰到食物
+ //蛇头坐标
+ var xSnake = this.snakebody[this.snakebody.length - 1][0];
+ var ySnake = this.snakebody[this.snakebody.length - 1][1];
+ //食物坐标food.xFood/food.yFood;
+ if (xSnake == food.xFood && ySnake == food.yFood) {
+ //吃食物增加蛇节
+ var newjie = [this.snakebody[0][0], this.snakebody[0][1], 'green', null];
+ this.snakebody.unshift(newjie);//把newjie放到数组的第一个位置去
+
+ //原食物消失,重新生成一个食物
+ food.showfood();
+ }
+
+ //控制小蛇在地图范围内移动
+ if (xSnake < 0 || xSnake > 39 || ySnake < 0 || ySnake > 19) {
+ alert('game over');
+ clearInterval(mytime);
+ return false;
+ }
+ //吃到自己判断(蛇头坐标与其他蛇节坐标一致)
+ for (var k = 0; k < this.snakebody.length - 1; k++) {
+ if (this.snakebody[k][0] == xSnake && this.snakebody[k][1] == ySnake) {
+ alert('game over kill you by yourself');
+ clearInterval(mytime);
+ return false;
+ }
+ }
+
+ //根据新坐标绘制小蛇
+ this.showsnake();
+ }
+ }
+
+ window.onload = function () {
+ var map = new Map();
+ map.showmap();
+
+ food = new Food();//声明为全局的以便在该加载事件函数外部访问
+ food.showfood();
+
+ snake = new Snake();//声明为全局的snake对象
+ snake.showsnake();
+
+ //移动小蛇
+ //setInterval(全局变量,时间)
+ mytime = setInterval("snake.movesnake()", 200);
+
+ //设置键盘事件,控制器小蛇移动方向
+ document.onkeydown = function (evt) {
+ var num = evt.keyCode;//通过事件对象获得数值码,进而知道被触发键子
+ if (num == 38) {
+ snake.redirect = "up";
+ }
+ if (num == 40) {
+ snake.redirect = "down";
+ }
+ if (num == 37) {
+ snake.redirect = "left";
+ }
+ if (num == 39) {
+ snake.redirect = "right";
+ }
+ }
+ }
+ </script>
+<!--
+ <style type="text/css">
+ body {
+ margin: 0;
+ }
+ </style> -->
+</head>
+<body></body>
+</html>
diff --git a/testdata/ui_file/profiles/hijack_files/test_jpeg_1.jpeg b/testdata/ui_file/profiles/hijack_files/test_jpeg_1.jpeg
new file mode 100644
index 00000000..c96c8ce8
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_jpeg_1.jpeg
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_png_1.png b/testdata/ui_file/profiles/hijack_files/test_png_1.png
new file mode 100644
index 00000000..76e778e0
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_png_1.png
Binary files differ
diff --git a/testdata/ui_file/profiles/hijack_files/test_svg_1.svg b/testdata/ui_file/profiles/hijack_files/test_svg_1.svg
new file mode 100644
index 00000000..e33f7250
--- /dev/null
+++ b/testdata/ui_file/profiles/hijack_files/test_svg_1.svg
Binary files differ
diff --git a/testdata/ui_file/profiles/insert_scripts/__init__.py b/testdata/ui_file/profiles/insert_scripts/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/profiles/insert_scripts/__init__.py
diff --git a/testdata/ui_file/profiles/insert_scripts/test_css_1.css b/testdata/ui_file/profiles/insert_scripts/test_css_1.css
new file mode 100644
index 00000000..4b928372
--- /dev/null
+++ b/testdata/ui_file/profiles/insert_scripts/test_css_1.css
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>菜鸟教程(runoob.com)</title>
+<style>
+body {
+ background-color:red;
+}
+h1 {
+ color:red;
+ text-align:center;
+}
+p {
+ font-family:"Times New Roman";
+ font-size:20px;
+}
+</style>
+</head>
+
+<body>
+
+<h1>CSS 实例!</h1>
+<p>这是一个段落。</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/testdata/ui_file/profiles/insert_scripts/test_css_2.css b/testdata/ui_file/profiles/insert_scripts/test_css_2.css
new file mode 100644
index 00000000..08fd48b5
--- /dev/null
+++ b/testdata/ui_file/profiles/insert_scripts/test_css_2.css
@@ -0,0 +1,3 @@
+body{
+ background:red !important;
+} \ No newline at end of file
diff --git a/testdata/ui_file/profiles/insert_scripts/test_js_1.js b/testdata/ui_file/profiles/insert_scripts/test_js_1.js
new file mode 100644
index 00000000..4f110c37
--- /dev/null
+++ b/testdata/ui_file/profiles/insert_scripts/test_js_1.js
@@ -0,0 +1 @@
+alert("鎵цjavascript!"); \ No newline at end of file
diff --git a/testdata/ui_file/profiles/insert_scripts/test_js_2.js b/testdata/ui_file/profiles/insert_scripts/test_js_2.js
new file mode 100644
index 00000000..6e7bffe1
--- /dev/null
+++ b/testdata/ui_file/profiles/insert_scripts/test_js_2.js
@@ -0,0 +1 @@
+alert("Hello World"); \ No newline at end of file
diff --git a/testdata/ui_file/profiles/response_pages/__init__.py b/testdata/ui_file/profiles/response_pages/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/profiles/response_pages/__init__.py
diff --git a/testdata/ui_file/profiles/response_pages/testa.html b/testdata/ui_file/profiles/response_pages/testa.html
new file mode 100644
index 00000000..a490e611
--- /dev/null
+++ b/testdata/ui_file/profiles/response_pages/testa.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="UTF-8" http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<title>404-对不起!您访问的页面不存在</title>
+
+<style type="text/css">
+
+.head404{ width:580px; height:234px; margin:50px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/head404.png) no-repeat; }
+
+.txtbg404{ width:499px; height:169px; margin:10px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/txtbg404.png) no-repeat;}
+
+.txtbg404 .txtbox{ width:390px; position:relative; top:30px; left:60px;color:#eee; font-size:13px;}
+
+.txtbg404 .txtbox p {margin:5px 0; line-height:18px;}
+
+.txtbg404 .txtbox .paddingbox { padding-top:15px;}
+
+.txtbg404 .txtbox p a { color:#eee; text-decoration:none;}
+
+.txtbg404 .txtbox p a:hover { color:#FC9D1D; text-decoration:underline;}
+
+</style>
+
+</head>
+
+
+
+<body bgcolor="#494949">
+
+ <div class="head404"></div>
+
+ <div class="txtbg404">
+
+ <div class="txtbox">
+
+ <p>对不起,您请求的页面不存在、或已被删除、或暂时不可用</p>
+
+ <p class="paddingbox">请点击以下链接继续浏览网页</p>
+
+ <p>》<a style="cursor:pointer" onclick="history.back()">返回上一页面</a></p>
+
+ <p>》<a href="https://www.daixiaorui.com">返回网站首页</a></p>
+
+ </div>
+
+ </div>
+
+</body>
+
+</html>
+</html>
diff --git a/testdata/ui_file/profiles/response_pages/testb.html b/testdata/ui_file/profiles/response_pages/testb.html
new file mode 100644
index 00000000..9fd8aa96
--- /dev/null
+++ b/testdata/ui_file/profiles/response_pages/testb.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="UTF-8" http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<title>404 sorry! The page you visited does not exist</title>
+
+<style type="text/css">
+
+.head404{ width:580px; height:234px; margin:50px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/head404.png) no-repeat; }
+
+.txtbg404{ width:499px; height:169px; margin:10px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/txtbg404.png) no-repeat;}
+
+.txtbg404 .txtbox{ width:390px; position:relative; top:30px; left:60px;color:#eee; font-size:13px;}
+
+.txtbg404 .txtbox p {margin:5px 0; line-height:18px;}
+
+.txtbg404 .txtbox .paddingbox { padding-top:15px;}
+
+.txtbg404 .txtbox p a { color:#eee; text-decoration:none;}
+
+.txtbg404 .txtbox p a:hover { color:#FC9D1D; text-decoration:underline;}
+
+</style>
+
+</head>
+
+
+
+<body bgcolor="#494949">
+
+ <div class="head404"></div>
+
+ <div class="txtbg404">
+
+ <div class="txtbox">
+
+ <p>Sorry, the page you requested does not exist, has been deleted, or is temporarily unavailable</p>
+
+ <p class="paddingbox">Please click the following link to continue browsing</p>
+
+ <p>》<a style="cursor:pointer" onclick="history.back()">Back to previous page</a></p>
+
+ <p>》<a href="https://www.daixiaorui.com">Back to home page</a></p>
+
+ </div>
+
+ </div>
+
+</body>
+
+</html>
+</html>
diff --git a/testdata/ui_file/profiles/response_pages/testc.html b/testdata/ui_file/profiles/response_pages/testc.html
new file mode 100644
index 00000000..21d6fcdc
--- /dev/null
+++ b/testdata/ui_file/profiles/response_pages/testc.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="UTF-8" http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<title> - 404, простите!  страница, к которой вы пришли, не существует </title>
+
+<style type="text/css">
+
+.head404{ width:580px; height:234px; margin:50px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/head404.png) no-repeat; }
+
+.txtbg404{ width:499px; height:169px; margin:10px auto 0 auto; background:url(https://www.daixiaorui.com/Public/images/txtbg404.png) no-repeat;}
+
+.txtbg404 .txtbox{ width:390px; position:relative; top:30px; left:60px;color:#eee; font-size:13px;}
+
+.txtbg404 .txtbox p {margin:5px 0; line-height:18px;}
+
+.txtbg404 .txtbox .paddingbox { padding-top:15px;}
+
+.txtbg404 .txtbox p a { color:#eee; text-decoration:none;}
+
+.txtbg404 .txtbox p a:hover { color:#FC9D1D; text-decoration:underline;}
+
+</style>
+
+</head>
+
+
+
+<body bgcolor="#494949">
+
+ <div class="head404"></div>
+
+ <div class="txtbg404">
+
+ <div class="txtbox">
+
+ <p> Извините, запрошенная страница не существует или была удалена или временно недоступна </p>
+
+ <p class="paddingbox">Продолжайте просматривать страницы</p>
+
+ <p>》<a style="cursor:pointer" onclick="history.back()">вернуться на предыдущую страницу </a></p>
+
+ <p>》<a href="https://www.daixiaorui.com">вернуться на главную страницу сайта </a></p>
+
+ </div>
+
+ </div>
+
+</body>
+
+</html>
+</html>
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/__init__.py b/testdata/ui_file/profiles/ssl_decryption_keyrings/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/__init__.py
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_cert_caentitytest.chain.pem b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_cert_caentitytest.chain.pem
new file mode 100644
index 00000000..730ea47b
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_cert_caentitytest.chain.pem
@@ -0,0 +1,93 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 72:cc:5f:e2:55:f6:e6:f6:c4:bc:7c:6b
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, ST=BJ, L=BJ, O=NT, OU=NT, CN=CA TRUST1
+ Validity
+ Not Before: Jul 7 11:39:21 2023 GMT
+ Not After : Nov 18 11:39:21 2024 GMT
+ Subject: C=CN, CN=www.bbc.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:df:ad:1c:bc:ae:44:16:8a:be:bf:eb:69:06:07:
+ 5e:16:35:3b:e7:41:5d:48:8b:0f:6c:38:ee:7e:97:
+ 0f:43:de:63:27:84:5e:65:bc:28:7c:57:f1:4c:2a:
+ 92:98:e2:73:33:be:39:58:f2:7a:cf:55:45:23:16:
+ f3:c1:e9:fd:3e:f8:a7:a2:02:c6:f1:20:ff:13:dc:
+ f2:0a:31:29:fc:d8:e7:90:2d:ef:8e:44:6d:65:92:
+ fa:3a:a2:73:99:26:ee:e8:35:6f:07:dd:2f:49:61:
+ 11:11:d2:fb:7a:4c:8a:b9:19:ab:e3:99:79:07:ac:
+ fc:dd:62:7b:7f:de:fe:ff:8b:a7:68:8c:61:f8:49:
+ 57:67:8d:a8:23:92:a4:3f:e5:69:0a:6a:38:e3:56:
+ e2:dc:d2:ac:d5:62:6e:16:9e:46:c5:f3:19:c1:85:
+ 95:f2:5c:99:d0:2a:a6:80:64:2c:d2:7e:06:b6:80:
+ fc:48:f0:fc:06:57:c0:89:17:6a:4b:06:c9:26:54:
+ f5:36:59:44:01:89:89:5c:8d:fb:50:d7:10:ca:bc:
+ 3a:76:2a:f5:fa:4d:dc:0f:bc:bc:49:e0:92:8d:1d:
+ 7a:33:42:52:83:dc:ce:78:59:86:31:88:c0:4f:25:
+ f2:4b:7b:6f:18:d8:59:fd:f4:53:1b:fd:b4:95:ad:
+ 99:d3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:*.bbc.com, DNS:*.bbc.cn
+ Signature Algorithm: sha256WithRSAEncryption
+ ba:a0:a4:49:aa:7f:04:9d:eb:df:c1:c6:27:27:2e:52:c1:3a:
+ 1d:31:73:be:37:d7:17:6e:7f:1d:ca:f6:f8:24:bb:40:e2:08:
+ aa:13:84:5e:94:c0:e0:7c:80:f2:75:91:2c:cf:b2:31:9c:38:
+ bf:45:63:81:7c:20:60:d0:23:cf:0c:ca:14:41:b4:95:a0:e2:
+ 8f:b7:b8:e9:cb:2e:69:19:f0:53:c6:8f:96:1c:94:bd:41:c2:
+ d6:81:6e:1f:84:45:00:fa:7c:5a:39:3e:fa:14:6d:75:bf:d9:
+ ad:c9:85:58:10:24:3a:38:2a:85:90:a2:0b:58:06:7d:c8:2f:
+ 4a:b8:31:92:8e:c8:3d:21:9d:f6:74:2f:29:57:b2:7b:ee:8e:
+ 90:47:34:69:54:34:af:93:e3:cf:3a:31:56:40:20:03:61:ec:
+ 38:49:5b:e9:5a:e4:23:41:6e:f1:33:64:7f:d6:44:96:7b:e8:
+ 14:79:bf:5e:34:03:d0:63:a0:06:bb:c7:b0:24:8b:87:c6:df:
+ 5e:24:54:2e:35:05:88:f4:36:12:3d:76:8b:92:8f:95:e9:9c:
+ 14:39:0e:8f:e4:50:70:f6:f7:cf:24:01:7b:30:7d:33:43:b0:
+ 20:e1:1c:93:64:15:66:f2:4f:b0:2b:ae:48:18:67:fc:86:fa:
+ b8:f2:5b:ec
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIMcsxf4lX25vbEvHxrMA0GCSqGSIb3DQEBCwUAMFUxCzAJ
+BgNVBAYTAkNOMQswCQYDVQQIDAJCSjELMAkGA1UEBwwCQkoxCzAJBgNVBAoMAk5U
+MQswCQYDVQQLDAJOVDESMBAGA1UEAwwJQ0EgVFJVU1QxMB4XDTIzMDcwNzExMzky
+MVoXDTI0MTExODExMzkyMVowIzELMAkGA1UEBhMCQ04xFDASBgNVBAMMC3d3dy5i
+YmMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA360cvK5EFoq+
+v+tpBgdeFjU750FdSIsPbDjufpcPQ95jJ4ReZbwofFfxTCqSmOJzM745WPJ6z1VF
+Ixbzwen9PvinogLG8SD/E9zyCjEp/NjnkC3vjkRtZZL6OqJzmSbu6DVvB90vSWER
+EdL7ekyKuRmr45l5B6z83WJ7f97+/4unaIxh+ElXZ42oI5KkP+VpCmo441bi3NKs
+1WJuFp5GxfMZwYWV8lyZ0CqmgGQs0n4GtoD8SPD8BlfAiRdqSwbJJlT1NllEAYmJ
+XI37UNcQyrw6dir1+k3cD7y8SeCSjR16M0JSg9zOeFmGMYjATyXyS3tvGNhZ/fRT
+G/20la2Z0wIDAQABoyIwIDAeBgNVHREEFzAVggkqLmJiYy5jb22CCCouYmJjLmNu
+MA0GCSqGSIb3DQEBCwUAA4IBAQC6oKRJqn8EnevfwcYnJy5SwTodMXO+N9cXbn8d
+yvb4JLtA4giqE4RelMDgfIDydZEsz7IxnDi/RWOBfCBg0CPPDMoUQbSVoOKPt7jp
+yy5pGfBTxo+WHJS9QcLWgW4fhEUA+nxaOT76FG11v9mtyYVYECQ6OCqFkKILWAZ9
+yC9KuDGSjsg9IZ32dC8pV7J77o6QRzRpVDSvk+PPOjFWQCADYew4SVvpWuQjQW7x
+M2R/1kSWe+gUeb9eNAPQY6AGu8ewJIuHxt9eJFQuNQWI9DYSPXaLko+V6ZwUOQ6P
+5FBw9vfPJAF7MH0zQ7Ag4RyTZBVm8k+wK65IGGf8hvq48lvs
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIJAJnxzpEq+vIfMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV
+BAYTAkNOMQswCQYDVQQIDAJCSjELMAkGA1UEBwwCQkoxCzAJBgNVBAoMAk5UMQsw
+CQYDVQQLDAJOVDESMBAGA1UEAwwJQ0EgVFJVU1QxMB4XDTIzMDcwNzExMjk1NVoX
+DTI0MTExODExMjk1NVowVTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYD
+VQQHDAJCSjELMAkGA1UECgwCTlQxCzAJBgNVBAsMAk5UMRIwEAYDVQQDDAlDQSBU
+UlVTVDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO+4rZA65F6tlt
+HEnbFG56FyYs/V9XAM6sSSnnFj8H8MNvxiRQXlaevdK8/7xwtN3udX+x4VdSnmi4
+wPGLhrPWvrrv2ZrDbRlBwNmIosmE+dQdqf9OyN44Pw4/TQoh14CWqjqxQXYLevrn
+45GH1POUR64U6qO5Uq5B83zimTRWTbXertvrYb4plOKNxvav3IKdNEufRJSqxelf
+AUMQnsrH1iO4iMpZHBYSNbfwl6gkgnXxsr8YTZrrQwk9Bcd/0bFQ+v3OiWD5oiYc
+XfcIBTeoy6IIICNc7krfnXRpsXO2oimNgMS6nHPKvXYF5jTbKr0A40ElDEIjtt5T
+Yb4oWNHfAgMBAAGjUDBOMB0GA1UdDgQWBBSD6d3VXldZQOiVGZC0Y3nuANvG2zAf
+BgNVHSMEGDAWgBSD6d3VXldZQOiVGZC0Y3nuANvG2zAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4IBAQCM3XHUZ1RwpLtF5DpEKDmC4osIiguk7ENF7Bg+LCQt
+GzIeBkHPZ0sKbqZr0og6a0r0Qn1Xzr5nku9cuFH1Gc9Wwg82i8zXLgD8//VSNy5k
+SLKb7MiAAnUHv6ZkluX8X9bdg32vb+sTwhuFhjbI5LVWvY3dq/Ez+WERFUxgNL3s
+dgiJABkslbkjobgB39m/Lr223P6HwG5n6YukKSmwfiion5QYsTbTpd9AYbAD5UTs
+A5H5pRdk/mxJ7yYsgosu60wAUI/xVAVvsaUDGa+koiVKPhUg4A7Qd/2oDByb/H9J
+atqHkSjkwvhAekC0mOjKh6ED/Nr2tnN5l0GIbwRvj9Xz
+-----END CERTIFICATE-----
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_keycaentitytest.key b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_keycaentitytest.key
new file mode 100644
index 00000000..7683dbe3
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_end_keycaentitytest.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA360cvK5EFoq+v+tpBgdeFjU750FdSIsPbDjufpcPQ95jJ4Re
+ZbwofFfxTCqSmOJzM745WPJ6z1VFIxbzwen9PvinogLG8SD/E9zyCjEp/NjnkC3v
+jkRtZZL6OqJzmSbu6DVvB90vSWEREdL7ekyKuRmr45l5B6z83WJ7f97+/4unaIxh
++ElXZ42oI5KkP+VpCmo441bi3NKs1WJuFp5GxfMZwYWV8lyZ0CqmgGQs0n4GtoD8
+SPD8BlfAiRdqSwbJJlT1NllEAYmJXI37UNcQyrw6dir1+k3cD7y8SeCSjR16M0JS
+g9zOeFmGMYjATyXyS3tvGNhZ/fRTG/20la2Z0wIDAQABAoIBAFqQNe1zRaA25wq/
+3xMQ0ph9T1bP0Vw46bKwzme08/pPxafPYYUhjObjmJB1QEvkjC5sG74W14CxDsAp
+X+Kowd/IP99J7pDdAkphkCJuS4jTrdZjsvXQYNbajrRE6DcfW2XrlJwDg0zbn1Sv
+LyEScqyFZ2JM1oM0GGHuqQBaIrcGa6c8LgtaxmgVKMGA5EbSL86eZ8s0UNwiQs8Y
+U1GLrb0ecxJxjI7qHkj3e6bzfJ84P+EA97ZwnSEx2xV9ceMYfzo/nUKFo6BZo9Qy
+S1vBbHCs6Pv+1jg5rObI4F+w3Q1xkXDtOo8iGsFjIYvAXVw8k8DeI6hgI1OhF8I1
+Xz/azMkCgYEA8N5JE/u8SVZCfvaHj+e2Orlll+hTvI9GWu7lLYEVd9vdfri31n7v
+hHrcV98JqSBVPiKO78H29kSYWfmLRGMWKHInFfdVmuEOi7Xq3b4yIUk+y308A4qo
+Wx5JppQQ7Ej/9+lO+AF1ru1x4qsvY+XlmfC9l3zYy9G2+TIKe1kzV1UCgYEA7bpW
+tA2ocmeCUWP69dxXwLihsrAMkyIww7DWZHcE2tTH1YxfRdQM4AxrlO2st2aDcP6G
+P74cF6ooyeijZS3825rnZpxdpIjic0k/MwJnkyD2Rf16qXhvvu82pA46uyZ2TBfk
+Z5kFJw2pC6maNhg2OZCHNlWj2Qprr2EdzcdYXIcCgYBvWNK/gifQXyfuOVkBlUQQ
+cZQdXTEYgcMsVjNrjbi259TEt++EILnorEMf++MjY+cECkW5YBkiTyN+tHVE7+lW
+WS7oYKYaKt/mhfpE95+E868rsoEDwh2BwcaaUuhf0n9Bw4DV9RbJ/soe1rPZonU5
+bKi4VuaBkjjbid5+lwW84QKBgEB1aBEGKwhqPJGpFGEZz8l3xpBW3/H9MU++YUN4
+ah6T12N13ldmud7+PyVwlIZeC4HV4bzi5WcdQlYM+FD0+TzqcZgHCfUVEKHF2JcS
+Lddc9qnfoyTUfSg+YIh3O0GHmkfjqpDUkusV7yI0aJYGVp2hLKh07CprgutY3+Xu
+CW19AoGAZzRkQeqrdwLEHOMY4p0GNrwDnubfwBzjEHWt3tBCgRQjPiwpdtXIdXgk
+LDc2ZRUMw38JDELQ/BnzhXZa7JKJJJY6mNFTP/mUiGW959C8axE8csiPbIbQopY2
+wseDiyumC8r2wkhUfFST115LoShLeK/ZoiIA2ThWxCdbm/1PHVg=
+-----END RSA PRIVATE KEY-----
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_cert_camiddletest.chain.pem b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_cert_camiddletest.chain.pem
new file mode 100644
index 00000000..c13ccf89
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_cert_camiddletest.chain.pem
@@ -0,0 +1,100 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 71:d9:ff:18:5a:34:cc:9f:ee:60:0b:bd
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=CN, ST=BJ, L=BJ, O=NT, OU=NT, CN=CA TRUST1
+ Validity
+ Not Before: Jul 7 11:30:01 2023 GMT
+ Not After : Nov 18 11:30:01 2024 GMT
+ Subject: C=CN, ST=BJ, O=NT, OU=NT, CN=camiddle1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cb:5a:af:94:d2:6a:98:91:f1:13:6e:95:9e:ed:
+ 50:96:85:0e:8e:0b:fd:7f:f2:20:b6:88:27:34:91:
+ 9f:b3:c4:27:43:e4:e9:44:80:fd:e2:51:67:d7:f8:
+ 9b:17:16:2c:36:7e:f4:75:29:63:40:ec:9b:29:a7:
+ 4e:a2:d9:e1:ca:1a:51:62:43:5e:af:55:8a:64:b5:
+ 76:ba:a4:78:d6:87:fa:d6:a1:cb:08:67:69:0c:ec:
+ 5a:d9:7b:78:6f:28:d3:1b:14:63:ee:bd:47:92:e1:
+ 57:18:33:bc:99:ba:2f:82:cd:45:15:b2:bd:13:fa:
+ 51:38:bb:2b:68:11:0a:a4:b9:18:88:70:56:5f:89:
+ e1:10:21:79:e9:b1:f4:15:8b:74:10:6f:d8:36:9e:
+ 60:4c:1d:61:63:52:7b:b7:3d:63:8b:65:b3:2f:ed:
+ e7:d4:b5:39:15:32:52:d3:73:ea:c4:85:53:45:ea:
+ 5a:77:67:4c:3c:bb:0a:b8:0b:63:69:39:38:d3:61:
+ 78:16:10:48:e6:40:bf:1a:a9:9b:7a:1c:6f:33:45:
+ c6:f7:71:43:8c:62:27:7b:78:c3:0e:a7:99:c3:46:
+ b0:9a:1a:57:aa:8d:aa:75:b3:3d:66:dc:6e:c2:a1:
+ 04:0c:1e:de:0b:47:22:a9:9e:79:f9:77:b0:4f:02:
+ a4:f9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5D:44:58:02:45:8B:00:5A:DC:03:69:84:EE:70:D6:41:3F:17:C6:10
+ X509v3 Authority Key Identifier:
+ keyid:83:E9:DD:D5:5E:57:59:40:E8:95:19:90:B4:63:79:EE:00:DB:C6:DB
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 42:d8:bc:41:ae:5f:f3:3b:49:c0:72:b3:79:d0:68:36:22:82:
+ 14:d6:71:56:2c:d2:85:39:2c:34:7c:0a:2c:d8:88:2b:0e:04:
+ 62:b2:5a:0b:ab:03:df:58:a8:ac:a9:16:a4:81:e8:e4:61:45:
+ 08:2b:82:3c:7c:66:ca:00:04:57:a5:47:7e:15:f4:1b:a8:7d:
+ c0:02:5d:2e:ad:ee:52:03:38:d4:5b:e2:d8:4e:04:7b:c2:cd:
+ 7e:0e:ca:9f:b9:e9:43:1c:25:01:60:2b:91:37:de:de:31:cc:
+ 88:47:88:1f:46:95:49:de:67:35:16:f1:21:77:c3:03:40:56:
+ 6a:ac:dc:49:4c:ba:b4:5a:13:cb:68:97:59:8d:5c:7e:ca:a2:
+ fc:5d:21:95:9f:3c:3f:9b:ea:25:b9:8f:30:6d:68:a6:58:6c:
+ b6:8f:4c:d3:4c:c4:a7:da:04:49:ca:d0:96:81:c3:fb:41:6d:
+ ba:4d:9a:b2:fd:b2:0b:30:7c:1e:da:90:54:d3:ac:e0:ad:e3:
+ 48:9f:ef:51:9e:e4:e8:2e:1d:a5:17:cd:8b:40:94:30:44:e0:
+ 1d:f3:7f:ec:a6:6e:c8:2f:1c:a3:84:17:f9:66:f7:74:f9:8d:
+ b5:59:86:da:36:31:71:14:0f:af:d9:c3:96:92:e2:54:c6:b4:
+ 8b:76:f6:08
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIMcdn/GFo0zJ/uYAu9MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
+BgNVBAYTAkNOMQswCQYDVQQIDAJCSjELMAkGA1UEBwwCQkoxCzAJBgNVBAoMAk5U
+MQswCQYDVQQLDAJOVDESMBAGA1UEAwwJQ0EgVFJVU1QxMB4XDTIzMDcwNzExMzAw
+MVoXDTI0MTExODExMzAwMVowSDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQsw
+CQYDVQQKDAJOVDELMAkGA1UECwwCTlQxEjAQBgNVBAMMCWNhbWlkZGxlMTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMtar5TSapiR8RNulZ7tUJaFDo4L
+/X/yILaIJzSRn7PEJ0Pk6USA/eJRZ9f4mxcWLDZ+9HUpY0DsmymnTqLZ4coaUWJD
+Xq9VimS1drqkeNaH+tahywhnaQzsWtl7eG8o0xsUY+69R5LhVxgzvJm6L4LNRRWy
+vRP6UTi7K2gRCqS5GIhwVl+J4RAheemx9BWLdBBv2DaeYEwdYWNSe7c9Y4tlsy/t
+59S1ORUyUtNz6sSFU0XqWndnTDy7CrgLY2k5ONNheBYQSOZAvxqpm3ocbzNFxvdx
+Q4xiJ3t4ww6nmcNGsJoaV6qNqnWzPWbcbsKhBAwe3gtHIqmeefl3sE8CpPkCAwEA
+AaNQME4wHQYDVR0OBBYEFF1EWAJFiwBa3ANphO5w1kE/F8YQMB8GA1UdIwQYMBaA
+FIPp3dVeV1lA6JUZkLRjee4A28bbMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBAELYvEGuX/M7ScBys3nQaDYighTWcVYs0oU5LDR8CizYiCsOBGKyWgur
+A99YqKypFqSB6ORhRQgrgjx8ZsoABFelR34V9BuofcACXS6t7lIDONRb4thOBHvC
+zX4Oyp+56UMcJQFgK5E33t4xzIhHiB9GlUneZzUW8SF3wwNAVmqs3ElMurRaE8to
+l1mNXH7KovxdIZWfPD+b6iW5jzBtaKZYbLaPTNNMxKfaBEnK0JaBw/tBbbpNmrL9
+sgswfB7akFTTrOCt40if71Ge5OguHaUXzYtAlDBE4B3zf+ymbsgvHKOEF/lm93T5
+jbVZhto2MXEUD6/Zw5aS4lTGtIt29gg=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIJAJnxzpEq+vIfMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV
+BAYTAkNOMQswCQYDVQQIDAJCSjELMAkGA1UEBwwCQkoxCzAJBgNVBAoMAk5UMQsw
+CQYDVQQLDAJOVDESMBAGA1UEAwwJQ0EgVFJVU1QxMB4XDTIzMDcwNzExMjk1NVoX
+DTI0MTExODExMjk1NVowVTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYD
+VQQHDAJCSjELMAkGA1UECgwCTlQxCzAJBgNVBAsMAk5UMRIwEAYDVQQDDAlDQSBU
+UlVTVDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO+4rZA65F6tlt
+HEnbFG56FyYs/V9XAM6sSSnnFj8H8MNvxiRQXlaevdK8/7xwtN3udX+x4VdSnmi4
+wPGLhrPWvrrv2ZrDbRlBwNmIosmE+dQdqf9OyN44Pw4/TQoh14CWqjqxQXYLevrn
+45GH1POUR64U6qO5Uq5B83zimTRWTbXertvrYb4plOKNxvav3IKdNEufRJSqxelf
+AUMQnsrH1iO4iMpZHBYSNbfwl6gkgnXxsr8YTZrrQwk9Bcd/0bFQ+v3OiWD5oiYc
+XfcIBTeoy6IIICNc7krfnXRpsXO2oimNgMS6nHPKvXYF5jTbKr0A40ElDEIjtt5T
+Yb4oWNHfAgMBAAGjUDBOMB0GA1UdDgQWBBSD6d3VXldZQOiVGZC0Y3nuANvG2zAf
+BgNVHSMEGDAWgBSD6d3VXldZQOiVGZC0Y3nuANvG2zAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4IBAQCM3XHUZ1RwpLtF5DpEKDmC4osIiguk7ENF7Bg+LCQt
+GzIeBkHPZ0sKbqZr0og6a0r0Qn1Xzr5nku9cuFH1Gc9Wwg82i8zXLgD8//VSNy5k
+SLKb7MiAAnUHv6ZkluX8X9bdg32vb+sTwhuFhjbI5LVWvY3dq/Ez+WERFUxgNL3s
+dgiJABkslbkjobgB39m/Lr223P6HwG5n6YukKSmwfiion5QYsTbTpd9AYbAD5UTs
+A5H5pRdk/mxJ7yYsgosu60wAUI/xVAVvsaUDGa+koiVKPhUg4A7Qd/2oDByb/H9J
+atqHkSjkwvhAekC0mOjKh6ED/Nr2tnN5l0GIbwRvj9Xz
+-----END CERTIFICATE-----
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_key_camiddletest.key b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_key_camiddletest.key
new file mode 100644
index 00000000..2060cc7d
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_mid_key_camiddletest.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAy1qvlNJqmJHxE26Vnu1QloUOjgv9f/IgtognNJGfs8QnQ+Tp
+RID94lFn1/ibFxYsNn70dSljQOybKadOotnhyhpRYkNer1WKZLV2uqR41of61qHL
+CGdpDOxa2Xt4byjTGxRj7r1HkuFXGDO8mbovgs1FFbK9E/pROLsraBEKpLkYiHBW
+X4nhECF56bH0FYt0EG/YNp5gTB1hY1J7tz1ji2WzL+3n1LU5FTJS03PqxIVTRepa
+d2dMPLsKuAtjaTk402F4FhBI5kC/GqmbehxvM0XG93FDjGIne3jDDqeZw0awmhpX
+qo2qdbM9ZtxuwqEEDB7eC0ciqZ55+XewTwKk+QIDAQABAoIBAGHBsaB4WrgHiH3P
+7mtdKB2Dz1Bn4TBtpF47K6Wwz7YqeLnBxIWjAOmYOrRvFZdOmGiGNVxRTh5638hx
+XnMZDNsMNc1oF49wLrxlI7Nrt49iBSrC0oiytaR5xt6/5VCCrqFY9wVgxpSMcUL4
+NBUulQJrTWe16gE9l2gPSjmX36b5XLG6n3wsMCh8yphwwOBg86DjYWVY+q/AKY+j
+emSka2HYNTXOLQw6cBMcx2dKXtz4/XxDEtbhn/Fwd8B4D4n5RsuqDlLe/vLSXoDp
+1IDuK+SsprFZg2O6ss6r9hFEpBtTLYlk9RPlCgtvrMhwCULcRhxoIVxfvL9i+75E
+WT6KoQECgYEA6J8btSUE/bNVgy3mmcTZ9t/ukagg3DOyAR/cojEZB3G4FocGxfI8
+BRWUYL3X4tTibLh222fWQMiJB2nUGCEstPKC4vBuorq8jdmNS4EvT0v7w0MiELrf
+MiBq2vRla74buweIlTO67kXt+2+MsY4H8jkUanj6ajseJYWvPPsEQWECgYEA38qW
+qE7Hc32VlgL00uIYjBGkvfEHDRzwROwTiWMtvqea2WpdR/mBfzrWle4rUXiH9c+A
+GTSh2aBpfEgIqzR5wDASYk4cbgfyl/PjsG0ibCf/auilMeHJXw9RDSdkWnfPmFd/
+633yzsY6aYNNauaxSuTLI09VxX8rVYXYfp2W0pkCgYEAiXFI67SdyFBnXASI1Z3r
+suQIj2MpVzHsIKH0uJgN08orHJRXOimvsMlZS/efUNS7m8U55NTrUIer/wdWW5Nu
+WNNY5kFs/RUcRyudQlln3JBmhq5puDzRl0p0GD6CljBTLiR7XLyd3B7RR9hW5qmm
+pEV5fJdSTeX0H/Nm4L7nesECgYBbTnnnk7TWzw9gFDa1b+AaDfzMLnH1DLCPPk6+
+SEPavOF2AWqrugX21hfFNlZgODAov4+BOTMr6sH/HhjDWXavTi3CBCKfVgjJrI1i
+ZzSbMjqI8QCteHTDnykvl7nfG3EMs+6SM2IEsWYVtKe6jQMbDnw/HNhe6wLQMvrg
+tgVaSQKBgQDRLgTP5YxrUMUT3dq1cyXy3DQoMCPjAka07zXBaAAALtnn57SxR1mN
+kJ4cl4YjhdhRBvGV7KSB4hDBKks+xRuuuQ+Eq+I68a9uWE/k4Sdh3MZpif57lC+L
+edJqQRviqD0xMi+JImb6rUtNCjVJ/OgLc5pGgdeFi/+lRkiX9M8xJA==
+-----END RSA PRIVATE KEY-----
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_cert_catest.cer b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_cert_catest.cer
new file mode 100644
index 00000000..8392b0d6
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_cert_catest.cer
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIJAJnxzpEq+vIfMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV
+BAYTAkNOMQswCQYDVQQIDAJCSjELMAkGA1UEBwwCQkoxCzAJBgNVBAoMAk5UMQsw
+CQYDVQQLDAJOVDESMBAGA1UEAwwJQ0EgVFJVU1QxMB4XDTIzMDcwNzExMjk1NVoX
+DTI0MTExODExMjk1NVowVTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYD
+VQQHDAJCSjELMAkGA1UECgwCTlQxCzAJBgNVBAsMAk5UMRIwEAYDVQQDDAlDQSBU
+UlVTVDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO+4rZA65F6tlt
+HEnbFG56FyYs/V9XAM6sSSnnFj8H8MNvxiRQXlaevdK8/7xwtN3udX+x4VdSnmi4
+wPGLhrPWvrrv2ZrDbRlBwNmIosmE+dQdqf9OyN44Pw4/TQoh14CWqjqxQXYLevrn
+45GH1POUR64U6qO5Uq5B83zimTRWTbXertvrYb4plOKNxvav3IKdNEufRJSqxelf
+AUMQnsrH1iO4iMpZHBYSNbfwl6gkgnXxsr8YTZrrQwk9Bcd/0bFQ+v3OiWD5oiYc
+XfcIBTeoy6IIICNc7krfnXRpsXO2oimNgMS6nHPKvXYF5jTbKr0A40ElDEIjtt5T
+Yb4oWNHfAgMBAAGjUDBOMB0GA1UdDgQWBBSD6d3VXldZQOiVGZC0Y3nuANvG2zAf
+BgNVHSMEGDAWgBSD6d3VXldZQOiVGZC0Y3nuANvG2zAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4IBAQCM3XHUZ1RwpLtF5DpEKDmC4osIiguk7ENF7Bg+LCQt
+GzIeBkHPZ0sKbqZr0og6a0r0Qn1Xzr5nku9cuFH1Gc9Wwg82i8zXLgD8//VSNy5k
+SLKb7MiAAnUHv6ZkluX8X9bdg32vb+sTwhuFhjbI5LVWvY3dq/Ez+WERFUxgNL3s
+dgiJABkslbkjobgB39m/Lr223P6HwG5n6YukKSmwfiion5QYsTbTpd9AYbAD5UTs
+A5H5pRdk/mxJ7yYsgosu60wAUI/xVAVvsaUDGa+koiVKPhUg4A7Qd/2oDByb/H9J
+atqHkSjkwvhAekC0mOjKh6ED/Nr2tnN5l0GIbwRvj9Xz
+-----END CERTIFICATE-----
diff --git a/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_key_catest.key b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_key_catest.key
new file mode 100644
index 00000000..a347d61e
--- /dev/null
+++ b/testdata/ui_file/profiles/ssl_decryption_keyrings/test_root_key_catest.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAzvuK2QOuRerZbRxJ2xRuehcmLP1fVwDOrEkp5xY/B/DDb8Yk
+UF5Wnr3SvP+8cLTd7nV/seFXUp5ouMDxi4az1r6679maw20ZQcDZiKLJhPnUHan/
+TsjeOD8OP00KIdeAlqo6sUF2C3r65+ORh9TzlEeuFOqjuVKuQfN84pk0Vk213q7b
+62G+KZTijcb2r9yCnTRLn0SUqsXpXwFDEJ7Kx9YjuIjKWRwWEjW38JeoJIJ18bK/
+GE2a60MJPQXHf9GxUPr9zolg+aImHF33CAU3qMuiCCAjXO5K3510abFztqIpjYDE
+upxzyr12BeY02yq9AONBJQxCI7beU2G+KFjR3wIDAQABAoIBAQClBnEhrYmZPTG1
+iMRp49Rhi2tom2sUVxRw0LSUBmyizBdGWthBK7YsQnRvNAbuZYY8xXnWPS/+M0aT
+Z2IuOGvSX6dz7C80eRuWDUhjZEb/uqCgNhXUntpuRff6CFZ3vPZNKdQ511Niu96o
+XAyAHA1IwA3Pp3R6Ia3F73g2wqez1jorYZC14OZl8zv2CMLhZ5ES76gilypRV/g0
+6bBbBrpGZ130Cg+kQ81T+HUZWRgNtByFNwzZfBAu1jcdxQdAR1kMtnCjHtUm/kUX
+z1h3XclM1nuWoLY6bOUttJKWlHz8J6NKb4pO2PGmsWOhZx7JuQcSJE3rfLbG6LiH
+JJSEYB7hAoGBAPCXMUvMwqOsW0uCmsAH1iC1UeNG1lAAgDo49qDeKPoMXLUKmkjw
+s/zcllWH1TawU0M4SpdRLolBFJjkgNZL/woiPJ67mUDFSLeYQ/hrgVdxTzWaUnCG
+5XUyaiCs9C22Pzs+hMIkAgBhf0rh61J0hCNX0UeyrsMG+tG524lrfAfzAoGBANw9
+TRkqoHRPM9GsM1Kme/5WzT89IpQwSYSFI1v07de5GFNnIFzY7/B8wI61vyne5Bwf
+PJmYtdzB4ebU0xJf02QozuKkkYIupju1pDaWctKpgR/0ZYPTh8TAVqjfS0IeOup1
+EVkUSOJffPJuiM6ukuut6e/OTZKI+R4FvDzOolVlAoGAQV3yyNNzNqEHlPaBMRdv
++CcLfqKqa8YXELqVV5PEsltVfOLKlHLBlDwipE5pgZhapvLOYVpvOF90Ry4eSxsO
+yiQPMFlsBAsV/LvkC8S5uZZRnRC2wVgFU9hEuWgEV78iYuhTjaPW31+eBCxpkVeS
+5z9e3woPLXHiB8Vlfmqzoj0CgYEA2hom8MZC8gvBUGHMzYurfRtu1LJxPPl4xLCo
+bJdotlpJ2cZlySzYqHqSooEf15IwqhzRAXa2mvCyCss2X5rgF+9FujKpGpeh7b2a
+6qgg+7f69K8tnNftOw4Sg9fliouvYqIeVO3+o5dWgCqwdqVxP84Rvna6YWQd9/pM
+CJfFMPUCgYEA5v064YjwtVkE5IIZR7b0HMpZKeJMLRhNkSrYGDpt8y/da/GnRpcw
+H8shApl6E+/rTElHPd7o+HTxQ4LdqqgEUDM08sGSFz9R+0DA7YARCPahh5ZIXTqV
+4QNdC8CUu20PR05YuLj0V9UXRaO+njtvr2785iv3AF7kBgl9K90sR5E=
+-----END RSA PRIVATE KEY-----