Skip to content

Commit 0fdfed4

Browse files
committed
feat(ci): split Better Stack heartbeat by concern — SDK / Platform API / applications
1 parent 28864d8 commit 0fdfed4

9 files changed

Lines changed: 204 additions & 62 deletions

File tree

.github/CLAUDE.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -712,12 +712,13 @@ External monitoring and alerting for scheduled jobs to detect failures outside G
712712

713713
* `_scheduled-audit.yml` - Audit job monitoring
714714
* `_scheduled-test.yml` - Test job monitoring (staging & production)
715+
* `_scheduled-test-hourly.yml` - Three-way split hourly monitoring
715716

716717
**Functionality**:
717718

718719
1. Job runs (audit or test)
719720
2. Captures exit code (0 = success, non-zero = failure)
720-
3. Constructs JSON payload with metadata
721+
3. Constructs JSON payload with metadata via `_betterstack_heartbeat.py`
721722
4. Sends POST request to BetterStack heartbeat URL with exit code appended
722723
5. BetterStack tracks heartbeat and alerts on failures or missed beats
723724

@@ -745,16 +746,35 @@ External monitoring and alerting for scheduled jobs to detect failures outside G
745746

746747
**URL Format**: `{HEARTBEAT_URL}/{EXIT_CODE}`
747748

749+
**Hourly Three-Way Split** (`_scheduled-test-hourly.yml`):
750+
751+
The hourly workflow runs tests in three independent slices and sends a separate heartbeat per slice so failures are routed to the correct BetterStack monitor:
752+
753+
| Slice | pytest marker filter | Heartbeat secret |
754+
|-------|---------------------|-----------------|
755+
| SDK | `not platform_api and not platform_applications` | `BETTERSTACK_HEARTBEAT_URL_{STAGING\|PRODUCTION}` |
756+
| Platform API | `platform_api` | `BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_{STAGING\|PRODUCTION}` |
757+
| Platform Applications | `platform_applications` | `BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_{STAGING\|PRODUCTION}` |
758+
759+
**Marker scheme for scheduled tests**:
760+
761+
* `platform_api` — test monitors the Platform API layer (auth, app listing, run listing)
762+
* `platform_applications` — test monitors a platform application (he-tme, test-app)
763+
* Neither marker — test is an SDK-layer health check (token management, service wiring)
764+
765+
Tag tests in `tests/` with the boolean markers above. The `monitors` parametrised marker has been removed; use the boolean markers for pytest `-m` expressions.
766+
748767
**Required Secrets**:
749768

750769
* `BETTERSTACK_AUDIT_HEARTBEAT_URL` - For audit jobs
751-
* `BETTERSTACK_HEARTBEAT_URL_STAGING` - For staging test jobs
752-
* `BETTERSTACK_HEARTBEAT_URL_PRODUCTION` - For production test jobs
770+
* `BETTERSTACK_HEARTBEAT_URL_{STAGING|PRODUCTION}` - SDK / general test monitoring
771+
* `BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_{STAGING|PRODUCTION}` - Platform API monitoring (optional)
772+
* `BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_{STAGING|PRODUCTION}` - Platform Applications monitoring (optional)
753773

754774
**Behavior**:
755775

756776
* If heartbeat URL is configured: Sends heartbeat regardless of job success/failure
757-
* If heartbeat URL is NOT configured: Logs warning and continues
777+
* If heartbeat URL is NOT configured: Logs info and continues (heartbeat steps never fail the job)
758778
* Exit code passed to URL allows BetterStack to distinguish success (0) from failures
759779

