Skip to content

Commit cffffb4

Browse files
committed
feat(consume): add initial implementation of consume enginex
1 parent 62455fc commit cffffb4

File tree

14 files changed

+714
-47
lines changed

14 files changed

+714
-47
lines changed

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ classifiers = [
2020
dependencies = [
2121
"click>=8.1.0,<9",
2222
"ethereum-execution==1.17.0rc6.dev1",
23-
"hive.py @ git+https://github.com/marioevz/hive.py",
23+
"hive-py",
2424
"ethereum-spec-evm-resolver",
2525
"gitpython>=3.1.31,<4",
2626
"PyJWT>=2.3.0,<3",
@@ -147,4 +147,5 @@ check-filenames = true
147147
ignore-words-list = "ingenuous"
148148

149149
[tool.uv.sources]
150-
ethereum-spec-evm-resolver = { git = "https://github.com/spencer-tb/ethereum-spec-evm-resolver", rev = "ee273e7344e24a739ebfbf0ea1f758530c4d032b" }
150+
ethereum-spec-evm-resolver = { git = "https://github.com/spencer-tb/ethereum-spec-evm-resolver", rev = "ee273e7344e24a739ebfbf0ea1f758530c4d032b" }
151+
hive-py = { git = "https://github.com/marioevz/hive.py", rev = "582703e2f94b4d5e61ae495d90d684852c87a580" }

src/cli/pytest_commands/consume.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
class ConsumeCommand(PytestCommand):
1414
"""Pytest command for consume operations."""
1515

16-
def __init__(self, command_paths: List[Path], is_hive: bool = False):
16+
def __init__(self, command_paths: List[Path], is_hive: bool = False, command_name: str = ""):
1717
"""Initialize consume command with paths and processors."""
1818
processors: List[ArgumentProcessor] = [HelpFlagsProcessor("consume")]
1919

2020
if is_hive:
2121
processors.extend(
2222
[
23-
HiveEnvironmentProcessor(),
23+
HiveEnvironmentProcessor(command_name),
2424
ConsumeCommandProcessor(is_hive=True),
2525
]
2626
)
@@ -49,18 +49,20 @@ def create_executions(self, pytest_args: List[str]) -> List[PytestExecution]:
4949
]
5050

5151

52-
def get_command_paths(command_name: str, is_hive: bool) -> List[Path]:
52+
def get_command_paths(command_name: str) -> List[Path]:
5353
"""Determine the command paths based on the command name and hive flag."""
5454
base_path = Path("src/pytest_plugins/consume")
5555
if command_name == "hive":
5656
commands = ["rlp", "engine"]
57+
command_paths = [base_path / "simulators" / cmd / f"test_via_{cmd}.py" for cmd in commands]
58+
elif command_name in ["engine", "engine-reorg", "engine_reorg"]:
59+
command_paths = [base_path / "simulators" / "hive_tests" / "test_via_engine.py"]
60+
elif command_name == "rlp":
61+
command_paths = [base_path / "simulators" / "hive_tests" / "test_via_rlp.py"]
62+
elif command_name == "direct":
63+
command_paths = [base_path / "direct" / "test_via_direct.py"]
5764
else:
58-
commands = [command_name]
59-
60-
command_paths = [
61-
base_path / ("simulators" if is_hive else "") / cmd / f"test_via_{cmd}.py"
62-
for cmd in commands
63-
]
65+
raise ValueError(f"Unexpected command: {command_name}.")
6466
return command_paths
6567

6668

@@ -76,7 +78,7 @@ def consume_command(is_hive: bool = False) -> Callable[[Callable[..., Any]], cli
7678
def decorator(func: Callable[..., Any]) -> click.Command:
7779
command_name = func.__name__
7880
command_help = func.__doc__
79-
command_paths = get_command_paths(command_name, is_hive)
81+
command_paths = get_command_paths(command_name)
8082

8183
@consume.command(
8284
name=command_name,
@@ -86,7 +88,7 @@ def decorator(func: Callable[..., Any]) -> click.Command:
8688
@common_pytest_options
8789
@functools.wraps(func)
8890
def command(pytest_args: List[str], **kwargs) -> None:
89-
consume_cmd = ConsumeCommand(command_paths, is_hive)
91+
consume_cmd = ConsumeCommand(command_paths, is_hive, command_name)
9092
consume_cmd.execute(list(pytest_args))
9193

9294
return command
@@ -112,17 +114,33 @@ def engine() -> None:
112114
pass
113115

114116

117+
@consume.command(
118+
name="engine-reorg",
119+
help="Client consumes via the Engine API with reorg fixtures.",
120+
context_settings={"ignore_unknown_options": True},
121+
)
122+
@common_pytest_options
123+
def engine_reorg(
124+
pytest_args: List[str], help_flag: bool = False, pytest_help_flag: bool = False
125+
) -> None:
126+
"""Client consumes via the Engine API with reorg fixtures."""
127+
command_name = "engine_reorg" # Use underscore for internal logic
128+
command_paths = get_command_paths(command_name)
129+
consume_cmd = ConsumeCommand(command_paths, is_hive=True, command_name=command_name)
130+
consume_cmd.execute(list(pytest_args))
131+
132+
115133
@consume_command(is_hive=True)
116134
def hive() -> None:
117-
"""Client consumes via all available hive methods (rlp, engine)."""
135+
"""Client consumes via rlp & engine hive methods."""
118136
pass
119137

120138

121139
@consume.command(
122140
context_settings={"ignore_unknown_options": True},
123141
)
124142
@common_pytest_options
125-
def cache(pytest_args: List[str], **kwargs) -> None:
143+
def cache(pytest_args: List[str], help_flag: bool = False, pytest_help_flag: bool = False) -> None:
126144
"""Consume command to cache test fixtures."""
127-
cache_cmd = ConsumeCommand([], is_hive=False)
145+
cache_cmd = ConsumeCommand([], is_hive=False, command_name="cache")
128146
cache_cmd.execute(list(pytest_args))

src/cli/pytest_commands/processors.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ def _is_writing_to_stdout(self, args: List[str]) -> bool:
7474
class HiveEnvironmentProcessor(ArgumentProcessor):
7575
"""Processes Hive environment variables for consume commands."""
7676

77+
def __init__(self, command_name: str = ""):
78+
"""
79+
Initialize the processor with command name to determine plugin.
80+
81+
Args:
82+
command_name: The command name to determine which plugin to load.
83+
84+
"""
85+
self.command_name = command_name
86+
7787
def process_args(self, args: List[str]) -> List[str]:
7888
"""Convert hive environment variables into pytest flags."""
7989
modified_args = args[:]
@@ -94,6 +104,14 @@ def process_args(self, args: List[str]) -> List[str]:
94104

95105
modified_args.extend(["-p", "pytest_plugins.pytest_hive.pytest_hive"])
96106

107+
if self.command_name == "engine":
108+
modified_args.extend(["-p", "pytest_plugins.consume.simulators.engine.conftest"])
109+
elif self.command_name == "engine_reorg":
110+
modified_args.extend(["-p", "pytest_plugins.consume.simulators.engine_reorg.conftest"])
111+
elif self.command_name == "rlp":
112+
modified_args.extend(["-p", "pytest_plugins.consume.simulators.rlp.conftest"])
113+
else:
114+
raise ValueError(f"Unknown command name: {self.command_name}")
97115
return modified_args
98116

99117
def _has_regex_or_sim_limit(self, args: List[str]) -> bool:

src/pytest_plugins/consume/consume.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ def pytest_generate_tests(metafunc):
426426
test_case,
427427
id=test_case.id,
428428
marks=[getattr(pytest.mark, m) for m in fork_markers]
429-
+ [getattr(pytest.mark, test_case.format.format_name)],
429+
+ [getattr(pytest.mark, test_case.format.format_name)]
430+
+ [pytest.mark.xdist_group(name=test_case.pre_hash)],
430431
)
431432
param_list.append(param)
432433

src/pytest_plugins/consume/simulators/engine/conftest.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
"""
2-
Pytest fixtures for the `consume engine` simulator.
3-
4-
Configures the hive back-end & EL clients for each individual test execution.
5-
"""
1+
"""Pytest plugin for the `consume engine` simulator."""
62

73
import io
84
from typing import Mapping
@@ -28,6 +24,18 @@ def pytest_configure(config):
2824
config._supported_fixture_formats = [BlockchainEngineFixture.format_name]
2925

3026

27+
@pytest.fixture(scope="module")
28+
def test_suite_name() -> str:
29+
"""The name of the hive test suite used in this simulator."""
30+
return "eest/consume-engine"
31+
32+
33+
@pytest.fixture(scope="module")
34+
def test_suite_description() -> str:
35+
"""The description of the hive test suite used in this simulator."""
36+
return "Execute blockchain tests against clients using the Engine API."
37+
38+
3139
@pytest.fixture(scope="function")
3240
def engine_rpc(client: Client, client_exception_mapper: ExceptionMapper | None) -> EngineRPC:
3341
"""Initialize engine RPC client for the execution client under test."""
@@ -41,18 +49,6 @@ def engine_rpc(client: Client, client_exception_mapper: ExceptionMapper | None)
4149
return EngineRPC(f"http://{client.ip}:8551")
4250

4351

44-
@pytest.fixture(scope="module")
45-
def test_suite_name() -> str:
46-
"""The name of the hive test suite used in this simulator."""
47-
return "eest/consume-engine"
48-
49-
50-
@pytest.fixture(scope="module")
51-
def test_suite_description() -> str:
52-
"""The description of the hive test suite used in this simulator."""
53-
return "Execute blockchain tests against clients using the Engine API."
54-
55-
5652
@pytest.fixture(scope="function")
5753
def client_files(buffered_genesis: io.BufferedReader) -> Mapping[str, io.BufferedReader]:
5854
"""Define the files that hive will start the client with."""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Consume Engine test functions."""
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Pytest fixtures for the `consume engine-reorg` simulator.
3+
4+
Configures the hive back-end & EL clients for test execution with BlockchainEngineReorgFixtures.
5+
"""
6+
7+
import pytest
8+
from hive.client import Client
9+
10+
from ethereum_test_exceptions import ExceptionMapper
11+
from ethereum_test_fixtures import BlockchainEngineReorgFixture
12+
from ethereum_test_rpc import EngineRPC
13+
14+
pytest_plugins = (
15+
"pytest_plugins.consume.simulators.base",
16+
"pytest_plugins.consume.simulators.multi_test_client",
17+
"pytest_plugins.consume.simulators.test_case_description",
18+
"pytest_plugins.consume.simulators.timing_data",
19+
"pytest_plugins.consume.simulators.exceptions",
20+
)
21+
22+
23+
def pytest_configure(config):
24+
"""Set the supported fixture formats for the engine simulator."""
25+
config._supported_fixture_formats = [BlockchainEngineReorgFixture.format_name]
26+
27+
28+
@pytest.fixture(scope="module")
29+
def test_suite_name() -> str:
30+
"""The name of the hive test suite used in this simulator."""
31+
return "eest/consume-engine-reorg"
32+
33+
34+
@pytest.fixture(scope="module")
35+
def test_suite_description() -> str:
36+
"""The description of the hive test suite used in this simulator."""
37+
return (
38+
"Execute blockchain tests against clients using the Engine API and shared clients "
39+
"using engine reorg fixtures."
40+
)
41+
42+
43+
@pytest.fixture(scope="function")
44+
def engine_rpc(client: Client, client_exception_mapper: ExceptionMapper | None) -> EngineRPC:
45+
"""Initialize engine RPC client for the execution client under test."""
46+
if client_exception_mapper:
47+
return EngineRPC(
48+
f"http://{client.ip}:8551",
49+
response_validation_context={
50+
"exception_mapper": client_exception_mapper,
51+
},
52+
)
53+
return EngineRPC(f"http://{client.ip}:8551")

0 commit comments

Comments
 (0)