Skip to content

Commit b60861c

Browse files
authored
ci(python-sdk): fix flaky unit tests (#629)
2 parents 8f0d2a6 + 6019a13 commit b60861c

4 files changed

Lines changed: 70 additions & 34 deletions

File tree

config/clients/python/template/test/api_test.py.mustache

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,12 +1514,12 @@ class TestOpenFgaApi(IsolatedAsyncioTestCase):
15141514
"message": "Rate Limit exceeded"
15151515
}
15161516
"""
1517-
retry_after_in_sec = 5
1518-
five_seconds_from_now = (datetime.now(timezone.utc) + timedelta(seconds=retry_after_in_sec)).strftime('%a, %d %b %Y %H:%M:%S GMT')
1517+
retry_after_in_sec = 10
1518+
ten_seconds_from_now = (datetime.now(timezone.utc) + timedelta(seconds=retry_after_in_sec)).strftime('%a, %d %b %Y %H:%M:%S GMT')
15191519
mock_http_response = http_mock_response(
15201520
body=error_response_body,
15211521
status=429,
1522-
headers={"Retry-After": five_seconds_from_now}
1522+
headers={"Retry-After": ten_seconds_from_now}
15231523
)
15241524
mock_request.side_effect = [
15251525
RateLimitExceededError(
@@ -1531,7 +1531,7 @@ class TestOpenFgaApi(IsolatedAsyncioTestCase):
15311531
retry = {{packageName}}.configuration.RetryParams(
15321532
max_retry=1,
15331533
min_wait_in_ms=10,
1534-
max_wait_in_sec=1
1534+
max_wait_in_sec=15
15351535
)
15361536
configuration = self.configuration
15371537
configuration.store_id = store_id
@@ -1552,7 +1552,7 @@ class TestOpenFgaApi(IsolatedAsyncioTestCase):
15521552
self.assertTrue(api_response.allowed)
15531553
mock_request.assert_called()
15541554
self.assertEqual(mock_request.call_count, 2)
1555-
self.assertTrue(retry_after_in_sec-1 <= mock_sleep.call_args[0][0] <= retry_after_in_sec)
1555+
self.assertTrue(retry_after_in_sec - 2 <= mock_sleep.call_args[0][0] <= retry_after_in_sec)
15561556
15571557
@patch('asyncio.sleep')
15581558
@patch.object(rest.RESTClientObject, "request")

config/clients/python/template/test/client/client_test.py.mustache

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,12 +2031,6 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
20312031
Check whether a user is authorized to access an object
20322032
"""
20332033