760780
## Environment Configuration
@@ -805,7 +825,9 @@ External monitoring and alerting for scheduled jobs to detect failures outside G
805825
* `AIGNOSTICS_REFRESH_TOKEN_{STAGING|PRODUCTION}`
806826
* `GCP_CREDENTIALS_{STAGING|PRODUCTION}` - Base64 encoded JSON
807827
* `BETTERSTACK_AUDIT_HEARTBEAT_URL` - Audit monitoring
808-
* `BETTERSTACK_HEARTBEAT_URL_{STAGING|PRODUCTION}` - Test monitoring
828+
* `BETTERSTACK_HEARTBEAT_URL_{STAGING|PRODUCTION}` - SDK test monitoring
829+
* `BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_{STAGING|PRODUCTION}` - Platform API monitoring (optional)
830+
* `BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_{STAGING|PRODUCTION}` - Platform Applications monitoring (optional)
809831
* `CODECOV_TOKEN` - Coverage reporting to Codecov
810832
* `SONAR_TOKEN` - Code quality reporting to SonarCloud
811833
* `UV_PUBLISH_TOKEN` - PyPI publishing token
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from __future__ import annotations
2+
3+
import json
4+
import os
5+
import sys
6+
import urllib.error
7+
import urllib.request
8+
from datetime import UTC, datetime
9+
10+
11+
def send_betterstack_heartbeat(url: str, exit_code: str, label: str) -> None:
12+
if not url:
13+
print(f"INFO: No BetterStack {label} heartbeat URL configured, skipped.")
14+
return
15+
16+
payload = {
17+
"github": {
18+
"workflow": os.environ.get("GITHUB_WORKFLOW", ""),
19+
"run_url": (
20+
f"{os.environ.get('GITHUB_SERVER_URL', '')}"
21+
f"/{os.environ.get('GITHUB_REPOSITORY', '')}"
22+
f"/actions/runs/{os.environ.get('GITHUB_RUN_ID', '')}"
23+
),
24+
"run_id": os.environ.get("GITHUB_RUN_ID", ""),
25+
"job": os.environ.get("GITHUB_JOB", ""),
26+
"sha": os.environ.get("GITHUB_SHA", ""),
27+
"actor": os.environ.get("GITHUB_ACTOR", ""),
28+
"repository": os.environ.get("GITHUB_REPOSITORY", ""),
29+
"ref": os.environ.get("GITHUB_REF", ""),
30+
"event_name": os.environ.get("GITHUB_EVENT_NAME", ""),
31+
},
32+
"job": {"status": os.environ.get("JOB_STATUS", "")},
33+
"timestamp": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
34+
}
35+
36+
data = json.dumps(payload).encode()
37+
req = urllib.request.Request( # noqa: S310
38+
f"{url}/{exit_code}",
39+
data=data,
40+
headers={"Content-Type": "application/json"},
41+
method="POST",
42+
)
43+
try:
44+
urllib.request.urlopen(req, timeout=10) # noqa: S310
45+
print(f"INFO: Sent {label} heartbeat to BetterStack (exit={exit_code})")
46+
except urllib.error.URLError as exc:
47+
print(f"WARNING: Failed to send {label} heartbeat to BetterStack: {exc}", file=sys.stderr)
48+
49+
50+
if __name__ == "__main__":
51+
send_betterstack_heartbeat(
52+
url=os.environ.get("BETTERSTACK_HEARTBEAT_URL", ""),
53+
exit_code=os.environ.get("BETTERSTACK_EXIT_CODE", "1"),
54+
label=os.environ.get("BETTERSTACK_LABEL", "unknown"),
55+
)

.github/workflows/_scheduled-test-hourly.yml

Lines changed: 101 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ on:
2222
required: true
2323
BETTERSTACK_HEARTBEAT_URL_STAGING:
2424
required: true
25+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING:
26+
required: false
27+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING:
28+
required: false
2529
AIGNOSTICS_CLIENT_ID_DEVICE_PRODUCTION:
2630
required: true
2731
AIGNOSTICS_REFRESH_TOKEN_PRODUCTION:
@@ -30,6 +34,10 @@ on:
3034
required: true
3135
BETTERSTACK_HEARTBEAT_URL_PRODUCTION:
3236
required: true
37+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION:
38+
required: false
39+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION:
40+
required: false
3341
SENTRY_DSN:
3442
required: true
3543

