|  | 
| 1 | 1 | import os | 
|  | 2 | +import sys | 
| 2 | 3 | import unittest.mock | 
| 3 | 4 | 
 | 
| 4 | 5 | import boto3 | 
|  | 
| 15 | 16 | @pytest.fixture | 
| 16 | 17 | def bedrock_client(): | 
| 17 | 18 |     with unittest.mock.patch.object(strands.models.bedrock.boto3, "Session") as mock_session_cls: | 
| 18 |  | -        yield mock_session_cls.return_value.client.return_value | 
|  | 19 | +        mock_client = mock_session_cls.return_value.client.return_value | 
|  | 20 | +        mock_client.meta = unittest.mock.MagicMock() | 
|  | 21 | +        mock_client.meta.region_name = "us-west-2" | 
|  | 22 | +        yield mock_client | 
| 19 | 23 | 
 | 
| 20 | 24 | 
 | 
| 21 | 25 | @pytest.fixture | 
| @@ -1029,3 +1033,80 @@ def test_converse_output_guardrails_redacts_output(bedrock_client): | 
| 1029 | 1033 | 
 | 
| 1030 | 1034 |     bedrock_client.converse.assert_called_once() | 
| 1031 | 1035 |     bedrock_client.converse_stream.assert_not_called() | 
|  | 1036 | + | 
|  | 1037 | + | 
|  | 1038 | +@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)") | 
|  | 1039 | +def test_add_note_on_client_error(bedrock_client, model): | 
|  | 1040 | +    """Test that add_note is called on ClientError with region and model ID information.""" | 
|  | 1041 | +    # Mock the client error response | 
|  | 1042 | +    error_response = {"Error": {"Code": "ValidationException", "Message": "Some error message"}} | 
|  | 1043 | +    bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream") | 
|  | 1044 | + | 
|  | 1045 | +    # Call the stream method which should catch and add notes to the exception | 
|  | 1046 | +    with pytest.raises(ClientError) as err: | 
|  | 1047 | +        list(model.stream({"modelId": "test-model"})) | 
|  | 1048 | + | 
|  | 1049 | +    assert err.value.__notes__ == ["└ Bedrock region: us-west-2", "└ Model id: m1"] | 
|  | 1050 | + | 
|  | 1051 | + | 
|  | 1052 | +def test_no_add_note_when_not_available(bedrock_client, model): | 
|  | 1053 | +    """Verify that on any python version (even < 3.11 where add_note is not available, we get the right exception).""" | 
|  | 1054 | +    # Mock the client error response | 
|  | 1055 | +    error_response = {"Error": {"Code": "ValidationException", "Message": "Some error message"}} | 
|  | 1056 | +    bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream") | 
|  | 1057 | + | 
|  | 1058 | +    # Call the stream method which should catch and add notes to the exception | 
|  | 1059 | +    with pytest.raises(ClientError): | 
|  | 1060 | +        list(model.stream({"modelId": "test-model"})) | 
|  | 1061 | + | 
|  | 1062 | + | 
|  | 1063 | +@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)") | 
|  | 1064 | +def test_add_note_on_access_denied_exception(bedrock_client, model): | 
|  | 1065 | +    """Test that add_note adds documentation link for AccessDeniedException.""" | 
|  | 1066 | +    # Mock the client error response for access denied | 
|  | 1067 | +    error_response = { | 
|  | 1068 | +        "Error": { | 
|  | 1069 | +            "Code": "AccessDeniedException", | 
|  | 1070 | +            "Message": "An error occurred (AccessDeniedException) when calling the ConverseStream operation: " | 
|  | 1071 | +            "You don't have access to the model with the specified model ID.", | 
|  | 1072 | +        } | 
|  | 1073 | +    } | 
|  | 1074 | +    bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream") | 
|  | 1075 | + | 
|  | 1076 | +    # Call the stream method which should catch and add notes to the exception | 
|  | 1077 | +    with pytest.raises(ClientError) as err: | 
|  | 1078 | +        list(model.stream({"modelId": "test-model"})) | 
|  | 1079 | + | 
|  | 1080 | +    assert err.value.__notes__ == [ | 
|  | 1081 | +        "└ Bedrock region: us-west-2", | 
|  | 1082 | +        "└ Model id: m1", | 
|  | 1083 | +        "└ For more information see " | 
|  | 1084 | +        "https://strandsagents.com/user-guide/concepts/model-providers/amazon-bedrock/#model-access-issue", | 
|  | 1085 | +    ] | 
|  | 1086 | + | 
|  | 1087 | + | 
|  | 1088 | +@pytest.mark.skipif(sys.version_info < (3, 11), reason="This test requires Python 3.11 or higher (need add_note)") | 
|  | 1089 | +def test_add_note_on_validation_exception_throughput(bedrock_client, model): | 
|  | 1090 | +    """Test that add_note adds documentation link for ValidationException about on-demand throughput.""" | 
|  | 1091 | +    # Mock the client error response for validation exception | 
|  | 1092 | +    error_response = { | 
|  | 1093 | +        "Error": { | 
|  | 1094 | +            "Code": "ValidationException", | 
|  | 1095 | +            "Message": "An error occurred (ValidationException) when calling the ConverseStream operation: " | 
|  | 1096 | +            "Invocation of model ID anthropic.claude-3-7-sonnet-20250219-v1:0 with on-demand throughput " | 
|  | 1097 | +            "isn’t supported. Retry your request with the ID or ARN of an inference profile that contains " | 
|  | 1098 | +            "this model.", | 
|  | 1099 | +        } | 
|  | 1100 | +    } | 
|  | 1101 | +    bedrock_client.converse_stream.side_effect = ClientError(error_response, "ConversationStream") | 
|  | 1102 | + | 
|  | 1103 | +    # Call the stream method which should catch and add notes to the exception | 
|  | 1104 | +    with pytest.raises(ClientError) as err: | 
|  | 1105 | +        list(model.stream({"modelId": "test-model"})) | 
|  | 1106 | + | 
|  | 1107 | +    assert err.value.__notes__ == [ | 
|  | 1108 | +        "└ Bedrock region: us-west-2", | 
|  | 1109 | +        "└ Model id: m1", | 
|  | 1110 | +        "└ For more information see " | 
|  | 1111 | +        "https://strandsagents.com/latest/user-guide/concepts/model-providers/amazon-bedrock/#on-demand-throughput-isnt-supported", | 
|  | 1112 | +    ] | 
0 commit comments