Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions backend/tests/unit/test_phone_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
from unittest.mock import MagicMock, patch

os.environ.setdefault("ENCRYPTION_SECRET", "omi_ZwB2ZNqB2HHpMK6wStk7sTpavJiPTFg7gXUHnc4tFABPU6pZ2c2DKgehtfgi4RZv")
os.environ.setdefault('TWILIO_ACCOUNT_SID', 'ACtest123')
os.environ.setdefault('TWILIO_AUTH_TOKEN', 'test_auth_token')
os.environ.setdefault('TWILIO_API_KEY_SID', 'SKtest123')
os.environ.setdefault('TWILIO_API_KEY_SECRET', 'test_api_secret')
os.environ.setdefault('TWILIO_TWIML_APP_SID', 'APtest123')

# Mock modules that initialize GCP/Firebase clients at import time
_mock_firebase = MagicMock()
Expand All @@ -14,6 +19,11 @@
from fastapi import FastAPI
from fastapi.testclient import TestClient

from tests.unit.twilio_stub import install_twilio_stub

install_twilio_stub()

import routers.phone_calls as phone_calls_router
from routers.phone_calls import router, _redact_phone, E164_PATTERN

# ---------------------------------------------------------------------------
Expand All @@ -24,6 +34,26 @@
TEST_UID_OTHER = 'test-uid-other'


def _make_quota_snapshot():
snapshot = MagicMock()
snapshot.has_access = True
snapshot.is_paid = True
snapshot.max_duration_seconds = None
snapshot.allowed_countries = []
return snapshot
Comment on lines +37 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 phone_call_usage_db unguarded when is_paid is flipped

The autouse fixture always sets snapshot.is_paid = True. In twiml_voice_webhook the only guard keeping phone_call_usage_db.increment_current_month from running is if not snapshot.is_paid:. Because the fixture hard-codes True, the usage DB is never exercised and is never mocked. Any future test that sets is_paid = False (to cover the free-tier billing path) will hit the real phone_call_usage_db call and fail with an uninitialized database connection, since database.phone_call_usage is not in the sys.modules stub table.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in aa699f6.

I added a router-level phone_call_usage_db mock in the autouse fixture and made the fixture return the quota snapshot plus usage DB mock. There is now a free-tier TwiML regression test that flips snapshot.is_paid = False and asserts increment_current_month(TEST_UID) is called without touching the real database.

Validation:

  • python -m pytest tests\unit\test_phone_calls.py -q -> 18 passed, 2 warnings
  • python -m pytest tests\unit\test_phone_calls.py tests\unit\test_twilio_service.py tests\unit\test_twilio_account_deletion.py -q -> 27 passed, 2 warnings
  • python -m py_compile tests\unit\test_phone_calls.py
  • git diff --check origin/main...HEAD



@pytest.fixture(autouse=True)
def isolate_phone_call_quota(monkeypatch):
snapshot = _make_quota_snapshot()
usage_db = MagicMock()
monkeypatch.setattr(phone_calls_router, 'check_call_access', MagicMock(return_value=snapshot))
monkeypatch.setattr(phone_calls_router, 'get_quota_snapshot', MagicMock(return_value=snapshot))
monkeypatch.setattr(phone_calls_router, 'check_destination_allowed', MagicMock(return_value=None))
monkeypatch.setattr(phone_calls_router, 'phone_call_usage_db', usage_db)
return snapshot, usage_db


def _make_app():
app = FastAPI()
app.include_router(router)
Expand Down Expand Up @@ -260,3 +290,17 @@ def test_twiml_success(mock_db, mock_check, mock_sig, client):
body = resp.text
assert '<Dial callerId="+15551234567">' in body
assert '+15559876543' in body


@patch('routers.phone_calls.validate_twilio_signature', return_value=True)
@patch('routers.phone_calls.check_caller_id_verified', return_value=True)
@patch('routers.phone_calls.phone_calls_db')
def test_twiml_free_tier_counts_usage(mock_db, mock_check, mock_sig, client, isolate_phone_call_quota):
snapshot, usage_db = isolate_phone_call_quota
snapshot.is_paid = False
mock_db.get_primary_phone_number.return_value = {'phone_number': '+15551234567'}

resp = client.post('/v1/phone/twiml', data={'To': '+15559876543', 'From': f'client:{TEST_UID}', 'CallId': 'C1'})

assert resp.status_code == 200
usage_db.increment_current_month.assert_called_once_with(TEST_UID)
Loading