2034-
# First, mock the response
2035-
mock_request.side_effect = [
2036-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2037-
mock_response('{"allowed": false, "resolution": "1234"}', 200),
2038-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2039-
]
20402034
body1 = ClientCheckRequest(
20412035
object="document:2021-budget",
20422036
relation="reader",
@@ -2052,6 +2046,20 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
20522046
relation="reader",
20532047
user="user:81684243-9356-4421-8fbf-a4f8d36aa31d",
20542048
)
2049+
2050+
# Mock the response based on request body to avoid race conditions
2051+
def mock_side_effect(*args, **kwargs):
2052+
body = kwargs.get("body", {})
2053+
user = body.get("tuple_key", {}).get("user", "")
2054+
if user == "user:81684243-9356-4421-8fbf-a4f8d36aa31b":
2055+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2056+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31c":
2057+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2058+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31d":
2059+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2060+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2061+
2062+
mock_request.side_effect = mock_side_effect
20552063
configuration = self.configuration
20562064
configuration.store_id = store_id
20572065
async with OpenFgaClient(configuration) as api_client:
@@ -2140,12 +2148,6 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
21402148
}
21412149
"""
21422150

2143-
# First, mock the response
2144-
mock_request.side_effect = [
2145-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2146-
ValidationException(http_resp=http_mock_response(response_body, 400)),
2147-
mock_response('{"allowed": false, "resolution": "1234"}', 200),
2148-
]
21492151
body1 = ClientCheckRequest(
21502152
object="document:2021-budget",
21512153
relation="reader",
@@ -2161,6 +2163,20 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
21612163
relation="reader",
21622164
user="user:81684243-9356-4421-8fbf-a4f8d36aa31d",
21632165
)
2166+
2167+
# Mock the response based on request body to avoid race conditions
2168+
def mock_side_effect(*args, **kwargs):
2169+
body = kwargs.get("body", {})
2170+
user = body.get("tuple_key", {}).get("user", "")
2171+
if user == "user:81684243-9356-4421-8fbf-a4f8d36aa31b":
2172+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2173+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31c":
2174+
raise ValidationException(http_resp=http_mock_response(response_body, 400))
2175+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31d":
2176+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2177+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2178+
2179+
mock_request.side_effect = mock_side_effect
21642180
configuration = self.configuration
21652181
configuration.store_id = store_id
21662182
async with OpenFgaClient(configuration) as api_client:

config/clients/python/template/test/sync/api_test.py.mustache

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,13 +1578,13 @@ class TestOpenFgaApiSync(IsolatedAsyncioTestCase):
15781578
"message": "Rate Limit exceeded"
15791579
}
15801580
"""
1581-
retry_after_in_sec = 5
1582-
five_seconds_from_now = (datetime.now(timezone.utc) + timedelta(seconds=retry_after_in_sec)).strftime(
1581+
retry_after_in_sec = 10
1582+
ten_seconds_from_now = (datetime.now(timezone.utc) + timedelta(seconds=retry_after_in_sec)).strftime(
15831583
'%a, %d %b %Y %H:%M:%S GMT')
15841584
mock_http_response = http_mock_response(
15851585
body=error_response_body,
15861586
status=429,
1587-
headers={"Retry-After": five_seconds_from_now}
1587+
headers={"Retry-After": ten_seconds_from_now}
15881588
)
15891589
mock_request.side_effect = [
15901590
RateLimitExceededError(
@@ -1596,7 +1596,7 @@ class TestOpenFgaApiSync(IsolatedAsyncioTestCase):
15961596
retry = {{packageName}}.configuration.RetryParams(
15971597
max_retry=1,
15981598
min_wait_in_ms=10,
1599-
max_wait_in_sec=1
1599+
max_wait_in_sec=15
16001600
)
16011601
configuration = self.configuration
16021602
configuration.store_id = store_id
@@ -1617,7 +1617,11 @@ class TestOpenFgaApiSync(IsolatedAsyncioTestCase):
16171617
self.assertTrue(api_response.allowed)
16181618
mock_request.assert_called()
16191619
self.assertEqual(mock_request.call_count, 2)
1620-
self.assertEqual(mock_sleep.call_args[0][0], retry_after_in_sec)
1620+
self.assertTrue(
1621+
retry_after_in_sec - 2
1622+
<= mock_sleep.call_args[0][0]
1623+
<= retry_after_in_sec
1624+
)
16211625
16221626
@patch('time.sleep')
16231627
@patch.object(rest.RESTClientObject, "request")

config/clients/python/template/test/sync/client/client_test.py.mustache

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,12 +2034,6 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
20342034
Check whether a user is authorized to access an object
20352035
"""
20362036

2037-
# First, mock the response
2038-
mock_request.side_effect = [
2039-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2040-
mock_response('{"allowed": false, "resolution": "1234"}', 200),
2041-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2042-
]
20432037
body1 = ClientCheckRequest(
20442038
object="document:2021-budget",
20452039
relation="reader",
@@ -2055,6 +2049,20 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
20552049
relation="reader",
20562050
user="user:81684243-9356-4421-8fbf-a4f8d36aa31d",
20572051
)
2052+
2053+
# Mock the response based on request body to avoid race conditions
2054+
def mock_side_effect(*args, **kwargs):
2055+
body = kwargs.get("body", {})
2056+
user = body.get("tuple_key", {}).get("user", "")
2057+
if user == "user:81684243-9356-4421-8fbf-a4f8d36aa31b":
2058+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2059+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31c":
2060+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2061+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31d":
2062+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2063+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2064+
2065+
mock_request.side_effect = mock_side_effect
20582066
configuration = self.configuration
20592067
configuration.store_id = store_id
20602068
with OpenFgaClient(configuration) as api_client:
@@ -2143,12 +2151,6 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
21432151
}
21442152
"""
21452153

2146-
# First, mock the response
2147-
mock_request.side_effect = [
2148-
mock_response('{"allowed": true, "resolution": "1234"}', 200),
2149-
ValidationException(http_resp=http_mock_response(response_body, 400)),
2150-
mock_response('{"allowed": false, "resolution": "1234"}', 200),
2151-
]
21522154
body1 = ClientCheckRequest(
21532155
object="document:2021-budget",
21542156
relation="reader",
@@ -2164,6 +2166,20 @@ class TestOpenFgaClient(IsolatedAsyncioTestCase):
21642166
relation="reader",
21652167
user="user:81684243-9356-4421-8fbf-a4f8d36aa31d",
21662168
)
2169+
2170+
# Mock the response based on request body to avoid race conditions
2171+
def mock_side_effect(*args, **kwargs):
2172+
body = kwargs.get("body", {})
2173+
user = body.get("tuple_key", {}).get("user", "")
2174+
if user == "user:81684243-9356-4421-8fbf-a4f8d36aa31b":
2175+
return mock_response('{"allowed": true, "resolution": "1234"}', 200)
2176+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31c":
2177+
raise ValidationException(http_resp=http_mock_response(response_body, 400))
2178+
elif user == "user:81684243-9356-4421-8fbf-a4f8d36aa31d":
2179+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2180+
return mock_response('{"allowed": false, "resolution": "1234"}', 200)
2181+
2182+
mock_request.side_effect = mock_side_effect
21672183
configuration = self.configuration
21682184
configuration.store_id = store_id
21692185
with OpenFgaClient(configuration) as api_client:

0 commit comments

Comments
 (0)