Skip to content

Commit c19112c

Browse files
committed
refactor(tests): parameterize metadata inclusion test cases
Signed-off-by: Major Hayden <major@redhat.com>
1 parent 0962cd0 commit c19112c

1 file changed

Lines changed: 74 additions & 110 deletions

File tree

tests/unit/app/endpoints/test_rlsapi_v1.py

Lines changed: 74 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -642,29 +642,34 @@ async def test_infer_empty_llm_response_returns_fallback(
642642
assert response.data.text == constants.UNABLE_TO_PROCESS_RESPONSE
643643

644644

645-
async def test_infer_include_metadata_returns_verbose_response(
645+
@pytest.mark.parametrize(
646+
("verbose_enabled", "expect_metadata"),
647+
[
648+
pytest.param(True, True, id="verbose_enabled"),
649+
pytest.param(False, False, id="verbose_disabled"),
650+
],
651+
)
652+
async def test_infer_include_metadata_respects_verbose_config(
646653
mocker: MockerFixture,
647654
mock_configuration: AppConfig,
648-
mock_llm_response: None,
649655
mock_auth_resolvers: None,
650656
mock_request_factory: Callable[..., Any],
651657
mock_background_tasks: Any,
658+
verbose_enabled: bool,
659+
expect_metadata: bool,
652660
) -> None:
653-
"""Test /infer with include_metadata=True and allow_verbose_infer returns metadata."""
654-
# Enable verbose infer (dual opt-in: config + request). customization is a
655-
# read-only property on AppConfig, so patch the module-level configuration.
661+
"""Test /infer metadata inclusion controlled by dual opt-in (config + request)."""
656662
custom_mock = mocker.Mock()
657-
custom_mock.allow_verbose_infer = True
663+
custom_mock.allow_verbose_infer = verbose_enabled
658664
custom_mock.system_prompt = "You are a helpful assistant."
659665
config_mock = mocker.Mock()
660666
config_mock.inference = mock_configuration.inference
661667
config_mock.customization = custom_mock
662668
mocker.patch("app.endpoints.rlsapi_v1.configuration", config_mock)
663669

664-
# Mock full response with usage so build_turn_summary can extract token counts
665670
mock_response = mocker.Mock()
666671
mock_response.output = [
667-
_create_mock_response_output(mocker, "Verbose metadata test response.")
672+
_create_mock_response_output(mocker, "Metadata test response.")
668673
]
669674
mock_usage = mocker.Mock()
670675
mock_usage.input_tokens = 42
@@ -675,72 +680,31 @@ async def test_infer_include_metadata_returns_verbose_response(
675680
infer_request = RlsapiV1InferRequest(
676681
question="How do I list files?", include_metadata=True
677682
)
678-
mock_request = mock_request_factory()
679683

680684
response = await infer_endpoint(
681685
infer_request=infer_request,
682-
request=mock_request,
686+
request=mock_request_factory(),
683687
background_tasks=mock_background_tasks,
684688
auth=MOCK_AUTH,
685689
)
686690

687-
assert isinstance(response, RlsapiV1InferResponse)
688-
assert response.data.text == "Verbose metadata test response."
689-
assert response.data.request_id is not None
690-
assert check_suid(response.data.request_id)
691-
# Verbose response must include metadata fields
692-
assert response.data.tool_calls is not None
693-
assert response.data.tool_results is not None
694-
assert response.data.rag_chunks is not None
695-
assert response.data.referenced_documents is not None
696-
assert response.data.input_tokens == 42
697-
assert response.data.output_tokens == 18
698-
699-
700-
async def test_infer_include_metadata_ignored_when_verbose_infer_disabled(
701-
mocker: MockerFixture,
702-
mock_configuration: AppConfig,
703-
mock_auth_resolvers: None,
704-
mock_request_factory: Callable[..., Any],
705-
mock_background_tasks: Any,
706-
) -> None:
707-
"""Metadata should remain excluded unless both request and config opt in."""
708-
custom_mock = mocker.Mock()
709-
custom_mock.allow_verbose_infer = False
710-
custom_mock.system_prompt = "You are a helpful assistant."
711-
config_mock = mocker.Mock()
712-
config_mock.inference = mock_configuration.inference
713-
config_mock.customization = custom_mock
714-
mocker.patch("app.endpoints.rlsapi_v1.configuration", config_mock)
715-
716-
mock_response = mocker.Mock()
717-
mock_response.output = [
718-
_create_mock_response_output(mocker, "Response with metadata disabled.")
719-
]
720-
mock_usage = mocker.Mock()
721-
mock_usage.input_tokens = 99
722-
mock_usage.output_tokens = 11
723-
mock_response.usage = mock_usage
724-
_setup_responses_mock(mocker, mocker.AsyncMock(return_value=mock_response))
725-
726-
infer_request = RlsapiV1InferRequest(
727-
question="How do I list files?", include_metadata=True
728-
)
729-
mock_request = mock_request_factory()
730-
731-
response = await infer_endpoint(
732-
infer_request=infer_request,
733-
request=mock_request,
734-
background_tasks=mock_background_tasks,
735-
auth=MOCK_AUTH,
736-
)
737-
738-
assert response.data.tool_calls is None
739-
assert response.data.tool_results is None
740-
assert response.data.rag_chunks is None
741-
assert response.data.referenced_documents is None
742-
assert response.data.input_tokens is None
743-
assert response.data.output_tokens is None
691+
if expect_metadata:
692+
assert isinstance(response, RlsapiV1InferResponse)
693+
assert response.data.text == "Metadata test response."
694+
assert response.data.request_id is not None
695+
assert response.data.tool_calls is not None
696+
assert response.data.tool_results is not None
697+
assert response.data.rag_chunks is not None
698+
assert response.data.referenced_documents is not None
699+
assert response.data.input_tokens == 42
700+
assert response.data.output_tokens == 18
701+
else:
702+
assert response.data.tool_calls is None
703+
assert response.data.tool_results is None
704+
assert response.data.rag_chunks is None
705+
assert response.data.referenced_documents is None
706+
assert response.data.input_tokens is None
707+
assert response.data.output_tokens is None
744708

745709

746710
def _setup_config_mock(
@@ -758,64 +722,64 @@ def _setup_config_mock(
758722
mocker.patch("app.endpoints.rlsapi_v1.configuration", config_mock)
759723

760724

761-
async def test_infer_verbose_extract_token_usage_on_text_extraction_failure(
725+
@pytest.mark.parametrize(
726+
("verbose_enabled", "expect_extract_called"),
727+
[
728+
pytest.param(True, True, id="verbose_calls_extract"),
729+
pytest.param(False, False, id="non_verbose_skips_extract"),
730+
],
731+
)
732+
async def test_infer_extract_token_usage_on_failure_depends_on_verbose(
762733
mocker: MockerFixture,
763734
mock_configuration: AppConfig,
764735
mock_auth_resolvers: None,
765736
mock_request_factory: Callable[..., Any],
766737
mock_background_tasks: Any,
738+
verbose_enabled: bool,
739+
expect_extract_called: bool,
767740
) -> None:
768-
"""Verify extract_token_usage called in except block when text extraction fails."""
769-
_setup_config_mock(mocker, mock_configuration, verbose_enabled=True)
770-
mock_response = mocker.Mock()
771-
mock_response.output = [_create_mock_response_output(mocker, "Response")]
772-
mock_usage = mocker.Mock()
773-
mock_usage.input_tokens = 50
774-
mock_usage.output_tokens = 25
775-
mock_response.usage = mock_usage
776-
_setup_responses_mock(mocker, mocker.AsyncMock(return_value=mock_response))
777-
mocker.patch(
778-
"app.endpoints.rlsapi_v1.extract_text_from_response_items",
779-
side_effect=RuntimeError("text extraction failed"),
780-
)
781-
mock_extract = mocker.patch("app.endpoints.rlsapi_v1.extract_token_usage")
782-
with pytest.raises(RuntimeError):
783-
await infer_endpoint(
784-
infer_request=RlsapiV1InferRequest(
785-
question="How do I list files?", include_metadata=True
786-
),
787-
request=mock_request_factory(),
788-
background_tasks=mock_background_tasks,
789-
auth=MOCK_AUTH,
741+
"""Verify extract_token_usage is called on failure only when verbose is enabled."""
742+
_setup_config_mock(mocker, mock_configuration, verbose_enabled=verbose_enabled)
743+
744+
mock_usage: Any = None
745+
if verbose_enabled:
746+
mock_response = mocker.Mock()
747+
mock_response.output = [_create_mock_response_output(mocker, "Response")]
748+
mock_usage = mocker.Mock()
749+
mock_usage.input_tokens = 50
750+
mock_usage.output_tokens = 25
751+
mock_response.usage = mock_usage
752+
_setup_responses_mock(mocker, mocker.AsyncMock(return_value=mock_response))
753+
mocker.patch(
754+
"app.endpoints.rlsapi_v1.extract_text_from_response_items",
755+
side_effect=RuntimeError("text extraction failed"),
756+
)
757+
else:
758+
mocker.patch(
759+
"app.endpoints.rlsapi_v1.retrieve_simple_response",
760+
side_effect=RuntimeError("retrieval failed"),
790761
)
791-
mock_extract.assert_called_once()
792-
call_args = mock_extract.call_args
793-
assert call_args[0][0] == mock_usage
794-
assert call_args[0][1] == "openai/gpt-4-turbo"
795-
796762

797-
async def test_infer_non_verbose_no_extract_token_usage_on_failure(
798-
mocker: MockerFixture,
799-
mock_configuration: AppConfig,
800-
mock_auth_resolvers: None,
801-
mock_request_factory: Callable[..., Any],
802-
mock_background_tasks: Any,
803-
) -> None:
804-
"""Verify extract_token_usage NOT called in except block for non-verbose."""
805-
_setup_config_mock(mocker, mock_configuration, verbose_enabled=False)
806-
mocker.patch(
807-
"app.endpoints.rlsapi_v1.retrieve_simple_response",
808-
side_effect=RuntimeError("retrieval failed"),
809-
)
810763
mock_extract = mocker.patch("app.endpoints.rlsapi_v1.extract_token_usage")
764+
811765
with pytest.raises(RuntimeError):
766+
infer_request = RlsapiV1InferRequest(question="How do I list files?")
767+
if verbose_enabled:
768+
infer_request.include_metadata = True
812769
await infer_endpoint(
813-
infer_request=RlsapiV1InferRequest(question="How do I list files?"),
770+
infer_request=infer_request,
814771
request=mock_request_factory(),
815772
background_tasks=mock_background_tasks,
816773
auth=MOCK_AUTH,
817774
)
818-
mock_extract.assert_not_called()
775+
776+
if expect_extract_called:
777+
mock_extract.assert_called_once()
778+
call_args = mock_extract.call_args
779+
assert call_args[0][0] == mock_usage
780+
assert call_args[0][1] == "openai/gpt-4-turbo"
781+
else:
782+
mock_extract.assert_not_called()
819783

820784

821785
# --- Test Splunk integration ---

0 commit comments

Comments
 (0)