@@ -90,18 +98,59 @@ jobs:
9098
echo "$GCP_CREDENTIALS" | base64 -d > credentials.json
9199
echo "GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/credentials.json" >> $GITHUB_ENV
92100
93-
- name: Test / scheduled
101+
- name: Test / scheduled / sdk
102+
id: test_sdk
103+
env:
104+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
105+
shell: bash
106+
run: |
107+
set +e
108+
XDIST_WORKER_FACTOR=1 uv run --all-extras nox -s test -- \
109+
-m "(scheduled or scheduled_only) and not platform_api and not platform_applications and not stress_only"
110+
echo "exit_code=$?" >> $GITHUB_OUTPUT
111+
112+
- name: Test / scheduled / platform-api
113+
id: test_platform_api
94114
env:
95-
BETTERSTACK_HEARTBEAT_URL: "${{ inputs.platform_environment == 'staging' && secrets.BETTERSTACK_HEARTBEAT_URL_STAGING || secrets.BETTERSTACK_HEARTBEAT_URL_PRODUCTION }}"
96115
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
97116
shell: bash
98117
run: |
99118
set +e
100-
make test_scheduled
101-
EXIT_CODE=$?
102-
# Show test execution in GitHub Job summary
119+
XDIST_WORKER_FACTOR=1 uv run --all-extras nox -s test -- \
120+
-m "(scheduled or scheduled_only) and platform_api and not stress_only"
121+
echo "exit_code=$?" >> $GITHUB_OUTPUT
122+
123+
- name: Test / scheduled / platform-applications
124+
id: test_platform_applications
125+
env:
126+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
127+
shell: bash
128+
run: |
129+
set +e
130+
XDIST_WORKER_FACTOR=1 uv run --all-extras nox -s test -- \
131+
-m "(scheduled or scheduled_only) and platform_applications and not stress_only"
132+
echo "exit_code=$?" >> $GITHUB_OUTPUT
133+
134+
- name: Collect combined exit code and publish summary
135+
id: collect
136+
if: always()
137+
shell: bash
138+
run: |
139+
SDK_EXIT=${{ steps.test_sdk.outputs.exit_code || '1' }}
140+
PLATFORM_API_EXIT=${{ steps.test_platform_api.outputs.exit_code || '1' }}
141+
PLATFORM_APPLICATIONS_EXIT=${{ steps.test_platform_applications.outputs.exit_code || '1' }}
142+
if [ "$SDK_EXIT" != "0" ] || [ "$PLATFORM_API_EXIT" != "0" ] || [ "$PLATFORM_APPLICATIONS_EXIT" != "0" ]; then
143+
COMBINED_EXIT=1
144+
else
145+
COMBINED_EXIT=0
146+
fi
147+
echo "sdk_exit=${SDK_EXIT}" >> $GITHUB_OUTPUT
148+
echo "platform_api_exit=${PLATFORM_API_EXIT}" >> $GITHUB_OUTPUT
149+
echo "platform_applications_exit=${PLATFORM_APPLICATIONS_EXIT}" >> $GITHUB_OUTPUT
150+
echo "combined_exit=${COMBINED_EXIT}" >> $GITHUB_OUTPUT
151+
103152
found_files=0
104-
for file in reports/pytest_*.md; do
153+
for file in reports/pytest_*.md reports/pytest.md; do
105154
if [ -f "$file" ]; then
106155
cat "$file" >> $GITHUB_STEP_SUMMARY
107156
echo "" >> $GITHUB_STEP_SUMMARY
@@ -112,7 +161,6 @@ jobs:
112161
echo "# All scheduled tests passed" >> $GITHUB_STEP_SUMMARY
113162
echo "" >> $GITHUB_STEP_SUMMARY
114163
fi
115-
# Show test coverage in GitHub Job summary
116164
if [ -f "reports/coverage.md" ]; then
117165
cat "reports/coverage.md" >> $GITHUB_STEP_SUMMARY
118166
echo "" >> $GITHUB_STEP_SUMMARY
@@ -121,63 +169,61 @@ jobs:
121169
echo "" >> $GITHUB_STEP_SUMMARY
122170
fi
123171
124-
# Send heartbeat to Sentry, defining the schedule on the fly
125-
SENTRY_EXIT_CODE=$(sentry-cli monitors run -e CI --schedule "0 * * * *" --check-in-margin 30 --max-runtime 1 scheduled-testing-${{ inputs.platform_environment }}-hourly --timezone "Europe/Berlin" -- sh -c "exit $EXIT_CODE")
126-
127-
# Provide heartbeat to BetterStack for monitoring/alerting if heartbeat url is configured as secret
128-
if [ -n "$BETTERSTACK_HEARTBEAT_URL" ]; then
129-
BETTERSTACK_METADATA_PAYLOAD=$(jq -n \
130-
--arg github_workflow "${{ github.workflow }}" \
131-
--arg github_run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
132-
--arg github_run_id "${{ github.run_id }}" \
133-
--arg github_job "${{ github.job }}" \
134-
--arg github_sha "${{ github.sha }}" \
135-
--arg github_actor "${{ github.actor }}" \
136-
--arg github_repository "${{ github.repository }}" \
137-
--arg github_ref "${{ github.ref }}" \
138-
--arg job_status "${{ job.status }}" \
139-
--arg github_event_name "${{ github.event_name }}" \
140-
--arg timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
141-
'{
142-
github: {
143-
workflow: $github_workflow,
144-
run_url: $github_run_url,
145-
run_id: $github_run_id,
146-
job: $github_job,
147-
sha: $github_sha,
148-
actor: $github_actor,
149-
repository: $github_repository,
150-
ref: $github_ref,
151-
event_name: $github_event_name
152-
},
153-
job: {
154-
status: $job_status,
155-
},
156-
timestamp: $timestamp,
157-
}'
158-
)
159-
curl \
160-
--fail-with-body \
161-
--silent \
162-
--request POST \
163-
--header "Content-Type: application/json" \
164-
--data-binary "${BETTERSTACK_METADATA_PAYLOAD}" \
165-
"${BETTERSTACK_HEARTBEAT_URL}/${EXIT_CODE}"
166-
echo "INFO: Sent heartbeat to betterstack with exit code '${EXIT_CODE}'"
167-
else
168-
echo "WARNING: No BetterStack heartbeat URL configured, skipped heartbeat notification."
169-
fi
170-
exit $EXIT_CODE
172+
- name: Heartbeat / Sentry
173+
if: always()
174+
shell: bash
175+
env:
176+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
177+
COMBINED_EXIT: ${{ steps.collect.outputs.combined_exit }}
178+
run: |
179+
sentry-cli monitors run -e CI --schedule "0 * * * *" --check-in-margin 30 --max-runtime 1 \
180+
scheduled-testing-${{ inputs.platform_environment }}-hourly \
181+
--timezone "Europe/Berlin" -- sh -c "exit ${COMBINED_EXIT}" || true
182+
183+
- name: Heartbeat / BetterStack / SDK
184+
if: always()
185+
env:
186+
BETTERSTACK_HEARTBEAT_URL: "${{ inputs.platform_environment == 'staging' && secrets.BETTERSTACK_HEARTBEAT_URL_STAGING || secrets.BETTERSTACK_HEARTBEAT_URL_PRODUCTION }}"
187+
BETTERSTACK_EXIT_CODE: ${{ steps.collect.outputs.sdk_exit }}
188+
BETTERSTACK_LABEL: SDK
189+
JOB_STATUS: ${{ job.status }}
190+
shell: bash
191+
run: python3 .github/workflows/_betterstack_heartbeat.py
192+
193+
- name: Heartbeat / BetterStack / Platform API
194+
if: always()
195+
env:
196+
BETTERSTACK_HEARTBEAT_URL: "${{ inputs.platform_environment == 'staging' && secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING || secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION }}"
197+
BETTERSTACK_EXIT_CODE: ${{ steps.collect.outputs.platform_api_exit }}
198+
BETTERSTACK_LABEL: "Platform API"
199+
JOB_STATUS: ${{ job.status }}
200+
shell: bash
201+
run: python3 .github/workflows/_betterstack_heartbeat.py
202+
203+
- name: Heartbeat / BetterStack / Platform Applications
204+
if: always()
205+
env:
206+
BETTERSTACK_HEARTBEAT_URL: "${{ inputs.platform_environment == 'staging' && secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING || secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION }}"
207+
BETTERSTACK_EXIT_CODE: ${{ steps.collect.outputs.platform_applications_exit }}
208+
BETTERSTACK_LABEL: "Platform Applications"
209+
JOB_STATUS: ${{ job.status }}
210+
shell: bash
211+
run: python3 .github/workflows/_betterstack_heartbeat.py
171212

