This commit is contained in:
2026-07-03 14:34:33 +08:00
commit c153853ca8
18 changed files with 7036 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
__pycache__
doc.xlsx
.env
logs/
.config.json

24
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,24 @@
exclude: "^assets|^test/"
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.11
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: https://github.com/asottile/pyupgrade
rev: v3.20.0
hooks:
- id: pyupgrade
args: [--py312-plus]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: check-yaml
exclude: "^helm/"
args: [--unsafe]
- id: check-merge-conflict

384
.pytest_cache/v/cache/nodeids vendored Normal file
View File

@@ -0,0 +1,384 @@
[
"scenarios/tc_generator.py::test_tc_0104_txt[9DFB21329C44-1-1]",
"scenarios/tc_generator.py::test_tc_0104_txt[FD9051834972-1-1]",
"scenarios/tc_generator.py::test_tc_0204_img[1F93C9FEF4A0-1-1]",
"scenarios/tc_generator.py::test_tc_0204_img[9045957E8876-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[37EAF58D4D52-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[46B57E76EF64-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[56F2673EBB5A-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[79A72FCDE5A9-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[8F6E33C8DC8D-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[A04FC61C8B0F-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[EF3D62B48B14-1-1]",
"scenarios/tc_generator.py::test_tc_0204_txt[F9054BE1ABBB-1-1]",
"scenarios/tc_generator.py::test_tc_0205_doc[03B13D7A203B-1-1]",
"scenarios/tc_generator.py::test_tc_0205_doc[08FF493B8286-1-1]",
"scenarios/tc_generator.py::test_tc_0205_doc[A31652C77D39-1-1]",
"scenarios/tc_generator.py::test_tc_0205_doc[F55B1CE87D28-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[39113F7B7458-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[4C6F9167E45D-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[8678CA4B04BC-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[8879504ABC9B-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[93DA29CB1E11-1-1]",
"scenarios/tc_generator.py::test_tc_0205_txt[E53BAE580D17-1-1]",
"scenarios/tc_generator.py::test_tc_0206_doc[0F99DF747E69-1-1]",
"scenarios/tc_generator.py::test_tc_0206_doc[30D20B6F7660-1-1]",
"scenarios/tc_generator.py::test_tc_0206_doc[7F1025C427E1-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[0DC670989D90-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[3E2D421D3370-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[63B9BC6FE477-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[66FAB04A2376-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[729C56A75FFC-1-1]",
"scenarios/tc_generator.py::test_tc_0206_txt[F6E60ACDBFCC-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[14CD348E2F2D-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[44F16035BDCE-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[4C6FD6F254BC-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[54CF715FBF6F-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[76C3888225A5-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[778EDAF80EEF-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[7EE7EB069FCA-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[94FDBD9C6ECD-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[A3788BDB1DCD-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[B3294BD57D55-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[C860E31299FB-1-1]",
"scenarios/tc_generator.py::test_tc_0207_txt[F397052091F8-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[10364136C496-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[1B20429D172C-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[208D26EEC82F-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[41CE7AC94FD0-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[4239A608AD02-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[4BE308DEB7FD-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[546AA0B34289-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[5C557D7A0D88-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[5EB0D7CEC31F-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[693FA4E58D1E-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[75FBE7045650-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[8013E8F21223-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[823D11F90218-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[85B3F552683D-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[9E72C874506A-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[9EDF3E3596D5-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[A34BDCBDC5DD-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[B556DF37F84D-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[C6DAAFE78ADD-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[D7096557C288-1-1]",
"scenarios/tc_generator.py::test_tc_0208_doc[E06CBCD80491-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[0FB6804CD669-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[1E9D81961596-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[562023429B3E-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[5B99F4315E75-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[6935F363EF83-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[7A5B6C7BEDC7-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[8464D5D872E2-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[8A5ACD67AB25-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[90C432F95A90-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[BE7E90C6BC31-1-1]",
"scenarios/tc_generator.py::test_tc_0209_doc[DB0986F12EC7-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[10CD04407635-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[4C5932CDDD87-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[675DDE3437ED-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[9F9F35D099E0-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[A31D9506F195-1-1]",
"scenarios/tc_generator.py::test_tc_0214_doc[D790A48D7524-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[0FA05EBF26D9-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[1E7DD95B5449-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[75876054C10A-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[9A805FF25F79-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[AB64C7D296A0-1-1]",
"scenarios/tc_generator.py::test_tc_0214_txt[C1272BAA503C-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[0FAAC7944E3C-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[111358B0B411-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[13C68813952D-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[50D7BEAFCB9B-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[5A77CAF005B1-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[601216BF0FAD-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[62461E6D9C32-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[7B4AA1D2500C-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[88A70D2F8EBC-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[8A442A7356CA-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[AADAABD74762-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[BC60448ADDD7-1-1]",
"scenarios/tc_generator.py::test_tc_0215_doc[D19D567DFA61-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[095CB0638708-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[0FF63BF27841-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[3BF550011012-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[43D932F2AF81-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[4D0964B1FDAE-1-1]",
"scenarios/tc_generator.py::test_tc_0216_txt[A8524F935940-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[10B7F88133FB-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[18B1E6D17FB0-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[1AA03ED21393-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[21EB49D29B97-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[348834D3A2EB-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[3EECEEDE4B79-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[4095F4987F30-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[5612129CC1A1-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[6776C85B3AC3-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[75013A8CE1ED-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[91E641549264-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[A25A2D83FE4C-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[BF5164C262AD-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[C88F50716B55-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[D93E5E472727-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[DB95D78DF285-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[DCBB4D42A116-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[E5C483F1D6D6-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[E9F5E7A6E220-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[EE5FF7C1C324-1-1]",
"scenarios/tc_generator.py::test_tc_0301_txt[F3A2EF1F9B37-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[0195F6051438-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[0CAF0A4D66C9-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[0FC619908EB3-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[33C7EC01BA6E-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[3C09B291113E-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[41E9610D9A6C-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[69A76BE6067D-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[6F3FEB5D7DE4-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[6FE7ED7D275E-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[937697176A39-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[940D4550F54E-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[97CE17F8C64F-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[BAF1BBFD33A3-1-1]",
"scenarios/tc_generator.py::test_tc_0302_doc[FFD1CD25A4C2-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[13771E26DBBA-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[1CA9AE0461B2-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[43A184F1A3F5-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[4B2BDD05C92F-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[4CB5530046B1-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[4F9EA424E73D-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[65E53371BA3E-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[6AC58B37164C-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[856AED5063CC-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[8910503396D2-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[8FE65558918E-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[AF206C366345-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[D99B2491864B-1-1]",
"scenarios/tc_generator.py::test_tc_0303_txt[FE4017192E92-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[1554388ACA3E-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[1B0291BD6200-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[23432A01F8D6-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[47F39C66F8C5-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[571CBB622668-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[863C56FFA0ED-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[8E7FE23D8EC0-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[92D0DE0C7C9B-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[93504114B41C-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[93E0C104BB55-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[A5ACC78F7828-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[A6EA6AF0377B-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[A9EA854DA7AF-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[B73F265C736E-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[C8C82EDD930D-1-1]",
"scenarios/tc_generator.py::test_tc_0304_txt[C8D491C84298-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[024966A1C5D1-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[2977B58E9720-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[32C6ACA64613-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[837B92DF7647-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[99B6895AC008-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[AAE9E864F2BC-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[ADE354770A63-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[B413EABA9C37-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[D25B85F48C97-1-1]",
"scenarios/tc_generator.py::test_tc_0306_txt[EBA0159C38B4-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[176B3E5F918C-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[22347AF19D46-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[2A7E0AC1192B-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[3434DD0C8B8A-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[37B8A79C3E06-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[3C2A2201FFD5-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[4287DA89DDEE-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[4D9B6D3AE05C-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[4F78D666E23E-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[6949AB1A85E1-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[75EFDFE4357C-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[7B9555623AEC-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[A6924FC1DC64-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[BFDFB3FC025F-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[CC60193A8612-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[E4C6D8553F04-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[EB10BC43C618-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[F707C8E8B9E4-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[F821812FD758-1-1]",
"scenarios/tc_generator.py::test_tc_0307_txt[F921934A639D-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[02B5AC52DE14-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[02CFA03F0F11-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[04143AA650CB-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[051EDA4EB173-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[08C8A65F6E2B-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[1C409416BAD2-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[1FB7CBC75DA2-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[22C49E6A3443-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[248295596F1D-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[27EB548685AA-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[2F1B5FF2F9FA-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[3BA09A701AB1-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[4138A26F51BE-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[4B2F3FDE69ED-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[4F6E4AECAFE6-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[5D606C0F597D-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[62F0FAB5D446-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[6BA481501340-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[6D2A6789B6F0-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[6F012E3A468E-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[6F2B5D308741-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[7069240BFB4F-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[7418A33F8683-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[7642DFC6D088-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[7ACE3217B21A-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[7F96342C5458-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[8056DD419695-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[996CE1F58298-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[9DB007A151AD-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[B232775A6D84-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[B2B2F9BC69F4-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[B41BB6BA715C-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[B69A366C54B1-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[D3803B2919BA-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[DF99EF36FDFC-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[E9B5DEE2CF66-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[EE6B8EF5AE14-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[F1BC601B7F54-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[F1E476FE06A8-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[F35388311F12-1-1]",
"scenarios/tc_generator.py::test_tc_0308_doc[FB18D7CDD3C8-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[0DF61906494F-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[20F25B74D1E0-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[216097767814-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[35166B715FD7-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[428CA2F525E6-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[5E690A5557D5-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[76185ECAB03D-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[B1505B8EB070-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[B60A10344C58-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[B8A81FBAC265-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[C142081F9285-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[C33F7C50191F-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[CC94EB454592-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[D24C3C3B544E-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[DF3022C47DEE-1-1]",
"scenarios/tc_generator.py::test_tc_0407_txt[FECCFB025A83-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[07C4BAF08870-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[139B0B6CE048-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[3383D0DCD3F2-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[361EE9A79CCE-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[3DF2700D03E3-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[4F6FD943A59B-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[546C56817A66-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[755AEF83BA68-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[8BCB7E7EE810-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[8E93BBAA418E-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[9F833ACCDCC3-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[A64CA1464D52-1-1]",
"scenarios/tc_generator.py::test_tc_0501_txt[BDB10FA4BAE0-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[2CD9137AF869-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[808512A10D0E-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[C0413DC74B0E-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[D533821E0FB4-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[DD960F0AEA11-1-1]",
"scenarios/tc_generator.py::test_tc_0502_txt[E275A941BA59-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[1FB976E992F6-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[84A20A2C0213-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[BCAE051A8D9F-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[DB1A74DB6E07-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[F11B13565CAD-1-1]",
"scenarios/tc_generator.py::test_tc_0503_txt[F355D48C95AE-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[50C602182609-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[62F4801A84A3-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[76F229E23E2F-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[8A4FF0F80057-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[BD0124A55C85-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[C38857FD8993-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[C9EF2AFEE352-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[D3A24FED1B77-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[E44787807EEA-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[E4E398B208D6-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[E78888EBFD33-1-1]",
"scenarios/tc_generator.py::test_tc_0504_txt[F72469D543BC-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[15812A20CC99-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[2CB027EE7634-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[3E12A2015C8B-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[4A4821181102-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[4FA7BE68FB07-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[5CAE0D62CE1F-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[7F70488F51DE-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[7FA8C2555E4B-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[863B2C0BD62A-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[A52CDECEBB57-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[ACA0D1B3EE0B-1-1]",
"scenarios/tc_generator.py::test_tc_0505_txt[C8BFB7BF137E-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[2A3D51E8AFCB-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[34002CC9AED7-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[51C36E2F31F0-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[52C5E554E13C-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[544209FD30CA-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[5669BB79E8B1-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[5E9E4ACB81FA-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[67C8C608D8CD-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[7EE6DDD7E304-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[814EA8C83F9D-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[A0D62161112A-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[AA9F2AF1A2B2-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[B77079426C04-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[BDA56B52CB53-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[C9200B3693D4-1-1]",
"scenarios/tc_generator.py::test_tc_0506_txt[FC42CF18291D-1-1]",
"scenarios/tc_generator.py::test_tc_0509_txt[4D9936D30BDD-1-1]",
"scenarios/tc_generator.py::test_tc_0509_txt[7738F22C1B85-1-1]",
"scenarios/tc_generator.py::test_tc_0509_txt[A7D1CEEA3002-1-1]",
"scenarios/tc_generator.py::test_tc_0509_txt[D39275DA4F74-1-1]",
"scenarios/tc_generator.py::test_tc_0510_img[12DF049CACA4-1-1]",
"scenarios/tc_generator.py::test_tc_0510_img[2B9850F73C48-1-1]",
"scenarios/tc_generator.py::test_tc_0510_img[349DC7316090-1-1]",
"scenarios/tc_generator.py::test_tc_0510_img[5B6A1ADF9252-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[08A55DA7E909-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[0AC437595406-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[0D122948B3D4-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[1645069B9C6D-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[1AB41B10FFF6-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[1D0AAAD58C1C-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[2AF46481B129-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[3C6BE31A3EAC-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[43887700E9E9-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[55FE5E3BE2F5-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[5D832E31520C-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[70934E29A67B-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[73D40991049D-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[DBAFCD722B3E-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[EB2AD485F312-1-1]",
"scenarios/tc_generator.py::test_tc_0510_txt[FF544CDA0770-1-1]",
"scenarios/tc_generator.py::test_tc_0511_img[55C27C8BDE70-1-1]",
"scenarios/tc_generator.py::test_tc_0511_img[6255F48CB70F-1-1]",
"scenarios/tc_generator.py::test_tc_0511_img[D3073B4FE819-1-1]",
"scenarios/tc_generator.py::test_tc_0511_img[EEC36FD4E7DE-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[1EFE420BA46A-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[228797ECD2DF-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[68989C691F24-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[753C5978493B-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[7AF6E10F3217-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[B31091260CEF-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[C1FDBD083E70-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[D3D5BA8BE2A3-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[E453E1879C6E-1-1]",
"scenarios/tc_generator.py::test_tc_0511_txt[EAFEAC436CD9-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[055097D78568-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[1C1A1119F8AB-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[5F1C1CD4273D-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[8E2DE9E18E7A-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[9E670DF9EEDC-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[A163DD42B7A6-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[C5AA4E3ED30B-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[D5481581829E-1-1]",
"scenarios/tc_generator.py::test_tc_0512_txt[DCA52816E08E-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[00FAE2C49B14-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[043C36D5576F-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[4DA04FBCC723-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[5EA8C874EB48-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[612E4083EC03-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[6F2B987759CD-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[77610428B885-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[85EEF04A358F-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[A0BD903D318C-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[C99AFD9FBD77-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[D4EC7ED8D4C1-1-1]",
"scenarios/tc_generator.py::test_tc_0513_txt[E4DC25537AF0-1-1]"
]

