mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-10 11:12:13 +02:00
* fix: increase concurrency limit an handle it across all call paths * fix: fix review comments and test * fix: address concurrency review findings (campaign-scoped counter, cleanup hardening, webrtc run validation) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: emit usage_concurrent_call_limit_reached PostHog event Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: align usage event with MPS org-event convention (per-member fan-out) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: cap max_call_duration at 20 min via typed workflow_configurations request Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from api.schemas.workflow_configurations import (
|
|
DEFAULT_MAX_CALL_DURATION_SECONDS,
|
|
MAX_CALL_DURATION_SECONDS,
|
|
WorkflowConfigurationDefaults,
|
|
)
|
|
|
|
|
|
def test_max_call_duration_default_within_bounds():
|
|
config = WorkflowConfigurationDefaults()
|
|
assert config.max_call_duration == DEFAULT_MAX_CALL_DURATION_SECONDS
|
|
|
|
|
|
def test_max_call_duration_accepts_cap():
|
|
config = WorkflowConfigurationDefaults(max_call_duration=MAX_CALL_DURATION_SECONDS)
|
|
assert config.max_call_duration == MAX_CALL_DURATION_SECONDS
|
|
|
|
|
|
def test_max_call_duration_rejects_over_cap():
|
|
with pytest.raises(ValidationError):
|
|
WorkflowConfigurationDefaults(max_call_duration=MAX_CALL_DURATION_SECONDS + 1)
|
|
|
|
|
|
def test_max_call_duration_rejects_non_positive():
|
|
with pytest.raises(ValidationError):
|
|
WorkflowConfigurationDefaults(max_call_duration=0)
|
|
|
|
|
|
def test_null_values_treated_as_unset():
|
|
"""Stored configs / older clients send explicit JSON nulls for keys the
|
|
user never configured; they must validate as defaults, not fail."""
|
|
config = WorkflowConfigurationDefaults.model_validate(
|
|
{
|
|
"max_call_duration": None,
|
|
"turn_start_strategy": None,
|
|
"turn_start_min_words": None,
|
|
}
|
|
)
|
|
assert config.max_call_duration == DEFAULT_MAX_CALL_DURATION_SECONDS
|
|
# Nulls count as unset, so a sparse round-trip drops them entirely.
|
|
assert config.model_dump(exclude_unset=True) == {}
|
|
|
|
|
|
def test_exclude_unset_round_trip_stays_sparse():
|
|
config = WorkflowConfigurationDefaults.model_validate(
|
|
{"max_call_duration": 600, "custom_extra_key": {"a": 1}}
|
|
)
|
|
assert config.model_dump(exclude_unset=True) == {
|
|
"max_call_duration": 600,
|
|
"custom_extra_key": {"a": 1},
|
|
}
|
|
|
|
|
|
def test_cap_stays_within_concurrency_stale_timeout():
|
|
"""A call outliving the rate limiter's stale window has its concurrency
|
|
slot purged mid-call, so the cap must never exceed it."""
|
|
from api.services.campaign.rate_limiter import rate_limiter
|
|
|
|
assert MAX_CALL_DURATION_SECONDS <= rate_limiter.stale_call_timeout
|