Skip to content

Stub Twilio imports in phone call router tests#7798

Open
tianmind-studio wants to merge 2 commits into
BasedHardware:mainfrom
tianmind-studio:codex/windows-phone-calls-twilio-stub
Open

Stub Twilio imports in phone call router tests#7798
tianmind-studio wants to merge 2 commits into
BasedHardware:mainfrom
tianmind-studio:codex/windows-phone-calls-twilio-stub

Conversation

@tianmind-studio

@tianmind-studio tianmind-studio commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add minimal Twilio SDK stubs for test_phone_calls.py, covering TwilioRestException, VoiceResponse, Dial, REST client, JWT token, grants, and request validator imports.
  • Stub phone-call plan/quota guards in an autouse fixture so router tests do not hit real subscription/database paths.
  • Add free-tier TwiML coverage to assert successful outbound calls increment the monthly usage bucket.

Why

In this Windows minimal backend venv, test_phone_calls.py failed during collection because the optional Twilio SDK is not installed. After stubbing Twilio imports, endpoint tests reached real phone-call access/quota guards and could hang on external database-backed paths.

These tests already patch the router's Twilio service and database collaborators; keeping the remaining Twilio/plan guard surface local makes the file self-contained and runnable without installing Twilio or connecting to backend services. The follow-up free-tier test keeps the permissive default fixture while explicitly covering the usage-counting branch with is_paid=False.

Testing

  • python -m pytest tests\unit\test_phone_calls.py -q -> 18 passed
  • python -m black --line-length 120 --skip-string-normalization tests\unit\test_phone_calls.py --check
  • python -m py_compile tests\unit\test_phone_calls.py
  • git diff --check -- backend/tests/unit/test_phone_calls.py

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes test_phone_calls.py self-contained by injecting lightweight Twilio SDK stubs via sys.modules.setdefault before any router import, and adds an autouse fixture that monkeypatches the three plan/quota guard functions so tests no longer hit database-backed subscription paths.

  • Twilio module stubs (TwilioRestException, VoiceResponse, Dial, Client, AccessToken, VoiceGrant, RequestValidator) are registered in sys.modules before the router is imported, allowing collection in environments where the optional twilio package is absent.
  • A new autouse=True fixture patches check_call_access, get_quota_snapshot, and check_destination_allowed with monkeypatch, so each test starts with a permissive access profile and reverts automatically after the test completes.

Confidence Score: 4/5

Safe to merge — only test infrastructure changes; no production code is modified.

The Twilio stubs and autouse fixture correctly isolate the tests from external dependencies, and the 17 existing tests pass. The one gap is that the autouse fixture always presents a paid-user profile, so the free-tier call-counting branch in the TwiML webhook is never exercised and a regression there would not be caught by this suite.

backend/tests/unit/test_phone_calls.py — specifically the autouse quota snapshot fixture and the absence of any free-tier twiml test.

Important Files Changed

Filename Overview
backend/tests/unit/test_phone_calls.py Adds Twilio module stubs and an autouse plan-guard fixture; the autouse fixture fixes collection and runtime failures but hardcodes is_paid=True, leaving the free-tier usage-increment path (phone_call_usage_db.increment_current_month) untested.

Sequence Diagram

sequenceDiagram
    participant pytest
    participant test_phone_calls.py
    participant sys.modules
    participant routers.phone_calls
    participant monkeypatch

    Note over test_phone_calls.py: Module-level setup (collection time)
    test_phone_calls.py->>sys.modules: setdefault('twilio', stub)
    test_phone_calls.py->>sys.modules: setdefault('twilio.base.exceptions', stub + TwilioRestException)
    test_phone_calls.py->>sys.modules: setdefault('twilio.twiml.voice_response', stub + VoiceResponse/Dial)
    test_phone_calls.py->>sys.modules: setdefault('twilio.rest', stub + Client)
    test_phone_calls.py->>sys.modules: setdefault('twilio.jwt.access_token.grants', stub + VoiceGrant)
    test_phone_calls.py->>routers.phone_calls: import router (uses stubs above)

    Note over pytest: Per-test setup
    pytest->>monkeypatch: autouse _stub_phone_call_plan_guards
    monkeypatch->>routers.phone_calls: patch check_call_access → MagicMock
    monkeypatch->>routers.phone_calls: "patch get_quota_snapshot → has_access=True, is_paid=True"
    monkeypatch->>routers.phone_calls: patch check_destination_allowed → MagicMock

    pytest->>test_phone_calls.py: run test
    test_phone_calls.py->>routers.phone_calls: HTTP request
    routers.phone_calls-->>test_phone_calls.py: response

    Note over pytest: Per-test teardown
    monkeypatch->>routers.phone_calls: revert all 3 patches automatically
Loading

Reviews (1): Last reviewed commit: "test(backend): stub twilio phone call te..." | Re-trigger Greptile

Comment on lines +102 to +109
@pytest.fixture(autouse=True)
def _stub_phone_call_plan_guards(monkeypatch):
monkeypatch.setattr('routers.phone_calls.check_call_access', MagicMock())
monkeypatch.setattr(
'routers.phone_calls.get_quota_snapshot',
MagicMock(return_value=SimpleNamespace(has_access=True, is_paid=True, max_duration_seconds=None)),
)
monkeypatch.setattr('routers.phone_calls.check_destination_allowed', MagicMock())

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 Free-tier usage increment path is silently bypassed

The autouse fixture sets is_paid=True on every test's quota snapshot. In the router, phone_call_usage_db.increment_current_month(uid) is only executed when not snapshot.is_paid (line 312 of phone_calls.py). Because is_paid is always True here, that branch is never reached, and phone_call_usage_db is never patched in any test — meaning a regression that drops the increment call would pass undetected. Consider adding at least one test (or a parameterized variant of test_twiml_success) that passes is_paid=False and asserts the counter is incremented.

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.

Addressed in f041b7027 by adding test_twiml_free_tier_counts_successful_call.

That test overrides the default paid quota snapshot with is_paid=False, patches phone_call_usage_db, posts a successful TwiML request, and asserts:

mock_usage_db.increment_current_month.assert_called_once_with(TEST_UID)

Revalidated on the Windows backend venv:

  • python -m pytest tests\unit\test_phone_calls.py -q -> 18 passed
  • python -m black --line-length 120 --skip-string-normalization tests\unit\test_phone_calls.py --check
  • python -m py_compile tests\unit\test_phone_calls.py

@tianmind-studio tianmind-studio left a comment

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.

Addressed the free-tier coverage gap in the latest commit. The new TwiML test overrides the quota snapshot with is_paid=False, patches phone_call_usage_db, and asserts increment_current_month(TEST_UID) is called after all dialing guards pass. Re-ran test_phone_calls.py (18 passed) plus black, py_compile, and diff check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant