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.
@@ -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,4 @@
1
+ {
2
+ "include": ["src", "tests"],
3
+ "extraPaths": ["src"]
4
+ }
@@ -0,0 +1,3 @@
1
+ """pytest-charisma: A pytest plugin that streams test results to the Charisma ingestion API."""
2
+
3
+ __version__ = "0.3.1"
@@ -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()