Skip to content

Conversation

AkhileshNegi
Copy link
Collaborator

@AkhileshNegi AkhileshNegi commented Aug 8, 2025

Summary

Target issue is #288

Checklist

Before submitting a pull request, please ensure that you mark these task.

  • Ran fastapi run --reload app/main.py or docker compose up in the repository root and test.
  • If you've fixed a bug or added code that is tested and has test cases.

Notes

Please add here if any other information is required for the reviewer.

Summary by CodeRabbit

  • Tests
    • Refactored response-related API tests to use mock-based verification and assert scheduling of a background processing task instead of direct external calls.
    • Added centralized mock helpers and common setup to reduce duplication.
    • Expanded coverage for ancestor-conversation present/absent, vector-store present/absent, response ID present/absent, missing credentials, and overall scheduling behavior.
    • Tests now target POST /api/v1/responses and verify scheduled task payload includes assistant ID, question, callback URL, and response-ID semantics.

@AkhileshNegi AkhileshNegi self-assigned this Aug 8, 2025
@AkhileshNegi AkhileshNegi added the bug Something isn't working label Aug 8, 2025
Copy link

coderabbitai bot commented Aug 8, 2025

Walkthrough

Tests for POST /api/v1/responses were refactored to centralized mock helpers and now assert that a background task process_response is scheduled with a ResponsesAPIRequest; new tests cover ancestor lookup, presence/absence of response_id, vector-store and credential scenarios. (33 words)

Changes

Cohort / File(s) Change Summary
Tests: responses endpoint & background scheduling
backend/app/tests/api/routes/test_responses.py
Refactored to mock-based scaffolding with helpers (create_mock_assistant, create_mock_openai_response, create_mock_conversation, setup_common_mocks); tests now mock process_response and assert it's scheduled with a ResponsesAPIRequest across scenarios (success, missing vector store, ancestor found/not found, absent response_id, missing OpenAI creds).
API surface: responses route
backend/app/api/routes/responses.py
process_response and ResponsesAPIRequest are referenced as public exports; tests expect process_response(request, client, assistant, tracer, project_id, organization_id, session) and a ResponsesAPIRequest type with fields like assistant_id, question, callback_url, optional response_id.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(220,240,255,0.6)
    participant Test as Test Suite
    participant API as POST /api/v1/responses
    participant Scheduler as Background Scheduler
    participant Worker as process_response
    end

    Test->>API: POST /api/v1/responses
    API->>Scheduler: schedule Worker(ResponsesAPIRequest)
    Scheduler->>Worker: invoke Worker (mocked in tests)
    Worker-->>Scheduler: complete
    API-->>Test: HTTP 200 / accepted
Loading
sequenceDiagram
    rect rgba(240,255,220,0.6)
    participant Worker as process_response
    participant DB as Conversation Store
    participant OAI as OpenAI Client
    participant CB as Callback Sender
    end

    Worker->>DB: lookup ancestor conversation (if provided)
    alt Ancestor found
        Worker->>OAI: generate response using ancestor.response_id as previous_response_id
    else Ancestor not found
        Worker->>OAI: generate response using request.response_id or none
    end
    Worker->>DB: create/update conversation & response records
    Worker->>CB: POST callback to request.callback_url with payload
    Worker-->>Caller: return / side-effects complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nishika26
  • avirajsingh7

Poem

"I hopped through mocks at dawn's first light,
Queued a task to run out of sight,
Ancestors checked and callbacks flew,
Responses formed, the tests all grew,
🐇✨"

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hotfix/response-api-testcases

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@AkhileshNegi AkhileshNegi linked an issue Aug 8, 2025 that may be closed by this pull request
Copy link

codecov bot commented Aug 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
backend/app/tests/api/routes/test_responses.py (5)

396-402: See earlier note on positional vs keyword assertions – same recommendation applies.


493-499: Same positional-arg caveat; please switch to kw-arg based check or helper.


587-593: Same positional-arg caveat; consider helper.


678-684: Same positional-arg caveat; consider helper.


787-874: Logic mirrors the previous test; same DRY & DB-skip concerns apply.

🧹 Nitpick comments (1)
backend/app/tests/api/routes/test_responses.py (1)

204-210: Duplicate assertion logic – extract helper

