Skip to content

Commit 9488fe7

Browse files
committed
Handle flaky tests a bit better:
Properly close tasks related to each test before ending tests: - Properly cancel and close all tasks for persistent connection provider tests - Clear caches as a cleanup for all persistent connection provider tests Increase dev period to allow `replace_transaction` tests more time: - Re-running these tests with flaky does not help, hey will end up failing every try. Increase the dev period to allow `replace_transaction` tests more time and remove the flaky decorator. - Lower request timeout for tests. No test should need more than 10s.
1 parent ee1d904 commit 9488fe7

File tree

8 files changed

+47
-46
lines changed

8 files changed

+47
-46
lines changed

tests/integration/go_ethereum/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def base_geth_command_arguments(geth_binary, datadir):
9494
datadir,
9595
"--dev",
9696
"--dev.period",
97-
"1",
97+
"2",
9898
"--password",
9999
os.path.join(datadir, "keystore", "pw.txt"),
100100
)

tests/integration/go_ethereum/test_goethereum_http.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import pytest
22

3+
from aiohttp import (
4+
ClientTimeout,
5+
)
36
import pytest_asyncio
47

58
from tests.utils import (
@@ -70,7 +73,7 @@ def geth_command_arguments(rpc_port, base_geth_command_arguments, get_geth_versi
7073
@pytest.fixture(scope="module")
7174
def w3(geth_process, endpoint_uri):
7275
wait_for_http(endpoint_uri)
73-
return Web3(Web3.HTTPProvider(endpoint_uri))
76+
return Web3(Web3.HTTPProvider(endpoint_uri, request_kwargs={"timeout": 10}))
7477

7578

7679
class TestGoEthereumWeb3ModuleTest(GoEthereumWeb3ModuleTest):
@@ -119,7 +122,9 @@ class TestGoEthereumTxPoolModuleTest(GoEthereumTxPoolModuleTest):
119122
@pytest_asyncio.fixture(scope="module")
120123
async def async_w3(geth_process, endpoint_uri):
121124
await wait_for_aiohttp(endpoint_uri)
122-
_w3 = AsyncWeb3(AsyncHTTPProvider(endpoint_uri))
125+
_w3 = AsyncWeb3(
126+
AsyncHTTPProvider(endpoint_uri, request_kwargs={"timeout": ClientTimeout(10)})
127+
)
123128
return _w3
124129

125130

tests/integration/go_ethereum/test_goethereum_ipc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def geth_ipc_path(datadir):
5656
@pytest.fixture(scope="module")
5757
def w3(geth_process, geth_ipc_path):
5858
wait_for_socket(geth_ipc_path)
59-
return Web3(Web3.IPCProvider(geth_ipc_path, timeout=30))
59+
return Web3(Web3.IPCProvider(geth_ipc_path, timeout=10))
6060

6161

6262
class TestGoEthereumWeb3ModuleTest(GoEthereumWeb3ModuleTest):
@@ -101,7 +101,7 @@ def test_admin_start_stop_ws(self, w3: "Web3") -> None:
101101
@pytest_asyncio.fixture(scope="module")
102102
async def async_w3(geth_process, geth_ipc_path):
103103
await wait_for_async_socket(geth_ipc_path)
104-
async with AsyncWeb3(AsyncIPCProvider(geth_ipc_path)) as _aw3:
104+
async with AsyncWeb3(AsyncIPCProvider(geth_ipc_path, request_timeout=10)) as _aw3:
105105
yield _aw3
106106

107107

tests/integration/go_ethereum/test_goethereum_ws/test_async_await_w3.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
@pytest_asyncio.fixture(scope="module")
2828
async def async_w3(geth_process, endpoint_uri):
2929
await wait_for_aiohttp(endpoint_uri)
30-
3130
# await the persistent connection itself
32-
return await AsyncWeb3(WebSocketProvider(endpoint_uri))
31+
return await AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10))
3332

3433

3534
class TestGoEthereumAsyncWeb3ModuleTest(GoEthereumAsyncWeb3ModuleTest):

