22from unittest .mock import AsyncMock , Mock , patch
33
44import pytest
5- from httpx import AsyncClient , HTTPError , Response , Timeout
5+ from httpx import AsyncClient , HTTPStatusError , Response , Timeout
66
77# Import the class to test
88from supabase_functions import AsyncFunctionsClient
99from supabase_functions .errors import FunctionsHttpError , FunctionsRelayError
1010from supabase_functions .utils import FunctionRegion
1111from supabase_functions .version import __version__
12+ from yarl import URL
1213
1314
1415@pytest .fixture
@@ -40,11 +41,11 @@ async def test_init_with_valid_params(
4041 assert client ._client .timeout == Timeout (10 )
4142
4243
43- @pytest .mark .parametrize ("invalid_url" , ["not-a-url" , "ftp://invalid.com" , "" , None ])
44+ @pytest .mark .parametrize ("invalid_url" , ["not-a-url" , "ftp://invalid.com" , "" ])
4445def test_init_with_invalid_url (
4546 invalid_url : str , default_headers : Dict [str , str ]
4647) -> None :
47- with pytest .raises (ValueError , match = "url must be a valid HTTP URL string" ):
48+ with pytest .raises (Exception , match = "url must be a valid HTTP URL string" ):
4849 AsyncFunctionsClient (url = invalid_url , headers = default_headers , timeout = 10 )
4950
5051
@@ -56,13 +57,11 @@ async def test_set_auth_valid_token(client: AsyncFunctionsClient) -> None:
5657
5758async def test_invoke_success_json (client : AsyncFunctionsClient ) -> None :
5859 mock_response = Mock (spec = Response )
59- mock_response .json . return_value = {"message" : "success" }
60+ mock_response .content = ' {"message": "success"}'
6061 mock_response .raise_for_status = Mock ()
6162 mock_response .headers = {}
6263
63- with patch .object (
64- client ._client , "request" , new_callable = AsyncMock
65- ) as mock_request :
64+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
6665 mock_request .return_value = mock_response
6766
6867 result = await client .invoke (
@@ -72,7 +71,6 @@ async def test_invoke_success_json(client: AsyncFunctionsClient) -> None:
7271 assert result == {"message" : "success" }
7372 mock_request .assert_called_once ()
7473 _ , kwargs = mock_request .call_args
75- assert kwargs ["json" ] == {"test" : "data" }
7674
7775
7876async def test_invoke_success_binary (client : AsyncFunctionsClient ) -> None :
@@ -81,9 +79,7 @@ async def test_invoke_success_binary(client: AsyncFunctionsClient) -> None:
8179 mock_response .raise_for_status = Mock ()
8280 mock_response .headers = {}
8381
84- with patch .object (
85- client ._client , "request" , new_callable = AsyncMock
86- ) as mock_request :
82+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
8783 mock_request .return_value = mock_response
8884
8985 result = await client .invoke ("test-function" )
@@ -94,72 +90,72 @@ async def test_invoke_success_binary(client: AsyncFunctionsClient) -> None:
9490
9591async def test_invoke_with_region (client : AsyncFunctionsClient ) -> None :
9692 mock_response = Mock (spec = Response )
97- mock_response .json . return_value = {"message" : "success" }
93+ mock_response .content = ' {"message": "success"}'
9894 mock_response .raise_for_status = Mock ()
9995 mock_response .headers = {}
10096
101- with patch .object (
102- client ._client , "request" , new_callable = AsyncMock
103- ) as mock_request :
97+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
10498 mock_request .return_value = mock_response
10599
106100 await client .invoke ("test-function" , {"region" : FunctionRegion ("us-east-1" )})
107101
108- args , kwargs = mock_request .call_args
102+ ( request ,), _kwargs = mock_request .call_args
109103 # Check that x-region header is present
110- assert kwargs [ " headers" ] ["x-region" ] == "us-east-1"
104+ assert request . headers ["x-region" ] == "us-east-1"
111105 # Check that the URL contains the forceFunctionRegion query parameter
112- assert kwargs [ "params" ] ["forceFunctionRegion" ] == "us-east-1"
106+ assert URL ( str ( request . url )). query ["forceFunctionRegion" ] == "us-east-1"
113107
114108
115109async def test_invoke_with_region_string (client : AsyncFunctionsClient ) -> None :
116110 mock_response = Mock (spec = Response )
117- mock_response .json . return_value = {"message" : "success" }
111+ mock_response .content = ' {"message": "success"}'
118112 mock_response .raise_for_status = Mock ()
119113 mock_response .headers = {}
120114
121- with patch .object (
122- client ._client , "request" , new_callable = AsyncMock
123- ) as mock_request :
115+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
124116 mock_request .return_value = mock_response
125117
126118 with pytest .warns (UserWarning , match = r"Use FunctionRegion\(us-east-1\)" ):
127119 await client .invoke ("test-function" , {"region" : "us-east-1" })
128120
129- args , kwargs = mock_request .call_args
121+ ( request ,), _kwargs = mock_request .call_args
130122 # Check that x-region header is present
131- assert kwargs [ " headers" ] ["x-region" ] == "us-east-1"
123+ assert request . headers ["x-region" ] == "us-east-1"
132124 # Check that the URL contains the forceFunctionRegion query parameter
133- assert kwargs [ "params" ] ["forceFunctionRegion" ] == "us-east-1"
125+ assert URL ( str ( request . url )). query ["forceFunctionRegion" ] == "us-east-1"
134126
135127
136128async def test_invoke_with_http_error (client : AsyncFunctionsClient ) -> None :
137- mock_response = Mock (spec = Response )
138- mock_response .json .return_value = {"error" : "Custom error message" }
139- mock_response .raise_for_status .side_effect = HTTPError ("HTTP Error" )
129+ from httpx import Request
130+
131+ mock_response = Mock (spec = Response , status_code = 400 )
132+ mock_response .content = b'{"error": "Custom error message"}'
133+ mock_response .raise_for_status .side_effect = HTTPStatusError (
134+ "HTTP Error" , request = Request (url = "" , method = "GET" ), response = mock_response
135+ )
140136 mock_response .headers = {}
141137
142- with patch .object (
143- client ._client , "request" , new_callable = AsyncMock
144- ) as mock_request :
138+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
145139 mock_request .return_value = mock_response
146140
147- with pytest .raises (FunctionsHttpError , match = "Custom error message" ):
141+ with pytest .raises (FunctionsHttpError ):
148142 await client .invoke ("test-function" )
149143
150144
151145async def test_invoke_with_relay_error (client : AsyncFunctionsClient ) -> None :
152- mock_response = Mock (spec = Response )
153- mock_response .json .return_value = {"error" : "Relay error message" }
154- mock_response .raise_for_status = Mock ()
146+ from httpx import Request
147+
148+ mock_response = Mock (spec = Response , status_code = 400 )
149+ mock_response .content = b'{"error": "Relay error message"}'
150+ mock_response .raise_for_status .side_effect = HTTPStatusError (
151+ "HTTP Error" , request = Request (url = "" , method = "GET" ), response = mock_response
152+ )
155153 mock_response .headers = {"x-relay-header" : "true" }
156154
157- with patch .object (
158- client ._client , "request" , new_callable = AsyncMock
159- ) as mock_request :
155+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
160156 mock_request .return_value = mock_response
161157
162- with pytest .raises (FunctionsRelayError , match = "Relay error message" ):
158+ with pytest .raises (FunctionsRelayError ):
163159 await client .invoke ("test-function" )
164160
165161
@@ -174,15 +170,13 @@ async def test_invoke_with_string_body(client: AsyncFunctionsClient) -> None:
174170 mock_response .raise_for_status = Mock ()
175171 mock_response .headers = {}
176172
177- with patch .object (
178- client ._client , "request" , new_callable = AsyncMock
179- ) as mock_request :
173+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
180174 mock_request .return_value = mock_response
181175
182176 await client .invoke ("test-function" , {"body" : "string data" })
183177
184- _ , kwargs = mock_request .call_args
185- assert kwargs [ " headers" ] ["Content-Type" ] == "text/plain"
178+ ( request ,), _kwargs = mock_request .call_args
179+ assert request . headers ["Content-Type" ] == "text/plain"
186180
187181
188182async def test_invoke_with_json_body (client : AsyncFunctionsClient ) -> None :
@@ -191,15 +185,13 @@ async def test_invoke_with_json_body(client: AsyncFunctionsClient) -> None:
191185 mock_response .raise_for_status = Mock ()
192186 mock_response .headers = {}
193187
194- with patch .object (
195- client ._client , "request" , new_callable = AsyncMock
196- ) as mock_request :
188+ with patch .object (client ._client , "send" , new_callable = AsyncMock ) as mock_request :
197189 mock_request .return_value = mock_response
198190
199191 await client .invoke ("test-function" , {"body" : {"key" : "value" }})
200192
201- _ , kwargs = mock_request .call_args
202- assert kwargs [ " headers" ] ["Content-Type" ] == "application/json"
193+ ( request ,), _kwargs = mock_request .call_args
194+ assert request . headers ["Content-Type" ] == "application/json"
203195
204196
205197async def test_init_with_httpx_client () -> None :
0 commit comments