The same positional-based assertions appear in multiple tests (Lines 115-122, 204-210, 396-402, etc.).
Factor them into a small helper, e.g. assert_request_fields(call_args, expected), to cut duplication and keep tests concise.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cae70be and f1f81e8.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (16 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: checks (3.11.7, 6)
🔇 Additional comments (8)
backend/app/tests/api/routes/test_responses.py (8)

7-8: No concerns for the added import – looks correct.


16-24: Decorator stack order & injected mock parameters line-up correctly – nothing to fix here.


38-40: Mocking the background task to prevent execution is sound.


145-147: Background task correctly stubbed.


323-324: Nothing to flag – simple stubbing.


427-428: OK.


524-525: OK.


618-619: OK.

Comment on lines +115 to +122
# Verify that the background task was scheduled with correct parameters
mock_process_response.assert_called_once()
call_args = mock_process_response.call_args
assert call_args[0][0].assistant_id == "assistant_dalgo"
assert call_args[0][0].question == "What is Dalgo?"
assert call_args[0][0].callback_url == "http://example.com/callback"
assert call_args[0][0].response_id is None

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Prefer kw-arg based assertion for long-term safety

process_response is asserted via call_args[0][0], assuming the request object is the first positional arg.
If the production code ever switches to keyword invocation (background_tasks.add_task(process_response, request=request, …)), this test will start failing even though behaviour is unchanged. Use call_args.kwargs["request"] (or call_args.kwargs.get("request")) instead.

-assert call_args[0][0].assistant_id == "assistant_dalgo"
+request_arg = call_args.kwargs.get("request") or call_args.args[0]
+assert request_arg.assistant_id == "assistant_dalgo"

Run the script below to confirm the current calling style:


🏁 Script executed:

#!/bin/bash
# Search for process_response scheduling
rg -n "add_task\(.*process_response" app/api/routes/responses.py

Length of output: 134


To locate where process_response is scheduled, let’s search the entire repo for any add_task invocation and usages of process_response without assuming the path. Please run:


🏁 Script executed:

#!/bin/bash
# Find any add_task calls that mention process_response
rg -n "add_task.*process_response" -A3

# Locate all references to process_response to see its definition and callers
rg -n "process_response" -A3

Length of output: 14544


To confirm how process_response is actually scheduled—positional vs. keyword args—let’s search for the background_tasks.add_task invocation in the routes file:


🏁 Script executed:

#!/bin/bash
# Find where process_response is queued in the responses router
rg -n "background_tasks.add_task" -A5 backend/app/api/routes/responses.py

Length of output: 222


Prefer kw-arg–safe assertions when inspecting the scheduled task

Although process_response is currently invoked with positional args, future changes to keyword invocation would break the existing checks. Let’s extract the request argument from either call_args.kwargs or fallback to call_args.args[0] and then assert against its attributes:

File: backend/app/tests/api/routes/test_responses.py
Lines: 115–122

-    # Verify that the background task was scheduled with correct parameters
-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    # Verify that the background task was scheduled with correct parameters
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Verify that the background task was scheduled with correct parameters
mock_process_response.assert_called_once()
call_args = mock_process_response.call_args
assert call_args[0][0].assistant_id == "assistant_dalgo"
assert call_args[0][0].question == "What is Dalgo?"
assert call_args[0][0].callback_url == "http://example.com/callback"
assert call_args[0][0].response_id is None
# Verify that the background task was scheduled with correct parameters
mock_process_response.assert_called_once()
call_args = mock_process_response.call_args
request_arg = call_args.kwargs.get("request") or call_args.args[0]
assert request_arg.assistant_id == "assistant_dalgo"
assert request_arg.question == "What is Dalgo?"
assert request_arg.callback_url == "http://example.com/callback"
assert request_arg.response_id is None
🤖 Prompt for AI Agents
In backend/app/tests/api/routes/test_responses.py around lines 115 to 122, the
test asserts the scheduled task's arguments using positional indexing, which can
break if the function is later called with keyword arguments. Modify the code to
first try extracting the request argument from call_args.kwargs by key, and if
not present, fallback to call_args.args[0]. Then perform assertions on the
extracted request object's attributes to ensure the test is robust against
changes in argument passing style.

response_id="resp_ancestor1234567890abcdef1234567890",
)

# Setup mock assistant
Copy link
Collaborator

Choose a reason for hiding this comment

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

make functions for mock setup can be made and re-used that way?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

made requested changes

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/app/tests/api/routes/test_responses.py (1)

178-184: Duplicate comment: Use kw-arg-safe assertion for scheduled task parameters

This is the same issue flagged in the previous review. The current code assumes positional argument access (call_args[0][0]) which could break if the function call switches to keyword arguments.

🧹 Nitpick comments (1)
backend/app/tests/api/routes/test_responses.py (1)

144-146: Consider removing unused fixture parameters

Static analysis indicates several test functions have unused db and user_api_key parameters. These may have been artifacts from refactoring when switching from direct execution to background task testing.

Since these tests now mock process_response and don't execute the actual background logic, consider removing the unused parameters:

def test_responses_endpoint_success(
    mock_get_conversation_by_ancestor_id,
    mock_create_conversation,
    mock_get_ancestor_id_from_response,
    mock_tracer_class,
    mock_get_assistant,
    mock_get_credential,
    mock_openai,
    mock_process_response,
-   db,
    user_api_key_header: dict[str, str],
-   user_api_key,
):

Apply similar changes to the other affected test functions.

