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"
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"
631641 assert call_args [1 ]["timeout" ] == 30
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,18 +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- )
686+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
687+ mock_urlopen .side_effect = URLError ("Connection refused" )
674688
675689 exit_code = app .invoke_command (
676690 argparse .Namespace (
@@ -687,8 +701,8 @@ def test_invoke_command_handles_timeout_error() -> None:
687701 """Test that invoke command handles timeout errors gracefully."""
688702 app = CliApp ()
689703
690- with patch ("requests.post " ) as mock_post :
691- mock_post .side_effect = requests . exceptions . Timeout ("Request timed out" )
704+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen " ) as mock_urlopen :
705+ mock_urlopen .side_effect = TimeoutError ("Request timed out" )
692706
693707 exit_code = app .invoke_command (
694708 argparse .Namespace (
@@ -705,13 +719,21 @@ def test_invoke_command_handles_http_error_response() -> None:
705719 """Test that invoke command handles HTTP error responses."""
706720 app = CliApp ()
707721
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 = {
722+ error_body = json .dumps (
723+ {
712724 "ErrorMessage" : "Invalid parameter value" ,
713725 "ErrorType" : "InvalidParameterValueException" ,
714726 }
727+ ).encode ("utf-8" )
728+
729+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
730+ mock_urlopen .side_effect = HTTPError (
731+ url = "http://0.0.0.0:5000/start-durable-execution" ,
732+ code = 400 ,
733+ msg = "Bad Request" ,
734+ hdrs = HTTPMessage (),
735+ fp = BytesIO (error_body ),
736+ )
715737
716738 with patch ("sys.stderr" , new_callable = StringIO ) as mock_stderr :
717739 exit_code = app .invoke_command (
@@ -730,11 +752,14 @@ def test_invoke_command_handles_non_json_error_response() -> None:
730752 """Test that invoke command handles non-JSON error responses."""
731753 app = CliApp ()
732754
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"
755+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen" ) as mock_urlopen :
756+ mock_urlopen .side_effect = HTTPError (
757+ url = "http://0.0.0.0:5000/start-durable-execution" ,
758+ code = 500 ,
759+ msg = "Internal Server Error" ,
760+ hdrs = HTTPMessage (),
761+ fp = BytesIO (b"Internal Server Error" ),
762+ )
738763
739764 exit_code = app .invoke_command (
740765 argparse .Namespace (
@@ -1050,8 +1075,8 @@ def test_invoke_command_handles_general_exception() -> None:
10501075 """Test that invoke command handles general exceptions."""
10511076 app = CliApp ()
10521077
1053- with patch ("requests.post " ) as mock_post :
1054- mock_post .side_effect = ValueError ("Some unexpected error" )
1078+ with patch ("aws_durable_execution_sdk_python_testing.cli.urlopen " ) as mock_urlopen :
1079+ mock_urlopen .side_effect = ValueError ("Some unexpected error" )
10551080
10561081 exit_code = app .invoke_command (
10571082 argparse .Namespace (
0 commit comments