mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-25 12:01:04 +02:00
chore: incorporate review comments
This commit is contained in:
parent
e486920db2
commit
fdc181e75d
11 changed files with 215 additions and 152 deletions
|
|
@ -1,7 +1,6 @@
|
|||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from api.routes import organization
|
||||
from api.services import tool_management
|
||||
|
|
@ -43,42 +42,6 @@ def test_nested_masked_external_pbx_secrets_are_restored_on_update():
|
|||
assert request["external_pbx"]["agent_api"]["password"] == "agent-secret"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_feature_allows_unchanged_telephony_configuration(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
organization,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=False),
|
||||
)
|
||||
existing = _credentials()
|
||||
|
||||
await organization._enforce_external_pbx_feature(
|
||||
7,
|
||||
"ari",
|
||||
_credentials(),
|
||||
existing_credentials=existing,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_feature_rejects_removing_telephony_configuration(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
organization,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=False),
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await organization._enforce_external_pbx_feature(
|
||||
7,
|
||||
"ari",
|
||||
{"external_pbx": None},
|
||||
existing_credentials=_credentials(),
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_feature_preserves_existing_tool_mapping(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
|
|
|
|||
|
|
@ -1704,7 +1704,6 @@ class TestCustomToolManagerUnit:
|
|||
assert [
|
||||
call.args[0] for call in mock_engine.set_mute_pipeline.call_args_list
|
||||
] == [
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
]
|
||||
|
|
@ -1716,8 +1715,8 @@ class TestCustomToolManagerUnit:
|
|||
assert "I will connect you with our Texas partner now." in spoken_texts
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_transfer_call_resolver_failure_resets_queued_speech_mute(self):
|
||||
"""Resolver failure after a wait message should not leave user input muted."""
|
||||
async def test_transfer_call_resolver_failure_does_not_toggle_pipeline_mute(self):
|
||||
"""Function-call muting covers resolver execution without pipeline state."""
|
||||
from api.services.workflow.pipecat_engine_custom_tools import CustomToolManager
|
||||
|
||||
mock_engine = Mock()
|
||||
|
|
@ -1729,7 +1728,6 @@ class TestCustomToolManagerUnit:
|
|||
mock_engine.task = SimpleNamespace(queue_frame=AsyncMock())
|
||||
mock_engine.set_mute_pipeline = Mock()
|
||||
mock_engine.end_call_with_reason = AsyncMock()
|
||||
mock_engine._queued_speech_mute_state = "idle"
|
||||
|
||||
manager = CustomToolManager(mock_engine)
|
||||
tool = MockToolModel(
|
||||
|
|
@ -1792,13 +1790,7 @@ class TestCustomToolManagerUnit:
|
|||
|
||||
assert result_received["status"] == "transfer_failed"
|
||||
assert result_received["reason"] == "no_destination"
|
||||
assert mock_engine._queued_speech_mute_state == "idle"
|
||||
assert [
|
||||
call.args[0] for call in mock_engine.set_mute_pipeline.call_args_list
|
||||
] == [
|
||||
True,
|
||||
False,
|
||||
]
|
||||
mock_engine.set_mute_pipeline.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_transfer_call_propagates_provider_destination_error(self):
|
||||
|
|
|
|||
|
|
@ -66,6 +66,17 @@ def test_transfer_call_context_mapping_accepts_unique_routes():
|
|||
assert config.context_mapping.routes[0].destination == "sales"
|
||||
|
||||
|
||||
def test_transfer_call_context_mapping_rejects_blank_context_path():
|
||||
with pytest.raises(ValueError, match="context path cannot be blank"):
|
||||
TransferCallConfig(
|
||||
destination_source="context_mapping",
|
||||
context_mapping={
|
||||
"context_path": " ",
|
||||
"routes": [{"context_value": "yes", "destination": "sales"}],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_transfer_call_context_mapping_rejects_duplicate_values_case_insensitively():
|
||||
with pytest.raises(ValueError, match="must be unique"):
|
||||
TransferCallConfig(
|
||||
|
|
|
|||
95
api/tests/test_workflow_configuration_policy.py
Normal file
95
api/tests/test_workflow_configuration_policy.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from api.services.workflow import configuration_policy
|
||||
|
||||
|
||||
def _stored_workflow(mappings: list[dict]):
|
||||
return SimpleNamespace(
|
||||
released_definition=SimpleNamespace(
|
||||
workflow_configurations={"external_pbx_field_mappings": mappings}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_external_pbx_policy_preserves_hidden_mappings(monkeypatch):
|
||||
mappings = [{"context_path": "qualified", "destination_field": "address3"}]
|
||||
get_workflow = AsyncMock(return_value=_stored_workflow(mappings))
|
||||
get_draft = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr(
|
||||
configuration_policy,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=False),
|
||||
)
|
||||
monkeypatch.setattr(configuration_policy.db_client, "get_workflow", get_workflow)
|
||||
monkeypatch.setattr(configuration_policy.db_client, "get_draft_version", get_draft)
|
||||
|
||||
incoming = {"max_call_duration": 600}
|
||||
prepared = await configuration_policy.apply_external_pbx_mapping_policy(
|
||||
incoming,
|
||||
workflow_id=12,
|
||||
organization_id=7,
|
||||
)
|
||||
|
||||
assert prepared == {
|
||||
"max_call_duration": 600,
|
||||
"external_pbx_field_mappings": mappings,
|
||||
}
|
||||
assert "external_pbx_field_mappings" not in incoming
|
||||
get_workflow.assert_awaited_once_with(12, organization_id=7)
|
||||
get_draft.assert_awaited_once_with(12)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disabled_external_pbx_policy_rejects_mapping_changes(monkeypatch):
|
||||
stored = [{"context_path": "qualified", "destination_field": "address3"}]
|
||||
monkeypatch.setattr(
|
||||
configuration_policy,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=False),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
configuration_policy.db_client,
|
||||
"get_workflow",
|
||||
AsyncMock(return_value=_stored_workflow(stored)),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
configuration_policy.db_client,
|
||||
"get_draft_version",
|
||||
AsyncMock(return_value=None),
|
||||
)
|
||||
|
||||
with pytest.raises(configuration_policy.ExternalPBXConfigurationDisabledError):
|
||||
await configuration_policy.apply_external_pbx_mapping_policy(
|
||||
{
|
||||
"external_pbx_field_mappings": [
|
||||
{"context_path": "qualified", "destination_field": "comments"}
|
||||
]
|
||||
},
|
||||
workflow_id=12,
|
||||
organization_id=7,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enabled_external_pbx_policy_does_not_load_workflow(monkeypatch):
|
||||
get_workflow = AsyncMock()
|
||||
monkeypatch.setattr(
|
||||
configuration_policy,
|
||||
"external_pbx_integrations_enabled",
|
||||
AsyncMock(return_value=True),
|
||||
)
|
||||
monkeypatch.setattr(configuration_policy.db_client, "get_workflow", get_workflow)
|
||||
incoming = {"external_pbx_field_mappings": []}
|
||||
|
||||
prepared = await configuration_policy.apply_external_pbx_mapping_policy(
|
||||
incoming,
|
||||
workflow_id=12,
|
||||
organization_id=7,
|
||||
)
|
||||
|
||||
assert prepared is incoming
|
||||
get_workflow.assert_not_awaited()
|
||||
|
|
@ -64,13 +64,23 @@ def test_cap_stays_within_concurrency_stale_timeout():
|
|||
def test_external_pbx_field_mapping_is_validated():
|
||||
config = WorkflowConfigurationDefaults(
|
||||
external_pbx_field_mappings=[
|
||||
{"context_path": "qualified", "destination_field": "address3"}
|
||||
{"context_path": " qualified ", "destination_field": " address3 "}
|
||||
]
|
||||
)
|
||||
|
||||
assert config.external_pbx_field_mappings[0].context_path == "qualified"
|
||||
assert config.external_pbx_field_mappings[0].destination_field == "address3"
|
||||
|
||||
|
||||
def test_external_pbx_field_mapping_rejects_blank_context_paths():
|
||||
with pytest.raises(ValidationError, match="context_path"):
|
||||
WorkflowConfigurationDefaults(
|
||||
external_pbx_field_mappings=[
|
||||
{"context_path": " ", "destination_field": "address3"}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_external_pbx_field_mapping_rejects_invalid_field_names():
|
||||
with pytest.raises(ValidationError, match="destination_field"):
|
||||
WorkflowConfigurationDefaults(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue