mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-25 12:01:04 +02:00
Fix auth and config validation regressions
This commit is contained in:
parent
e4b53f78e9
commit
8ac6f1aa06
9 changed files with 346 additions and 49 deletions
|
|
@ -15,6 +15,7 @@ from api.services.configuration.ai_model_configuration import (
|
|||
WORKFLOW_MODEL_CONFIGURATION_V2_OVERRIDE_KEY,
|
||||
check_for_masked_keys_in_ai_model_configuration_v2,
|
||||
convert_legacy_ai_model_configuration_to_v2,
|
||||
get_resolved_ai_model_configuration,
|
||||
mask_ai_model_configuration_v2,
|
||||
merge_ai_model_configuration_v2_secrets,
|
||||
migrate_workflow_configuration_model_override_to_v2,
|
||||
|
|
@ -148,6 +149,35 @@ async def test_byok_realtime_validator_does_not_require_stt_or_tts():
|
|||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resolved_org_v2_uses_configuration_updated_at_as_validation_cache(
|
||||
monkeypatch,
|
||||
):
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from api.services.configuration import ai_model_configuration
|
||||
|
||||
last_validated_at = datetime.now(UTC)
|
||||
config = OrganizationAIModelConfigurationV2(
|
||||
mode="dograh",
|
||||
dograh=DograhManagedAIModelConfiguration(api_key="mps-secret"),
|
||||
)
|
||||
row = SimpleNamespace(
|
||||
value=config.model_dump(mode="json", exclude_none=True),
|
||||
updated_at=last_validated_at,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
ai_model_configuration.db_client,
|
||||
"get_configuration",
|
||||
AsyncMock(return_value=row),
|
||||
)
|
||||
|
||||
resolved = await get_resolved_ai_model_configuration(organization_id=42)
|
||||
|
||||
assert resolved.source == "organization_v2"
|
||||
assert resolved.effective.last_validated_at == last_validated_at
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pipeline_validator_requires_stt_and_tts_when_not_realtime():
|
||||
effective = EffectiveAIModelConfiguration(
|
||||
|
|
|
|||
99
api/tests/test_user_configuration_validation.py
Normal file
99
api/tests/test_user_configuration_validation.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
from datetime import UTC, datetime, timedelta
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from api.routes import user as user_routes
|
||||
from api.schemas.ai_model_configuration import EffectiveAIModelConfiguration
|
||||
from api.services.configuration.ai_model_configuration import (
|
||||
ResolvedAIModelConfiguration,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_user_configurations_marks_stale_org_v2_config_validated(
|
||||
monkeypatch,
|
||||
):
|
||||
stale_config = EffectiveAIModelConfiguration(
|
||||
last_validated_at=datetime.now(UTC) - timedelta(seconds=120)
|
||||
)
|
||||
resolved = ResolvedAIModelConfiguration(
|
||||
effective=stale_config,
|
||||
source="organization_v2",
|
||||
)
|
||||
validate = AsyncMock(return_value={"status": [{"model": "all", "message": "ok"}]})
|
||||
touch_validation_cache = AsyncMock()
|
||||
|
||||
class FakeValidator:
|
||||
def __init__(self):
|
||||
self.validate = validate
|
||||
|
||||
monkeypatch.setattr(
|
||||
user_routes,
|
||||
"get_resolved_ai_model_configuration",
|
||||
AsyncMock(return_value=resolved),
|
||||
)
|
||||
monkeypatch.setattr(user_routes, "UserConfigurationValidator", FakeValidator)
|
||||
monkeypatch.setattr(
|
||||
user_routes,
|
||||
"update_organization_ai_model_configuration_last_validated_at",
|
||||
touch_validation_cache,
|
||||
)
|
||||
|
||||
response = await user_routes.validate_user_configurations(
|
||||
validity_ttl_seconds=60,
|
||||
user=SimpleNamespace(
|
||||
provider_id="provider-123",
|
||||
selected_organization_id=42,
|
||||
),
|
||||
)
|
||||
|
||||
assert response == {"status": [{"model": "all", "message": "ok"}]}
|
||||
validate.assert_awaited_once_with(
|
||||
stale_config,
|
||||
organization_id=42,
|
||||
created_by="provider-123",
|
||||
)
|
||||
touch_validation_cache.assert_awaited_once_with(42)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_user_configurations_uses_fresh_org_v2_validation_cache(
|
||||
monkeypatch,
|
||||
):
|
||||
fresh_config = EffectiveAIModelConfiguration(last_validated_at=datetime.now(UTC))
|
||||
resolved = ResolvedAIModelConfiguration(
|
||||
effective=fresh_config,
|
||||
source="organization_v2",
|
||||
)
|
||||
validate = AsyncMock()
|
||||
touch_validation_cache = AsyncMock()
|
||||
|
||||
class FakeValidator:
|
||||
def __init__(self):
|
||||
self.validate = validate
|
||||
|
||||
monkeypatch.setattr(
|
||||
user_routes,
|
||||
"get_resolved_ai_model_configuration",
|
||||
AsyncMock(return_value=resolved),
|
||||
)
|
||||
monkeypatch.setattr(user_routes, "UserConfigurationValidator", FakeValidator)
|
||||
monkeypatch.setattr(
|
||||
user_routes,
|
||||
"update_organization_ai_model_configuration_last_validated_at",
|
||||
touch_validation_cache,
|
||||
)
|
||||
|
||||
response = await user_routes.validate_user_configurations(
|
||||
validity_ttl_seconds=60,
|
||||
user=SimpleNamespace(
|
||||
provider_id="provider-123",
|
||||
selected_organization_id=42,
|
||||
),
|
||||
)
|
||||
|
||||
assert response == {"status": []}
|
||||
validate.assert_not_awaited()
|
||||
touch_validation_cache.assert_not_awaited()
|
||||
Loading…
Add table
Add a link
Reference in a new issue