From b52364defe23104cf66e368d3557d0728bd1b2a2 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Fri, 21 Nov 2025 21:34:20 -0500 Subject: [PATCH 1/5] Add integration tests for Bedrock Runtime --- clients/aws-sdk-bedrock-runtime/CHANGELOG.md | 5 +- .../tests/integration/__init__.py | 2 + .../tests/integration/conftest.py | 64 ++++ .../tests/integration/fixtures/test.pcm | Bin 0 -> 81836 bytes .../test_bidirectional_streaming.py | 305 ++++++++++++++++++ .../tests/integration/test_non_streaming.py | 41 +++ .../integration/test_output_streaming.py | 49 +++ 7 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/fixtures/test.pcm create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py create mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py diff --git a/clients/aws-sdk-bedrock-runtime/CHANGELOG.md b/clients/aws-sdk-bedrock-runtime/CHANGELOG.md index f7cc37e..aa7b89b 100644 --- a/clients/aws-sdk-bedrock-runtime/CHANGELOG.md +++ b/clients/aws-sdk-bedrock-runtime/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +### Enhancements +* Add comprehensive integration tests for non-streaming, output streaming, and bidirectional streaming operations. + ## v0.2.0 ### API Changes @@ -26,7 +29,7 @@ * New stop reason for Converse and ConverseStream ### Enhancements -* Improvements to the underlying AWS CRT HTTP client result in a signifigant decrease in CPU usage. Addresses [aws-sdk-python#11](https://github.com/awslabs/aws-sdk-python/issues/11). +* Improvements to the underlying AWS CRT HTTP client result in a significant decrease in CPU usage. Addresses [aws-sdk-python#11](https://github.com/awslabs/aws-sdk-python/issues/11). ### Dependencies diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py new file mode 100644 index 0000000..04f8b7b --- /dev/null +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py b/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py new file mode 100644 index 0000000..6c36050 --- /dev/null +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py @@ -0,0 +1,64 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + + +from pathlib import Path + +import pytest +from smithy_aws_core.identity.chain import create_default_chain +from smithy_http.aio.crt import AWSCRTHTTPClient + +from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient +from aws_sdk_bedrock_runtime.config import Config + +AWS_REGION = "us-west-2" +ENDPOINT_URI = f"https://bedrock-runtime.{AWS_REGION}.amazonaws.com" +MODEL_ID = "amazon.titan-text-express-v1" +BIDIRECTIONAL_MODEL_ID = "amazon.nova-sonic-v1:0" + + +@pytest.fixture +async def bedrock_client(): + """Create a new BedrockRuntimeClient with default credential chain.""" + http_client = AWSCRTHTTPClient() + client = BedrockRuntimeClient( + config=Config( + endpoint_uri=ENDPOINT_URI, + region=AWS_REGION, + aws_credentials_identity_resolver=create_default_chain(http_client), + transport=http_client, + ) + ) + return client + + +@pytest.fixture +def model_id(): + """Model ID that supports non-streaming and output streaming operations.""" + return MODEL_ID + + +@pytest.fixture +def bidirectional_model_id(): + """Model ID that supports bidirectional streaming operations.""" + return BIDIRECTIONAL_MODEL_ID + + +@pytest.fixture +def message(): + """Simple test message for Bedrock operations.""" + return "Who created the Python programming language?" + + +@pytest.fixture +def audio_file(): + """PCM audio file for bidirectional streaming tests. + + The audio asks: "Who created the Python programming language?" + Expected response should mention "Guido van Rossum". + """ + fixtures_dir = Path(__file__).parent / "fixtures" + audio_file = fixtures_dir / "test.pcm" + if not audio_file.exists(): + pytest.fail(f"Audio file does not exist: {audio_file}") + return audio_file diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/fixtures/test.pcm b/clients/aws-sdk-bedrock-runtime/tests/integration/fixtures/test.pcm new file mode 100644 index 0000000000000000000000000000000000000000..0fc61db6d309790ccf4d8275a17a228329bec061 GIT binary patch literal 81836 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 ag6{eHDC7FS?f-h None: + """Send a raw event JSON string to the Bedrock stream.""" + event = InvokeModelWithBidirectionalStreamInputChunk( + value=BidirectionalInputPayloadPart(bytes_=event_json.encode("utf-8")) + ) + await stream.input_stream.send(event) + + +async def _send_audio_chunks( + stream: DuplexEventStream[ + InvokeModelWithBidirectionalStreamInput, + InvokeModelWithBidirectionalStreamOutput, + InvokeModelWithBidirectionalStreamOperationOutput, + ], + audio_file: Path, + prompt_name: str, + audio_content_name: str, +) -> None: + """Send audio chunks from file simulating real-time delay.""" + chunk_count = 0 + with audio_file.open("rb") as f: + while chunk := f.read(CHUNK_SIZE): + chunk_count += 1 + encoded_chunk = base64.b64encode(chunk).decode("utf-8") + await _send_event( + stream, + AUDIO_INPUT_EVENT % (prompt_name, audio_content_name, encoded_chunk), + ) + # 512 bytes / (16000 Hz * 2 bytes/sample) = 0.016s per chunk + await asyncio.sleep(0.016) + + assert chunk_count > 0, f"No audio chunks were sent from {audio_file}" + + silence_chunk = bytes(CHUNK_SIZE) + encoded_silence = base64.b64encode(silence_chunk).decode("utf-8") + for _ in range(SILENCE_CHUNKS): + await _send_event( + stream, + AUDIO_INPUT_EVENT % (prompt_name, audio_content_name, encoded_silence), + ) + await asyncio.sleep(0.016) + + await _send_event(stream, CONTENT_END_EVENT % (prompt_name, audio_content_name)) + await asyncio.sleep(RESPONSE_WAIT_TIME) + await _send_event(stream, PROMPT_END_EVENT % prompt_name) + await _send_event(stream, SESSION_END_EVENT) + + +async def _receive_stream_output( + stream: DuplexEventStream[ + InvokeModelWithBidirectionalStreamInput, + InvokeModelWithBidirectionalStreamOutput, + InvokeModelWithBidirectionalStreamOperationOutput, + ], +) -> tuple[bool, bool, list[str]]: + """Receive and collect output from the bidirectional stream. + + Returns: + Tuple of (got_text, got_audio, all_text_output) + """ + got_text = False + got_audio = False + all_text_output: list[str] = [] + + await stream.await_output() + output_stream = stream.output_stream + if output_stream is None: + return got_text, got_audio, all_text_output + + async for out in output_stream: + if not isinstance(out, InvokeModelWithBidirectionalStreamOutputChunk): + continue + + payload = out.value.bytes_ + if not payload: + continue + + msg = json.loads(payload.decode("utf-8")) + event_data = msg.get("event", {}) + + if "textOutput" in event_data: + got_text = True + text_content = event_data["textOutput"].get("content", "") + all_text_output.append(text_content) + if "audioOutput" in event_data: + got_audio = True + if "completionEnd" in event_data: + break + + return got_text, got_audio, all_text_output + + +async def test_invoke_model_with_bidirectional_stream( + bedrock_client: BedrockRuntimeClient, bidirectional_model_id: str, audio_file: Path +) -> None: + """Test bidirectional streaming with audio input and text/audio output.""" + stream = await bedrock_client.invoke_model_with_bidirectional_stream( + InvokeModelWithBidirectionalStreamOperationInput( + model_id=bidirectional_model_id + ) + ) + + prompt_name = str(uuid.uuid4()) + content_name = str(uuid.uuid4()) + audio_content_name = str(uuid.uuid4()) + + init_events = [ + START_SESSION_EVENT, + START_PROMPT_EVENT % prompt_name, + TEXT_CONTENT_START_EVENT % (prompt_name, content_name, "SYSTEM"), + TEXT_INPUT_EVENT % (prompt_name, content_name, DEFAULT_SYSTEM_PROMPT), + CONTENT_END_EVENT % (prompt_name, content_name), + ] + + for event in init_events: + await _send_event(stream, event) + + await _send_event( + stream, AUDIO_CONTENT_START_EVENT % (prompt_name, audio_content_name) + ) + + results = await asyncio.gather( + _send_audio_chunks(stream, audio_file, prompt_name, audio_content_name), + _receive_stream_output(stream), + ) + got_text, got_audio, all_text_output = results[1] + + assert got_text, "Expected to receive text output" + assert got_audio, "Expected to receive audio output" + + assistant_response = " ".join(all_text_output[1:]).lower() + assert "guido" in assistant_response, ( + f"Expected response to mention 'Guido' (van Rossum). Got: {assistant_response}" + ) diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py new file mode 100644 index 0000000..d0ce3b5 --- /dev/null +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py @@ -0,0 +1,41 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Test non-streaming output type handling.""" + +from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient +from aws_sdk_bedrock_runtime.models import ( + ContentBlockText, + ConverseInput, + ConverseOperationOutput, + ConverseOutputMessage, + Message, +) + + +async def test_converse( + bedrock_client: BedrockRuntimeClient, model_id: str, message: str +) -> None: + input_message = Message(role="user", content=[ContentBlockText(value=message)]) + response = await bedrock_client.converse( + ConverseInput(model_id=model_id, messages=[input_message]) + ) + + assert isinstance(response, ConverseOperationOutput) + assert isinstance(response.output, ConverseOutputMessage) + + output_message = response.output.value + assert output_message.role == "assistant" + assert len(output_message.content) > 0 + + content_block = output_message.content[0] + assert isinstance(content_block, ContentBlockText) + assert isinstance(content_block.value, str) and content_block.value + + response_text = content_block.value.lower() + assert "guido" in response_text, ( + f"Expected response to mention 'Guido' (van Rossum). Got: {content_block.value}" + ) + + assert response.usage.input_tokens > 0 + assert response.usage.output_tokens > 0 diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py new file mode 100644 index 0000000..f0e8ca6 --- /dev/null +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py @@ -0,0 +1,49 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Test output streaming event stream handling.""" + +from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient +from aws_sdk_bedrock_runtime.models import ( + ContentBlockDeltaText, + ContentBlockText, + ConverseStreamInput, + ConverseStreamOperationOutput, + ConverseStreamOutputContentBlockDelta, + ConverseStreamOutputMetadata, + Message, +) + + +async def test_converse_stream( + bedrock_client: BedrockRuntimeClient, model_id: str, message: str +) -> None: + input_message = Message(role="user", content=[ContentBlockText(value=message)]) + response = await bedrock_client.converse_stream( + ConverseStreamInput(model_id=model_id, messages=[input_message]) + ) + + received_text: list[str] = [] + metadata_received = False + + async with response as stream: + async for event in stream.output_stream: + if isinstance(event, ConverseStreamOutputContentBlockDelta): + delta = event.value.delta + if isinstance(delta, ContentBlockDeltaText): + received_text.append(delta.value) + elif isinstance(event, ConverseStreamOutputMetadata): + metadata_received = True + assert event.value.usage.input_tokens > 0 + assert event.value.usage.output_tokens > 0 + + full_response = "".join(received_text) + assert full_response + + response_text = full_response.lower() + assert "guido" in response_text, ( + f"Expected response to mention 'Guido' (van Rossum). Got: {full_response}" + ) + + assert metadata_received + assert isinstance(stream.output, ConverseStreamOperationOutput) From d9f246f7106a15ad7e556c44ff4afae1c84be417 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Tue, 25 Nov 2025 15:02:22 -0500 Subject: [PATCH 2/5] Update test fixtures --- .../tests/integration/conftest.py | 26 ++++++++++++------- .../test_bidirectional_streaming.py | 25 +++--------------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py b/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py index 6c36050..d7b6b7a 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py @@ -11,25 +11,33 @@ from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient from aws_sdk_bedrock_runtime.config import Config -AWS_REGION = "us-west-2" -ENDPOINT_URI = f"https://bedrock-runtime.{AWS_REGION}.amazonaws.com" MODEL_ID = "amazon.titan-text-express-v1" BIDIRECTIONAL_MODEL_ID = "amazon.nova-sonic-v1:0" -@pytest.fixture -async def bedrock_client(): - """Create a new BedrockRuntimeClient with default credential chain.""" +def _create_bedrock_client(region: str): + """Helper to create a BedrockRuntimeClient for a given region.""" http_client = AWSCRTHTTPClient() - client = BedrockRuntimeClient( + return BedrockRuntimeClient( config=Config( - endpoint_uri=ENDPOINT_URI, - region=AWS_REGION, + endpoint_uri=f"https://bedrock-runtime.{region}.amazonaws.com", + region=region, aws_credentials_identity_resolver=create_default_chain(http_client), transport=http_client, ) ) - return client + + +@pytest.fixture +def bedrock_client(): + """Create a BedrockRuntimeClient for us-west-2.""" + return _create_bedrock_client("us-west-2") + + +@pytest.fixture +def bedrock_client_us_east_1(): + """Create a BedrockRuntimeClient for us-east-1 (for nova-sonic model).""" + return _create_bedrock_client("us-east-1") @pytest.fixture diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py index 088fae9..821a292 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py @@ -9,13 +9,9 @@ import uuid from pathlib import Path -import pytest -from smithy_aws_core.identity.chain import create_default_chain from smithy_core.aio.eventstream import DuplexEventStream -from smithy_http.aio.crt import AWSCRTHTTPClient from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient -from aws_sdk_bedrock_runtime.config import Config from aws_sdk_bedrock_runtime.models import ( BidirectionalInputPayloadPart, InvokeModelWithBidirectionalStreamInputChunk, @@ -147,21 +143,6 @@ }""" -@pytest.fixture -async def bedrock_client(): - """Create a BedrockRuntimeClient for us-east-1.""" - http_client = AWSCRTHTTPClient() - client = BedrockRuntimeClient( - config=Config( - endpoint_uri="https://bedrock-runtime.us-east-1.amazonaws.com", - region="us-east-1", - aws_credentials_identity_resolver=create_default_chain(http_client), - transport=http_client, - ) - ) - return client - - async def _send_event( stream: DuplexEventStream[ InvokeModelWithBidirectionalStreamInput, @@ -262,10 +243,12 @@ async def _receive_stream_output( async def test_invoke_model_with_bidirectional_stream( - bedrock_client: BedrockRuntimeClient, bidirectional_model_id: str, audio_file: Path + bedrock_client_us_east_1: BedrockRuntimeClient, + bidirectional_model_id: str, + audio_file: Path, ) -> None: """Test bidirectional streaming with audio input and text/audio output.""" - stream = await bedrock_client.invoke_model_with_bidirectional_stream( + stream = await bedrock_client_us_east_1.invoke_model_with_bidirectional_stream( InvokeModelWithBidirectionalStreamOperationInput( model_id=bidirectional_model_id ) From 48854e7f56092fcb0e0b614ee7b15749cbabec79 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Tue, 25 Nov 2025 17:43:56 -0500 Subject: [PATCH 3/5] Implement feedback --- .../tests/integration/__init__.py | 24 +++++++ .../tests/integration/conftest.py | 72 ------------------- .../test_bidirectional_streaming.py | 28 +++----- .../tests/integration/test_non_streaming.py | 18 ++--- .../integration/test_output_streaming.py | 18 ++--- 5 files changed, 48 insertions(+), 112 deletions(-) delete mode 100644 clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py index 04f8b7b..579507d 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py @@ -1,2 +1,26 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 + + +from pathlib import Path + +from smithy_aws_core.identity import EnvironmentCredentialsResolver + +from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient +from aws_sdk_bedrock_runtime.config import Config + +MODEL_ID = "amazon.titan-text-express-v1" +BIDIRECTIONAL_MODEL_ID = "amazon.nova-sonic-v1:0" +MESSAGE = "Who created the Python programming language?" +AUDIO_FILE = Path(__file__).parent / "fixtures" / "test.pcm" + + +def create_bedrock_client(region: str) -> BedrockRuntimeClient: + """Helper to create a BedrockRuntimeClient for a given region.""" + return BedrockRuntimeClient( + config=Config( + endpoint_uri=f"https://bedrock-runtime.{region}.amazonaws.com", + region=region, + aws_credentials_identity_resolver=EnvironmentCredentialsResolver(), + ) + ) diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py b/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py deleted file mode 100644 index d7b6b7a..0000000 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/conftest.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - - -from pathlib import Path - -import pytest -from smithy_aws_core.identity.chain import create_default_chain -from smithy_http.aio.crt import AWSCRTHTTPClient - -from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient -from aws_sdk_bedrock_runtime.config import Config - -MODEL_ID = "amazon.titan-text-express-v1" -BIDIRECTIONAL_MODEL_ID = "amazon.nova-sonic-v1:0" - - -def _create_bedrock_client(region: str): - """Helper to create a BedrockRuntimeClient for a given region.""" - http_client = AWSCRTHTTPClient() - return BedrockRuntimeClient( - config=Config( - endpoint_uri=f"https://bedrock-runtime.{region}.amazonaws.com", - region=region, - aws_credentials_identity_resolver=create_default_chain(http_client), - transport=http_client, - ) - ) - - -@pytest.fixture -def bedrock_client(): - """Create a BedrockRuntimeClient for us-west-2.""" - return _create_bedrock_client("us-west-2") - - -@pytest.fixture -def bedrock_client_us_east_1(): - """Create a BedrockRuntimeClient for us-east-1 (for nova-sonic model).""" - return _create_bedrock_client("us-east-1") - - -@pytest.fixture -def model_id(): - """Model ID that supports non-streaming and output streaming operations.""" - return MODEL_ID - - -@pytest.fixture -def bidirectional_model_id(): - """Model ID that supports bidirectional streaming operations.""" - return BIDIRECTIONAL_MODEL_ID - - -@pytest.fixture -def message(): - """Simple test message for Bedrock operations.""" - return "Who created the Python programming language?" - - -@pytest.fixture -def audio_file(): - """PCM audio file for bidirectional streaming tests. - - The audio asks: "Who created the Python programming language?" - Expected response should mention "Guido van Rossum". - """ - fixtures_dir = Path(__file__).parent / "fixtures" - audio_file = fixtures_dir / "test.pcm" - if not audio_file.exists(): - pytest.fail(f"Audio file does not exist: {audio_file}") - return audio_file diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py index 821a292..ff8ea4b 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py @@ -7,11 +7,9 @@ import base64 import json import uuid -from pathlib import Path from smithy_core.aio.eventstream import DuplexEventStream -from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient from aws_sdk_bedrock_runtime.models import ( BidirectionalInputPayloadPart, InvokeModelWithBidirectionalStreamInputChunk, @@ -22,6 +20,7 @@ InvokeModelWithBidirectionalStreamOutputChunk, ) +from . import AUDIO_FILE, BIDIRECTIONAL_MODEL_ID, create_bedrock_client CHUNK_SIZE = 512 SILENCE_CHUNKS = 125 @@ -164,13 +163,12 @@ async def _send_audio_chunks( InvokeModelWithBidirectionalStreamOutput, InvokeModelWithBidirectionalStreamOperationOutput, ], - audio_file: Path, prompt_name: str, audio_content_name: str, ) -> None: """Send audio chunks from file simulating real-time delay.""" chunk_count = 0 - with audio_file.open("rb") as f: + with AUDIO_FILE.open("rb") as f: while chunk := f.read(CHUNK_SIZE): chunk_count += 1 encoded_chunk = base64.b64encode(chunk).decode("utf-8") @@ -181,7 +179,7 @@ async def _send_audio_chunks( # 512 bytes / (16000 Hz * 2 bytes/sample) = 0.016s per chunk await asyncio.sleep(0.016) - assert chunk_count > 0, f"No audio chunks were sent from {audio_file}" + assert chunk_count > 0, f"No audio chunks were sent from {AUDIO_FILE}" silence_chunk = bytes(CHUNK_SIZE) encoded_silence = base64.b64encode(silence_chunk).decode("utf-8") @@ -242,15 +240,13 @@ async def _receive_stream_output( return got_text, got_audio, all_text_output -async def test_invoke_model_with_bidirectional_stream( - bedrock_client_us_east_1: BedrockRuntimeClient, - bidirectional_model_id: str, - audio_file: Path, -) -> None: +async def test_invoke_model_with_bidirectional_stream() -> None: """Test bidirectional streaming with audio input and text/audio output.""" - stream = await bedrock_client_us_east_1.invoke_model_with_bidirectional_stream( + bedrock_client = create_bedrock_client("us-east-1") + + stream = await bedrock_client.invoke_model_with_bidirectional_stream( InvokeModelWithBidirectionalStreamOperationInput( - model_id=bidirectional_model_id + model_id=BIDIRECTIONAL_MODEL_ID ) ) @@ -274,15 +270,11 @@ async def test_invoke_model_with_bidirectional_stream( ) results = await asyncio.gather( - _send_audio_chunks(stream, audio_file, prompt_name, audio_content_name), + _send_audio_chunks(stream, prompt_name, audio_content_name), _receive_stream_output(stream), ) got_text, got_audio, all_text_output = results[1] assert got_text, "Expected to receive text output" assert got_audio, "Expected to receive audio output" - - assistant_response = " ".join(all_text_output[1:]).lower() - assert "guido" in assistant_response, ( - f"Expected response to mention 'Guido' (van Rossum). Got: {assistant_response}" - ) + assert len(all_text_output) > 0, "Expected non-empty text output" diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py index d0ce3b5..aefb9de 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_non_streaming.py @@ -3,7 +3,6 @@ """Test non-streaming output type handling.""" -from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient from aws_sdk_bedrock_runtime.models import ( ContentBlockText, ConverseInput, @@ -12,13 +11,15 @@ Message, ) +from . import MESSAGE, MODEL_ID, create_bedrock_client -async def test_converse( - bedrock_client: BedrockRuntimeClient, model_id: str, message: str -) -> None: - input_message = Message(role="user", content=[ContentBlockText(value=message)]) + +async def test_converse() -> None: + bedrock_client = create_bedrock_client("us-west-2") + + input_message = Message(role="user", content=[ContentBlockText(value=MESSAGE)]) response = await bedrock_client.converse( - ConverseInput(model_id=model_id, messages=[input_message]) + ConverseInput(model_id=MODEL_ID, messages=[input_message]) ) assert isinstance(response, ConverseOperationOutput) @@ -32,10 +33,5 @@ async def test_converse( assert isinstance(content_block, ContentBlockText) assert isinstance(content_block.value, str) and content_block.value - response_text = content_block.value.lower() - assert "guido" in response_text, ( - f"Expected response to mention 'Guido' (van Rossum). Got: {content_block.value}" - ) - assert response.usage.input_tokens > 0 assert response.usage.output_tokens > 0 diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py index f0e8ca6..b06b53e 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_output_streaming.py @@ -3,7 +3,6 @@ """Test output streaming event stream handling.""" -from aws_sdk_bedrock_runtime.client import BedrockRuntimeClient from aws_sdk_bedrock_runtime.models import ( ContentBlockDeltaText, ContentBlockText, @@ -14,13 +13,15 @@ Message, ) +from . import MESSAGE, MODEL_ID, create_bedrock_client -async def test_converse_stream( - bedrock_client: BedrockRuntimeClient, model_id: str, message: str -) -> None: - input_message = Message(role="user", content=[ContentBlockText(value=message)]) + +async def test_converse_stream() -> None: + bedrock_client = create_bedrock_client("us-west-2") + + input_message = Message(role="user", content=[ContentBlockText(value=MESSAGE)]) response = await bedrock_client.converse_stream( - ConverseStreamInput(model_id=model_id, messages=[input_message]) + ConverseStreamInput(model_id=MODEL_ID, messages=[input_message]) ) received_text: list[str] = [] @@ -40,10 +41,5 @@ async def test_converse_stream( full_response = "".join(received_text) assert full_response - response_text = full_response.lower() - assert "guido" in response_text, ( - f"Expected response to mention 'Guido' (van Rossum). Got: {full_response}" - ) - assert metadata_received assert isinstance(stream.output, ConverseStreamOperationOutput) From 752a17c957920c1d7c1012456ae5901766fee2bd Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Tue, 25 Nov 2025 20:07:20 -0500 Subject: [PATCH 4/5] Update directory name --- .../tests/integration/__init__.py | 2 +- .../tests/integration/{fixtures => assets}/test.pcm | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename clients/aws-sdk-bedrock-runtime/tests/integration/{fixtures => assets}/test.pcm (100%) diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py index 579507d..3373189 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/__init__.py @@ -12,7 +12,7 @@ MODEL_ID = "amazon.titan-text-express-v1" BIDIRECTIONAL_MODEL_ID = "amazon.nova-sonic-v1:0" MESSAGE = "Who created the Python programming language?" -AUDIO_FILE = Path(__file__).parent / "fixtures" / "test.pcm" +AUDIO_FILE = Path(__file__).parent / "assets" / "test.pcm" def create_bedrock_client(region: str) -> BedrockRuntimeClient: diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/fixtures/test.pcm b/clients/aws-sdk-bedrock-runtime/tests/integration/assets/test.pcm similarity index 100% rename from clients/aws-sdk-bedrock-runtime/tests/integration/fixtures/test.pcm rename to clients/aws-sdk-bedrock-runtime/tests/integration/assets/test.pcm From d62c946e24646ef2d0c01db105ec00ff65b0d003 Mon Sep 17 00:00:00 2001 From: Alessandra Romero Date: Wed, 26 Nov 2025 15:07:27 -0500 Subject: [PATCH 5/5] Raise RuntimeError on non-chunk events in bidirectional stream --- .../tests/integration/test_bidirectional_streaming.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py index ff8ea4b..67f6955 100644 --- a/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py +++ b/clients/aws-sdk-bedrock-runtime/tests/integration/test_bidirectional_streaming.py @@ -219,7 +219,9 @@ async def _receive_stream_output( async for out in output_stream: if not isinstance(out, InvokeModelWithBidirectionalStreamOutputChunk): - continue + raise RuntimeError( + f"Received unexpected event type in stream: {type(out).__name__}" + ) payload = out.value.bytes_ if not payload: