Skip to content

Commit 9f0f747

Browse files
authored
Merge pull request #3237 from darwintree/fix-coverage
Fix coverage
2 parents 2090dda + 46d40e1 commit 9f0f747

File tree

4 files changed

+63
-42
lines changed

4 files changed

+63
-42
lines changed

docs/coverage.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,18 @@ cargo nextest run --no-fail-fast -p cfx-addr --no-default-features
4646

4747
Run integration tests:
4848

49+
> It should be noted that we compile the binary in debug mode, so the performance is not good.
50+
> You might need to change parallel parameters if frequent io error or timeout error occurs.
51+
4952
```bash
5053
# Run integration tests
54+
# Change -n to control the number of tests running in parallel.
5155
pytest integration_tests/tests -vv -n 6 --dist loadscope --conflux-binary $(pwd)/target/debug/conflux
5256

5357
# Set up benchmark binary path before running `python tests/test_all.py`
54-
export CONFLUX_BENCH=$(pwd)/target/debug/consensus_bench
55-
# Run additional tests
58+
export CONFLUX_BENCH=$(pwd)/tools/consensus_bench/target/debug/consensus_bench
59+
# Run additional tests.
60+
# Use --max-workers and --max-nodes to control the number of workers and nodes.
5661
python tests/test_all.py --conflux-binary $(pwd)/target/debug/conflux
5762
```
5863

integration_tests/test_framework/util/adapter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def get_raw_tx_from_transaction(tx: Transaction) -> bytes:
142142
for tx in block.txs:
143143
raw_tx = get_raw_tx_from_transaction(tx)
144144
tx_hash = ew3.eth.send_raw_transaction(raw_tx)
145-
receipt = ew3.eth.wait_for_transaction_receipt(tx_hash, timeout=1, poll_latency=0.5)
145+
receipt = ew3.eth.wait_for_transaction_receipt(tx_hash, timeout=10, poll_latency=0.5)
146146

147147
elif tx:
148148
raw_tx = get_raw_tx_from_transaction(tx)
@@ -155,7 +155,7 @@ def get_raw_tx_from_transaction(tx: Transaction) -> bytes:
155155
assert tx.error.name.lower().replace("_", " ") in e.rpc_response["error"]["message"].lower()
156156
else:
157157
tx_hash = ew3.eth.send_raw_transaction(raw_tx)
158-
receipt = ew3.eth.wait_for_transaction_receipt(tx_hash, timeout=1, poll_latency=0.5)
158+
receipt = ew3.eth.wait_for_transaction_receipt(tx_hash, timeout=10, poll_latency=0.5)
159159
if receipt["status"] == 0:
160160
print(f"Transaction failed: {tx_hash.hex()}")
161161
print(f"TxErrorMsg: {receipt.get('txErrorMsg', 'No error message')}")

tests/test_all.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def run():
6767
parser.add_argument(
6868
"--max-nodes",
6969
dest="max_nodes",
70-
default=24,
70+
default=0,
7171
type=int,
7272
)
7373
parser.add_argument(
@@ -96,6 +96,10 @@ def run():
9696
"../target/release/conflux"),
9797
type=str)
9898
options = parser.parse_args()
99+
100+
if options.max_nodes == 0:
101+
options.max_nodes = os.cpu_count()
102+
print(f"Max nodes not specified, using {options.max_nodes} nodes")
99103

100104
all_failed = set()
101105

tests/test_utils/test_scheduler.py

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
import os
66
import tomllib
77
import time
8+
from typing import Callable
89

910
SPECIAL_SCRIPTS = {
1011
"ghast_consensus_test.py": 1
1112
}
1213