172213
- name: Upload test results
173214
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
174215
if: ${{ always() && (env.GITHUB_WORKFLOW_RUNTIME != 'ACT') }}
175216
with:
176217
name: test-results-scheduled
177218
path: |
178-
reports/junit.xml
219+
reports/junit_*.xml
179220
reports/coverage.xml
180221
reports/coverage.md
181222
reports/coverage_html
182223
aignostics.log
183224
retention-days: 7
225+
226+
- name: Fail job if any tests failed
227+
if: always()
228+
shell: bash
229+
run: exit ${{ steps.collect.outputs.combined_exit }}

.github/workflows/scheduled-testing-production-hourly.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ jobs:
2424
AIGNOSTICS_REFRESH_TOKEN_STAGING: ${{ secrets.AIGNOSTICS_REFRESH_TOKEN_STAGING }}
2525
GCP_CREDENTIALS_STAGING: ${{ secrets.GCP_CREDENTIALS_STAGING }}
2626
BETTERSTACK_HEARTBEAT_URL_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_STAGING }}
27+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING }}
28+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING }}
2729
AIGNOSTICS_CLIENT_ID_DEVICE_PRODUCTION: ${{ secrets.AIGNOSTICS_CLIENT_ID_DEVICE_PRODUCTION }}
2830
AIGNOSTICS_REFRESH_TOKEN_PRODUCTION: ${{ secrets.AIGNOSTICS_REFRESH_TOKEN_PRODUCTION }}
2931
GCP_CREDENTIALS_PRODUCTION: ${{ secrets.GCP_CREDENTIALS_PRODUCTION }}
3032
BETTERSTACK_HEARTBEAT_URL_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PRODUCTION }}
31-
SENTRY_DSN: ${{ secrets.SENTRY_DSN }} # For metrics and heartbeat
33+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION }}
34+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION }}
35+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}