1
.pytest_cache/v/cache/stepwise vendored Normal file
View File

@@ -0,0 +1 @@
[]

3658
.well-known/schema.json Normal file

File diff suppressed because it is too large Load Diff

1
README Normal file
View File

@@ -0,0 +1 @@
Honor

0
__init__.py Normal file
View File

120
conftest.py Normal file
View File

@@ -0,0 +1,120 @@
from typing import Callable, Literal
from glrocky.framework.schemas import (
TestSessionRuntime,
Device as _Device,
TestCaseExecutionState,
TestCaseRuntime,
)
from glrocky.framework.const_stash_keys import CASE_RUNTIME_CONFIG_KEY
import pytest
from glrocky.framework.schemas import TestCaseMertic as MetricItem
from glrocky.framework.schemas import TestCaseMetrics as MetricPacked
from glrocky.core.logger import core_logger
@pytest.fixture(scope="function")
def device_info(
request: pytest.FixtureRequest,
) -> _Device:
runtime: TestSessionRuntime | None = getattr(request.config, "project", None)
if runtime is None:
raise RuntimeError("unreachable!!!!!")
ret = runtime.devices[0] if runtime.devices else None
if not ret:
raise RuntimeError("no device found")
return ret
@pytest.fixture(scope="function", autouse=True)
def metric(record_metric: Callable[[MetricPacked], None]):
"""usage:
def test_g(metric):
metric.span() # optional
metric.add()
metric.add()
metric.send_all() # optianl
"""
class M:
def __init__(self):
self.data: list[tuple[str, str, int, list[MetricItem]]] = []
self.span()
def add(
self,
name: str,
value: float | int | str,
label: str | None = None,
type: Literal["number", "image", "video", "text"] = "text",
) -> None:
metric = MetricItem(
name=name, value=value, label=label or name, unit=None, type=type
)
self.data[-1][-1].append(metric)
def span(
self,
material_type: str = "default",
material_id: str = "default",
material_iteration: int = 1,
):
# DO NOT ADD DUPLICATE ITEM!!
if len(self.data):
last_span = self.data[-1]
if all(
(
last_span[0] == material_type,
last_span[1] == material_id,
last_span[2] == material_iteration,
)
):
core_logger.debug(
f"SKIP DUPLICATE SPAN:{material_type=},{material_id=},{material_iteration=}"
)
return
self.data.append((material_type, material_id, material_iteration, []))
core_logger.info(
f"added new span for metric:{material_type=},{material_id=},{material_iteration=}"
)
def send_all(
self,
):
if len(self.data) < 1:
core_logger.debug("no materics to send")
return # no span at all,skip
data = self.data[::-1]
self.data.clear() # TODO: not safe,to be improved
core_logger.info(f"{len(data)} metrics for send.")
while True:
if len(data) == 0:
break
item = data.pop()
material_type, material_id, material_iteration, metrics = (
item[0],
item[1],
item[2],
item[3],
)
if len(metrics) == 0:
core_logger.info("skip empty metrics")
continue
for_send = MetricPacked(
type=material_type,
material=material_id,
iteration=material_iteration,
metrics=metrics,
)
core_logger.info(f"rebuild metric:{for_send=}")
core_logger.info("sending metrics to executor...")
record_metric(for_send)
core_logger.info("sent")
_m = M()
yield _m
try:
_m.send_all()
except Exception as e:
raise RuntimeError(f"Cloud not send metric to server,Detail: {e}")

0
core/__init__.py Normal file
View File

82
core/metric_manager.py Normal file
View File

@@ -0,0 +1,82 @@
from pathlib import Path
class MetricManager:
def __init__(self, metric):
self.metric = metric
def new_span(self, m_type: str = "default", m_id: str = "default", m_iter: int = 1):
self.metric.span(m_type, m_id, m_iter)
def _smart_name_label(self, name: str, label: str | None) -> tuple[str, str]:
"""retruns: (name,label)"""
if not name:
raise ValueError()
if not name.strip():
raise ValueError("Empty name")
if label:
return name, label
for sep in ("|", ":"):
if sep in name:
_n, _l = name.split(sep, maxsplit=1)
return (_n, _l)
return name, name
def add_text_metric(self, name: str, value: str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="text",
)
def add_number_metric(self, name: str, value: float, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="number",
)
def add_image_metric(self, name: str, value: Path | str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=str(value),
type="image",
)
def add_video_metric(self, name: str, value: Path | str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="video",
)
def send(self):
self.metric.send_all()
def from_dict(self, the_dict: dict):
if not the_dict:
raise ValueError("dict is null")
for k, v in the_dict.items():
if isinstance(v, (int, float)):
self.add_number_metric(name=k, value=v)
elif isinstance(v, str):
self.add_text_metric(name=k, value=v)
elif isinstance(v, Path):
if v.suffix.lower() in (".jpg", ".png", ".gif", ".bmp"):
self.add_image_metric(name=k, value=str(v.resolve()))
elif v.suffix.lower() in (".mp4", ".mkv"):
self.add_video_metric(name=k, value=str(v.resolve()))
else:
self.add_text_metric(name=k, value=str(v.resolve()))
else:
raise NotImplementedError(f"{type(v)} not supported")