tests/integration/go_ethereum/test_goethereum_ws/test_async_ctx_manager_w3.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
@pytest_asyncio.fixture(scope="module")
2828
async def async_w3(geth_process, endpoint_uri):
2929
await wait_for_aiohttp(endpoint_uri)
30-
3130
# async context manager pattern
32-
async with AsyncWeb3(WebSocketProvider(endpoint_uri)) as w3:
31+
async with AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10)) as w3:
3332
yield w3
3433

3534

tests/integration/go_ethereum/test_goethereum_ws/test_async_iterator_w3.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
@pytest_asyncio.fixture(scope="module")
2828
async def async_w3(geth_process, endpoint_uri):
2929
await wait_for_aiohttp(endpoint_uri)
30-
3130
# async iterator pattern
32-
async for w3 in AsyncWeb3(WebSocketProvider(endpoint_uri)):
31+
async for w3 in AsyncWeb3(WebSocketProvider(endpoint_uri, request_timeout=10)):
3332
return w3
3433

3534

web3/_utils/module_testing/eth_module.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
assert_contains_log,
5959
async_mock_offchain_lookup_request_response,
6060
flaky_geth_dev_mining,
61-
flaky_with_xfail_on_exception,
6261
mock_offchain_lookup_request_response,
6362
)
6463
from web3._utils.module_testing.utils import (
@@ -77,7 +76,6 @@
7776
MultipleFailedRequests,
7877
NameNotFound,
7978
OffchainLookup,
80-
RequestTimedOut,
8179
TimeExhausted,
8280
TooManyRequests,
8381
TransactionNotFound,
@@ -2390,10 +2388,6 @@ async def test_async_eth_replace_transaction_gas_price_too_low(
23902388
with pytest.raises(Web3ValueError):
23912389
await async_w3.eth.replace_transaction(txn_hash, txn_params)
23922390

2393-
@flaky_with_xfail_on_exception(
2394-
reason="Very flaky on CI runs, hard to reproduce locally.",
2395-
exception=RequestTimedOut,
2396-
)
23972391
@pytest.mark.asyncio
23982392
async def test_async_eth_replace_transaction_gas_price_defaulting_minimum(
23992393
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -2417,10 +2411,6 @@ async def test_async_eth_replace_transaction_gas_price_defaulting_minimum(
24172411
gas_price * 1.125
24182412
) # minimum gas price
24192413

2420-
@flaky_with_xfail_on_exception(
2421-
reason="Very flaky on CI runs, hard to reproduce locally.",
2422-
exception=RequestTimedOut,
2423-
)
24242414
@pytest.mark.asyncio
24252415
async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_higher(
24262416
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
@@ -2436,7 +2426,7 @@ async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_highe
24362426

24372427
two_gwei_in_wei = async_w3.to_wei(2, "gwei")
24382428

2439-
def higher_gas_price_strategy(async_w3: "AsyncWeb3", txn: TxParams) -> Wei:
2429+
def higher_gas_price_strategy(_async_w3: "AsyncWeb3", _txn: TxParams) -> Wei:
24402430
return two_gwei_in_wei
24412431

24422432
async_w3.eth.set_gas_price_strategy(higher_gas_price_strategy)
@@ -2449,16 +2439,11 @@ def higher_gas_price_strategy(async_w3: "AsyncWeb3", txn: TxParams) -> Wei:
24492439
) # Strategy provides higher gas price
24502440
async_w3.eth.set_gas_price_strategy(None) # reset strategy
24512441

2452-
@flaky_with_xfail_on_exception(
2453-
reason="Very flaky on CI runs, hard to reproduce locally.",
2454-
exception=RequestTimedOut,
2455-
)
24562442
@pytest.mark.asyncio
24572443
async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_lower(
24582444
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
24592445
) -> None:
24602446
gas_price = async_w3.to_wei(2, "gwei")
2461-
24622447
txn_params: TxParams = {
24632448
"from": async_keyfile_account_address,
24642449
"to": async_keyfile_account_address,

web3/_utils/module_testing/persistent_connection_provider.py

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
TYPE_CHECKING,
88
Any,
99
Dict,
10+
Generator,
1011
List,
1112
Tuple,
1213
Union,
@@ -174,7 +175,7 @@ async def emit_contract_event(
174175
acct: ChecksumAddress,
175176
contract_function: "AsyncContractFunction",
176177
args: Any = (),
177-
delay: float = 0.1,
178+
delay: float = 0.25,
178179
) -> None:
179180
await asyncio.sleep(delay)
180181
tx_hash = await contract_function(*args).transact({"from": acct})
@@ -213,7 +214,21 @@ def assert_no_subscriptions_left(sub_container: "SubscriptionContainer") -> None
213214
assert len(sub_container.handler_subscriptions) == 0
214215

215216

217+
async def clean_up_task(task: "asyncio.Task[Any]") -> None:
218+
task.cancel()
219+
try:
220+
await task
221+
except asyncio.CancelledError:
222+
pass
223+
224+
216225
class PersistentConnectionProviderTest:
226+
@pytest.fixture(autouse=True)
227+
def clear_caches(self, async_w3: AsyncWeb3) -> Generator[None, None, None]:
228+
yield
229+
async_w3.provider._request_processor.clear_caches()
230+
async_w3.subscription_manager.total_handler_calls = 0
231+
217232
@staticmethod
218233
async def seed_transactions_to_geth(
219234
async_w3: AsyncWeb3,
@@ -318,9 +333,6 @@ async def test_async_eth_subscribe_syncing_mocked(
318333
async_w3.subscription_manager._subscription_container
319334
)
320335

321-
# cleanup
322-
async_w3.provider._request_processor.clear_caches()
323-
324336
@pytest.mark.asyncio
325337
async def test_async_eth_subscribe_new_heads(self, async_w3: AsyncWeb3) -> None:
326338
sub_id = await async_w3.eth.subscribe("newHeads")
@@ -365,11 +377,8 @@ async def test_async_eth_subscribe_creates_and_handles_new_heads_subscription_ty
365377
assert sub_manager.total_handler_calls == 1
366378
assert sub.handler_call_count == 1
367379

368-
# cleanup
369-
sub_manager.total_handler_calls = 0
370-
371380
@pytest.mark.asyncio
372-
async def test_async_eth_subscribe_new_and_process_pending_tx_true(
381+
async def test_async_eth_subscribe_process_pending_tx_true(
373382
self,
374383
async_w3: AsyncWeb3,
375384
) -> None:
@@ -409,7 +418,7 @@ async def test_async_eth_subscribe_new_and_process_pending_tx_true(
409418
)
410419
async_w3.provider._request_processor.clear_caches()
411420
await async_w3.eth.wait_for_transaction_receipt(tx_hash)
412-
tx_seeder_task.cancel()
421+
await clean_up_task(tx_seeder_task)
413422

414423
@pytest.mark.asyncio
415424
async def test_async_eth_subscribe_and_process_pending_tx_false(
@@ -446,7 +455,7 @@ async def test_async_eth_subscribe_and_process_pending_tx_false(
446455
async_w3.subscription_manager._subscription_container
447456
)
448457
await async_w3.eth.wait_for_transaction_receipt(tx_hash)
449-
tx_seeder_task.cancel()
458+
await clean_up_task(tx_seeder_task)
450459

451460
@pytest.mark.asyncio
452461
async def test_async_eth_subscribe_creates_and_handles_pending_tx_subscription_type(
@@ -472,9 +481,8 @@ async def test_async_eth_subscribe_creates_and_handles_pending_tx_subscription_t
472481
accts = await async_w3.eth.accounts
473482
acct = accts[0]
474483
tx_seeder_task = asyncio.create_task(
475-
self.seed_transactions_to_geth(async_w3, acct, num_txs=1, delay=0.5)
484+
self.seed_transactions_to_geth(async_w3, acct)
476485
)
477-
478486
await sub_manager.handle_subscriptions()
479487

480488
assert pending_tx_handler_test.passed
@@ -485,7 +493,7 @@ async def test_async_eth_subscribe_creates_and_handles_pending_tx_subscription_t
485493

486494
# cleanup
487495
sub_manager.total_handler_calls = 0
488-
tx_seeder_task.cancel()
496+
await clean_up_task(tx_seeder_task)
489497

490498
@pytest.mark.asyncio
491499
async def test_async_eth_subscribe_and_process_logs(
@@ -523,7 +531,7 @@ async def test_async_eth_subscribe_and_process_logs(
523531

524532
assert await async_w3.eth.unsubscribe(sub_id)
525533
assert len(async_w3.subscription_manager.subscriptions) == 0
526-
emit_event_task.cancel()
534+
await clean_up_task(emit_event_task)
527535

528536
@pytest.mark.asyncio
529537
async def test_async_eth_subscribe_creates_and_handles_logs_subscription_type(
@@ -571,7 +579,7 @@ async def test_async_eth_subscribe_creates_and_handles_logs_subscription_type(
571579

572580
# cleanup
573581
sub_manager.total_handler_calls = 0
574-
emit_event_task.cancel()
582+
await clean_up_task(emit_event_task)
575583

576584
@pytest.mark.asyncio
577585
async def test_async_extradata_poa_middleware_on_eth_subscription(
@@ -731,7 +739,6 @@ async def test_async_subscription_manager_subscribes_to_many_subscriptions(
731739
subs = sub_manager.subscriptions
732740

733741
await sub_manager.handle_subscriptions()
734-
emit_event_task.cancel()
735742

736743
# assert unsubscribed and removed subscriptions
737744
assert len(sub_manager.subscriptions) == 0
@@ -745,6 +752,7 @@ async def test_async_subscription_manager_subscribes_to_many_subscriptions(
745752

746753
# cleanup
747754
sub_manager.total_handler_calls = 0
755+
await clean_up_task(emit_event_task)
748756

749757
@pytest.mark.asyncio
750758
async def test_subscription_handler_context(self, async_w3: AsyncWeb3) -> None:
@@ -764,9 +772,10 @@ async def test_sub_handler(
764772
assert handler_context.str2 == "bar"
765773

766774
handler_context.handler_test.passed = True
767-
await handler_context.subscription.unsubscribe()
775+
unsubscribed = await handler_context.subscription.unsubscribe()
776+
assert unsubscribed
768777

769-
await async_w3.eth.subscribe(
778+
subscribed = await async_w3.eth.subscribe(
770779
"newHeads",
771780
label="foo",
772781
handler=test_sub_handler,
@@ -779,6 +788,7 @@ async def test_sub_handler(
779788
"handler_test": handler_test,
780789
},
781790
)
791+
assert is_hexstr(subscribed)
782792

783793
sub_manager = async_w3.subscription_manager
784794

@@ -853,13 +863,17 @@ async def unsubscribe_subs(
853863
sub_manager = async_w3.subscription_manager
854864
sub1 = NewHeadsSubscription(label="foo", handler=idle_handler)
855865
sub2 = LogsSubscription(label="bar", handler=idle_handler)
866+
856867
await sub_manager.subscribe([sub1, sub2])
868+
857869
assert sub_manager.subscriptions == [sub1, sub2]
858870

859-
asyncio.create_task(unsubscribe_subs([sub1, sub2]))
871+
unsubscribe_task = asyncio.create_task(unsubscribe_subs([sub1, sub2]))
860872
# With no subscriptions in the queue, ``handle_subscriptions`` should hang
861873
# indefinitely. Test that when the last subscription is unsubscribed from,
862874
# the method breaks out of the loop. This is done via a raised
863875
# ``SubscriptionProcessingFinished`` within the ``TaskReliantQueue``.
864876
await sub_manager.handle_subscriptions()
877+
865878
assert_no_subscriptions_left(sub_manager._subscription_container)
879+
await clean_up_task(unsubscribe_task)

0 commit comments

Comments
 (0)