Skip to content

Commit 526466f

Browse files
authored
Fixing flaky tests (#3833)
* Fixing flaky tests * Fixing flaky vset test. * Fixing test_execute_command_against_correct_db_on_background_health_check_determine_active_db_unhealthy * Fixing with patch + one more test * Fixing MSETEX tests - time set with pxat might be approximated to 1 sec higher than it was set as test expectation * Fix Monitor's next_command parsing for CLUSTER SHARDS command - issue catched by a flaky test behavior
1 parent bb7ae74 commit 526466f

File tree

7 files changed

+101
-102
lines changed

7 files changed

+101
-102
lines changed

redis/client.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -761,9 +761,14 @@ def next_command(self):
761761
client_port = client_info[5:]
762762
client_type = "unix"
763763
else:
764-
# use rsplit as ipv6 addresses contain colons
765-
client_address, client_port = client_info.rsplit(":", 1)
766-
client_type = "tcp"
764+
if client_info == "":
765+
client_address = ""
766+
client_port = ""
767+
client_type = "unknown"
768+
else:
769+
# use rsplit as ipv6 addresses contain colons
770+
client_address, client_port = client_info.rsplit(":", 1)
771+
client_type = "tcp"
767772
return {
768773
"time": float(command_time),
769774
"db": int(db_id),

tests/test_asyncio/test_commands.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ async def test_msetex_expiration_pxat_and_nx_with_cluster_client(self, r):
13211321
for ttl in old_ttls:
13221322
assert 10 < ttl <= 30
13231323
for ttl in new_ttls:
1324-
assert ttl <= 10
1324+
assert ttl <= 11
13251325
assert await r.mget(*mapping.keys(), "new:{test:1}", "new_2:{test:1}") == [
13261326
b"1",
13271327
b"2",
@@ -1370,8 +1370,8 @@ async def test_msetex_expiration_exat_and_xx_with_cluster_client(self, r):
13701370
== 1
13711371
)
13721372
ttls = await asyncio.gather(*[r.ttl(key) for key in mapping.keys()])
1373-
assert ttls[0] <= 10
1374-
assert ttls[1] <= 10
1373+
assert ttls[0] <= 11
1374+
assert ttls[1] <= 11
13751375
assert 10 < ttls[2] <= 30
13761376
assert await r.mget(
13771377
"1:{test:1}", "2:{test:1}", "3:{test:1}", "new:{test:1}"
@@ -1483,7 +1483,7 @@ async def test_msetex_expiration_pxat_and_nx(self, r):
14831483
for ttl in old_ttls:
14841484
assert 10 < ttl <= 30
14851485
for ttl in new_ttls:
1486-
assert ttl <= 10
1486+
assert ttl <= 11
14871487
assert await r.mget(*mapping.keys(), "new", "new_2") == [
14881488
b"1",
14891489
b"2",
@@ -1527,8 +1527,8 @@ async def test_msetex_expiration_exat_and_xx(self, r):
15271527
== 1
15281528
)
15291529
ttls = await asyncio.gather(*[r.ttl(key) for key in mapping.keys()])
1530-
assert ttls[0] <= 10
1531-
assert ttls[1] <= 10
1530+
assert ttls[0] <= 11
1531+
assert ttls[1] <= 11
15321532
assert 10 < ttls[2] <= 30
15331533
assert await r.mget("1", "2", "3", "new") == [
15341534
b"new_value",

tests/test_asyncio/test_multidb/test_client.py

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ async def test_execute_command_against_correct_db_on_successful_initialization(
3636
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
3737
mock_multi_db_config.health_checks = [mock_hc]
3838

39-
with (
40-
patch.object(mock_multi_db_config, "databases", return_value=databases),
41-
):
39+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
4240
mock_db1.client.execute_command = AsyncMock(return_value="OK1")
4341

4442
mock_hc.check_health.return_value = True
@@ -71,9 +69,7 @@ async def test_execute_command_against_correct_db_and_closed_circuit(
7169
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
7270
mock_multi_db_config.health_checks = [mock_hc]
7371

74-
with (
75-
patch.object(mock_multi_db_config, "databases", return_value=databases),
76-
):
72+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
7773
mock_db1.client.execute_command = AsyncMock(return_value="OK1")
7874

7975
mock_hc.check_health.side_effect = [
@@ -88,7 +84,8 @@ async def test_execute_command_against_correct_db_and_closed_circuit(
8884

8985
client = MultiDBClient(mock_multi_db_config)
9086
assert mock_multi_db_config.failover_strategy.set_databases.call_count == 1
91-
assert await client.set("key", "value") == "OK1"
87+
result = await client.set("key", "value")
88+
assert result == "OK1"
9289
assert mock_hc.check_health.call_count == 7
9390

9491
assert mock_db.circuit.state == CBState.CLOSED
@@ -185,9 +182,7 @@ async def mock_check_health(database):
185182
mock_hc.check_health.side_effect = mock_check_health
186183
mock_multi_db_config.health_checks = [mock_hc]
187184

188-
with (
189-
patch.object(mock_multi_db_config, "databases", return_value=databases),
190-
):
185+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
191186
mock_db.client.execute_command.return_value = "OK"
192187
mock_db1.client.execute_command.return_value = "OK1"
193188
mock_db2.client.execute_command.return_value = "OK2"
@@ -201,6 +196,7 @@ async def mock_check_health(database):
201196
assert await db1_became_unhealthy.wait(), (
202197
"Timeout waiting for mock_db1 to become unhealthy"
203198
)
199+
204200
await asyncio.sleep(0.01)
205201

206202
assert await client.set("key", "value") == "OK2"
@@ -209,7 +205,14 @@ async def mock_check_health(database):
209205
assert await db2_became_unhealthy.wait(), (
210206
"Timeout waiting for mock_db2 to become unhealthy"
211207
)
212-
await asyncio.sleep(0.01)
208+
209+
# Wait for circuit breaker state to actually reflect the unhealthy status
210+
# (instead of just sleeping)
211+
max_retries = 20
212+
for _ in range(max_retries):
213+
if cb2.state == CBState.OPEN: # Circuit is open (unhealthy)
214+
break
215+
await asyncio.sleep(0.01)
213216

214217
assert await client.set("key", "value") == "OK"
215218

@@ -258,9 +261,7 @@ async def mock_check_health(database):
258261
mock_hc.check_health.side_effect = mock_check_health
259262
mock_multi_db_config.health_checks = [mock_hc]
260263

261-
with (
262-
patch.object(mock_multi_db_config, "databases", return_value=databases),
263-
):
264+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
264265
mock_db.client.execute_command.return_value = "OK"
265266
mock_db1.client.execute_command.return_value = "OK1"
266267
mock_db2.client.execute_command.return_value = "OK2"
@@ -271,6 +272,14 @@ async def mock_check_health(database):
271272
async with MultiDBClient(mock_multi_db_config) as client:
272273
assert await client.set("key", "value") == "OK1"
273274
await error_event.wait()
275+
# Wait for circuit breaker to actually open (not just the event)
276+
max_retries = 20
277+
for _ in range(max_retries):
278+
if mock_db1.circuit.state == CBState.OPEN: # Circuit is open
279+
break
280+
await asyncio.sleep(0.01)
281+
282+
# Now the failover strategy will select mock_db2
274283
assert await client.set("key", "value") == "OK2"
275284
await asyncio.sleep(0.5)
276285
assert await client.set("key", "value") == "OK1"
@@ -312,9 +321,7 @@ async def mock_check_health(database):
312321
mock_hc.check_health.side_effect = mock_check_health
313322
mock_multi_db_config.health_checks = [mock_hc]
314323

315-
with (
316-
patch.object(mock_multi_db_config, "databases", return_value=databases),
317-
):
324+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
318325
mock_db.client.execute_command.return_value = "OK"
319326
mock_db1.client.execute_command.return_value = "OK1"
320327
mock_db2.client.execute_command.return_value = "OK2"
@@ -325,6 +332,15 @@ async def mock_check_health(database):
325332
async with MultiDBClient(mock_multi_db_config) as client:
326333
assert await client.set("key", "value") == "OK1"
327334
await error_event.wait()
335+
# Wait for circuit breaker state to actually reflect the unhealthy status
336+
# (instead of just sleeping)
337+
max_retries = 20
338+
for _ in range(max_retries):
339+
if (
340+
mock_db1.circuit.state == CBState.OPEN
341+
): # Circuit is open (unhealthy)
342+
break
343+
await asyncio.sleep(0.01)
328344
assert await client.set("key", "value") == "OK2"
329345
await asyncio.sleep(0.5)
330346
assert await client.set("key", "value") == "OK2"
@@ -348,9 +364,7 @@ async def test_execute_command_throws_exception_on_failed_initialization(
348364
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
349365
mock_multi_db_config.health_checks = [mock_hc]
350366

351-
with (
352-
patch.object(mock_multi_db_config, "databases", return_value=databases),
353-
):
367+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
354368
mock_hc.check_health.return_value = False
355369

356370
client = MultiDBClient(mock_multi_db_config)
@@ -382,9 +396,7 @@ async def test_add_database_throws_exception_on_same_database(
382396
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
383397
mock_multi_db_config.health_checks = [mock_hc]
384398

385-
with (
386-
patch.object(mock_multi_db_config, "databases", return_value=databases),
387-
):
399+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
388400
mock_hc.check_health.return_value = False
389401

390402
client = MultiDBClient(mock_multi_db_config)
@@ -413,9 +425,7 @@ async def test_add_database_makes_new_database_active(
413425
databases = create_weighted_list(mock_db, mock_db2)
414426
mock_multi_db_config.health_checks = [mock_hc]
415427

416-
with (
417-
patch.object(mock_multi_db_config, "databases", return_value=databases),
418-
):
428+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
419429
mock_db1.client.execute_command.return_value = "OK1"
420430
mock_db2.client.execute_command.return_value = "OK2"
421431

@@ -451,9 +461,7 @@ async def test_remove_highest_weighted_database(
451461
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
452462
mock_multi_db_config.health_checks = [mock_hc]
453463

454-
with (
455-
patch.object(mock_multi_db_config, "databases", return_value=databases),
456-
):
464+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
457465
mock_db1.client.execute_command.return_value = "OK1"
458466
mock_db2.client.execute_command.return_value = "OK2"
459467

@@ -487,9 +495,7 @@ async def test_update_database_weight_to_be_highest(
487495
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
488496
mock_multi_db_config.health_checks = [mock_hc]
489497

490-
with (
491-
patch.object(mock_multi_db_config, "databases", return_value=databases),
492-
):
498+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
493499
mock_db1.client.execute_command.return_value = "OK1"
494500
mock_db2.client.execute_command.return_value = "OK2"
495501

@@ -525,9 +531,7 @@ async def test_add_new_failure_detector(
525531
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
526532
mock_multi_db_config.health_checks = [mock_hc]
527533

528-
with (
529-
patch.object(mock_multi_db_config, "databases", return_value=databases),
530-
):
534+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
531535
mock_db1.client.execute_command.return_value = "OK1"
532536
mock_multi_db_config.event_dispatcher = EventDispatcher()
533537
mock_fd = mock_multi_db_config.failure_detectors[0]
@@ -546,7 +550,7 @@ async def test_add_new_failure_detector(
546550
assert mock_hc.check_health.call_count == 9
547551

548552
# Simulate failing command events that lead to a failure detection
549-
for i in range(5):
553+
for _ in range(5):
550554
await mock_multi_db_config.event_dispatcher.dispatch_async(
551555
command_fail_event
552556
)
@@ -557,7 +561,7 @@ async def test_add_new_failure_detector(
557561
client.add_failure_detector(another_fd)
558562

559563
# Simulate failing command events that lead to a failure detection
560-
for i in range(5):
564+
for _ in range(5):
561565
await mock_multi_db_config.event_dispatcher.dispatch_async(
562566
command_fail_event
563567
)
@@ -584,9 +588,7 @@ async def test_add_new_health_check(
584588
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
585589
mock_multi_db_config.health_checks = [mock_hc]
586590

587-
with (
588-
patch.object(mock_multi_db_config, "databases", return_value=databases),
589-
):
591+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
590592
mock_db1.client.execute_command.return_value = "OK1"
591593

592594
mock_hc.check_health.return_value = True
@@ -624,9 +626,7 @@ async def test_set_active_database(
624626
databases = create_weighted_list(mock_db, mock_db1, mock_db2)
625627
mock_multi_db_config.health_checks = [mock_hc]
626628

627-
with (
628-
patch.object(mock_multi_db_config, "databases", return_value=databases),
629-
):
629+
with patch.object(mock_multi_db_config, "databases", return_value=databases):
630630
mock_db1.client.execute_command.return_value = "OK1"
631631
mock_db.client.execute_command.return_value = "OK"
632632

tests/test_asyncio/test_vsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ async def test_vsim_truth_no_thread_enabled(d_client):
454454
elements_count = 5000
455455
vector_dim = 50
456456
for i in range(1, elements_count + 1):
457-
float_array = [random.uniform(10 * i, 1000 * i) for x in range(vector_dim)]
457+
float_array = [i for _ in range(vector_dim)]
458458
await d_client.vset().vadd("myset", float_array, f"elem_{i}")
459459

460460
await d_client.vset().vadd("myset", [-22 for _ in range(vector_dim)], "elem_man_2")

tests/test_commands.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,7 @@ def test_msetex_expiration_pxat_and_nx_with_cluster_client(self, r):
18961896
)
18971897
== 0
18981898
)
1899+
18991900
ttls = [r.ttl(key) for key in mapping.keys()]
19001901
for ttl in ttls:
19011902
assert 10 < ttl <= 30
@@ -1915,7 +1916,7 @@ def test_msetex_expiration_pxat_and_nx_with_cluster_client(self, r):
19151916
for ttl in old_ttls:
19161917
assert 10 < ttl <= 30
19171918
for ttl in new_ttls:
1918-
assert ttl <= 10
1919+
assert ttl <= 11
19191920
assert r.mget(*mapping.keys(), "new:{test:1}", "new_2:{test:1}") == [
19201921
b"1",
19211922
b"2",
@@ -1959,8 +1960,8 @@ def test_msetex_expiration_exat_and_xx_with_cluster_client(self, r):
19591960
== 1
19601961
)
19611962
ttls = [r.ttl(key) for key in mapping.keys()]
1962-
assert ttls[0] <= 10
1963-
assert ttls[1] <= 10
1963+
assert ttls[0] <= 11
1964+
assert ttls[1] <= 11
19641965
assert 10 < ttls[2] <= 30
19651966
assert r.mget("1:{test:1}", "2:{test:1}", "3:{test:1}", "new:{test:1}") == [
19661967
b"new_value",
@@ -2070,7 +2071,7 @@ def test_msetex_expiration_pxat_and_nx(self, r):
20702071
for ttl in old_ttls:
20712072
assert 10 < ttl <= 30
20722073
for ttl in new_ttls:
2073-
assert ttl <= 10
2074+
assert ttl <= 11
20742075
assert r.mget(*mapping.keys(), "new", "new_2") == [
20752076
b"1",
20762077
b"2",
@@ -2114,8 +2115,8 @@ def test_msetex_expiration_exat_and_xx(self, r):
21142115
== 1
21152116
)
21162117
ttls = [r.ttl(key) for key in mapping.keys()]
2117-
assert ttls[0] <= 10
2118-
assert ttls[1] <= 10
2118+
assert ttls[0] <= 11
2119+
assert ttls[1] <= 11
21192120
assert 10 < ttls[2] <= 30
21202121
assert r.mget("1", "2", "3", "new") == [
21212122
b"new_value",

0 commit comments

Comments
 (0)