Binary file not shown.

Binary file not shown.

62
justfile Normal file
View File

@@ -0,0 +1,62 @@
set shell := ["powershell.exe","-NoLogo","-NoProfile", "-c"] # windows
set dotenv-load
set quiet :=true
@_:
just --list
[group("build")]
generate-schema:
rm {{quote(".well-known"/"*.json")}}
@fd -e json -H "schema"
uv run --reinstall-package glrocky-sdk \
python -m \
pytest --co --generate-schema --continue-on-collection-errors -q
mv {{ quote (".well-known" / "schema_autogenerated.json")}} {{ quote (".well-known" / "schema.json")}}
@fd -e json -H "schema"
[group("qa")]
lint:
uvx ruff check --fix --unsafe-fixes .
uvx ruff format
[group("run")]
[doc("run a specific test,eg: j run 0101_02")]
run TEST:
uv run python -m pytest -sqv -k {{TEST}}
[group("clean")]
clean-pycache:
@rm.exe -rf .pytest_cache .mypy_cache .ruff_cache .coverage
rm.exe -rf log out
@fd -td -I "__pycache__" -x rm -rf '{}'
@echo "✅ Done"
[group("clean")]
clean-cache:
@rm.exe -rf .pytest_cache .mypy_cache .ruff_cache .coverage
[group("clean")]
clean-out-and-log:
rm.exe -rf logs/ out/
[group("clean")]
clean-all:
just clean-cache
just clean-out-and-log
just clean-pycache
[group("dev")]
[doc("invoke ipython with u2")]
debug-u2:
uvx --with uiautomator2 --with .packages/glrocky_sdk-0.1.2-py3-none-any.whl --directory . ipython
[group("dev")]
[doc("show android ui")]
debug-ui:
uvx uiviewer
[group("dev")]
[doc("start test executor server,from glrocky framework")]
debug-srv:
uv run api-test-server

77
pyproject.toml Normal file
View File

@@ -0,0 +1,77 @@
[project]
name = "huawei-Phone-Test-Project-huawei"
version = "0.3.0"
description = "huawei手机用例集"
readme = "README.md"
authors = [{ name = "liumin", email = "liumin@glrocy.com" }]
requires-python = "==3.12.6"
dependencies = ["glrocky-sdk", "uvicorn>=0.34.2"]
[tool.pytest.ini_options]
minversion = "8.3.5"
#addopts = "--no-summary --no-header -rfEX --strict-markers --capture=tee-sys "
addopts = "--capture=tee-sys "
testpaths = ["scenarios"]
python_files = "tc_*.py"
markers = []
[tool.pyright]
venv = ".venv"
venvPath = "."
reportMissingTypeStubs = false
reportUnknownMemberType = false
[tool.uv.sources]
#glrocky-sdk = { path = "../../packages/glrocky-sdk" }
#glrocky-sdk = { path = "./glrocky_sdk-0.4.3-py3-none-any.whl" }
glrocky-sdk = { path = "./glrocky_sdk-0.4.5-py3-none-any.whl" }
[[tool.uv.index]]
url = "https://mirrors.aliyun.com/pypi/simple/"
default = true
[tool.glrocky]
remote_url = "https://gitea.glrocky.cn/scripts/huawei.git"
branch = "master"
uuid = "107f58111-aaa9-4636-b476-huawei001"
[tool.glrocky.tags]
osName="OpenHarmony-6.0.1.115" #hdc -s 5MT0225928000011 shell param get const.ohos.fullname
osVersion="21"
brand="HUAWEI" #hdc -s 5MT0225928000011 shell param get const.product.brand
model="SGT-AL10" #hdc -s 5MT0225928000011 shell param get const.product.model
manufacturer="HUAWEI" #hdc -s 5MT0225928000011 shell param get const.product.manufacturer
[tool.glrocky.commands]
generateSchema = "uv run --reinstall-package glrocky-sdk pytest --co --generate-schema --continue-on-collection-errors"
startTest = "uv run pytest"
[tool.glrocky.requirements]
devices = [{ type = "phone", os = "OpenHarmony", count = 1 }]
[tool.glrocky.project_settings]
screen-record-extra-commands = [
"--window-x=1380",
"--window-y=50",
"--always-on-top",
"--disable-screensaver",
"--window-borderless",
"-m",
"600",
"--video-codec",
"h264",
"--video-bit-rate",
"5M",
"--max-fps",
"60",
"--time-limit",
"3600",
"--print-fps",
"--video-buffer",
"100",
"--no-audio-playback",
"--no-audio",
]
[dependency-groups]
dev = ["ruff>=0.12.2"]