.github/workflows/scheduled-testing-staging-hourly.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ jobs:
2424
AIGNOSTICS_REFRESH_TOKEN_STAGING: ${{ secrets.AIGNOSTICS_REFRESH_TOKEN_STAGING }}
2525
GCP_CREDENTIALS_STAGING: ${{ secrets.GCP_CREDENTIALS_STAGING }}
2626
BETTERSTACK_HEARTBEAT_URL_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_STAGING }}
27+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_STAGING }}
28+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_STAGING }}
2729
AIGNOSTICS_CLIENT_ID_DEVICE_PRODUCTION: ${{ secrets.AIGNOSTICS_CLIENT_ID_DEVICE_PRODUCTION }}
2830
AIGNOSTICS_REFRESH_TOKEN_PRODUCTION: ${{ secrets.AIGNOSTICS_REFRESH_TOKEN_PRODUCTION }}
2931
GCP_CREDENTIALS_PRODUCTION: ${{ secrets.GCP_CREDENTIALS_PRODUCTION }}
3032
BETTERSTACK_HEARTBEAT_URL_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PRODUCTION }}
31-
SENTRY_DSN: ${{ secrets.SENTRY_DSN }} # For metrics and heartbeat
33+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_APPLICATIONS_PRODUCTION }}
34+
BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION: ${{ secrets.BETTERSTACK_HEARTBEAT_URL_PLATFORM_API_PRODUCTION }}
35+
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ markers = [
383383
"unit: Solitary unit tests - test a layer of a module in isolation with all dependencies mocked, except interaction with shared utils and the systems module. Unit tests must be able to pass offline, i.e. not calls to external services. The timeout should not be bigger than the default 10s, and must be <5 min.",
384384
"integration: Sociable integration tests - test interactions across architectural layers (e.g. CLI/GUI→Service, Service→Utils) or between modules (e.g. Application→Platform), using real SDK collaborators, real file I/O, real subprocesses, and real Docker containers. Integration test must be able to pass offline, i.e. mock external services (Aignostics Platform API, Auth0, S3/GCS buckets, IDC). The timeout should not be bigger than the default 10s, and must be <5 min.",
385385
"e2e: End-to-end tests - test complete workflows with real external network services (Aignostics Platform API, cloud storage, IDC, etc). If the test timeout is >= 5 min and < 60 min, additionally mark as `long_running`, if >= 60min mark as 'very_long_running'.",
386+
"platform_api: Tag a scheduled test that monitors the Platform API layer (auth, application listing, run listing). Routes Better Stack heartbeats to the Platform API monitor.",
387+
"platform_applications: Tag a scheduled test that monitors a platform application (he-tme, test-app). Routes Better Stack heartbeats to the Platform Applications monitor.",
386388
]
387389
md_report = true
388390
md_report_output = "reports/pytest.md"

tests/aignostics/application/cli_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def test_cli_application_list_non_verbose(runner: CliRunner, record_property) ->
164164

165165
@pytest.mark.e2e
166166
@pytest.mark.scheduled
167+
@pytest.mark.platform_api
167168
@pytest.mark.timeout(timeout=60)
168169
def test_cli_application_list_verbose(runner: CliRunner, record_property) -> None:
169170
"""Check application list command runs successfully."""
@@ -801,6 +802,7 @@ def test_cli_run_submit_and_describe_and_cancel_and_download_and_delete( # noqa
801802

802803
@pytest.mark.e2e
803804
@pytest.mark.scheduled
805+
@pytest.mark.platform_api
804806
@pytest.mark.timeout(timeout=60)
805807
def test_cli_run_list_limit_10(runner: CliRunner, record_property) -> None:
806808
"""Check run list command runs successfully."""

0 commit comments

Comments
 (0)