Files
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

116 lines
4.1 KiB
Python

"""Property-based tests for the PAT Manager expiry checker module using Hypothesis."""
from __future__ import annotations
import os
from unittest.mock import patch
import pytest
import respx
from httpx import Response
from hypothesis import given, settings
from hypothesis import strategies as st
from scripts.pat_manager.checker import ExpiryChecker
from scripts.pat_manager.models import CheckResult, PatEntry, PatStatus
# --- Strategies ---
# HTTP status codes that are NOT in {200-299, 401, 403}
# These should all yield "check failed" classification.
non_auth_error_codes = st.one_of(
st.just(400),
st.just(402),
st.integers(min_value=404, max_value=499),
st.integers(min_value=500, max_value=599),
)
# --- Property 12 Test ---
# Feature: pat-renewal, Property 12: Non-auth HTTP errors yield "check failed"
class TestNonAuthHttpErrorsYieldCheckFailed:
"""
**Validates: Requirements 6.6**
Property 12: For any HTTP response status code that is not 200-299, 401,
or 403, the classification SHALL be "check failed". This includes 4xx errors
(other than 401/403), 5xx errors, and timeout conditions.
"""
@given(status_code=non_auth_error_codes)
@settings(max_examples=100, deadline=None)
async def test_jira_non_auth_errors_yield_check_failed(
self, status_code: int
) -> None:
"""Jira check with non-auth HTTP errors produces check_failed status."""
entry = PatEntry(
service="Jira",
token_name="test-jira-token",
expiry_date="2025-12-01",
renewal_method="manual",
)
checker = ExpiryChecker(max_retries=0)
with patch.dict(os.environ, {"JIRA_URL": "https://jira.example.com"}):
with respx.mock:
respx.get("https://jira.example.com/rest/api/2/myself").mock(
return_value=Response(status_code)
)
result = await checker.check_jira(entry, "fake-token")
assert result.status == PatStatus.CHECK_FAILED
assert result.error_message is not None
assert len(result.error_message) > 0
@given(status_code=non_auth_error_codes)
@settings(max_examples=100, deadline=None)
async def test_confluence_non_auth_errors_yield_check_failed(
self, status_code: int
) -> None:
"""Confluence check with non-auth HTTP errors produces check_failed status."""
entry = PatEntry(
service="Confluence",
token_name="test-confluence-token",
expiry_date="2025-12-01",
renewal_method="manual",
)
checker = ExpiryChecker(max_retries=0)
with patch.dict(os.environ, {"CONFLUENCE_URL": "https://confluence.example.com"}):
with respx.mock:
respx.get(
"https://confluence.example.com/rest/api/user/current"
).mock(return_value=Response(status_code))
result = await checker.check_confluence(entry, "fake-token")
assert result.status == PatStatus.CHECK_FAILED
assert result.error_message is not None
assert len(result.error_message) > 0
@given(status_code=non_auth_error_codes)
@settings(max_examples=100, deadline=None)
async def test_orgmylife_non_auth_errors_yield_check_failed(
self, status_code: int
) -> None:
"""OrgMyLife check with non-auth HTTP errors produces check_failed status."""
entry = PatEntry(
service="OrgMyLife",
token_name="test-orgmylife-token",
expiry_date="2025-12-01",
renewal_method="manual",
)
checker = ExpiryChecker(max_retries=0)
with patch.dict(os.environ, {"ORGMYLIFE_URL": "https://orgmylife.example.com"}):
with respx.mock:
respx.get("https://orgmylife.example.com/api/tasks").mock(
return_value=Response(status_code)
)
result = await checker.check_orgmylife(entry, "fake-token")
assert result.status == PatStatus.CHECK_FAILED
assert result.error_message is not None
assert len(result.error_message) > 0