Also applies to: 204-206, 344-346, 404-406, 465-467, 526-528

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1f81e8 and 99cfff1.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (15 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (2)
backend/app/api/routes/responses.py (5)
  • responses (286-360)
  • process_response (127-282)
  • ResponsesAPIRequest (46-53)
  • process_response (127-293)
  • responses (297-376)
backend/app/tests/conftest.py (4)
  • client (46-49)
  • db (18-35)
  • user_api_key_header (71-73)
  • user_api_key (83-85)
🪛 Ruff (0.12.2)
backend/app/tests/api/routes/test_responses.py

144-144: Unused function argument: db

(ARG001)


146-146: Unused function argument: user_api_key

(ARG001)


204-204: Unused function argument: db

(ARG001)


206-206: Unused function argument: user_api_key

(ARG001)


344-344: Unused function argument: db

(ARG001)


346-346: Unused function argument: user_api_key

(ARG001)


404-404: Unused function argument: db

(ARG001)


406-406: Unused function argument: user_api_key

(ARG001)


465-465: Unused function argument: db

(ARG001)


467-467: Unused function argument: user_api_key

(ARG001)


526-526: Unused function argument: db

(ARG001)


528-528: Unused function argument: user_api_key

(ARG001)

🔇 Additional comments (14)
backend/app/tests/api/routes/test_responses.py (14)

4-4: Good: Import added for direct testing of process_response

The import of process_response enables unit testing of the background processing function directly, which provides better test coverage and isolation.


13-24: Good: Helper function reduces test setup duplication

The create_mock_assistant function centralizes mock assistant creation with sensible defaults, improving test maintainability.


27-47: Good: Comprehensive mock OpenAI response factory

The function covers all necessary response attributes including usage, output, and previous_response_id fields, providing flexible test data creation.


50-64: Good: Mock file search results helper

Creates realistic file search result structures with scores and text content, enabling comprehensive testing of file search functionality.


67-75: Good: Mock conversation factory with key attributes

Provides both response_id and ancestor_response_id fields needed for conversation chain testing.


78-124: Excellent: Centralized mock setup reduces duplication

The setup_common_mocks function significantly reduces test boilerplate by centralizing the setup of common dependencies. The parameterization options (assistant_model, vector_store_ids, conversation_found, response_output) provide good flexibility for different test scenarios.


127-151: Good: Comprehensive patching for endpoint isolation

The test properly patches all external dependencies including process_response, ensuring the endpoint test focuses only on request validation and background task scheduling.


187-244: Good: Test coverage for different assistant configurations

The test properly validates behavior when the assistant has no vector store, using the setup_common_mocks with vector_store_ids=[] to simulate this scenario.


278-324: Good: Comprehensive credential validation testing

Both tests properly validate the different credential failure scenarios (missing credentials vs missing api_key in credentials), ensuring robust error handling.


327-384: Good: File search results testing

The test validates that the endpoint works correctly when file search results are present in the response output, using the create_mock_file_search_results() helper.


387-506: Good: Comprehensive ancestor conversation testing

Both tests (conversation found vs not found) properly validate the endpoint behavior in different conversation chain scenarios, ensuring the response_id parameter is handled correctly.


509-566: Good: Complete test scenario coverage

The test validates the endpoint behavior when no response_id is provided, ensuring the parameter is correctly set to None in the scheduled task.


569-647: Good: Direct unit testing of background processing logic

This test properly validates the process_response function's behavior when an ancestor conversation is found, including:

  • Correct database query with proper parameters
  • OpenAI API call with the found conversation's response_id as previous_response_id
  • Proper conversation creation and callback execution

The test isolation is excellent with focused mocking.


650-727: Good: Complete coverage of ancestor conversation scenarios

This test validates the alternate path when no ancestor conversation is found, ensuring the original response_id is used as previous_response_id in the OpenAI API call.

@AkhileshNegi AkhileshNegi requested a review from nishika26 August 13, 2025 08:15
Copy link
Collaborator

@avirajsingh7 avirajsingh7 left a comment

Choose a reason for hiding this comment

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

It looks like there’s a lot of mocking happening in these tests.
possibly more than we actually need, which makes the tests harder to follow and maintain.
I think we could simplify this by:

  1. Only mocking the dependencies that needed.
  2. Can you check if we can group the patch or use some type of helper fixture for mocking or anyother way to simplify this test cases?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (5)
backend/app/tests/api/routes/test_responses.py (5)

159-166: Extract scheduled request via kwargs for forward-compatibility

Indexing call_args[0][0] assumes positional invocation. If the production code switches to keyword args, the test will fail despite correct behavior. Use kwargs-first with positional fallback.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

217-223: Extract scheduled request via kwargs (same issue as above)

Repeat the kwargs-first extraction here.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_123"
-    assert call_args[0][0].question == "What is Glific?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_123"
+    assert request_arg.question == "What is Glific?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

357-364: Extract scheduled request via kwargs (same issue as above)

Make the assertion resilient to kwarg invocation.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

419-424: Extract scheduled request via kwargs (same issue as above)

Make this robust against changes in argument passing style.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

479-485: Extract scheduled request via kwargs (same issue as above)

Same fix here.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
🧹 Nitpick comments (5)
backend/app/tests/api/routes/test_responses.py (5)

38-46: Initialize usage explicitly to avoid implicit MagicMock chains

Be explicit to make the intent clear and avoid surprises if MagicMock behavior changes. This also helps IDE/static tools.

 mock_response = MagicMock()
 mock_response.id = response_id
 mock_response.output_text = output_text
 mock_response.model = model
-mock_response.usage.input_tokens = 10
-mock_response.usage.output_tokens = 5
-mock_response.usage.total_tokens = 15
+mock_response.usage = MagicMock()
+mock_response.usage.input_tokens = 10
+mock_response.usage.output_tokens = 5
+mock_response.usage.total_tokens = 15
 mock_response.output = output
 mock_response.previous_response_id = previous_response_id
 return mock_response

491-509: Import ResponsesAPIRequest once at module level

Minor cleanup: import ResponsesAPIRequest at the top and reuse it, avoiding repeated imports inside tests.

-from app.api.routes.responses import ResponsesAPIRequest
+# Move to the top of the file:
+# from app.api.routes.responses import ResponsesAPIRequest

Optionally add at the top with the other imports:

from app.api.routes.responses import ResponsesAPIRequest

Also applies to: 581-590


168-176: Unnecessary patches in endpoint tests

Endpoint tests patch get_ancestor_id_from_response, create_conversation, and get_conversation_by_ancestor_id, but these are only used inside process_response—which is already patched out. These extra patches add noise and maintenance overhead.

  • Drop the patches for get_ancestor_id_from_response, create_conversation, get_conversation_by_ancestor_id in endpoint-only tests.
  • Keep them in the process_response unit tests where they are asserted.

Also applies to: 305-313, 427-435


191-203: Add a focused unit test for vector-store tools behavior

You cover the “no vector store configured” endpoint path, but the behavior detail (tools absent/present) is exercised inside process_response. Consider a unit test for process_response that asserts tools are included/excluded based on assistant.vector_store_ids and that max_num_results propagates.

If helpful, I can draft this test case.


2-11: Helper to DRY request extraction from scheduled call

To avoid repetition across tests, add a tiny helper that extracts the scheduled request argument safely.

Add this helper near your other helpers:

def get_scheduled_request_arg(mock_process_response):
    call_args = mock_process_response.call_args
    return call_args.kwargs.get("request") or call_args.args[0]

Then replace repeated extraction/assert blocks with:

request_arg = get_scheduled_request_arg(mock_process_response)

Also applies to: 159-166, 217-223, 357-364, 419-424, 479-485

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 58ea5b7 and 6367156.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (10 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (3)
backend/app/api/routes/responses.py (3)
  • responses (297-376)
  • process_response (127-293)
  • ResponsesAPIRequest (46-53)
backend/app/tests/conftest.py (4)
  • client (46-49)
  • user_api_key_header (71-73)
  • db (18-35)
  • user_api_key (83-85)
backend/app/tests/api/routes/test_assistants.py (1)
  • assistant_id (25-26)
🪛 Ruff (0.12.2)
backend/app/tests/api/routes/test_responses.py

322-322: Unused function argument: db

(ARG001)


324-324: Unused function argument: user_api_key

(ARG001)


383-383: Unused function argument: db

(ARG001)


385-385: Unused function argument: user_api_key

(ARG001)


444-444: Unused function argument: db

(ARG001)


446-446: Unused function argument: user_api_key

(ARG001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: checks (3.11.7, 6)
🔇 Additional comments (4)
backend/app/tests/api/routes/test_responses.py (4)

13-24: Good factory for assistants; reduces duplication

The helper cleanly centralizes assistant defaults and improves readability across tests.


61-108: Solid shared mock setup

The setup_common_mocks helper meaningfully reduces duplication and keeps individual tests focused on behavior.


487-566: Robust coverage of ancestor-found flow in process_response

Good assertions around ancestor lookup, previous_response_id usage, persistence, and callback invocation. This meaningfully validates the branching logic.


568-646: Robust coverage of ancestor-not-found flow in process_response

Strong verification of the alternative path, including previous_response_id derivation and callback behavior.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/app/tests/api/routes/test_responses.py (1)

159-166: Use kw-arg–safe extraction when asserting scheduled task arguments

Current assertions assume positional invocation (call_args[0][0]) which will break if the route switches to keyword args. Extract the request from kwargs first, then fallback to args. This was noted earlier; applying it here will make tests resilient.

For lines 159–166:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

For lines 217–224:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_123"
-    assert call_args[0][0].question == "What is Glific?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_123"
+    assert request_arg.question == "What is Glific?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

For lines 353–360:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

For lines 412–419:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

For lines 470–476:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

Also applies to: 217-224, 353-360, 412-419, 470-476

🧹 Nitpick comments (14)
backend/app/tests/api/routes/test_responses.py (14)

1-10: Prefer the shared TestClient fixture; drop the bespoke FastAPI app and router import

Building a local app/client bypasses dependency overrides from tests/conftest.py (DB/auth), making these tests brittle. Use the client fixture and import only what you actually directly invoke in this file.

Apply this diff to remove the local app and narrow the import:

-from fastapi import FastAPI
-from fastapi.testclient import TestClient
-from app.api.routes.responses import router, process_response
+from app.api.routes.responses import process_response
@@
-# Wrap the router in a FastAPI app instance
-app = FastAPI()
-app.include_router(router)
-client = TestClient(app)

Follow-up: add the client fixture parameter to tests that call client.post(...). See suggestions on individual test signatures below.


118-129: Adopt the shared TestClient fixture in this test

Now that the bespoke TestClient is removed, take client from conftest so dependency overrides apply.

 def test_responses_endpoint_success(
@@
-    mock_process_response,
-    user_api_key_header: dict[str, str],
+    mock_process_response,
+    user_api_key_header: dict[str, str],
+    client,
 ):

176-187: Adopt the shared TestClient fixture here as well

Use the repo’s client fixture.

 def test_responses_endpoint_without_vector_store(
@@
-    mock_process_response,
-    user_api_key_header,
+    mock_process_response,
+    user_api_key_header,
+    client,
 ):

226-233: Update to use the client fixture once bespoke client is removed

This test posts to the endpoint and should receive client via fixture rather than the module-level client.

Example update:

@patch("app.api.routes.responses.get_assistant_by_id")
def test_responses_endpoint_assistant_not_found(
    mock_get_assistant,
    user_api_key_header,
    client,
):
    ...

247-253: Update to use the client fixture for consistent overrides

Same rationale as above.

Example update:

@patch("app.api.routes.responses.get_provider_credential")
@patch("app.api.routes.responses.get_assistant_by_id")
def test_responses_endpoint_no_openai_credentials(
    mock_get_assistant,
    mock_get_credential,
    user_api_key_header,
    client,
):
    ...

277-285: Update to use the client fixture here too

Aligns with removal of bespoke client and ensures DB/auth overrides are applied.

Example update:

@patch("app.api.routes.responses.get_provider_credential")
@patch("app.api.routes.responses.get_assistant_by_id")
def test_responses_endpoint_missing_api_key_in_credentials(
    mock_get_assistant,
    mock_get_credential,
    user_api_key_header,
    client,
):
    ...

311-321: Adopt the shared TestClient fixture in this test

Add the client fixture parameter.

 def test_responses_endpoint_with_ancestor_conversation_found(
@@
-    mock_process_response,
-    user_api_key_header: dict[str, str],
+    mock_process_response,
+    user_api_key_header: dict[str, str],
+    client,
 ):

370-380: Adopt the shared TestClient fixture in this test

Add the client fixture parameter.

 def test_responses_endpoint_with_ancestor_conversation_not_found(
@@
-    mock_process_response,
-    user_api_key_header: dict[str, str],
+    mock_process_response,
+    user_api_key_header: dict[str, str],
+    client,
 ):

429-439: Adopt the shared TestClient fixture in this test

Add the client fixture parameter.

 def test_responses_endpoint_without_response_id(
@@
-    mock_process_response,
-    user_api_key_header: dict[str, str],
+    mock_process_response,
+    user_api_key_header: dict[str, str],
+    client,
 ):

61-108: Nit: setup_common_mocks returns values that are often unused; consider streamlining

In endpoint tests, mock_client and mock_assistant are assigned but unused. Either return only what’s required per caller or assign to _ to avoid reader confusion.


556-558: Strengthen callback assertions to validate destination URL

Asserting only “called once” can miss regressions where a wrong URL is used. Also check the first argument equals the request callback URL with a kwargs fallback.

     # Verify send_callback was called
-    mock_send_callback.assert_called_once()
+    mock_send_callback.assert_called_once()
+    callback_url_arg = mock_send_callback.call_args.kwargs.get("callback_url") or mock_send_callback.call_args.args[0]
+    assert callback_url_arg == request.callback_url

636-638: Strengthen callback assertions to validate destination URL (second test)

Mirror the check from the previous test to ensure both branches validate the URL.

     # Verify send_callback was called
-    mock_send_callback.assert_called_once()
+    mock_send_callback.assert_called_once()
+    callback_url_arg = mock_send_callback.call_args.kwargs.get("callback_url") or mock_send_callback.call_args.args[0]
+    assert callback_url_arg == request.callback_url

303-360: Consider parametrizing the ancestor-conversation found vs. not-found tests

The two tests are nearly identical, differing only in the conversation lookup result and expected previous_response_id. Parametrizing would reduce duplication and simplify maintenance.

Also applies to: 362-419


168-224: Optional: Drop unnecessary patches in endpoint scheduling tests

Since process_response is mocked and not executed, patches for OpenAI, LangfuseTracer, get_ancestor_id_from_response, and create_conversation are redundant in these endpoint tests. Removing them will simplify and speed up the tests.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6367156 and b1e9832.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (10 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (2)
backend/app/api/routes/responses.py (3)
  • responses (288-379)
  • process_response (128-284)
  • ResponsesAPIRequest (47-54)
backend/app/tests/conftest.py (4)
  • client (46-49)
  • user_api_key_header (71-73)
  • db (18-35)
  • user_api_key (83-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: checks (3.11.7, 6)
🔇 Additional comments (2)
backend/app/tests/api/routes/test_responses.py (2)

186-203: Scenario coverage for “no vector store” looks good

Good use of vector_store_ids=[] to ensure tool injection paths aren’t assumed by the endpoint.


110-118: Decorator stacking order is correct

The order of injected mocks matches the reverse of the patch decorators. Nice.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/app/tests/api/routes/test_responses.py (1)

154-160: Make scheduled-task assertions robust to kwargs (repeat from earlier review)

These assertions assume positional invocation of process_response. If production switches to keyword args, tests will fail despite correct behavior. Extract the request (and other) args via kwargs with positional fallback.

Apply the following diffs:

For Lines 154–160:

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

For Lines 215–221:

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_123"
-    assert call_args[0][0].question == "What is Glific?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_123"
+    assert request_arg.question == "What is Glific?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

For Lines 364–370 (also assert scheduled ancestor/latest args):

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"
+    ancestor_arg = (call_args.kwargs.get("ancestor_id") if call_args.kwargs else call_args.args[6])
+    latest_conv_arg = (call_args.kwargs.get("latest_conversation") if call_args.kwargs else call_args.args[7])
+    assert ancestor_arg == "resp_latest1234567890abcdef1234567890"
+    assert latest_conv_arg is not None

For Lines 426–432 (no conversation found case):

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"
+    ancestor_arg = (call_args.kwargs.get("ancestor_id") if call_args.kwargs else call_args.args[6])
+    latest_conv_arg = (call_args.kwargs.get("latest_conversation") if call_args.kwargs else call_args.args[7])
+    assert ancestor_arg == "resp_ancestor1234567890abcdef1234567890"
+    assert latest_conv_arg is None

For Lines 487–493 (no response_id provided):

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
+    ancestor_arg = (call_args.kwargs.get("ancestor_id") if call_args.kwargs else call_args.args[6])
+    latest_conv_arg = (call_args.kwargs.get("latest_conversation") if call_args.kwargs else call_args.args[7])
+    assert ancestor_arg is None
+    assert latest_conv_arg is None

Also applies to: 215-221, 364-370, 426-432, 487-493

🧹 Nitpick comments (5)
backend/app/tests/api/routes/test_responses.py (5)

128-136: Drop unused variables from setup_common_mocks in endpoint tests

In these endpoint tests, the returned mock_client and mock_assistant aren’t used. Calling setup_common_mocks for its side-effects is sufficient and avoids unused-variable noise.

Apply these diffs across the listed blocks:

-    mock_client, mock_assistant = setup_common_mocks(
+    setup_common_mocks(
         mock_get_credential,
         mock_get_assistant,
         mock_openai,
         mock_tracer_class,
         mock_get_ancestor_id_from_response,
         mock_create_conversation,
         mock_get_conversation_by_ancestor_id,
-    )
+    )

Also applies to: 187-198, 336-345, 398-407, 459-468


249-256: Assert process_response is not scheduled when OpenAI credentials are missing

This path returns early; asserting that the background task was not queued hardens the test. Patch process_response and assert not called.

 @patch("app.api.routes.responses.get_provider_credential")
 @patch("app.api.routes.responses.get_assistant_by_id")
+@patch("app.api.routes.responses.process_response")
 def test_responses_endpoint_no_openai_credentials(
     mock_get_assistant,
     mock_get_credential,
+    mock_process_response,
     user_api_key_header,
     client,
 ):
@@
     response = client.post(
         "/api/v1/responses", json=request_data, headers=user_api_key_header
     )
     assert response.status_code == 200
     response_json = response.json()
     assert response_json["success"] is False
     assert "OpenAI API key not configured" in response_json["error"]
+    # Ensure background task was not scheduled
+    mock_process_response.assert_not_called()

Also applies to: 271-278


280-287: Also assert no scheduling when credentials lack api_key

Same rationale as the previous test—verify we do not enqueue work with invalid credentials.

 @patch("app.api.routes.responses.get_provider_credential")
 @patch("app.api.routes.responses.get_assistant_by_id")
+@patch("app.api.routes.responses.process_response")
 def test_responses_endpoint_missing_api_key_in_credentials(
     mock_get_assistant,
     mock_get_credential,
+    mock_process_response,
     user_api_key_header,
     client,
 ):
@@
     response = client.post(
         "/api/v1/responses", json=request_data, headers=user_api_key_header
     )
     assert response.status_code == 200
     response_json = response.json()
     assert response_json["success"] is False
     assert "OpenAI API key not configured" in response_json["error"]
+    # Ensure background task was not scheduled
+    mock_process_response.assert_not_called()

Also applies to: 302-309


509-517: Silence Ruff ARG001 for db and prefer kwargs when inspecting OpenAI call

  • db fixture is intentionally used for DB/engine side-effects; explicitly delete it to satisfy Ruff ARG001.
  • Prefer call_args.kwargs over tuple indexing for resilience.
 from app.api.routes.responses import ResponsesAPIRequest
+
+    # Silence linter: db fixture is used for DB/engine side-effects
+    del db
@@
-    call_args = mock_client.responses.create.call_args[1]
-    assert call_args["previous_response_id"] == (
+    kwargs = mock_client.responses.create.call_args.kwargs
+    assert kwargs["previous_response_id"] == (
         "resp_latest1234567890abcdef1234567890"
     )

Also applies to: 562-565


587-596: Mirror minor fixes in the “no ancestor conversation” variant

  • Delete db to satisfy Ruff ARG001.
  • Use kwargs for safer assertion of previous_response_id.
 from app.api.routes.responses import ResponsesAPIRequest
+
+    # Silence linter: db fixture is used for DB/engine side-effects
+    del db
@@
-    call_args = mock_client.responses.create.call_args[1]
-    assert call_args["previous_response_id"] == (
+    kwargs = mock_client.responses.create.call_args.kwargs
+    assert kwargs["previous_response_id"] == (
         "resp_ancestor1234567890abcdef1234567890"
     )

Also applies to: 639-643

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b1e9832 and 14a3677.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (8 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (2)
backend/app/api/routes/responses.py (3)
  • responses (288-379)
  • process_response (128-284)
  • ResponsesAPIRequest (47-54)
backend/app/tests/conftest.py (4)
  • user_api_key_header (71-73)
  • client (46-49)
  • db (18-35)
  • user_api_key (83-85)
🪛 Ruff (0.12.2)
backend/app/tests/api/routes/test_responses.py

505-505: Unused function argument: db

(ARG001)


583-583: Unused function argument: db

(ARG001)

🔇 Additional comments (5)
backend/app/tests/api/routes/test_responses.py (5)

5-16: Helper factory for assistant looks good

Good defaults, avoids mutable default pitfalls via None+assignment. Clear and reusable.


19-39: Mock OpenAI response helper is solid

Covers all fields used by production code (id, output_text, model, usage, previous_response_id). This will keep the tests stable.


42-51: Conversation mock helper LGTM

Concise and readable. Matches the fields accessed in process_response.


53-101: Centralized mock setup improves readability

This shared setup reduces duplication across endpoint tests and keeps intent clear. Nice.


240-247: Custom HTTPException handler wraps errors into the APIResponse envelope

A custom @app.exception_handler(HTTPException) is registered in backend/app/core/exception_handlers.py (lines 19–24), returning APIResponse.failure_response(exc.detail). This ensures 404 errors are rendered as { success: False, error: … }, so your test assertions are valid. No changes required.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (5)
backend/app/tests/api/routes/test_responses.py (5)

154-160: Make scheduled-task assertions kwargs-safe (positional indexing is brittle).

Accessing the first positional arg via call_args[0][0] will break if the production code switches to keyword-based invocation. Extract the request from kwargs first, with positional fallback.

-    # Verify that the background task was scheduled with correct parameters
-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    # Verify that the background task was scheduled with correct parameters
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

216-221: Make scheduled-task assertions kwargs-safe (positional indexing is brittle).

Same issue in this test; prefer kwargs with positional fallback.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_123"
-    assert call_args[0][0].question == "What is Glific?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_123"
+    assert request_arg.question == "What is Glific?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None

373-378: Make scheduled-task assertions kwargs-safe (positional indexing is brittle).

Future-proof the assertions by resolving the request via kwargs first.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

435-440: Make scheduled-task assertions kwargs-safe (positional indexing is brittle).

Use kwargs-first extraction for robustness.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"

496-501: Make scheduled-task assertions kwargs-safe (positional indexing is brittle).

Same change here.

-    mock_process_response.assert_called_once()
-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    mock_process_response.assert_called_once()
+    call_args = mock_process_response.call_args
+    request_arg = call_args.kwargs.get("request") or call_args.args[0]
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
🧹 Nitpick comments (5)
backend/app/tests/api/routes/test_responses.py (5)

188-198: Avoid unused local variables from setup_common_mocks.

mock_client and mock_assistant are not used; switch to underscore assignment (or no assignment) to silence F841 and clarify intent.

-    mock_client, mock_assistant = setup_common_mocks(
+    _, _ = setup_common_mocks(
         mock_get_credential,
         mock_get_assistant,
         mock_openai,
         mock_tracer_class,
         mock_get_ancestor_id_from_response,
         mock_create_conversation,
         mock_get_conversation_by_ancestor_id,
         assistant_model="gpt-4",
         vector_store_ids=[],
     )

344-353: Avoid unused local variables from setup_common_mocks.

Same here; assigned values are not referenced.

-    mock_client, mock_assistant = setup_common_mocks(
+    _, _ = setup_common_mocks(
         mock_get_credential,
         mock_get_assistant,
         mock_openai,
         mock_tracer_class,
         mock_get_ancestor_id_from_response,
         mock_create_conversation,
         mock_get_conversation_by_ancestor_id,
         conversation_found=True,
     )

468-476: Avoid unused local variables from setup_common_mocks.

Same pattern; use underscores to make it explicit.

-    mock_client, mock_assistant = setup_common_mocks(
+    _, _ = setup_common_mocks(
         mock_get_credential,
         mock_get_assistant,
         mock_openai,
         mock_tracer_class,
         mock_get_ancestor_id_from_response,
         mock_create_conversation,
         mock_get_conversation_by_ancestor_id,
     )

513-515: Remove unused fixture parameter db (Ruff ARG001).

db isn’t referenced in the body. Drop it from the signature.

-def test_process_response_ancestor_conversation_found(
+def test_process_response_ancestor_conversation_found(
     mock_send_callback,
     mock_get_ancestor_id_from_response,
     mock_create_conversation,
     mock_get_conversation_by_ancestor_id,
-    db,
     user_api_key,
 ):

591-593: Remove unused fixture parameter db (Ruff ARG001).

Same as above; not used.

-def test_process_response_ancestor_conversation_not_found(
+def test_process_response_ancestor_conversation_not_found(
     mock_send_callback,
     mock_get_ancestor_id_from_response,
     mock_create_conversation,
     mock_get_conversation_by_ancestor_id,
-    db,
     user_api_key,
 ):
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 14a3677 and b9bc72f.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (2)
backend/app/api/routes/responses.py (3)
  • responses (288-379)
  • process_response (128-284)
  • ResponsesAPIRequest (47-54)
backend/app/tests/conftest.py (4)
  • user_api_key_header (71-73)
  • client (46-49)
  • db (18-35)
  • user_api_key (83-85)
🪛 Ruff (0.12.2)
backend/app/tests/api/routes/test_responses.py

513-513: Unused function argument: db

(ARG001)


591-591: Unused function argument: db

(ARG001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: checks (3.11.7, 6)
🔇 Additional comments (2)
backend/app/tests/api/routes/test_responses.py (2)

27-29: Good defensive default for mutable argument.

Using output=None and setting output = [] avoids mutable default arg pitfalls. Nice.


245-246: Global HTTPException handler ensures unified error format

I found the global HTTPException handler in backend/app/core/exception_handlers.py (lines 19–22), which uses APIResponse.failure_response(…) to wrap errors into the { "success": False, "error": "…" } shape. Your existing assertions are therefore correct and no changes are needed here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (5)
backend/app/tests/api/routes/test_responses.py (5)

154-160: Make scheduled-task assertions resilient to kwargs (avoid brittle positional indexing)

Future refactors may switch to keyword-arg scheduling for process_response, which would break call_args[0][0]. Extract the request via kwargs with a positional fallback.

Apply:

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
+
+    # Optional: assert tracer wiring for completeness
+    tracer_call = mock_tracer_class.call_args
+    assert (tracer_call.kwargs.get("response_id") if tracer_call.kwargs else None) is None

215-221: Same here: extract request from kwargs for robustness

Mirror the kwargs-first extraction pattern to avoid brittleness.

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_123"
-    assert call_args[0][0].question == "What is Glific?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_123"
+    assert request_arg.question == "What is Glific?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
+
+    # Optional: sanity-check the assistant passed through
+    assistant_arg = call_args.kwargs.get("assistant") if call_args.kwargs else call_args.args[2]
+    assert getattr(assistant_arg, "vector_store_ids", None) == []

372-378: Use kwargs-safe extraction and assert ancestor/latest wiring

In addition to kwargs-safe request extraction, assert that the endpoint passes the latest conversation’s response_id as ancestor_id and the latest_conversation instance when the ancestor is found.

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"
+
+    ancestor_arg = call_args.kwargs.get("ancestor_id") if call_args.kwargs else call_args.args[6]
+    latest_conv_arg = call_args.kwargs.get("latest_conversation") if call_args.kwargs else call_args.args[7]
+    # When a conversation exists, ancestor_id should be set to latest.response_id
+    assert ancestor_arg == "resp_latest1234567890abcdef1234567890"
+    assert latest_conv_arg is not None
+
+    # Optional: verify tracer carries the response_id from the request
+    tracer_call = mock_tracer_class.call_args
+    assert (tracer_call.kwargs.get("response_id") if tracer_call.kwargs else None) == request_data["response_id"]

434-440: Same: kwargs-safe extraction and verify ancestor passthrough when no conversation found

When no conversation is found, ancestor_id should remain the original response_id and latest_conversation should be None.

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id == "resp_ancestor1234567890abcdef1234567890"
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id == "resp_ancestor1234567890abcdef1234567890"
+
+    ancestor_arg = call_args.kwargs.get("ancestor_id") if call_args.kwargs else call_args.args[6]
+    latest_conv_arg = call_args.kwargs.get("latest_conversation") if call_args.kwargs else call_args.args[7]
+    assert ancestor_arg == request_data["response_id"]
+    assert latest_conv_arg is None

495-501: Repeat: kwargs-safe extraction for scheduled request assertions

Make the request extraction robust across calling styles.

-    call_args = mock_process_response.call_args
-    assert call_args[0][0].assistant_id == "assistant_dalgo"
-    assert call_args[0][0].question == "What is Dalgo?"
-    assert call_args[0][0].callback_url == "http://example.com/callback"
-    assert call_args[0][0].response_id is None
+    call_args = mock_process_response.call_args
+    request_arg = (call_args.kwargs.get("request") if call_args.kwargs else call_args.args[0])
+    assert request_arg.assistant_id == "assistant_dalgo"
+    assert request_arg.question == "What is Dalgo?"
+    assert request_arg.callback_url == "http://example.com/callback"
+    assert request_arg.response_id is None
🧹 Nitpick comments (4)
backend/app/tests/api/routes/test_responses.py (4)

508-516: Remove unused fixture db (Ruff ARG001) in direct process_response test

db is not used in this test. Drop it to satisfy ARG001 and tighten the signature.

-def test_process_response_ancestor_conversation_found(
+def test_process_response_ancestor_conversation_found(
     mock_send_callback,
     mock_get_ancestor_id_from_response,
     mock_create_conversation,
     mock_get_conversation_by_ancestor_id,
-    db,
     user_api_key,
 ):

586-593: Remove unused fixture db (Ruff ARG001) in the second direct process_response test

Same rationale as above; db is unused here as well.

-def test_process_response_ancestor_conversation_not_found(
+def test_process_response_ancestor_conversation_not_found(
     mock_send_callback,
     mock_get_ancestor_id_from_response,
     mock_create_conversation,
     mock_get_conversation_by_ancestor_id,
-    db,
     user_api_key,
 ):

519-526: Minor: import ResponsesAPIRequest once at module top to avoid repeated intra-test imports

This avoids repetitive in-function imports and keeps imports centralized.

Outside these ranges, at the top of the file, adjust imports to:

from app.api.routes.responses import process_response, ResponsesAPIRequest

Then remove the in-function imports in these two tests.

Also applies to: 597-604


183-199: Optional: add a process_response unit test for assistant without vector store

You already cover the endpoint path for an assistant with no vector store. Consider a direct process_response unit test with vector_store_ids=[] to assert that tools and include are omitted in the call to client.responses.create. I can draft this test if helpful.

Also applies to: 343-353, 405-415, 467-477

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9bc72f and 9f5d574.

📒 Files selected for processing (1)
  • backend/app/tests/api/routes/test_responses.py (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/tests/api/routes/test_responses.py (2)
backend/app/api/routes/responses.py (3)
  • responses (288-379)
  • process_response (128-284)
  • ResponsesAPIRequest (47-54)
backend/app/tests/conftest.py (4)
  • user_api_key_header (71-73)
  • client (46-49)
  • db (18-35)
  • user_api_key (83-85)
🪛 Ruff (0.12.2)
backend/app/tests/api/routes/test_responses.py

513-513: Unused function argument: db

(ARG001)


591-591: Unused function argument: db

(ARG001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: checks (3.11.7, 6)
🔇 Additional comments (3)
backend/app/tests/api/routes/test_responses.py (3)

5-16: Good test scaffolding: helpers de-duplicate setup across tests

The helper factory functions and the setup_common_mocks utility substantially reduce duplication and improve readability. Clear defaults, and the optional parameters handle vector-store/no-vector-store cases cleanly.

Also applies to: 19-39, 42-50, 53-101


280-281: Nice guard: ensure background task not scheduled when OpenAI credentials are missing

These checks are appropriate and prevent false positives.

Also applies to: 315-316


240-247: Confirmed global HTTPException handler normalizes errors to {"success": False, "error": …}

The app calls register_exception_handlers(app) in backend/app/main.py, and http_exception_handler in backend/app/core/exception_handlers.py uses APIResponse.failure_response(exc.detail).model_dump(), which produces exactly the success/error shape your test asserts. No changes needed.

@AkhileshNegi AkhileshNegi merged commit d10181b into main Aug 20, 2025
3 checks passed
@AkhileshNegi AkhileshNegi deleted the hotfix/response-api-testcases branch August 20, 2025 17:18
kartpop pushed a commit that referenced this pull request Sep 4, 2025
* fixes to testcases

* using user_api_key instead

* using functions for fixtures

* fixing coderabbit suggestions

* few more cleanups

* removing unnecessary params

* cleanups for testcases

* coderabbit suggestions

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix slow & failing callback in test functions of test_responses.py

3 participants