Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ lint: up
$(EXEC_CMD) pylint src tests --jobs=2
$(EXEC_CMD) mypy src

isort: up
$(EXEC_CMD) isort $(ORACLE_ISORT_PATH)

# Use ORACLE_TEST_PATH to run specific tests, e.g.:
# make test ORACLE_TEST_PATH=tests/providers_clients/test_keys_api_client.py
test: up
$(EXEC_CMD) pytest $(ORACLE_TEST_PATH)
$(EXEC_CMD) pytest $${ORACLE_TEST_PATH:-tests/}

# Use ORACLE_MODULE to run specific module, e.g.:
# make run-module ORACLE_MODULE=accounting
Expand Down
26 changes: 13 additions & 13 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 8 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ license = "GPL 3.0"
python = "^3.12"
prometheus-client = "0.21.1"
timeout-decorator = "^0.5.0"
pytest = "^7.2.1"
pytest-xdist = "^3.2.1"
pytest = "^8.3.5"
pytest-xdist = "^3.6.1"
more-itertools = "^10.1.0"
web3 = "^7.8.0"
web3-multi-provider = { version = "^2.2.0", extras = ["metrics"] }
Expand All @@ -46,7 +46,7 @@ black = "^24.8"
pylint = "^3.2.3"
mypy = "^1.10.0"
responses = "^0.25.7"
eth-tester = "^0.12.1b1"
eth-tester = "^0.13.0b1"
pre-commit = "3.8"
ipython = "^9.0"
isort = "^6.0.1"
Expand All @@ -57,12 +57,11 @@ build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
markers = [
"unit: tests with using mocks and don't make external requests",
"integration: tests with using providers",
"e2e: complex tests with using providers and real Ethereum network",
"fork: tests with using forked Ethereum network",
"mainnet: tests that depends on mainnet",
"testnet: tests that depends on testnet",
"unit: tests using mocks without external requests",
"integration: tests involving external providers",
"mainnet: integration tests reliant on the mainnet",
"testnet: integration tests reliant on the testnet",
"fork: integration tests using a forked Ethereum network",
]
addopts = "-s -vv --strict-markers"

Expand Down
24 changes: 18 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@
from src.web3py.extensions import (
CSM,
ConsensusClientModule,
FallbackProviderModule,
KeysAPIClientModule,
LidoContracts,
LidoValidatorsProvider,
TransactionUtils,
)
from src.web3py.types import Web3
from src.web3py.extensions import FallbackProviderModule

UNIT_MARKER = 'unit'
INTEGRATION_MARKER = 'integration'
MAINNET_MARKER = 'mainnet'
TESTNET_MARKER = 'testnet'
FORK_MARKER = 'fork'

INTEGRATION_TESTS_MODIFICATORS_MARKERS = {
MAINNET_MARKER,
TESTNET_MARKER,
FORK_MARKER,
}

DUMMY_ADDRESS = "0x0000000000000000000000000000000000000000"

Expand All @@ -40,14 +47,19 @@
def check_test_marks_compatibility(request):
all_test_markers = {x.name for x in request.node.iter_markers()}

if not all_test_markers:
pytest.fail('Test must be marked.')
if not all_test_markers or not {UNIT_MARKER, INTEGRATION_MARKER} & all_test_markers:
pytest.fail('Test must be marked with at least one marker, e.g. @pytest.mark.unit or @pytest.mark.integration.')

elif UNIT_MARKER in all_test_markers and {MAINNET_MARKER, TESTNET_MARKER, INTEGRATION_MARKER} & all_test_markers:
elif (
UNIT_MARKER in all_test_markers
and {INTEGRATION_MARKER}.union(INTEGRATION_TESTS_MODIFICATORS_MARKERS) & all_test_markers
):
pytest.fail('Test can not be both unit and integration at the same time.')

elif {MAINNET_MARKER, TESTNET_MARKER} & all_test_markers and INTEGRATION_MARKER not in all_test_markers:
pytest.fail('Test can not be run on mainnet or testnet without integration marker.')
elif INTEGRATION_TESTS_MODIFICATORS_MARKERS & all_test_markers and INTEGRATION_MARKER not in all_test_markers:
pytest.fail(
f'Test can not be run with {INTEGRATION_TESTS_MODIFICATORS_MARKERS} markers without @pytest.mark.integration.'
)


@pytest.fixture(autouse=True)
Expand Down
60 changes: 0 additions & 60 deletions tests/e2e/conftest.py

This file was deleted.

16 changes: 0 additions & 16 deletions tests/e2e/test_accounting.py

This file was deleted.

1 change: 1 addition & 0 deletions tests/fork/test_csm_oracle_cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def missed_initial_frame(frame_config: FrameConfig):


@pytest.mark.fork
@pytest.mark.integration
@pytest.mark.parametrize(
'module',
[csm_module],
Expand Down
1 change: 1 addition & 0 deletions tests/fork/test_lido_oracle_cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def missed_initial_frame(frame_config: FrameConfig):


@pytest.mark.fork
@pytest.mark.integration
@pytest.mark.parametrize(
'module',
[accounting_module, ejector_module],
Expand Down
Empty file added tests/main/__init__.py
Empty file.
53 changes: 53 additions & 0 deletions tests/main/test_main_cycle_smoke.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import logging
import logging.handlers
import multiprocessing
from concurrent.futures import ProcessPoolExecutor

import pytest

from src import variables
from src.main import main
from src.types import OracleModule


@pytest.mark.mainnet
@pytest.mark.integration
class TestIntegrationMainCycleSmoke:

def run_main_with_logging(self, module_name, log_queue):
queue_handler = logging.handlers.QueueHandler(log_queue)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.addHandler(queue_handler)

main(module_name)

@pytest.mark.parametrize(
"module_name",
[
"accounting",
"ejector",
"csm",
],
)
def test_main_cycle_smoke__oracle_module__cycle_runs_successfully(
self, monkeypatch, caplog, module_name: OracleModule
):
monkeypatch.setattr(variables, 'DAEMON', False)
monkeypatch.setattr(variables, 'CYCLE_SLEEP_IN_SECONDS', 0)
monkeypatch.setattr("src.web3py.extensions.CSM.CONTRACT_LOAD_MAX_RETRIES", 3)
monkeypatch.setattr("src.web3py.extensions.CSM.CONTRACT_LOAD_RETRY_DELAY", 0)

manager = multiprocessing.Manager()
log_queue = manager.Queue()
listener = logging.handlers.QueueListener(log_queue, caplog.handler)
listener.start()

with ProcessPoolExecutor(max_workers=1) as executor:
future = executor.submit(self.run_main_with_logging, module_name, log_queue)
future.result()

listener.stop()

error_logs = [record for record in caplog.records if record.levelno >= logging.ERROR]
assert not error_logs, f"Found error logs: {[record.message for record in error_logs]}"
1 change: 1 addition & 0 deletions tests/modules/csm/test_csm_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ class RewardsTreeTestParam:
expected_tree_values: list | Type[ValueError]


@pytest.mark.unit
@pytest.mark.parametrize(
"param",
[
Expand Down
1 change: 1 addition & 0 deletions tests/modules/submodules/consensus/test_consensus.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ class NoContractVersionConsensusImpl(ConsensusImpl):
CONSENSUS_VERSION = 1


@pytest.mark.unit
@pytest.mark.parametrize(
"impl",
[
Expand Down
Loading