44from optimizely .cmab .cmab_client import DefaultCmabClient , CmabRetryConfig
55from requests .exceptions import RequestException
66from optimizely .helpers .enums import Errors
7+ from optimizely .exceptions import CmabFetchError , CmabInvalidResponseError
78
89
910class TestDefaultCmabClient_do_fetch (unittest .TestCase ):
@@ -20,40 +21,52 @@ def test_do_fetch_success(self):
2021 }
2122 self .mock_http_client .post .return_value = mock_response
2223
23- result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' })
24+ result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' }, 1.0 )
2425 self .assertEqual (result , 'abc123' )
2526
2627 def test_do_fetch_http_exception (self ):
2728 self .mock_http_client .post .side_effect = RequestException ('Connection error' )
28- result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' })
29- self .assertIsNone (result )
30- self .mock_logger .exception .assert_called_with (Errors .CMAB_FETCH_FAILED .format ('Connection error' ))
29+
30+ with self .assertRaises (CmabFetchError ) as context :
31+ self .client ._do_fetch ('http://fake-url' , {'some' : 'data' }, 1.0 )
32+
33+ self .mock_logger .error .assert_called_with (Errors .CMAB_FETCH_FAILED .format ('Connection error' ))
34+ self .assertIn ('Connection error' , str (context .exception ))
3135
3236 def test_do_fetch_non_2xx_status (self ):
3337 mock_response = MagicMock ()
3438 mock_response .status_code = 500
3539 self .mock_http_client .post .return_value = mock_response
36- result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' })
37- self .assertIsNone (result )
38- self .mock_logger .exception .assert_called_with (Errors .CMAB_FETCH_FAILED .format (str (mock_response .status_code )))
40+
41+ with self .assertRaises (CmabFetchError ) as context :
42+ self .client ._do_fetch ('http://fake-url' , {'some' : 'data' }, 1.0 )
43+
44+ self .mock_logger .error .assert_called_with (Errors .CMAB_FETCH_FAILED .format (str (mock_response .status_code )))
45+ self .assertIn (str (mock_response .status_code ), str (context .exception ))
3946
4047 def test_do_fetch_invalid_json (self ):
4148 mock_response = MagicMock ()
4249 mock_response .status_code = 200
4350 mock_response .json .side_effect = json .JSONDecodeError ("Expecting value" , "" , 0 )
4451 self .mock_http_client .post .return_value = mock_response
45- result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' })
46- self .assertIsNone (result )
47- self .mock_logger .exception .assert_called_with (Errors .INVALID_CMAB_FETCH_RESPONSE )
52+
53+ with self .assertRaises (CmabInvalidResponseError ) as context :
54+ self .client ._do_fetch ('http://fake-url' , {'some' : 'data' }, 1.0 )
55+
56+ self .mock_logger .error .assert_called_with (Errors .INVALID_CMAB_FETCH_RESPONSE )
57+ self .assertIn (Errors .INVALID_CMAB_FETCH_RESPONSE , str (context .exception ))
4858
4959 def test_do_fetch_invalid_response_structure (self ):
5060 mock_response = MagicMock ()
5161 mock_response .status_code = 200
5262 mock_response .json .return_value = {'no_predictions' : []}
5363 self .mock_http_client .post .return_value = mock_response
54- result = self .client ._do_fetch ('http://fake-url' , {'some' : 'data' })
55- self .assertIsNone (result )
56- self .mock_logger .exception .assert_called_with (Errors .INVALID_CMAB_FETCH_RESPONSE )
64+
65+ with self .assertRaises (CmabInvalidResponseError ) as context :
66+ self .client ._do_fetch ('http://fake-url' , {'some' : 'data' }, 1.0 )
67+
68+ self .mock_logger .error .assert_called_with (Errors .INVALID_CMAB_FETCH_RESPONSE )
69+ self .assertIn (Errors .INVALID_CMAB_FETCH_RESPONSE , str (context .exception ))
5770
5871
5972class TestDefaultCmabClientWithRetry (unittest .TestCase ):
@@ -76,7 +89,7 @@ def test_do_fetch_with_retry_success_on_first_try(self, _):
7689 }
7790 self .mock_http_client .post .return_value = mock_response
7891
79- result = self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config )
92+ result = self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config , 1.0 )
8093 self .assertEqual (result , "abc123" )
8194 self .assertEqual (self .mock_http_client .post .call_count , 1 )
8295
@@ -97,7 +110,7 @@ def test_do_fetch_with_retry_success_on_retry(self, _):
97110 success_response
98111 ]
99112
100- result = self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config )
113+ result = self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config , 1.0 )
101114 self .assertEqual (result , "xyz456" )
102115 self .assertEqual (self .mock_http_client .post .call_count , 2 )
103116 self .mock_logger .info .assert_called_with ("Retrying CMAB request (attempt: 1) after 0.01 seconds..." )
@@ -109,8 +122,9 @@ def test_do_fetch_with_retry_exhausts_all_attempts(self, _):
109122
110123 self .mock_http_client .post .return_value = failure_response
111124
112- result = self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config )
113- self .assertIsNone (result )
125+ with self .assertRaises (CmabFetchError ):
126+ self .client ._do_fetch_with_retry ("http://fake-url" , {}, self .retry_config , 1.0 )
127+
114128 self .assertEqual (self .mock_http_client .post .call_count , 3 ) # 1 original + 2 retries
115129 self .mock_logger .error .assert_called_with (
116130 Errors .CMAB_FETCH_FAILED .format ("Exhausted all retries for CMAB request." ))
@@ -124,7 +138,7 @@ def setUp(self):
124138 self .client = DefaultCmabClient (
125139 http_client = self .mock_http_client ,
126140 logger = self .mock_logger ,
127- retry_config = self . retry_config
141+ retry_config = None
128142 )
129143 self .rule_id = 'test_rule'
130144 self .user_id = 'user123'
@@ -150,12 +164,6 @@ def test_fetch_decision_success_with_retry(self, mock_do_fetch_with_retry):
150164
151165 @patch .object (DefaultCmabClient , '_do_fetch' , side_effect = RequestException ("Network error" ))
152166 def test_fetch_decision_request_exception (self , mock_do_fetch ):
153- result = self .client . fetch_decision ( self . rule_id , self . user_id , self . attributes , self . cmab_uuid )
154- self .assertIsNone ( result )
167+ with self .assertRaises ( CmabFetchError ):
168+ self .client . fetch_decision ( self . rule_id , self . user_id , self . attributes , self . cmab_uuid )
155169 self .mock_logger .error .assert_called_with (Errors .CMAB_FETCH_FAILED .format ("Network error" ))
156-
157- @patch .object (DefaultCmabClient , '_do_fetch' , return_value = None )
158- def test_fetch_decision_invalid_response (self , mock_do_fetch ):
159- result = self .client .fetch_decision (self .rule_id , self .user_id , self .attributes , self .cmab_uuid )
160- self .assertIsNone (result )
161- self .mock_logger .error .assert_called_once ()
0 commit comments