77import logging
88import os
99import sys
10- from io import StringIO
10+ from http .client import HTTPMessage
11+ from io import StringIO , BytesIO
1112from unittest .mock import Mock , patch
1213
1314import pytest
14- import requests
15+ from urllib .error import HTTPError , URLError
16+
1517from botocore .exceptions import ConnectionError # type: ignore
1618
1719from aws_durable_execution_sdk_python_testing .cli import CliApp , CliConfig , main
@@ -604,14 +606,21 @@ def test_invoke_command_makes_http_request_to_start_execution_endpoint() -> None
604606 """Test that invoke command makes HTTP request to start-durable-execution endpoint."""
605607 app = CliApp ()
606608
607- with patch ("requests.post" ) as mock_post :
608- # Mock successful response
609- mock_response = mock_post .return_value
610- mock_response .status_code = 201
611- mock_response .json .return_value = {
609+ response_body = json .dumps (
610+ {
612611 "ExecutionArn" : "arn:aws:lambda:us-west-2:123456789012:function:test-function:execution:test-execution"
613612 }
613+ ).encode ("utf-8" )
614+
615+ mock_response = Mock ()
616+ mock_response .read .return_value = response_body
617+ mock_response .__enter__ = Mock (return_value = mock_response )
618+ mock_response .__exit__ = Mock (return_value = False )
614619
620+ with patch (
621+ "aws_durable_execution_sdk_python_testing.cli.urlopen" ,
622+ return_value = mock_response ,
623+ ) as mock_urlopen :
615624 with patch ("sys.stdout" , new_callable = StringIO ) as mock_stdout :
616625 exit_code = app .invoke_command (
617626 argparse .Namespace (
@@ -622,16 +631,17 @@ def test_invoke_command_makes_http_request_to_start_execution_endpoint() -> None
622631 )
623632
624633 assert exit_code == 0
625- mock_post .assert_called_once ()
634+ mock_urlopen .assert_called_once ()
626635
627636 # Verify the request details
628- call_args = mock_post .call_args
629- assert call_args [0 ][0 ].endswith ("/start-durable-execution" )
630- assert call_args [1 ]["headers" ]["Content-Type" ] == "application/json"
631- assert call_args [1 ]["timeout" ] == 30
637+ call_args = mock_urlopen .call_args
638+ req = call_args [0 ][0 ]
639+ assert req .full_url .endswith ("/start-durable-execution" )
640+ assert req .get_header ("Content-type" ) == "application/json"
641+ assert call_args [1 ]["timeout" ] == 10
632642
633643 # Verify payload structure
634- payload = call_args [ 1 ][ " json" ]
644+ payload = json . loads ( req . data . decode ( "utf-8" ))
635645 assert payload ["FunctionName" ] == "test-function"
636646 assert payload ["Input" ] == '{"key": "value"}'
637647 assert payload ["ExecutionName" ] == "test-execution"
@@ -645,11 +655,16 @@ def test_invoke_command_uses_default_execution_name_when_not_provided() -> None:
645655 """Test that invoke command generates default execution name when not provided."""
646656 app = CliApp ()
647657
648- with patch ("requests.post" ) as mock_post :
649- mock_response = mock_post .return_value
650- mock_response .status_code = 201
651- mock_response .json .return_value = {"ExecutionArn" : "test-arn" }
658+ response_body = json .dumps ({"ExecutionArn" : "test-arn" }).encode ("utf-8" )
659+ mock_response = Mock ()
660+ mock_response .read .return_value = response_body
661+ mock_response .__enter__ = Mock (return_value = mock_response )
662+ mock_response .__exit__ = Mock (return_value = False )
652663
664+ with patch (
665+ "aws_durable_execution_sdk_python_testing.cli.urlopen" ,
666+ return_value = mock_response ,
667+ ) as mock_urlopen :
653668 app .invoke_command (
654669 argparse .Namespace (
655670 function_name = "my-function" ,
@@ -659,36 +674,17 @@ def test_invoke_command_uses_default_execution_name_when_not_provided() -> None:
659674 )
660675
661676 # Verify default execution name is generated
662- payload = mock_post .call_args [1 ]["json" ]
677+ req = mock_urlopen .call_args [0 ][0 ]
678+ payload = json .loads (req .data .decode ("utf-8" ))
663679 assert payload ["ExecutionName" ] == "my-function-execution"
664680
665681
666682def test_invoke_command_handles_connection_error () -> None :
667683 """Test that invoke command handles connection errors gracefully."""
668684 app = CliApp ()
669685
670- with patch ("requests.post" ) as mock_post :
671- mock_post .side_effect = requests .exceptions .ConnectionError (
672- "Connection refused"
673- )
674-
675- exit_code = app .invoke_command (
676- argparse .Namespace (
677- function_name = "test-function" ,
678- input = "{}" ,
679- durable_execution_name = None ,
680- )
681- )
682-
683- assert exit_code == 1
684-
685-
686- def test_invoke_command_handles_timeout_error () -> None :
687- """Test that invoke command handles timeout errors gracefully."""
688- app = CliApp ()
689-
690- with patch ("requests.post" ) as mock_post :
691- mock_post .side_effect = requests .exceptions .Timeout ("Request timed out" )
686+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
687+ mock_urlopen .side_effect = URLError ("Connection refused" )
692688
693689 exit_code = app .invoke_command (
694690 argparse .Namespace (
@@ -705,13 +701,21 @@ def test_invoke_command_handles_http_error_response() -> None:
705701 """Test that invoke command handles HTTP error responses."""
706702 app = CliApp ()
707703
708- with patch ("requests.post" ) as mock_post :
709- mock_response = mock_post .return_value
710- mock_response .status_code = 400
711- mock_response .json .return_value = {
704+ error_body = json .dumps (
705+ {
712706 "ErrorMessage" : "Invalid parameter value" ,
713707 "ErrorType" : "InvalidParameterValueException" ,
714708 }
709+ ).encode ("utf-8" )
710+
711+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
712+ mock_urlopen .side_effect = HTTPError (
713+ url = "http://0.0.0.0:5000/start-durable-execution" ,
714+ code = 400 ,
715+ msg = "Bad Request" ,
716+ hdrs = HTTPMessage (),
717+ fp = BytesIO (error_body ),
718+ )
715719
716720 with patch ("sys.stderr" , new_callable = StringIO ) as mock_stderr :
717721 exit_code = app .invoke_command (
@@ -730,11 +734,14 @@ def test_invoke_command_handles_non_json_error_response() -> None:
730734 """Test that invoke command handles non-JSON error responses."""
731735 app = CliApp ()
732736
733- with patch ("requests.post" ) as mock_post :
734- mock_response = mock_post .return_value
735- mock_response .status_code = 500
736- mock_response .json .side_effect = json .JSONDecodeError ("Invalid JSON" , "" , 0 )
737- mock_response .text = "Internal Server Error"
737+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
738+ mock_urlopen .side_effect = HTTPError (
739+ url = "http://0.0.0.0:5000/start-durable-execution" ,
740+ code = 500 ,
741+ msg = "Internal Server Error" ,
742+ hdrs = HTTPMessage (),
743+ fp = BytesIO (b"Internal Server Error" ),
744+ )
738745
739746 exit_code = app .invoke_command (
740747 argparse .Namespace (
@@ -1050,8 +1057,8 @@ def test_invoke_command_handles_general_exception() -> None:
10501057 """Test that invoke command handles general exceptions."""
10511058 app = CliApp ()
10521059
1053- with patch ("requests.post " ) as mock_post :
1054- mock_post .side_effect = ValueError ("Some unexpected error" )
1060+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen " ) as mock_urlopen :
1061+ mock_urlopen .side_effect = ValueError ("Some unexpected error" )
10551062
10561063 exit_code = app .invoke_command (
10571064 argparse .Namespace (
0 commit comments