tuner-testkit 4.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tuner-testkit might be problematic. Click here for more details.
- tuner_testkit-4.0.0/LICENSE +21 -0
- tuner_testkit-4.0.0/PKG-INFO +176 -0
- tuner_testkit-4.0.0/README.md +118 -0
- tuner_testkit-4.0.0/pyproject.toml +109 -0
- tuner_testkit-4.0.0/setup.cfg +4 -0
- tuner_testkit-4.0.0/tuner_testkit/__init__.py +5 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/__init__.py +48 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/__main__.py +111 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/__init__.py +5 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/api.py +56 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/db.py +48 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/generators.py +37 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/ids.py +78 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/_internal/wait.py +27 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/base.py +131 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/context.py +105 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/plane.py +83 -0
- tuner_testkit-4.0.0/tuner_testkit/action_words/registry.py +96 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/__init__.py +68 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/app.py +419 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/errors.py +17 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/router.py +100 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/spec.py +180 -0
- tuner_testkit-4.0.0/tuner_testkit/api_mock/store.py +214 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/__init__.py +1 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/auth.py +227 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/__init__.py +35 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/capture.py +271 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/codegen.py +381 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/freeze.py +312 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/mocks.py +149 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/normalize.py +256 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/pipeline.py +149 -0
- tuner_testkit-4.0.0/tuner_testkit/api_objects/recording/sanitize.py +99 -0
- tuner_testkit-4.0.0/tuner_testkit/api_test/__init__.py +18 -0
- tuner_testkit-4.0.0/tuner_testkit/api_test/client.py +274 -0
- tuner_testkit-4.0.0/tuner_testkit/api_test/errors.py +26 -0
- tuner_testkit-4.0.0/tuner_testkit/api_test/jsonpath.py +88 -0
- tuner_testkit-4.0.0/tuner_testkit/api_test/model.py +350 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/__init__.py +1 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/__init__.py +1 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/changelog.py +77 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/plane.py +25 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/plane_app.py +296 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/plane_asset.py +147 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/tests/test_plane_asset.py +124 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/_shared/tests/test_plane_collect.py +45 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/__init__.py +11 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/__main__.py +6 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/addon.py +67 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/cli.py +201 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/playwright_tap.py +113 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/api_recorder/tests/test_addon.py +117 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/__init__.py +1 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/__main__.py +4 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/build.py +80 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/cli.py +147 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +102 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +45 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +11 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +49 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +29 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +44 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +65 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +53 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +53 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +21 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +33 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +131 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +59 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +60 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +92 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +84 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +64 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +110 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +52 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +37 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +75 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +57 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +47 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +93 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +51 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +51 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +64 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/AGENTS.md +79 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +13 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +172 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +240 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +75 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +70 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +159 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +282 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +199 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +83 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +282 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +28 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +20 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +22 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +178 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/paths.py +15 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/source.py +84 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dna/tests/test_cli.py +21 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/dump_ddl.py +1333 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_ai/__init__.py +8 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_ai/__main__.py +42 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_ai/registry.py +237 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/__init__.py +9 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/__main__.py +29 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/build.py +63 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/catalog.py +228 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/plane.py +29 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/index_platform/tests/test_catalog.py +29 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/init_repo/__init__.py +11 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/init_repo/__main__.py +87 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/init_repo/manifest.py +133 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/init_repo/scaffold.py +149 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/mock_server/__init__.py +1 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/mock_server/__main__.py +6 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/mock_server/cli.py +213 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/mock_server/plane.py +52 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/mock_server/seed.py +215 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/__init__.py +7 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/__main__.py +6 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/capture.py +215 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/cli.py +134 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/codegen.py +239 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/freeze.py +390 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/inject.py +235 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/session.py +253 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/tests/__init__.py +0 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/tests/test_capture.py +171 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/tests/test_cli.py +53 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/page_recorder/tests/test_freeze.py +192 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/recorder/__init__.py +11 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/recorder/__main__.py +6 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/recorder/cli.py +233 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
- tuner_testkit-4.0.0/tuner_testkit/apps/recorder/tests/test_cli.py +169 -0
- tuner_testkit-4.0.0/tuner_testkit/config.py +333 -0
- tuner_testkit-4.0.0/tuner_testkit/db/__init__.py +34 -0
- tuner_testkit-4.0.0/tuner_testkit/db/client.py +247 -0
- tuner_testkit-4.0.0/tuner_testkit/db/connection.py +140 -0
- tuner_testkit-4.0.0/tuner_testkit/excel/__init__.py +37 -0
- tuner_testkit-4.0.0/tuner_testkit/excel/workbook.py +225 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/__init__.py +220 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/__main__.py +4 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/catalog.py +195 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/china.py +139 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/cli.py +162 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/core.py +340 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/medical.py +237 -0
- tuner_testkit-4.0.0/tuner_testkit/fake/wrappers.py +95 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/__init__.py +50 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/context.py +130 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/core.py +202 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/helpers.py +152 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/hooks.py +196 -0
- tuner_testkit-4.0.0/tuner_testkit/logging/scenario_file.py +98 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/__init__.py +182 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/__main__.py +216 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/base.py +208 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/driver.py +724 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/errors.py +51 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/harvest.py +526 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/health.py +369 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/locator.py +575 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/model.py +522 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/registry.py +237 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/session.py +192 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/steps.py +517 -0
- tuner_testkit-4.0.0/tuner_testkit/page_test/testing.py +375 -0
- tuner_testkit-4.0.0/tuner_testkit/project.py +180 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/PKG-INFO +176 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/SOURCES.txt +150 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/dependency_links.txt +1 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/entry_points.txt +14 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/requires.txt +58 -0
- tuner_testkit-4.0.0/tuner_testkit.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tuner-testkit contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tuner-testkit
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: Shared test runtime, recorders, and DNA overlay for SUT test repos
|
|
5
|
+
Author: tuner-testkit contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: pydantic>=2
|
|
11
|
+
Provides-Extra: db
|
|
12
|
+
Requires-Dist: pymysql>=1.2.0; extra == "db"
|
|
13
|
+
Requires-Dist: pymssql>=2.3.0; extra == "db"
|
|
14
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "db"
|
|
15
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "db"
|
|
16
|
+
Provides-Extra: api
|
|
17
|
+
Requires-Dist: requests>=2.33.1; extra == "api"
|
|
18
|
+
Provides-Extra: web-ui
|
|
19
|
+
Requires-Dist: playwright>=1.54.0; extra == "web-ui"
|
|
20
|
+
Provides-Extra: phone-ui
|
|
21
|
+
Provides-Extra: excel
|
|
22
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
23
|
+
Provides-Extra: fake
|
|
24
|
+
Requires-Dist: faker>=37.0.0; extra == "fake"
|
|
25
|
+
Provides-Extra: mock
|
|
26
|
+
Requires-Dist: fastapi>=0.115.0; extra == "mock"
|
|
27
|
+
Requires-Dist: uvicorn[standard]>=0.32.0; extra == "mock"
|
|
28
|
+
Requires-Dist: httpx>=0.28.0; extra == "mock"
|
|
29
|
+
Provides-Extra: recorder
|
|
30
|
+
Requires-Dist: playwright>=1.54.0; extra == "recorder"
|
|
31
|
+
Requires-Dist: mitmproxy>=11.1.3; extra == "recorder"
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest>=9.0.3; extra == "test"
|
|
34
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "test"
|
|
35
|
+
Requires-Dist: httpx>=0.28.0; extra == "test"
|
|
36
|
+
Provides-Extra: bdd
|
|
37
|
+
Requires-Dist: behave>=1.2.6; extra == "bdd"
|
|
38
|
+
Requires-Dist: playwright>=1.54.0; extra == "bdd"
|
|
39
|
+
Requires-Dist: behave-html-pretty-formatter>=1.16.1; extra == "bdd"
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: pymysql>=1.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pymssql>=2.3.0; extra == "dev"
|
|
43
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "dev"
|
|
44
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "dev"
|
|
45
|
+
Requires-Dist: requests>=2.33.1; extra == "dev"
|
|
46
|
+
Requires-Dist: pydantic>=2; extra == "dev"
|
|
47
|
+
Requires-Dist: faker>=37.0.0; extra == "dev"
|
|
48
|
+
Requires-Dist: openpyxl>=3.1.0; extra == "dev"
|
|
49
|
+
Requires-Dist: fastapi>=0.115.0; extra == "dev"
|
|
50
|
+
Requires-Dist: uvicorn[standard]>=0.32.0; extra == "dev"
|
|
51
|
+
Requires-Dist: httpx>=0.28.0; extra == "dev"
|
|
52
|
+
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
53
|
+
Requires-Dist: behave>=1.2.6; extra == "dev"
|
|
54
|
+
Requires-Dist: playwright>=1.54.0; extra == "dev"
|
|
55
|
+
Requires-Dist: behave-html-pretty-formatter>=1.16.1; extra == "dev"
|
|
56
|
+
Requires-Dist: mitmproxy>=11.1.3; extra == "dev"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# tuner-testkit
|
|
60
|
+
|
|
61
|
+
发行名 **`tuner-testkit`**,导入名 **`tuner_testkit`**。给被测系统(SUT)测试仓提供公共运行库与 CLI(db / API / Web UI / 录制 / mock),以及 Cursor/git **DNA**(rules、skills、hooks)。
|
|
62
|
+
|
|
63
|
+
业务资产(page/api objects、action words、features)留在**各项目仓**的 `packages/` 与 `tests/`,不进本包。平台发新版本后,下游用 `uv` 按需升级,不必再整树拷贝运行库。
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 标准作业流程
|
|
68
|
+
|
|
69
|
+
### 1. 安装 `tuner-testkit`
|
|
70
|
+
|
|
71
|
+
还没有任何项目仓时,先把 CLI 装到工具环境:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv tool install "tuner-testkit[db,api]"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
需要 headed 录制或 Playwright 时加上对应 extra(见下方 extras)。已有项目仓则在该仓根目录:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
uv add "tuner-testkit[db,api]>=4.0.0"
|
|
81
|
+
uv sync
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
入口命令是 `tuner-init`、`tuner-dna`、`tuner-recorder` 等(`tuner-*`),**没有** `tuner-testkit` 这个 script。
|
|
85
|
+
|
|
86
|
+
### 2. 初始化测试仓
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
tuner-init scaffold ../my-sut-tests
|
|
90
|
+
cd ../my-sut-tests
|
|
91
|
+
uv sync
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`scaffold` 会铺六层目录、写入依赖 `tuner-testkit` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。不要用 `tuner-testkit init repo`。
|
|
95
|
+
|
|
96
|
+
Web UI / 合录按需再加 extra:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv add "tuner-testkit[web-ui]"
|
|
100
|
+
uv add "tuner-testkit[recorder]"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 3. 开始写业务
|
|
104
|
+
|
|
105
|
+
在**项目仓**里写,不要改 site-packages 里的 kit:
|
|
106
|
+
|
|
107
|
+
| 你写什么 | 放哪里 |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| 页面 / 接口资产 | `packages/page_objects/`、`packages/api_objects/` |
|
|
110
|
+
| 业务动作 | `packages/action_words/` |
|
|
111
|
+
| BDD / pytest | `tests/features/`、`tests/pytest/` |
|
|
112
|
+
| 知识(DDL、用例) | `assets/` |
|
|
113
|
+
| 本仓私有工具 | `apps/`(`python -m apps.<name>`) |
|
|
114
|
+
|
|
115
|
+
代码里 `from tuner_testkit.db import …` / `from tuner_testkit.page_test import …`。密钥只放本机 `config/env_local.py` 或环境变量(`TUNER_ENV`、`TUNER_DB_<ALIAS>_*`),**不要提交**。
|
|
116
|
+
|
|
117
|
+
录制产物同样写到项目仓 `packages/`,不会写进 venv。
|
|
118
|
+
|
|
119
|
+
### 4. 升级已发布的 kit
|
|
120
|
+
|
|
121
|
+
平台把新版本推上 PyPI 之后,在项目仓改依赖并同步 DNA——**两步都要做**:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# 改版本:直接改 pyproject.toml,或
|
|
125
|
+
uv add "tuner-testkit[db,api]==4.1.0"
|
|
126
|
+
uv sync
|
|
127
|
+
|
|
128
|
+
# Cursor 不会读 site-packages 里的 rule/skill,必须再铺进本仓并提交
|
|
129
|
+
tuner-dna sync
|
|
130
|
+
git add -A && git commit
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
只跑 `uv add` / `uv sync` 只会更新运行库与 CLI;AI 约束和 git hooks 仍停留在旧 DNA。检查是否与当前安装的 kit 一致:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
tuner-dna check
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
一个 wheel 不能「只升 web-ui、钉死旧 db」。`[phone-ui]` 为预留空 extra,4.0 未实现。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## extras
|
|
144
|
+
|
|
145
|
+
| extra | 内容 |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| (默认 wheel) | `config` / `logging`、`tuner-init`、`tuner-dna`、`tuner-dump-ddl` 等 |
|
|
148
|
+
| `[db]` | MySQL / SQL Server / PostgreSQL |
|
|
149
|
+
| `[api]` | `api_test`(HTTP 客户端) |
|
|
150
|
+
| `[web-ui]` | `page_test` + Playwright |
|
|
151
|
+
| `[phone-ui]` | 预留,无实现 |
|
|
152
|
+
| `[recorder]` | 合录 / 仅 UI / mitmproxy 代理 |
|
|
153
|
+
| `[mock]` | 按冻结的 api_objects 回放 |
|
|
154
|
+
| `[excel]` / `[fake]` | 表格 / 假数据 |
|
|
155
|
+
| `[bdd]` / `[test]` / `[dev]` | behave / pytest / 开发全集 |
|
|
156
|
+
|
|
157
|
+
CLI 与 `python -m tuner_testkit.…` 等价,例如 `tuner-recorder`、`tuner-page-recorder`、`tuner-api-recorder`、`tuner-mock-server`。
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 安全
|
|
162
|
+
|
|
163
|
+
不得把 token、cookie、Authorization、密码、session 写入仓库(含 capture 与 api_objects)。凭证只允许运行时注入。
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 本仓库(平台源码)
|
|
168
|
+
|
|
169
|
+
克隆后在仓库根目录开发 kit 本身:
|
|
170
|
+
|
|
171
|
+
```powershell
|
|
172
|
+
uv venv
|
|
173
|
+
uv sync --extra dev
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
下游迁移清单见 [`docs/changelog/TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# tuner-testkit
|
|
2
|
+
|
|
3
|
+
发行名 **`tuner-testkit`**,导入名 **`tuner_testkit`**。给被测系统(SUT)测试仓提供公共运行库与 CLI(db / API / Web UI / 录制 / mock),以及 Cursor/git **DNA**(rules、skills、hooks)。
|
|
4
|
+
|
|
5
|
+
业务资产(page/api objects、action words、features)留在**各项目仓**的 `packages/` 与 `tests/`,不进本包。平台发新版本后,下游用 `uv` 按需升级,不必再整树拷贝运行库。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 标准作业流程
|
|
10
|
+
|
|
11
|
+
### 1. 安装 `tuner-testkit`
|
|
12
|
+
|
|
13
|
+
还没有任何项目仓时,先把 CLI 装到工具环境:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
uv tool install "tuner-testkit[db,api]"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
需要 headed 录制或 Playwright 时加上对应 extra(见下方 extras)。已有项目仓则在该仓根目录:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv add "tuner-testkit[db,api]>=4.0.0"
|
|
23
|
+
uv sync
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
入口命令是 `tuner-init`、`tuner-dna`、`tuner-recorder` 等(`tuner-*`),**没有** `tuner-testkit` 这个 script。
|
|
27
|
+
|
|
28
|
+
### 2. 初始化测试仓
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
tuner-init scaffold ../my-sut-tests
|
|
32
|
+
cd ../my-sut-tests
|
|
33
|
+
uv sync
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`scaffold` 会铺六层目录、写入依赖 `tuner-testkit` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。不要用 `tuner-testkit init repo`。
|
|
37
|
+
|
|
38
|
+
Web UI / 合录按需再加 extra:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv add "tuner-testkit[web-ui]"
|
|
42
|
+
uv add "tuner-testkit[recorder]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 3. 开始写业务
|
|
46
|
+
|
|
47
|
+
在**项目仓**里写,不要改 site-packages 里的 kit:
|
|
48
|
+
|
|
49
|
+
| 你写什么 | 放哪里 |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| 页面 / 接口资产 | `packages/page_objects/`、`packages/api_objects/` |
|
|
52
|
+
| 业务动作 | `packages/action_words/` |
|
|
53
|
+
| BDD / pytest | `tests/features/`、`tests/pytest/` |
|
|
54
|
+
| 知识(DDL、用例) | `assets/` |
|
|
55
|
+
| 本仓私有工具 | `apps/`(`python -m apps.<name>`) |
|
|
56
|
+
|
|
57
|
+
代码里 `from tuner_testkit.db import …` / `from tuner_testkit.page_test import …`。密钥只放本机 `config/env_local.py` 或环境变量(`TUNER_ENV`、`TUNER_DB_<ALIAS>_*`),**不要提交**。
|
|
58
|
+
|
|
59
|
+
录制产物同样写到项目仓 `packages/`,不会写进 venv。
|
|
60
|
+
|
|
61
|
+
### 4. 升级已发布的 kit
|
|
62
|
+
|
|
63
|
+
平台把新版本推上 PyPI 之后,在项目仓改依赖并同步 DNA——**两步都要做**:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 改版本:直接改 pyproject.toml,或
|
|
67
|
+
uv add "tuner-testkit[db,api]==4.1.0"
|
|
68
|
+
uv sync
|
|
69
|
+
|
|
70
|
+
# Cursor 不会读 site-packages 里的 rule/skill,必须再铺进本仓并提交
|
|
71
|
+
tuner-dna sync
|
|
72
|
+
git add -A && git commit
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
只跑 `uv add` / `uv sync` 只会更新运行库与 CLI;AI 约束和 git hooks 仍停留在旧 DNA。检查是否与当前安装的 kit 一致:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
tuner-dna check
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
一个 wheel 不能「只升 web-ui、钉死旧 db」。`[phone-ui]` 为预留空 extra,4.0 未实现。
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## extras
|
|
86
|
+
|
|
87
|
+
| extra | 内容 |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| (默认 wheel) | `config` / `logging`、`tuner-init`、`tuner-dna`、`tuner-dump-ddl` 等 |
|
|
90
|
+
| `[db]` | MySQL / SQL Server / PostgreSQL |
|
|
91
|
+
| `[api]` | `api_test`(HTTP 客户端) |
|
|
92
|
+
| `[web-ui]` | `page_test` + Playwright |
|
|
93
|
+
| `[phone-ui]` | 预留,无实现 |
|
|
94
|
+
| `[recorder]` | 合录 / 仅 UI / mitmproxy 代理 |
|
|
95
|
+
| `[mock]` | 按冻结的 api_objects 回放 |
|
|
96
|
+
| `[excel]` / `[fake]` | 表格 / 假数据 |
|
|
97
|
+
| `[bdd]` / `[test]` / `[dev]` | behave / pytest / 开发全集 |
|
|
98
|
+
|
|
99
|
+
CLI 与 `python -m tuner_testkit.…` 等价,例如 `tuner-recorder`、`tuner-page-recorder`、`tuner-api-recorder`、`tuner-mock-server`。
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 安全
|
|
104
|
+
|
|
105
|
+
不得把 token、cookie、Authorization、密码、session 写入仓库(含 capture 与 api_objects)。凭证只允许运行时注入。
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 本仓库(平台源码)
|
|
110
|
+
|
|
111
|
+
克隆后在仓库根目录开发 kit 本身:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
uv venv
|
|
115
|
+
uv sync --extra dev
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
下游迁移清单见 [`docs/changelog/TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tuner-testkit"
|
|
3
|
+
version = "4.0.0"
|
|
4
|
+
description = "Shared test runtime, recorders, and DNA overlay for SUT test repos"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{name = "tuner-testkit contributors"}]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"pydantic>=2",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
db = [
|
|
16
|
+
"pymysql>=1.2.0",
|
|
17
|
+
"pymssql>=2.3.0",
|
|
18
|
+
"psycopg[binary]>=3.2",
|
|
19
|
+
"sqlalchemy>=2.0",
|
|
20
|
+
]
|
|
21
|
+
api = [
|
|
22
|
+
"requests>=2.33.1",
|
|
23
|
+
]
|
|
24
|
+
web-ui = [
|
|
25
|
+
"playwright>=1.54.0",
|
|
26
|
+
]
|
|
27
|
+
# Reserved extra name for a future mobile stack (not implemented in 4.0).
|
|
28
|
+
phone-ui = []
|
|
29
|
+
excel = [
|
|
30
|
+
"openpyxl>=3.1.0",
|
|
31
|
+
]
|
|
32
|
+
fake = [
|
|
33
|
+
"faker>=37.0.0",
|
|
34
|
+
]
|
|
35
|
+
mock = [
|
|
36
|
+
"fastapi>=0.115.0",
|
|
37
|
+
"uvicorn[standard]>=0.32.0",
|
|
38
|
+
"httpx>=0.28.0",
|
|
39
|
+
]
|
|
40
|
+
recorder = [
|
|
41
|
+
"playwright>=1.54.0",
|
|
42
|
+
"mitmproxy>=11.1.3",
|
|
43
|
+
]
|
|
44
|
+
test = [
|
|
45
|
+
"pytest>=9.0.3",
|
|
46
|
+
"openpyxl>=3.1.0",
|
|
47
|
+
"httpx>=0.28.0",
|
|
48
|
+
]
|
|
49
|
+
bdd = [
|
|
50
|
+
"behave>=1.2.6",
|
|
51
|
+
"playwright>=1.54.0",
|
|
52
|
+
"behave-html-pretty-formatter>=1.16.1",
|
|
53
|
+
]
|
|
54
|
+
dev = [
|
|
55
|
+
"pymysql>=1.2.0",
|
|
56
|
+
"pymssql>=2.3.0",
|
|
57
|
+
"psycopg[binary]>=3.2",
|
|
58
|
+
"sqlalchemy>=2.0",
|
|
59
|
+
"requests>=2.33.1",
|
|
60
|
+
"pydantic>=2",
|
|
61
|
+
"faker>=37.0.0",
|
|
62
|
+
"openpyxl>=3.1.0",
|
|
63
|
+
"fastapi>=0.115.0",
|
|
64
|
+
"uvicorn[standard]>=0.32.0",
|
|
65
|
+
"httpx>=0.28.0",
|
|
66
|
+
"pytest>=9.0.3",
|
|
67
|
+
"behave>=1.2.6",
|
|
68
|
+
"playwright>=1.54.0",
|
|
69
|
+
"behave-html-pretty-formatter>=1.16.1",
|
|
70
|
+
"mitmproxy>=11.1.3",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[project.scripts]
|
|
74
|
+
tuner-config = "tuner_testkit.config:main"
|
|
75
|
+
tuner-recorder = "tuner_testkit.apps.recorder.cli:main"
|
|
76
|
+
tuner-page-recorder = "tuner_testkit.apps.page_recorder.cli:main"
|
|
77
|
+
tuner-api-recorder = "tuner_testkit.apps.api_recorder.cli:main"
|
|
78
|
+
tuner-dump-ddl = "tuner_testkit.apps.dump_ddl:main"
|
|
79
|
+
tuner-mock-server = "tuner_testkit.apps.mock_server.cli:main"
|
|
80
|
+
tuner-dna = "tuner_testkit.apps.dna.cli:main"
|
|
81
|
+
tuner-init = "tuner_testkit.apps.init_repo.__main__:main"
|
|
82
|
+
tuner-index-ai = "tuner_testkit.apps.index_ai.__main__:main"
|
|
83
|
+
tuner-index-platform = "tuner_testkit.apps.index_platform.__main__:main"
|
|
84
|
+
tuner-fake = "tuner_testkit.fake.cli:main"
|
|
85
|
+
tuner-page-test = "tuner_testkit.page_test.__main__:main"
|
|
86
|
+
tuner-action-words = "tuner_testkit.action_words.__main__:main"
|
|
87
|
+
|
|
88
|
+
[build-system]
|
|
89
|
+
requires = ["setuptools>=77", "wheel"]
|
|
90
|
+
build-backend = "setuptools.build_meta"
|
|
91
|
+
|
|
92
|
+
[tool.setuptools.packages.find]
|
|
93
|
+
include = ["tuner_testkit*"]
|
|
94
|
+
|
|
95
|
+
[tool.setuptools.package-data]
|
|
96
|
+
"tuner_testkit.apps.dna" = ["dna_payload/**/*"]
|
|
97
|
+
|
|
98
|
+
[tool.setuptools.cmdclass]
|
|
99
|
+
build_py = "tuner_testkit.apps.dna.build.BuildPyWithDna"
|
|
100
|
+
sdist = "tuner_testkit.apps.dna.build.SdistWithDna"
|
|
101
|
+
|
|
102
|
+
[tool.tuner-testkit]
|
|
103
|
+
page_objects = "packages/page_objects"
|
|
104
|
+
api_objects = "packages/api_objects"
|
|
105
|
+
mocks = "data/mocks"
|
|
106
|
+
|
|
107
|
+
[tool.pytest.ini_options]
|
|
108
|
+
pythonpath = ["."]
|
|
109
|
+
testpaths = ["packages/tests", "tuner_testkit"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Action Words — 统一管理自动化测试资产的最小业务动作层。
|
|
2
|
+
|
|
3
|
+
设计目标(见 docs/spec/action-words-syntax.md):
|
|
4
|
+
|
|
5
|
+
- 每个 action word 是一个独立可运行的业务动作(DB 造数 / DB 断言 /
|
|
6
|
+
接口请求 / 接口断言 / 页面操作 / 页面断言),入参经 pydantic 强类型
|
|
7
|
+
声明并带样例,可 CLI 一键执行,也可被 behave / pytest 步骤直接调用;
|
|
8
|
+
- 接口类 word 只做冻结 ``packages/api_objects`` 资产的引用与编排,
|
|
9
|
+
不重复定义请求契约;
|
|
10
|
+
- DB 类 word 统一走 ``tuner_testkit.db.DbClient``(经类元数据 ``datasource``
|
|
11
|
+
声明目标库),造数结果按表登记 ``cleanup``,供测试夹具精确清理。
|
|
12
|
+
|
|
13
|
+
CLI::
|
|
14
|
+
|
|
15
|
+
uv run python -m tuner_testkit.action_words list
|
|
16
|
+
uv run python -m tuner_testkit.action_words describe <word_id>
|
|
17
|
+
uv run python -m tuner_testkit.action_words run <word_id> --params '{...}'
|
|
18
|
+
uv run python -m tuner_testkit.action_words catalog --out report/action_words_catalog.json
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from tuner_testkit.action_words.base import (
|
|
23
|
+
ActionCategory,
|
|
24
|
+
ActionResult,
|
|
25
|
+
ActionWord,
|
|
26
|
+
TableRows,
|
|
27
|
+
)
|
|
28
|
+
from tuner_testkit.action_words.context import ActionContext
|
|
29
|
+
from tuner_testkit.action_words.registry import (
|
|
30
|
+
discover,
|
|
31
|
+
export_catalog,
|
|
32
|
+
get,
|
|
33
|
+
list_all,
|
|
34
|
+
register,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"ActionCategory",
|
|
39
|
+
"ActionContext",
|
|
40
|
+
"ActionResult",
|
|
41
|
+
"ActionWord",
|
|
42
|
+
"TableRows",
|
|
43
|
+
"discover",
|
|
44
|
+
"export_catalog",
|
|
45
|
+
"get",
|
|
46
|
+
"list_all",
|
|
47
|
+
"register",
|
|
48
|
+
]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Action Words CLI — 列出 / 查看 / 一键运行 / 导出目录。
|
|
2
|
+
|
|
3
|
+
用法::
|
|
4
|
+
|
|
5
|
+
uv run python -m tuner_testkit.action_words list
|
|
6
|
+
uv run python -m tuner_testkit.action_words describe db_seed.create_example
|
|
7
|
+
uv run python -m tuner_testkit.action_words run db_seed.create_example --params "{...}"
|
|
8
|
+
uv run python -m tuner_testkit.action_words run db_seed.create_example --params-file p.json
|
|
9
|
+
uv run python -m tuner_testkit.action_words run db_seed.create_example --example
|
|
10
|
+
uv run python -m tuner_testkit.action_words catalog --out report/action_words_catalog.json
|
|
11
|
+
|
|
12
|
+
``run`` 未提供 ``--params`` 时使用 ``{}``(即全部默认值);``--example``
|
|
13
|
+
使用 word 自带的 ``example_params`` 样例运行。
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from tuner_testkit.action_words import ActionContext, export_catalog, get, list_all
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _print_json(data: object) -> None:
|
|
26
|
+
print(json.dumps(data, ensure_ascii=False, indent=2, default=str))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _cmd_list(_args: argparse.Namespace) -> int:
|
|
30
|
+
rows = [
|
|
31
|
+
{"word_id": cls.word_id, "name": cls.name, "category": str(cls.category)}
|
|
32
|
+
for cls in list_all()
|
|
33
|
+
]
|
|
34
|
+
_print_json(rows)
|
|
35
|
+
return 0
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _cmd_describe(args: argparse.Namespace) -> int:
|
|
39
|
+
_print_json(get(args.word_id).describe())
|
|
40
|
+
return 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _cmd_run(args: argparse.Namespace) -> int:
|
|
44
|
+
cls = get(args.word_id)
|
|
45
|
+
if args.example:
|
|
46
|
+
raw = dict(cls.example_params)
|
|
47
|
+
elif args.params_file:
|
|
48
|
+
raw = json.loads(Path(args.params_file).read_text(encoding="utf-8"))
|
|
49
|
+
else:
|
|
50
|
+
raw = json.loads(args.params or "{}")
|
|
51
|
+
|
|
52
|
+
with ActionContext(username=args.username, password=args.password) as ctx:
|
|
53
|
+
try:
|
|
54
|
+
result = cls(ctx).run_from_dict(raw)
|
|
55
|
+
except AssertionError as exc:
|
|
56
|
+
_print_json({"ok": False, "error": str(exc)})
|
|
57
|
+
return 1
|
|
58
|
+
_print_json(result.model_dump(mode="json"))
|
|
59
|
+
return 0 if result.ok else 1
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _cmd_catalog(args: argparse.Namespace) -> int:
|
|
63
|
+
catalog = export_catalog()
|
|
64
|
+
if args.out:
|
|
65
|
+
out = Path(args.out)
|
|
66
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
out.write_text(
|
|
68
|
+
json.dumps(catalog, ensure_ascii=False, indent=2, default=str),
|
|
69
|
+
encoding="utf-8",
|
|
70
|
+
)
|
|
71
|
+
print(f"catalog written: {out} ({len(catalog)} words)")
|
|
72
|
+
else:
|
|
73
|
+
_print_json(catalog)
|
|
74
|
+
return 0
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def main(argv: list[str] | None = None) -> int:
|
|
78
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
79
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
80
|
+
|
|
81
|
+
parser = argparse.ArgumentParser(prog="python -m tuner_testkit.action_words")
|
|
82
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
83
|
+
|
|
84
|
+
sub.add_parser("list", help="列出全部已注册 action words")
|
|
85
|
+
|
|
86
|
+
p_desc = sub.add_parser("describe", help="查看某个 word 的元数据 / 入参 schema / 样例")
|
|
87
|
+
p_desc.add_argument("word_id")
|
|
88
|
+
|
|
89
|
+
p_run = sub.add_parser("run", help="一键运行某个 word")
|
|
90
|
+
p_run.add_argument("word_id")
|
|
91
|
+
p_run.add_argument("--params", help="JSON 入参字符串(默认 {})")
|
|
92
|
+
p_run.add_argument("--params-file", help="JSON 入参文件路径")
|
|
93
|
+
p_run.add_argument("--example", action="store_true", help="使用 example_params 样例运行")
|
|
94
|
+
p_run.add_argument("--username", help="接口登录用户名(覆盖环境变量/配置)")
|
|
95
|
+
p_run.add_argument("--password", help="接口登录密码(覆盖环境变量/配置)")
|
|
96
|
+
|
|
97
|
+
p_cat = sub.add_parser("catalog", help="导出全量目录 JSON(平台化数据源)")
|
|
98
|
+
p_cat.add_argument("--out", help="输出文件路径;缺省打印到 stdout")
|
|
99
|
+
|
|
100
|
+
args = parser.parse_args(argv)
|
|
101
|
+
handlers = {
|
|
102
|
+
"list": _cmd_list,
|
|
103
|
+
"describe": _cmd_describe,
|
|
104
|
+
"run": _cmd_run,
|
|
105
|
+
"catalog": _cmd_catalog,
|
|
106
|
+
}
|
|
107
|
+
return handlers[args.command](args)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""API 辅助 — 冻结 api_objects 的动态加载与登录换 token。
|
|
2
|
+
|
|
3
|
+
登录资产模块由环境变量 ``TEST_LOGIN_API_MODULE`` /
|
|
4
|
+
``TEST_LOGIN_API_ATTR`` 配置(默认未设置时明确报错),避免模板硬编码
|
|
5
|
+
业务路由目录。含连字符的包路径(如 ``packages.api_objects.prod-api.login``)
|
|
6
|
+
同样经 :func:`load_api` 按名加载。
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import os
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_api(module_path: str, attr: str) -> Any:
|
|
16
|
+
"""按模块路径与属性名加载一个冻结的 APIModel 资产。"""
|
|
17
|
+
return getattr(importlib.import_module(module_path), attr)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def login_token(username: str, password: str) -> str:
|
|
21
|
+
"""调用冻结的 login 接口资产换取 bearer token。
|
|
22
|
+
|
|
23
|
+
配置(环境变量):
|
|
24
|
+
- ``TEST_LOGIN_API_MODULE`` — 如 ``tuner_testkit.api_objects.auth_api.login``
|
|
25
|
+
- ``TEST_LOGIN_API_ATTR`` — 如 ``login_post_v1``(默认 ``login_post_v1``)
|
|
26
|
+
"""
|
|
27
|
+
module = (os.getenv("TEST_LOGIN_API_MODULE") or "").strip()
|
|
28
|
+
attr = (os.getenv("TEST_LOGIN_API_ATTR") or "login_post_v1").strip()
|
|
29
|
+
if not module:
|
|
30
|
+
raise RuntimeError(
|
|
31
|
+
"未配置登录 API Object:请设置环境变量 TEST_LOGIN_API_MODULE "
|
|
32
|
+
"(及可选 TEST_LOGIN_API_ATTR),指向冻结的 login 资产;"
|
|
33
|
+
"或向 ActionContext 显式传入 bearer_token。"
|
|
34
|
+
)
|
|
35
|
+
login_model = load_api(module, attr)
|
|
36
|
+
resp = login_model.set_json({"username": username, "password": password}).execute()
|
|
37
|
+
token = _extract_token(resp)
|
|
38
|
+
if not token:
|
|
39
|
+
keys = sorted(resp.json.keys()) if isinstance(resp.json, dict) else type(resp.json)
|
|
40
|
+
raise RuntimeError(f"登录响应中未找到 token(响应顶层键: {keys})")
|
|
41
|
+
return token
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _extract_token(resp: Any) -> str | None:
|
|
45
|
+
payload = resp.json if isinstance(resp.json, dict) else {}
|
|
46
|
+
for candidate in (payload.get("token"), payload.get("access_token")):
|
|
47
|
+
if candidate:
|
|
48
|
+
return str(candidate)
|
|
49
|
+
data = payload.get("data")
|
|
50
|
+
if isinstance(data, dict):
|
|
51
|
+
for key in ("token", "access_token", "accessToken"):
|
|
52
|
+
if data.get(key):
|
|
53
|
+
return str(data[key])
|
|
54
|
+
if isinstance(data, str) and data:
|
|
55
|
+
return data
|
|
56
|
+
return None
|