13-
def get_num_test_nodes(py, test_dir, script):
14+
def get_num_test_nodes(py: str, test_dir: str, script: str) -> int:
1415
if script in SPECIAL_SCRIPTS:
1516
return SPECIAL_SCRIPTS[script]
1617
toml_output = subprocess.check_output(
@@ -22,7 +23,15 @@ def get_num_test_nodes(py, test_dir, script):
2223
class TestScheduler:
2324
"""Scheduler for managing test execution and controlling concurrency based on resource requirements"""
2425

25-
def __init__(self, task_executable, py, test_dir, max_workers, available_nodes, port_min, port_max, conflux_binary):
26+
def __init__(self,
27+
task_executable: Callable[[str, str, str, int, int, int, str], None],
28+
py: str,
29+
test_dir: str,
30+
max_workers: int,
31+
available_nodes: int,
32+
port_min: int,
33+
port_max: int,
34+
conflux_binary: str):
2635
self.task_executable = task_executable
2736
self.py = py
2837
self.test_dir = test_dir
@@ -41,7 +50,7 @@ def __init__(self, task_executable, py, test_dir, max_workers, available_nodes,
4150
self.results = []
4251
self.failed_tests = set()
4352

44-
def schedule(self, test_scripts):
53+
def schedule(self, test_scripts: list[str]) -> set[str]:
4554
"""Schedules the execution of test scripts"""
4655

4756
# Prepare task queue
@@ -53,11 +62,11 @@ def schedule(self, test_scripts):
5362
self._collect_results()
5463
return self.failed_tests
5564

56-
def _prepare_task_queue(self, test_scripts):
65+
def _prepare_task_queue(self, test_scripts: list[str]) -> list[tuple[str, int, int]]:
5766
"""Prepares a task queue with scripts and resource requirements"""
5867

59-
task_queue = queue.Queue()
60-
print("Scanning num_nodes requirement for each task.", end = "")
68+
task_queue = []
69+
print("Scanning num_nodes requirement for each task")
6170
with ThreadPoolExecutor() as executor:
6271
tasks = [(executor.submit(
6372
get_num_test_nodes,
@@ -68,40 +77,43 @@ def _prepare_task_queue(self, test_scripts):
6877
# Collect completed task results and add them to the queue
6978
for future, i, script in tasks:
7079
result = future.result()
71-
task_queue.put((script, result, i))
72-
print(" Done")
80+
if result > self.available_nodes:
81+
raise RuntimeError(f"Cannot run {script} because it requires {result} nodes, "
82+
f"but only max to {self.available_nodes} nodes are available"
83+
f"Please specify --max-nodes to run the test")
84+
85+
task_queue.append((script, result, i))
86+
for script, nodes_needed, index in task_queue:
87+
print(f"Task {index}: {script} requires {nodes_needed} nodes")
88+
print("Scanning done")
7389
return task_queue
90+
91+
def _pop_next_task(self, task_queue: list[tuple[str, int, int]]) -> tuple[str, int, int]:
92+
"""Selects the next task to process"""
93+
if not task_queue:
94+
raise RuntimeError("No tasks to process")
95+
while True:
96+
for i, (script, nodes_needed, index) in enumerate(task_queue):
97+
if self._try_acquire_resources(nodes_needed):
98+
task_queue.pop(i)
99+
return script, nodes_needed, index
100+
self.resource_event.wait(timeout=10)
101+
self.resource_event.clear()
74102

75-
def _process_task_queue(self, executor, task_queue):
103+
def _process_task_queue(self, executor: ThreadPoolExecutor, task_queue: list[tuple[str, int, int]]):
76104
"""Processes the task queue, scheduling tests based on resource availability"""
77105

78-
while not task_queue.empty():
79-
try:
80-
# Retrieve task
81-
script, nodes_needed, index = task_queue.get(block=False)
82-
83-
# Attempt to allocate resources
84-
if self._try_acquire_resources(nodes_needed):
85-
# Enough resources available, execute test
86-
future = executor.submit(
87-
self._run_test_with_cleanup,
88-
script,
89-
index,
90-
nodes_needed
91-
)
92-
self.results.append((script, future))
93-
94-
# Wait for at least 1 second to avoid launch a lot of tasks
95-
time.sleep(1)
96-
else:
97-
# Insufficient resources, re-add to queue and wait
98-
task_queue.put((script, nodes_needed, index))
99-
self.resource_event.wait(timeout=0.2)
100-
self.resource_event.clear()
101-
except queue.Empty:
102-
break
106+
while task_queue:
107+
script, nodes_needed, index = self._pop_next_task(task_queue)
108+
future = executor.submit(
109+
self._run_test_with_cleanup,
110+
script,
111+
index,
112+
nodes_needed
113+
)
114+
self.results.append((script, future))
103115

104-
def _try_acquire_resources(self, nodes_needed):
116+
def _try_acquire_resources(self, nodes_needed: int) -> bool:
105117
"""Attempts to acquire required resources, returns True if successful"""
106118

107119
with self.resource_lock:
@@ -111,15 +123,15 @@ def _try_acquire_resources(self, nodes_needed):
111123
return True
112124
return False
113125

114-
def _release_resources(self, nodes_count):
126+
def _release_resources(self, nodes_count: int):
115127
"""Releases resources and notifies waiting threads"""
116128

117129
with self.resource_lock:
118130
self.available_nodes += nodes_count
119131
self.available_workers += 1
120132
self.resource_event.set()
121133

122-
def _run_test_with_cleanup(self, script, index, nodes_count):
134+
def _run_test_with_cleanup(self, script: str, index: int, nodes_count: int):
123135
"""Runs a test and ensures resources are released"""
124136

125137
try:

0 commit comments

Comments
 (0)