pytest-charisma 0.3.1__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.
- pytest_charisma-0.3.1/.gitignore +134 -0
- pytest_charisma-0.3.1/PKG-INFO +157 -0
- pytest_charisma-0.3.1/README.md +133 -0
- pytest_charisma-0.3.1/charisma.ini.example +27 -0
- pytest_charisma-0.3.1/py.typed +1 -0
- pytest_charisma-0.3.1/pyproject.toml +53 -0
- pytest_charisma-0.3.1/pyrightconfig.json +4 -0
- pytest_charisma-0.3.1/src/pytest_charisma/__init__.py +3 -0
- pytest_charisma-0.3.1/src/pytest_charisma/client.py +121 -0
- pytest_charisma-0.3.1/src/pytest_charisma/config.py +265 -0
- pytest_charisma-0.3.1/src/pytest_charisma/models.py +120 -0
- pytest_charisma-0.3.1/src/pytest_charisma/plugin.py +536 -0
- pytest_charisma-0.3.1/src/pytest_charisma/worker.py +154 -0
- pytest_charisma-0.3.1/tests/__init__.py +1 -0
- pytest_charisma-0.3.1/tests/conftest.py +290 -0
- pytest_charisma-0.3.1/tests/test_client.py +344 -0
- pytest_charisma-0.3.1/tests/test_config.py +520 -0
- pytest_charisma-0.3.1/tests/test_crash_recovery.py +389 -0
- pytest_charisma-0.3.1/tests/test_integration.py +546 -0
- pytest_charisma-0.3.1/tests/test_models.py +372 -0
- pytest_charisma-0.3.1/tests/test_plugin.py +977 -0
- pytest_charisma-0.3.1/tests/test_worker.py +489 -0
- pytest_charisma-0.3.1/tests/test_xdist.py +386 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
npm-debug.log*
|
|
4
|
+
yarn-debug.log*
|
|
5
|
+
yarn-error.log*
|
|
6
|
+
|
|
7
|
+
# Environment variables
|
|
8
|
+
.env
|
|
9
|
+
.env.local
|
|
10
|
+
.env.*.local
|
|
11
|
+
|
|
12
|
+
# IDE
|
|
13
|
+
.vscode/*
|
|
14
|
+
!.vscode/settings.json
|
|
15
|
+
!.vscode/tasks.json
|
|
16
|
+
!.vscode/launch.json
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
*~
|
|
22
|
+
|
|
23
|
+
# OS
|
|
24
|
+
.DS_Store
|
|
25
|
+
Thumbs.db
|
|
26
|
+
|
|
27
|
+
# Build outputs
|
|
28
|
+
dist/
|
|
29
|
+
build/
|
|
30
|
+
*.log
|
|
31
|
+
|
|
32
|
+
# Local pipeline secrets (do not commit)
|
|
33
|
+
.env.pipeline
|
|
34
|
+
|
|
35
|
+
# Database
|
|
36
|
+
*.sqlite
|
|
37
|
+
*.db
|
|
38
|
+
|
|
39
|
+
# Test coverage
|
|
40
|
+
coverage/
|
|
41
|
+
.nyc_output/
|
|
42
|
+
|
|
43
|
+
# Temporary files
|
|
44
|
+
tmp/
|
|
45
|
+
temp/
|
|
46
|
+
*.tmp
|
|
47
|
+
|
|
48
|
+
# Confluence sync metadata (optional - can be committed)
|
|
49
|
+
# .amazonq/knowledge-base/.confluence-sync.json
|
|
50
|
+
|
|
51
|
+
# Nuxt build outputs
|
|
52
|
+
.nuxt/
|
|
53
|
+
.output/
|
|
54
|
+
dist/
|
|
55
|
+
|
|
56
|
+
# Python cache
|
|
57
|
+
*.pyc
|
|
58
|
+
*/__pycache__/
|
|
59
|
+
|
|
60
|
+
# Python virtual environments
|
|
61
|
+
.venv/
|
|
62
|
+
venv/
|
|
63
|
+
|
|
64
|
+
# Hypothesys cache
|
|
65
|
+
.hypothesis/
|
|
66
|
+
|
|
67
|
+
# Kiro hooks (auto-generated)
|
|
68
|
+
.kiro/hooks/
|
|
69
|
+
.kiro/settings/*
|
|
70
|
+
.kiro/settings/mcp.json
|
|
71
|
+
|
|
72
|
+
# Kiro spec config (local)
|
|
73
|
+
.kiro/specs/**/.config.kiro
|
|
74
|
+
|
|
75
|
+
# Coverage
|
|
76
|
+
.coverage
|
|
77
|
+
|
|
78
|
+
# AWS SAM build artifacts
|
|
79
|
+
.aws-sam/
|
|
80
|
+
|
|
81
|
+
# Zip files in repo root (test artifacts, allure exports, etc.)
|
|
82
|
+
*.zip
|
|
83
|
+
|
|
84
|
+
# Playwright test results
|
|
85
|
+
frontend/test-results/
|
|
86
|
+
frontend/playwright-report/
|
|
87
|
+
frontend/e2e-results/
|
|
88
|
+
test-results/
|
|
89
|
+
|
|
90
|
+
# E2E auth state (contains secrets)
|
|
91
|
+
frontend/e2e/.auth/
|
|
92
|
+
|
|
93
|
+
# E2E test environment (contains secrets)
|
|
94
|
+
frontend/.env.e2e
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
test-reporting.code-workspace
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
.vscode/extensions.json
|
|
101
|
+
Aurora.session.sql
|
|
102
|
+
Charisma DB.session.sql
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# API integration test setup scripts (contains sensitive token generation)
|
|
106
|
+
backend/api_integration_test_setup_scripts/
|
|
107
|
+
|
|
108
|
+
# Local test/debug scripts
|
|
109
|
+
scripts/test-ingestion-token.py
|
|
110
|
+
|
|
111
|
+
# vs code settings
|
|
112
|
+
.vscode/settings.json
|
|
113
|
+
backend/integration_test_report.xml
|
|
114
|
+
backend/unit_test_report.xml
|
|
115
|
+
frontend/app/pages/proto.vue
|
|
116
|
+
scripts/connect-aurora.ps1
|
|
117
|
+
|
|
118
|
+
# mock test result files
|
|
119
|
+
test-data-junit-debug*
|
|
120
|
+
|
|
121
|
+
# scripts for creating mock data
|
|
122
|
+
scripts/ingest-test-run/*
|
|
123
|
+
|
|
124
|
+
# --- ltm-power ---
|
|
125
|
+
ltm/*
|
|
126
|
+
ltm/store/*.jsonl
|
|
127
|
+
ltm/runtime/*
|
|
128
|
+
ltm/reports/*
|
|
129
|
+
ltm/snapshots/*
|
|
130
|
+
.kiro/steering/ltm-memory-format.md
|
|
131
|
+
.kiro/steering/ltm-operations.md
|
|
132
|
+
backend/coverage.json
|
|
133
|
+
*/__pycache__/*
|
|
134
|
+
allure-results/*
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytest-charisma
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: A pytest plugin that streams test results to the Charisma ingestion API as tests execute.
|
|
5
|
+
Author: Charisma Team
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Framework :: Pytest
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Testing
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx<1.0,>=0.24
|
|
18
|
+
Requires-Dist: pytest<10.0,>=7.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: hypothesis; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
22
|
+
Requires-Dist: respx; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# pytest-charisma
|
|
26
|
+
|
|
27
|
+
A pytest plugin that streams test results to the Charisma ingestion API as tests execute.
|
|
28
|
+
|
|
29
|
+
Results are batched and sent in a background thread so test execution is not blocked by network I/O. The plugin implements retry-once semantics and a circuit breaker (3 consecutive failures disables streaming for the rest of the session).
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install pytest-charisma
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No token, no index URL — works on any laptop and in any CI. The package is published to public PyPI; the Charisma repo itself stays private (only this client plugin wheel is public).
|
|
38
|
+
|
|
39
|
+
For local development from a checkout of the repo:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e packages/pytest-charisma
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Publishing (maintainers)
|
|
46
|
+
|
|
47
|
+
Releases publish to public PyPI automatically from the merge-queue workflow using a **PyPI API token**.
|
|
48
|
+
|
|
49
|
+
> Trusted publishing (OIDC) is not used because this repo runs on **GitHub Enterprise Server**, whose OIDC issuer PyPI does not trust. A stored API token is required instead.
|
|
50
|
+
|
|
51
|
+
One-time setup (done once by a PyPI project owner):
|
|
52
|
+
|
|
53
|
+
1. Sign in to [PyPI](https://pypi.org) with the team-owned account (2FA enabled).
|
|
54
|
+
2. Go to **Account settings → API tokens → Add API token**. Scope it to the `pytest-charisma` project once the project exists; for the very first publish use an account-scoped token, then re-scope it to the project afterward.
|
|
55
|
+
3. Copy the token (starts with `pypi-`).
|
|
56
|
+
4. In the GitHub Enterprise repo, add it as an Actions secret named **`PYPI_API_TOKEN`** (org-level secret recommended so both packages share it).
|
|
57
|
+
5. Bump `version` in `pyproject.toml` and merge — the workflow builds and publishes on the next release.
|
|
58
|
+
|
|
59
|
+
Rotate the token periodically and store it in the team secret manager.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pytest \
|
|
67
|
+
--charisma-url https://api.charisma.example.com \
|
|
68
|
+
--charisma-token $CHARISMA_TOKEN \
|
|
69
|
+
--charisma-project-alias my-project
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The plugin activates automatically when `charisma_url` is configured. If the URL is absent, the plugin stays silent and does nothing.
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
Options are resolved with priority: **CLI flag > pytest.ini / pyproject.toml > environment variable**.
|
|
77
|
+
|
|
78
|
+
| CLI flag | ini key | Env var | Required | Description |
|
|
79
|
+
| -------------------------- | ------------------------ | ------------------------ | -------- | ------------------------------------- |
|
|
80
|
+
| `--charisma-url` | `charisma_url` | `CHARISMA_URL` | Yes | API base URL |
|
|
81
|
+
| `--charisma-token` | `charisma_token` | `CHARISMA_TOKEN` | Yes | Bearer token for authentication |
|
|
82
|
+
| `--charisma-project-alias` | `charisma_project_alias` | `CHARISMA_PROJECT_ALIAS` | Yes | Project alias in Charisma |
|
|
83
|
+
| `--charisma-batch-size` | `charisma_batch_size` | `CHARISMA_BATCH_SIZE` | No | Results per batch, 1–50 (default: 20) |
|
|
84
|
+
| `--charisma-build-id` | `charisma_build_id` | `CHARISMA_BUILD_ID` | No | CI build number or identifier |
|
|
85
|
+
| `--charisma-commit-sha` | `charisma_commit_sha` | `CHARISMA_COMMIT_SHA` | No | Git commit SHA |
|
|
86
|
+
| `--charisma-branch` | `charisma_branch` | `CHARISMA_BRANCH` | No | Git branch name |
|
|
87
|
+
| `--charisma-component` | `charisma_component` | `CHARISMA_COMPONENT` | No | Component alias within the project |
|
|
88
|
+
| `--charisma-source-url` | `charisma_source_url` | `CHARISMA_SOURCE_URL` | No | Link back to CI/CD run |
|
|
89
|
+
|
|
90
|
+
## Configuration via pyproject.toml
|
|
91
|
+
|
|
92
|
+
```toml
|
|
93
|
+
[tool.pytest.ini_options]
|
|
94
|
+
charisma_url = "https://api.charisma.example.com"
|
|
95
|
+
charisma_project_alias = "my-project"
|
|
96
|
+
charisma_batch_size = "10"
|
|
97
|
+
charisma_branch = "main"
|
|
98
|
+
# Token should come from env var for security:
|
|
99
|
+
# export CHARISMA_TOKEN=your-token
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Configuration via pytest.ini
|
|
103
|
+
|
|
104
|
+
```ini
|
|
105
|
+
[pytest]
|
|
106
|
+
charisma_url = https://api.charisma.example.com
|
|
107
|
+
charisma_project_alias = my-project
|
|
108
|
+
charisma_batch_size = 10
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Environment variables only (CI-friendly)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
export CHARISMA_URL=https://api.charisma.example.com
|
|
115
|
+
export CHARISMA_TOKEN=your-api-token
|
|
116
|
+
export CHARISMA_PROJECT_ALIAS=my-project
|
|
117
|
+
export CHARISMA_BUILD_ID=$CI_BUILD_NUMBER
|
|
118
|
+
export CHARISMA_COMMIT_SHA=$CI_COMMIT_SHA
|
|
119
|
+
export CHARISMA_BRANCH=$CI_BRANCH
|
|
120
|
+
export CHARISMA_SOURCE_URL=$CI_BUILD_URL
|
|
121
|
+
|
|
122
|
+
pytest
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## How it works
|
|
126
|
+
|
|
127
|
+
1. **Collection** — After pytest collects tests, the plugin opens a launch session via `POST /api/v1/launches`.
|
|
128
|
+
2. **Execution** — As each test completes, results are buffered. When the buffer reaches `batch_size`, the batch is submitted to a background worker thread.
|
|
129
|
+
3. **Flush** — At session end, remaining results are flushed and the worker drains its queue (up to 30s timeout).
|
|
130
|
+
4. **Resilience** — Each batch gets one retry on failure. After 3 consecutive batch failures, the circuit breaker trips and streaming is disabled for the rest of the session. Test execution is never affected.
|
|
131
|
+
|
|
132
|
+
## Outcome mapping
|
|
133
|
+
|
|
134
|
+
| pytest outcome | Charisma status |
|
|
135
|
+
| ------------------------- | --------------- |
|
|
136
|
+
| `passed` (call phase) | `passed` |
|
|
137
|
+
| `failed` (call phase) | `failed` |
|
|
138
|
+
| `skipped` | `skipped` |
|
|
139
|
+
| `failed` (setup/teardown) | `broken` |
|
|
140
|
+
|
|
141
|
+
## Requirements
|
|
142
|
+
|
|
143
|
+
- Python ≥ 3.10
|
|
144
|
+
- pytest ≥ 7.0, < 9.0
|
|
145
|
+
- httpx ≥ 0.24, < 1.0
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
cd packages/pytest-charisma
|
|
151
|
+
pip install -e ".[dev]"
|
|
152
|
+
pytest
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# pytest-charisma
|
|
2
|
+
|
|
3
|
+
A pytest plugin that streams test results to the Charisma ingestion API as tests execute.
|
|
4
|
+
|
|
5
|
+
Results are batched and sent in a background thread so test execution is not blocked by network I/O. The plugin implements retry-once semantics and a circuit breaker (3 consecutive failures disables streaming for the rest of the session).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install pytest-charisma
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No token, no index URL — works on any laptop and in any CI. The package is published to public PyPI; the Charisma repo itself stays private (only this client plugin wheel is public).
|
|
14
|
+
|
|
15
|
+
For local development from a checkout of the repo:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install -e packages/pytest-charisma
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Publishing (maintainers)
|
|
22
|
+
|
|
23
|
+
Releases publish to public PyPI automatically from the merge-queue workflow using a **PyPI API token**.
|
|
24
|
+
|
|
25
|
+
> Trusted publishing (OIDC) is not used because this repo runs on **GitHub Enterprise Server**, whose OIDC issuer PyPI does not trust. A stored API token is required instead.
|
|
26
|
+
|
|
27
|
+
One-time setup (done once by a PyPI project owner):
|
|
28
|
+
|
|
29
|
+
1. Sign in to [PyPI](https://pypi.org) with the team-owned account (2FA enabled).
|
|
30
|
+
2. Go to **Account settings → API tokens → Add API token**. Scope it to the `pytest-charisma` project once the project exists; for the very first publish use an account-scoped token, then re-scope it to the project afterward.
|
|
31
|
+
3. Copy the token (starts with `pypi-`).
|
|
32
|
+
4. In the GitHub Enterprise repo, add it as an Actions secret named **`PYPI_API_TOKEN`** (org-level secret recommended so both packages share it).
|
|
33
|
+
5. Bump `version` in `pyproject.toml` and merge — the workflow builds and publishes on the next release.
|
|
34
|
+
|
|
35
|
+
Rotate the token periodically and store it in the team secret manager.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pytest \
|
|
43
|
+
--charisma-url https://api.charisma.example.com \
|
|
44
|
+
--charisma-token $CHARISMA_TOKEN \
|
|
45
|
+
--charisma-project-alias my-project
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The plugin activates automatically when `charisma_url` is configured. If the URL is absent, the plugin stays silent and does nothing.
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
Options are resolved with priority: **CLI flag > pytest.ini / pyproject.toml > environment variable**.
|
|
53
|
+
|
|
54
|
+
| CLI flag | ini key | Env var | Required | Description |
|
|
55
|
+
| -------------------------- | ------------------------ | ------------------------ | -------- | ------------------------------------- |
|
|
56
|
+
| `--charisma-url` | `charisma_url` | `CHARISMA_URL` | Yes | API base URL |
|
|
57
|
+
| `--charisma-token` | `charisma_token` | `CHARISMA_TOKEN` | Yes | Bearer token for authentication |
|
|
58
|
+
| `--charisma-project-alias` | `charisma_project_alias` | `CHARISMA_PROJECT_ALIAS` | Yes | Project alias in Charisma |
|
|
59
|
+
| `--charisma-batch-size` | `charisma_batch_size` | `CHARISMA_BATCH_SIZE` | No | Results per batch, 1–50 (default: 20) |
|
|
60
|
+
| `--charisma-build-id` | `charisma_build_id` | `CHARISMA_BUILD_ID` | No | CI build number or identifier |
|
|
61
|
+
| `--charisma-commit-sha` | `charisma_commit_sha` | `CHARISMA_COMMIT_SHA` | No | Git commit SHA |
|
|
62
|
+
| `--charisma-branch` | `charisma_branch` | `CHARISMA_BRANCH` | No | Git branch name |
|
|
63
|
+
| `--charisma-component` | `charisma_component` | `CHARISMA_COMPONENT` | No | Component alias within the project |
|
|
64
|
+
| `--charisma-source-url` | `charisma_source_url` | `CHARISMA_SOURCE_URL` | No | Link back to CI/CD run |
|
|
65
|
+
|
|
66
|
+
## Configuration via pyproject.toml
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[tool.pytest.ini_options]
|
|
70
|
+
charisma_url = "https://api.charisma.example.com"
|
|
71
|
+
charisma_project_alias = "my-project"
|
|
72
|
+
charisma_batch_size = "10"
|
|
73
|
+
charisma_branch = "main"
|
|
74
|
+
# Token should come from env var for security:
|
|
75
|
+
# export CHARISMA_TOKEN=your-token
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration via pytest.ini
|
|
79
|
+
|
|
80
|
+
```ini
|
|
81
|
+
[pytest]
|
|
82
|
+
charisma_url = https://api.charisma.example.com
|
|
83
|
+
charisma_project_alias = my-project
|
|
84
|
+
charisma_batch_size = 10
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Environment variables only (CI-friendly)
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
export CHARISMA_URL=https://api.charisma.example.com
|
|
91
|
+
export CHARISMA_TOKEN=your-api-token
|
|
92
|
+
export CHARISMA_PROJECT_ALIAS=my-project
|
|
93
|
+
export CHARISMA_BUILD_ID=$CI_BUILD_NUMBER
|
|
94
|
+
export CHARISMA_COMMIT_SHA=$CI_COMMIT_SHA
|
|
95
|
+
export CHARISMA_BRANCH=$CI_BRANCH
|
|
96
|
+
export CHARISMA_SOURCE_URL=$CI_BUILD_URL
|
|
97
|
+
|
|
98
|
+
pytest
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## How it works
|
|
102
|
+
|
|
103
|
+
1. **Collection** — After pytest collects tests, the plugin opens a launch session via `POST /api/v1/launches`.
|
|
104
|
+
2. **Execution** — As each test completes, results are buffered. When the buffer reaches `batch_size`, the batch is submitted to a background worker thread.
|
|
105
|
+
3. **Flush** — At session end, remaining results are flushed and the worker drains its queue (up to 30s timeout).
|
|
106
|
+
4. **Resilience** — Each batch gets one retry on failure. After 3 consecutive batch failures, the circuit breaker trips and streaming is disabled for the rest of the session. Test execution is never affected.
|
|
107
|
+
|
|
108
|
+
## Outcome mapping
|
|
109
|
+
|
|
110
|
+
| pytest outcome | Charisma status |
|
|
111
|
+
| ------------------------- | --------------- |
|
|
112
|
+
| `passed` (call phase) | `passed` |
|
|
113
|
+
| `failed` (call phase) | `failed` |
|
|
114
|
+
| `skipped` | `skipped` |
|
|
115
|
+
| `failed` (setup/teardown) | `broken` |
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
- Python ≥ 3.10
|
|
120
|
+
- pytest ≥ 7.0, < 9.0
|
|
121
|
+
- httpx ≥ 0.24, < 1.0
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
cd packages/pytest-charisma
|
|
127
|
+
pip install -e ".[dev]"
|
|
128
|
+
pytest
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# pytest-charisma example configuration
|
|
2
|
+
# Copy this file to pytest.ini or merge into pyproject.toml [tool.pytest.ini_options]
|
|
3
|
+
#
|
|
4
|
+
# Configuration priority: CLI flags > ini values > environment variables
|
|
5
|
+
# Required fields: charisma_url, charisma_token, charisma_project_alias
|
|
6
|
+
|
|
7
|
+
[pytest]
|
|
8
|
+
# --- Required ---
|
|
9
|
+
# Charisma API base URL
|
|
10
|
+
charisma_url = https://yv1d62map2.execute-api.us-east-1.amazonaws.com/prod
|
|
11
|
+
|
|
12
|
+
# Project alias (must match a project configured in Charisma)
|
|
13
|
+
charisma_project_alias = tdg-service
|
|
14
|
+
|
|
15
|
+
# API token — prefer env var CHARISMA_TOKEN for security
|
|
16
|
+
# charisma_token = eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjaS1iYW1ib28tcHJvZCIsImVtYWlsIjoiY2lAaW50ZXJuYWwiLCJuYW1lIjoiYmFtYm9vLXByb2QiLCJ0b2tlblR5cGUiOiJjaSIsImlhdCI6MTc3ODc3MzExMSwiZXhwIjoxODEwMzA5MTExLCJqdGkiOiI0ZDgwNTlhNS1lNDMzLTRlY2ItYmY2YS02YWY0MDFhZDdhZjMifQ.blnhhElVsswcW9oYqnTeKecYGcBZXqstZEW4n9TiX1rtjC7Je4ZG-4vJ-dLgOBVOkJWfuaa_RaZT7fC73B2EFkrPoTe89-C3afCNEmpLWyiq6N7SZjQW6tPWj5MOlbjaEDlxlgr4oSjOluCe1midHZOG9IO22kXaxxBmOQmz6kucLQUnlDWXu9OdRFZl-zmdUg5qir-XxV6LWBEGsAUYIu_LzvodPHMyNcjxnPbmuwVZJn_Wn6VYdLuFXFs59lb8BByhENmFTci8pd-fRqJwXWgOt3AKBUsfzLnnjY8JtqmHUNLQ27SzG622pygN7tE-N9heUptJhMIJUAal9uBDzg
|
|
17
|
+
|
|
18
|
+
# --- Optional ---
|
|
19
|
+
# Number of test results per batch (1–50, default: 20)
|
|
20
|
+
charisma_batch_size = 20
|
|
21
|
+
|
|
22
|
+
# CI metadata (typically set via env vars in CI pipelines)
|
|
23
|
+
# charisma_build_id = 1234
|
|
24
|
+
# charisma_commit_sha = abc123def456
|
|
25
|
+
# charisma_branch = main
|
|
26
|
+
# charisma_component = backend
|
|
27
|
+
# charisma_source_url = https://ci.example.com/builds/1234
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Build: hatchling
|
|
2
|
+
[build-system]
|
|
3
|
+
requires = ["hatchling"]
|
|
4
|
+
build-backend = "hatchling.build"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "pytest-charisma"
|
|
8
|
+
version = "0.3.1"
|
|
9
|
+
description = "A pytest plugin that streams test results to the Charisma ingestion API as tests execute."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Charisma Team" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Framework :: Pytest",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Topic :: Software Development :: Testing",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"pytest>=7.0,<10.0",
|
|
29
|
+
"httpx>=0.24,<1.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.entry-points.pytest11]
|
|
33
|
+
charisma = "pytest_charisma.plugin"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"respx",
|
|
38
|
+
"hypothesis",
|
|
39
|
+
"pytest-xdist",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/pytest_charisma"]
|
|
44
|
+
|
|
45
|
+
[tool.pytest.ini_options]
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
line-length = 120
|
|
50
|
+
target-version = "py310"
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "W", "I"]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""HTTP client wrapper for Charisma API communication.
|
|
2
|
+
|
|
3
|
+
Provides CharismaClient for opening launches and flushing test result batches
|
|
4
|
+
to the Charisma streaming ingestion API. Uses httpx with connection pooling
|
|
5
|
+
and configured timeouts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
import httpx
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("pytest-charisma")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CharismaClient:
|
|
18
|
+
"""HTTP client for the Charisma ingestion API.
|
|
19
|
+
|
|
20
|
+
Wraps httpx.Client with connection pooling, Bearer token auth,
|
|
21
|
+
and configured timeouts (5s connect, 10s read).
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
base_url: Base URL of the Charisma API (e.g. "https://api.charisma.dev").
|
|
25
|
+
token: Bearer token for API authentication.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
CONNECT_TIMEOUT = 5.0
|
|
29
|
+
READ_TIMEOUT = 10.0
|
|
30
|
+
|
|
31
|
+
def __init__(self, base_url: str, token: str) -> None:
|
|
32
|
+
self._http = httpx.Client(
|
|
33
|
+
base_url=base_url,
|
|
34
|
+
headers={
|
|
35
|
+
"Authorization": f"Bearer {token}",
|
|
36
|
+
"Content-Type": "application/json",
|
|
37
|
+
},
|
|
38
|
+
timeout=httpx.Timeout(self.CONNECT_TIMEOUT, read=self.READ_TIMEOUT),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def open_launch(self, payload: dict) -> str:
|
|
42
|
+
"""Open a new launch session.
|
|
43
|
+
|
|
44
|
+
POST /api/v1/launches with the given payload. Returns the launchId
|
|
45
|
+
from the response body. Raises on any non-2xx response or missing launchId.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
payload: Launch request body containing projectAlias, expectedTests,
|
|
49
|
+
and optional fields (buildId, commitSha, branch, etc.).
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
The launchId string from the API response.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
httpx.HTTPStatusError: On non-2xx response status.
|
|
56
|
+
ValueError: If the response body does not contain a launchId.
|
|
57
|
+
"""
|
|
58
|
+
url = "/api/v1/launches"
|
|
59
|
+
response = self._http.post(url, json=payload)
|
|
60
|
+
if response.status_code >= 400:
|
|
61
|
+
logger.warning("open_launch failed: status=%d, body=%s", response.status_code, response.text[:500])
|
|
62
|
+
response.raise_for_status()
|
|
63
|
+
data = response.json()
|
|
64
|
+
launch_id = data.get("launchId")
|
|
65
|
+
if not launch_id:
|
|
66
|
+
raise ValueError(f"API response missing 'launchId': {data}")
|
|
67
|
+
return launch_id
|
|
68
|
+
|
|
69
|
+
def flush_batch(self, launch_id: str, results: list[dict]) -> bool:
|
|
70
|
+
"""Flush a batch of test results to the API.
|
|
71
|
+
|
|
72
|
+
POST /api/v1/launches/{launch_id}/results with results wrapped in
|
|
73
|
+
a {"results": [...]} payload. Returns True on HTTP 200, False on
|
|
74
|
+
any failure (HTTP errors, network errors). Never raises.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
launch_id: The launch session ID to append results to.
|
|
78
|
+
results: List of serialized test result dicts.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
True if the API returned 200, False otherwise.
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
response = self._http.post(
|
|
85
|
+
f"/api/v1/launches/{launch_id}/results",
|
|
86
|
+
json={"results": results},
|
|
87
|
+
)
|
|
88
|
+
if response.status_code != 200:
|
|
89
|
+
logger.warning("flush_batch got status=%d, body=%s", response.status_code, response.text[:200])
|
|
90
|
+
return response.status_code == 200
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.warning("flush_batch exception: %s", e)
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
def close_launch(self, launch_id: str) -> bool:
|
|
96
|
+
"""Close a streaming launch, finalizing its status.
|
|
97
|
+
|
|
98
|
+
POST /api/v1/launches/{launch_id}/close. Signals the API that no more
|
|
99
|
+
results will be sent and the launch should compute its final status
|
|
100
|
+
from whatever results were received. Idempotent.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
launch_id: The launch session ID to close.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
True if the API returned 200, False otherwise.
|
|
107
|
+
"""
|
|
108
|
+
try:
|
|
109
|
+
response = self._http.post(
|
|
110
|
+
f"/api/v1/launches/{launch_id}/close",
|
|
111
|
+
)
|
|
112
|
+
if response.status_code != 200:
|
|
113
|
+
logger.warning("close_launch got status=%d, body=%s", response.status_code, response.text[:200])
|
|
114
|
+
return response.status_code == 200
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.warning("close_launch exception: %s", e)
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
def close(self) -> None:
|
|
120
|
+
"""Close the underlying httpx.Client and release connection pool."""
|
|
121
|
+
self._http.close()
|