0
scenarios/__init__.py Normal file
View File

390
scenarios/tc_generator.py Normal file
View File

@@ -0,0 +1,390 @@
import re
import sys
import json
from pathlib import Path
from typing import Callable, Any
import pytest
import yaml
from glrocky.core.logger import logger
from glrocky.framework.marks import Marks as M
from glrocky.framework.schemas import Device
from glrocky.services.dify.dify import run_workflow
from loguru._logger import Logger
from pydantic import BaseModel, ConfigDict, Field, field_serializer
import socket
def _get_local_ip() -> str:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip: str = s.getsockname()[0]
s.close()
return str(ip)
PRODUCTION_EXECUTOR = "192.168.0.139"
IS_PRODUCTION = _get_local_ip() == PRODUCTION_EXECUTOR
class MetricManager:
def __init__(self, metric):
self.metric = metric
def new_span(self, m_type: str = "default", m_id: str = "default", m_iter: int = 1):
self.metric.span(m_type, m_id, m_iter)
def _smart_name_label(self, name: str, label: str | None) -> tuple[str, str]:
"""retruns: (name,label)"""
if not name:
raise ValueError()
if not name.strip():
raise ValueError("Empty name")
if label:
return name, label
for sep in ("|", ":"):
if sep in name:
_n, _l = name.split(sep, maxsplit=1)
return (_n, _l)
return name, name
def add_text_metric(self, name: str, value: str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="text",
)
def add_number_metric(self, name: str, value: float, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="number",
)
def add_image_metric(self, name: str, value: Path | str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=str(value),
type="image",
)
def add_video_metric(self, name: str, value: Path | str, label: str | None = None):
_n, _l = self._smart_name_label(name, label)
self.metric.add(
name=_n,
label=_l,
value=value,
type="video",
)
def send(self):
self.metric.send_all()
def from_dict(self, the_dict: dict[str, Any]):
if not the_dict:
raise ValueError("dict is null")
for _k, v in the_dict.items():
k = {
"result": "result|结果", # True ,False
"_dify_result": "_dify_result|业务完成", # True ,False
"_dify_message": "_dify_message|业务错误信息", # string,None
"resultText": "resultText|文本结果",
"recordVideo": "recordVideo|录像",
"recordAudio": "recordAudio|录音",
"screenshotList": "screenshotList|截图",
"firstToken": "firstToken|首字符时长",
"timeSeries":"timeSeries|时间序列",
"fileList":"fileList|文件"
}.get(_k, _k)
logger.info(k)
if v is None:
self.add_text_metric(name=k, value="")
elif isinstance(v, (int, float)):
self.add_number_metric(name=k, value=v)
elif isinstance(v, str):
self.add_text_metric(name=k, value=v)
elif isinstance(v, Path):
if v.suffix.lower() in (".jpg", ".png", ".gif", ".bmp"):
self.add_image_metric(name=k, value=str(v.resolve()))
elif v.suffix.lower() in (".mp4", ".mkv"):
self.add_video_metric(name=k, value=str(v.resolve()))
else:
self.add_text_metric(name=k, value=str(v.resolve()))
else:
raise NotImplementedError(f"{type(v)} not supported")
class DifySettings(BaseModel):
difyUrl: str = Field(
title="Dify服务地址",
)
difyWorkflowId: str = Field(
title="Dify工作流ID",
)
difyApiKey: str = Field(
title="Dify API密钥",
)
class MaterialForDify(BaseModel):
paramGroupUuid: list[str] = Field(default=[], title="UUID", description="UUID")
inputTextList: list[str] = Field(
default=[], title="对话列表,支持多轮对话", description="对话列表,支持多轮对话"
)
prompt: list[str] = Field(default=[], title="提示词", description="提示词")
model_config = ConfigDict(arbitrary_types_allowed=True) # allows uuid extra...
def pre_process_material(input:list[str])->str:
assert isinstance(input,list)
if not input:
return json.dumps([],ensure_ascii=False)
result=[]
p=re.compile(r"Q\d+\s*[:\.]+\s*",flags=re.MULTILINE)
for text in input:
splited=re.split(p,text,maxsplit=50)
for part in splited:
if not part.strip():
continue
result.append(part.strip())
return json.dumps(result, ensure_ascii=False)
class DifyPayload(BaseModel):
inputTextList: list[str] | str
prompt: list[str] | str
deviceId: str
address: str
caseId:str # 用例名称,当前运行的用例编号
appName: str | None = None
@field_serializer("inputTextList")
def serialize_input_text(self, value: list[str] | str) -> str:
if isinstance(value, list):
return pre_process_material(value)
return value
@field_serializer("prompt")
def serialize_prompt_as_single_str(self, value: list[str] | str) -> str:
if isinstance(value, list):
return value[0] if len(value) > 0 else ""
return value
def call_dify(
case_meta_info:dict[str,str],
logger: Logger,
device_info: Device,
material: list[MaterialForDify],
dify_cfg: DifySettings,
metric,
material_reporter,
app_name: str | None = None,
):
# logger.info(device_info.device_serial)
logger.info(dify_cfg)
event_callbacks: dict[str, Callable[..., None]] = {}
def on_node_started(c, n, d: dict[str, Any]):
logger.info(f"开始执行:{d.get('title', '')}")
logger.info(f"输入节点参数:{d.get('inputs')}")
def on_node_finished(c, n, d):
logger.info(f"结束执行:{d.get('title', '')}")
logger.info(f"节点输出:{d.get('outputs')}")
event_callbacks["on_node_started"] = on_node_started
event_callbacks["on_node_finished"] = on_node_finished
if not material or len(material) < 1:
raise RuntimeError("缺少素材")
else:
logger.info(f"下发素材:{material}")
mm = MetricManager(metric)
for material_index, item in enumerate(material, 1):
paramGroupUuid = item.paramGroupUuid[0]
assert paramGroupUuid, "The param Group Uuid Value must be set."
material_reporter.begin(paramGroupUuid)
dify_final_status = False
try:
# IMPORTANT: the group uuid for params
payload = DifyPayload(
**item.model_dump(),
deviceId=device_info.device_serial,
address=_get_local_ip(),
caseId=case_meta_info.get('id','Unkown'),
appName=app_name,
)
logger.info(f"payload send to dify:\n{payload.model_dump_json()}\n")
mm.new_span("default", f"default-{material_index}", material_index)
result = run_workflow(
api_key=dify_cfg.difyApiKey,
base_url=dify_cfg.difyUrl,
workflow_id=dify_cfg.difyWorkflowId,
inputs=payload.model_dump(),
event_callbacks=event_callbacks,
)
logger.info(f"工作流返回结果:{result.outputs}")
logger.info(f"工作流最终状态:{result.success}")
if result.outputs and len(result.outputs):
logger.info("提交结果到执行器")
mm.from_dict(result.outputs)
metric.send_all()
logger.info("提交结果到执行器完成")
else:
logger.warning("dify 工作流无返回")
if not result.success:
logger.error(f"工作流执行失败:{result.error}")
dify_final_status = result.success
except Exception as e:
logger.error(e)
dify_final_status = False
continue # do not break next round
finally:
material_reporter.end_with(paramGroupUuid, dify_final_status)
def make_dify_test(
case_meta: dict[str, str],
apps_config: dict[str, DifySettings] | None = None,
) -> Callable[..., None]:
@M.meta(**case_meta)
def _func(
logger: Logger,
device_info: Device,
material: list[MaterialForDify],
metric,
material_reporter,
meta,
) -> None:
dify_settings = apps_config.get(meta.app_name) if apps_config else None
call_dify(
case_meta,
logger,
device_info,
material,
dify_cfg=dify_settings,
metric=metric,
material_reporter=material_reporter,
app_name=meta.app_name,
)
return _func
def make_skip_test(meta: dict[str, str]) -> Callable[..., None]:
@M.skip(reason=f"{meta['id']} 未实现")
@M.meta(**meta)
def _func(
logger: Logger,
device_info: Device,
material: list[MaterialForDify],
metric,
) -> None:
logger.error(f"此用例在手机{device_info.device_serial}上暂未实现")
assert False, "not implemented"
return _func
def generate_cases_from_yaml(module_name: str, yaml_path: Path):
if not yaml_path.exists():
logger.warning(f"Test case definition file not found: {yaml_path}")
return
with open(file=yaml_path, mode="r", encoding="utf-8") as f:
all_cases: list[dict[str, Any]] = yaml.safe_load( # pyright: ignore[reportAny]
f
)
if not all_cases:
return
for case_info in all_cases["cases"]:
if not isinstance(case_info, dict):
logger.debug(f"Skipping non-dictionary item in YAML file: {case_info}")
continue
case_id: str = case_info.get("id",'')
if not case_id:
logger.warning(f"用例 缺少 case_id 字段。{case_info=}")
pytest.fail(f"用例 缺少 case_id 字段。{case_info=}")
description: str = case_info.get("description",'')
if not description:
logger.warning(f"用例{case_id} 缺少 description 字段。")
pytest.fail(f"用例{case_id} 缺少 description 字段。")
action: str = case_info.get("action", "skipped")
meta = {"id": case_id, "description": description, "appNames": ["agent"]}
fn_name = f"test_{case_id.lower().replace('-', '_')}"
if action == "dify":
apps_config: dict[str, DifySettings] = {}
if apps_list := case_info.get("apps"):
app_names = []
for app_entry in apps_list:
name = app_entry.get("name", "")
app_names.append(name)
if cfg_block := app_entry.get("dify_config"):
env_key = "production" if IS_PRODUCTION else "testing"
if env_cfg := cfg_block.get(env_key):
apps_config[name] = DifySettings(
difyUrl=env_cfg.get("url"),
difyWorkflowId=env_cfg.get("workflow_id"),
difyApiKey=env_cfg.get("api_key"),
)
meta["appNames"] = app_names
elif cfg_block := case_info.get("dify_config"):
env_key = "production" if IS_PRODUCTION else "testing"
if env_cfg := cfg_block.get(env_key):
apps_config["agent"] = DifySettings(
difyUrl=env_cfg.get("url"),
difyWorkflowId=env_cfg.get("workflow_id"),
difyApiKey=env_cfg.get("api_key"),
)
meta["appNames"] = ["agent"]
fn = make_dify_test(meta, apps_config or None)
elif action == "skipped":
fn = make_skip_test(meta)
elif action == "custom":
logger.info(f"Case {case_id} is a custom test.")
continue
else:
logger.warning(f"Unknown action '{action}' for case {case_id}. Skipping.")
continue
setattr(sys.modules[module_name], fn_name, fn)
logger.info(f"Generated {fn_name} for {case_id} with action '{action}'")
# class TC_CUSTOME_CONFIG(BaseModel):
# phoneNumber: str = Field(
# default="15338070617", title="拨号电话", description="待测机的手机号码"
# )
# @M.meta(id="TC-9991")
# def tc_9991(cfg:TC_CUSTOME_CONFIG):
# ...
# class TC_CUSTOME_CONFIG2(BaseModel):
# phoneNumber: str = Field(
# default="15338070617", title="拨号电话", description="待测机的手机号码"
# )
# phoneNumber2: str = Field(
# default="15338070617", title="拨号电话", description="待测机的手机号码"
# )
# def tc_9992(cfg:TC_CUSTOME_CONFIG2):
# ...
YAML_FILE = Path(__file__).parent / "test_cases.yaml"
generate_cases_from_yaml(__name__, YAML_FILE)

981
scenarios/test_cases.yaml Normal file
View File

@@ -0,0 +1,981 @@
dify_templates:
tianjin_dify_config: &testing_config
url: "http://192.168.0.213:8090/v1"
workflow_id: "b054aa56-fc1f-4770-9969-edb731831e73"
api_key: "app-0ukQIPzRCuaXv4UaBUTFGhVF"
guangzhou_dify_config: &production_config
url: "http://192.168.0.140:8090/v1"
workflow_id: "4b0f55c0-348b-4c51-a536-ce2c95d122bf"
api_key: "app-ByiOi9gp9WA2ejFgkUy8VR1n"
cases:
- id: TC-0101-audio
description: AI代接
category: AI社交.语音交流
action: skipped
- id: TC-0102-audio
description: 通话实时翻译
category: AI社交.语音交流
action: skipped
- id: TC-0103-audio
description: 通话摘要
category: AI社交.语音交流
action: skipped
- id: TC-0104-txt
description: 文本通话
category: AI社交.语音交流
action: skipped
- id: TC-0105-audio
description: AI通话降噪
category: AI社交.语音交流
action: skipped
- id: TC-0106-audio
description: AI隐私保护防漏音
category: AI社交.语音交流
action: skipped
- id: TC-0107-audio
description: 对话翻译
category: AI社交.语音交流
action: skipped
- id: TC-0108-audio
description: 面对面同声传译
category: AI社交.语音交流
action: skipped
- id: TC-0109-txt
description: AI短信
category: AI社交.短信
action: skipped
- id: TC-0110-txt
description: AR虚拟表情
category: AI社交.短信
action: skipped
- id: TC-0110-img
description: AR虚拟表情
category: AI社交.短信
action: skipped
- id: TC-0111-video
description: 视频电话AI鉴伪
category: AI社交.社交应用
action: skipped
- id: TC-0112-doc
description: 语音快传
category: AI社交.语音快传
action: skipped
- id: TC-0112-img
description: 语音快传
category: AI社交.语音快传
action: skipped
- id: TC-0113-txt
description: 社交应用内翻译
category: AI社交.跨语言沟通
action: skipped
- id: TC-0201-img
description: 日程管理
category: AI办公.日程管理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0201-audio
description: 日程管理
category: AI办公.日程管理
action: skipped
- id: TC-0202-audio
description: 语音转写
category: AI办公.会议助手
action: skipped
- id: TC-0202-video
description: 语音转写
category: AI办公.会议助手
action: skipped
- id: TC-0203-doc
description: 智能纪要
category: AI办公.会议助手
action: skipped
- id: TC-0204-txt
description: 文稿创作
category: AI办公.工作文稿处理
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0204-img
description: 文稿创作
category: AI办公.工作文稿处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0205-txt
description: 文稿润色-文本
category: AI办公.工作文稿处理
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0205-doc
description: 文稿润色-文档
category: AI办公.工作文稿处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0206-txt
description: 文稿排版
category: AI办公.工作文稿处理
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0206-doc
description: 文稿排版
category: AI办公.工作文稿处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0207-txt
description: 长文本摘要
category: AI办公.工作文稿处理
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0208-doc
description: 文档摘要
category: AI办公.工作文稿处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0209-doc
description: 多语言摘要
category: AI办公.工作文稿处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0210-img
description: 图片转表格
category: AI办公.表格处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0211-img
description: 表格提取
category: AI办公.表格处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0212-txt
description: 文件搜索
category: AI办公.AI全局搜索
action: skipped
- id: TC-0213-txt
description: 图片搜索
category: AI办公.AI全局搜索
action: skipped
- id: TC-0214-txt
description: PPT生成
category: AI办公.PPT生成
action: skipped
- id: TC-0214-doc
description: PPT生成
category: AI办公.PPT生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0215-doc
description: 思维导图
category: AI办公.思维导图生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0216-txt
description: 代码
category: AI办公.代码生成
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0217-txt
description: 实时翻译
category: AI办公.翻译
action: skipped
- id: TC-0218-txt
description: AI帮写邮件
category: AI办公.文稿处理
action: skipped
- id: TC-0219-txt
description: 邮件翻译
category: AI办公.文稿处理
action: skipped
- id: TC-0220-txt
description: 邮件总结摘要
category: AI办公.文稿处理
action: skipped
- id: TC-0221-txt
description: 网页摘要
category: AI办公.文稿处理
action: skipped
- id: TC-0301-txt
description: 用机问答
category: AI学习.学习问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0302-doc
description: 文档问答
category: AI学习.学习问答
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0303-txt
description: 对话问答
category: AI学习.学习问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0304-txt
description: 网页问答
category: AI学习.学习问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0305-img
description: 多模态问答
category: AI学习.学习问答
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0305-audio
description: 多模态问答
category: AI学习.学习问答
action: skipped
- id: TC-0305-video
description: 多模态问答
category: AI学习.学习问答
action: skipped
- id: TC-0306-txt
description: 深度推理
category: AI学习.学习问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0307-txt
description: 文本翻译
category: AI学习.翻译
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0308-doc
description: 文档翻译
category: AI学习.翻译
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "22559a81-78f9-4d9b-9414-111854df41ec"
api_key: "app-HZJw84iY0byIxGbQv4Cnpz52"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "676b86bd-4dd7-4326-b696-905b8a27ebb1"
api_key: "app-SUoEb1FNixXwUQN5g26NpH8T"
- id: TC-0309-txt
description: 网页翻译
category: AI学习.翻译
action: skipped
- id: TC-0310-audio
description: 口语陪练
category: AI学习.AI教学
action: skipped
- id: TC-0311-img
description: 图片解题
category: AI学习.AI教学
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0312-img
description: 拍摄解题
category: AI学习.AI教学
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0313-img
description: 试卷还原
category: AI学习.AI教学
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0314-img
description: 作业批改
category: AI学习.AI教学
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0315-img
description: 作业讲解
category: AI学习.AI教学
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0316-doc
description: 屏幕问答
category: AI学习.AI学习
action: skipped
- id: TC-0316-img
description: 屏幕问答
category: AI学习.AI学习
action: skipped
- id: TC-0401-txt
description: 智能体唤醒拍照
category: AI影像.AI拍摄
action: skipped
- id: TC-0401-audio
description: 智能体唤醒拍照
category: AI影像.AI拍摄
action: skipped
- id: TC-0402-img
description: 笑脸抓拍
category: AI影像.AI拍摄
action: skipped
- id: TC-0403-video
description: 录制视频(美颜/美化)
category: AI影像.AI拍摄
action: skipped
- id: TC-0404-video
description: 识文
category: AI影像.AI拍摄
action: skipped
- id: TC-0405-img
description: 识物
category: AI影像.AI拍摄
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0406-img
description: AR翻译
category: AI影像.AI拍摄
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0407-txt
description: 文生图
category: AI影像.图片生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "34681f80-2bc3-487e-b5be-31dc93516e98"
api_key: "app-XQqfe9JUM2Ys4lIlVjXNzhjF"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "10c9268e-853e-4fde-826a-9dd8b0563517"
api_key: "app-4TYzQtnl5ioqLlWpU9wqKRs7"
- id: TC-0408-img
description: AI路人消除
category: AI影像.图片生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0409-img
description: AI物体消除
category: AI影像.图片生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0410-img
description: AI扩图
category: AI影像.图片生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0411-img
description: 图片风格转化
category: AI影像.图片生成
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0412-img
description: 涂鸦生图
category: AI影像.图片生成
action: skipped
- id: TC-0413-img
description: 图片翻译
category: AI影像.图片处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0414-img
description: AI搜图
category: AI影像.图片处理
action: skipped
- id: TC-0415-img
description: AI美颜
category: AI影像.图片处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0416-img
description: AI美化
category: AI影像.图片处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0417-img
description: 智能抠图
category: AI影像.图片处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0418-img
description: 闭眼修复
category: AI影像.图片处理
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0419-img
description: 一键成片
category: AI影像.视频生成
action: skipped
- id: TC-0420-img
description: 视频字幕生成
category: AI影像.视频处理
action: skipped
- id: TC-0421-img
description: 视频翻译
category: AI影像.视频处理
action: skipped
- id: TC-0422-txt
description: 音乐生成
category: AI影像.音乐生成
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0501-txt
description: 公共服务查询(天气/交通路线/节假日等)
category: AI生活.生活类问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0502-txt
description: 通信业务查询(话费/流量/短信等)
category: AI生活.生活类问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0503-txt
description: 生活费用查询(水/电/煤/物业等)
category: AI生活.生活类问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0504-txt
description: 生活建议(美食推荐/穿搭建议等)
category: AI生活.生活类问答
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0505-txt
description: 系统控制(开关机/音量/字体等)
category: AI生活.系统操作
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0506-txt
description: 应用管理
category: AI生活.系统操作
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0507-img
description: AI圈选
category: AI生活.系统操作
action: skipped
- id: TC-0508-audio
description: 智能打开乘车码(地铁/公交等)
category: AI生活.购物/支付
action: skipped
- id: TC-0509-txt
description: 商品比价
category: AI生活.购物/支付
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0509-img
description: 商品比价
category: AI生活.购物/支付
action: dify
dify_config:
production:
url: "http://192.168.0.140:8090/v1"
workflow_id: "64b1f907-5cd6-4ed0-b03b-d0ae0b3d2508"
api_key: "app-mCAGe4O0UavVujE7QDV2Rb42"
testing:
url: "http://192.168.0.213:8090/v1"
workflow_id: "2efde4e1-c0b7-4577-b10d-fe3212e03f68"
api_key: "app-esd86YCuKVURPBBgquXZT9U1"
- id: TC-0510-txt
description: AI导航
category: AI生活.出行
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0510-img
description: AI导航
category: AI生活.出行
action: skipped
- id: TC-0511-img
description: 网约车
category: AI生活.出行
action: skipped
- id: TC-0511-txt
description: 网约车
category: AI生活.出行
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0512-txt
description: 行程规划
category: AI生活.出行
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0513-txt
description: 健康问答
category: AI生活.运动健康
action: dify
dify_config:
production: *production_config
testing: *testing_config
- id: TC-0514-txt
description: AI读屏
category: AI生活.无障碍辅助
action: skipped
- id: TC-0515-txt
description: AI看见
category: AI生活.无障碍辅助
action: skipped
- id: TC-0516-txt
description: AI播客生成
category: AI生活.咨询传播
action: skipped
- id: TC-0516-audio
description: AI播客生成
category: AI生活.咨询传播
action: skipped
- id: TC-0517-txt
description: 个人信息查询
category: AI生活.生活服务
action: skipped
- id: TC-0518-img
description: AI壁纸
category: AI生活.个性化推荐
action: skipped
- id: TC-0519-txt
description: 应用级翻译
category: AI生活.跨语言服务
action: skipped
- id: TC-0520-txt
description: 智能打开付款码
category: AI生活.购物/支付
action: skipped
- id: TC-0521-txt
description: 话费充值
category: AI生活.生活服务
action: skipped
- id: TC-0522-txt
description: 点外卖
category: AI生活.生活服务
action: skipped
- id: TC-0523-txt
description: 生活缴费
category: AI生活.生活服务
action: skipped
- id: TC-0524-txt
description: 餐厅预定
category: AI生活.生活服务
action: skipped
- id: TC-0525-txt
description: 电影预定
category: AI生活.文娱消费服务
action: skipped
- id: TC-0526-txt
description: 演出预定
category: AI生活.文娱消费服务
action: skipped
- id: TC-0527-txt
description: 快递查询
category: AI生活.生活服务
action: skipped
- id: TC-0528-txt
description: 快递提醒
category: AI生活.生活服务
action: skipped
- id: TC-0529-txt
description: 机票/酒店/火车票预定
category: AI生活.智能出行
action: skipped
- id: TC-0530-txt
description: 出行推荐
category: AI生活.智能出行
action: skipped
- id: TC-0531-txt
description: 出行提醒
category: AI生活.日程提醒
action: skipped
- id: TC-0532-txt
description: 健康检测
category: AI生活.运动健康
action: skipped
- id: TC-0533-txt
description: 健康风险预警(心律/睡眠)
category: AI生活.运动健康
action: skipped
- id: TC-0534-txt
description: 健身计划生成
category: AI生活.运动健康
action: skipped
- id: TC-0535-txt
description: 声音修复
category: AI生活.音频智能处理
action: skipped
- id: TC-0536-txt
description: 手语翻译
category: AI生活.无障碍服务
action: skipped
- id: TC-0601-audio
description: 语音唤醒
category: 智能体基础测试.语音唤醒
action: skipped

1251
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff