genlayer-test 0.1.0b4__tar.gz → 0.1.0b6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/PKG-INFO +1 -1
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/PKG-INFO +1 -1
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/SOURCES.txt +3 -0
- genlayer_test-0.1.0b6/gltest/exceptions.py +20 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/glchain/__init__.py +2 -1
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/glchain/client.py +8 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/glchain/contract.py +37 -5
- genlayer_test-0.1.0b6/gltest/helpers/__init__.py +8 -0
- genlayer_test-0.1.0b6/gltest/helpers/fixture_snapshot.py +67 -0
- genlayer_test-0.1.0b6/gltest/helpers/take_snapshot.py +41 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/plugin_hooks.py +1 -1
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/pyproject.toml +1 -1
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/tests/test_plugin_hooks.py +1 -1
- genlayer_test-0.1.0b4/gltest/exceptions.py +0 -4
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/LICENSE +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/README.md +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/dependency_links.txt +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/entry_points.txt +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/requires.txt +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/genlayer_test.egg-info/top_level.txt +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/__init__.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/artifacts/__init__.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/artifacts/contract.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/assertions.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/glchain/account.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/plugin_config.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest/types.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/gltest_cli/main.py +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/setup.cfg +0 -0
- {genlayer_test-0.1.0b4 → genlayer_test-0.1.0b6}/tests/conftest.py +0 -0
@@ -19,6 +19,9 @@ gltest/glchain/__init__.py
|
|
19
19
|
gltest/glchain/account.py
|
20
20
|
gltest/glchain/client.py
|
21
21
|
gltest/glchain/contract.py
|
22
|
+
gltest/helpers/__init__.py
|
23
|
+
gltest/helpers/fixture_snapshot.py
|
24
|
+
gltest/helpers/take_snapshot.py
|
22
25
|
gltest_cli/main.py
|
23
26
|
tests/conftest.py
|
24
27
|
tests/test_plugin_hooks.py
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class DeploymentError(Exception):
|
2
|
+
"""Raised when a contract deployment fails."""
|
3
|
+
|
4
|
+
pass
|
5
|
+
class FixtureSnapshotError(Exception):
|
6
|
+
"""Raised when there's an error restoring a snapshot."""
|
7
|
+
pass
|
8
|
+
|
9
|
+
class FixtureAnonymousFunctionError(Exception):
|
10
|
+
"""Raised when a fixture is an anonymous function."""
|
11
|
+
pass
|
12
|
+
|
13
|
+
class InvalidSnapshotError(Exception):
|
14
|
+
"""Raised when a snapshot is invalid."""
|
15
|
+
pass
|
16
|
+
|
17
|
+
class HelperError(Exception):
|
18
|
+
"""Raised when a helper function fails."""
|
19
|
+
pass
|
20
|
+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from .contract import Contract, ContractFactory, get_contract_factory
|
2
|
-
from .client import get_gl_client
|
2
|
+
from .client import get_gl_client, get_gl_provider
|
3
3
|
from .account import create_accounts, create_account, accounts, default_account
|
4
4
|
|
5
5
|
|
@@ -12,4 +12,5 @@ __all__ = [
|
|
12
12
|
"accounts",
|
13
13
|
"create_accounts",
|
14
14
|
"get_gl_client",
|
15
|
+
"get_gl_provider",
|
15
16
|
]
|
@@ -13,3 +13,11 @@ def get_gl_client():
|
|
13
13
|
return create_client(
|
14
14
|
chain=localnet, account=default_account, endpoint=get_rpc_url()
|
15
15
|
)
|
16
|
+
|
17
|
+
|
18
|
+
def get_gl_provider():
|
19
|
+
"""
|
20
|
+
Get the GenLayer provider instance.
|
21
|
+
"""
|
22
|
+
client = get_gl_client()
|
23
|
+
return client.provider
|
@@ -1,10 +1,15 @@
|
|
1
|
+
from eth_typing import (
|
2
|
+
Address,
|
3
|
+
ChecksumAddress,
|
4
|
+
)
|
5
|
+
from eth_account.signers.local import LocalAccount
|
6
|
+
from typing import Union
|
1
7
|
from dataclasses import dataclass
|
2
8
|
from gltest.artifacts import find_contract_definition
|
3
9
|
from gltest.assertions import tx_execution_failed
|
4
10
|
from gltest.exceptions import DeploymentError
|
5
11
|
from .client import get_gl_client
|
6
12
|
from gltest.types import CalldataEncodable, GenLayerTransaction, TransactionStatus
|
7
|
-
from eth_account.signers.local import LocalAccount
|
8
13
|
from typing import List, Any, Type, Optional, Dict, Callable
|
9
14
|
import types
|
10
15
|
from gltest.plugin_config import get_default_wait_interval, get_default_wait_retries
|
@@ -89,14 +94,18 @@ class Contract:
|
|
89
94
|
consensus_max_rotations: Optional[int] = None,
|
90
95
|
leader_only: bool = False,
|
91
96
|
wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
|
92
|
-
wait_interval: int =
|
93
|
-
wait_retries: int =
|
97
|
+
wait_interval: Optional[int] = None,
|
98
|
+
wait_retries: Optional[int] = None,
|
94
99
|
wait_triggered_transactions: bool = True,
|
95
100
|
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
96
101
|
) -> GenLayerTransaction:
|
97
102
|
"""
|
98
103
|
Wrapper to the contract write method.
|
99
104
|
"""
|
105
|
+
if wait_interval is None:
|
106
|
+
wait_interval = get_default_wait_interval()
|
107
|
+
if wait_retries is None:
|
108
|
+
wait_retries = get_default_wait_retries()
|
100
109
|
client = get_gl_client()
|
101
110
|
tx_hash = client.write_contract(
|
102
111
|
address=self.address,
|
@@ -152,19 +161,42 @@ class ContractFactory:
|
|
152
161
|
contract_name=contract_name, contract_code=contract_info.contract_code
|
153
162
|
)
|
154
163
|
|
164
|
+
def build_contract(
|
165
|
+
self,
|
166
|
+
contract_address: Union[Address, ChecksumAddress],
|
167
|
+
account: Optional[LocalAccount] = None,
|
168
|
+
) -> Contract:
|
169
|
+
"""
|
170
|
+
Build contract from address
|
171
|
+
"""
|
172
|
+
client = get_gl_client()
|
173
|
+
try:
|
174
|
+
schema = client.get_contract_schema(address=contract_address)
|
175
|
+
return Contract.new(
|
176
|
+
address=contract_address, schema=schema, account=account
|
177
|
+
)
|
178
|
+
except Exception as e:
|
179
|
+
raise ValueError(
|
180
|
+
f"Failed to build contract {self.contract_name}: {str(e)}"
|
181
|
+
) from e
|
182
|
+
|
155
183
|
def deploy(
|
156
184
|
self,
|
157
185
|
args: List[Any] = [],
|
158
186
|
account: Optional[LocalAccount] = None,
|
159
187
|
consensus_max_rotations: Optional[int] = None,
|
160
188
|
leader_only: bool = False,
|
161
|
-
wait_interval: int =
|
162
|
-
wait_retries: int =
|
189
|
+
wait_interval: Optional[int] = None,
|
190
|
+
wait_retries: Optional[int] = None,
|
163
191
|
wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
|
164
192
|
) -> Contract:
|
165
193
|
"""
|
166
194
|
Deploy the contract
|
167
195
|
"""
|
196
|
+
if wait_interval is None:
|
197
|
+
wait_interval = get_default_wait_interval()
|
198
|
+
if wait_retries is None:
|
199
|
+
wait_retries = get_default_wait_retries()
|
168
200
|
client = get_gl_client()
|
169
201
|
try:
|
170
202
|
tx_hash = client.deploy_contract(
|
@@ -0,0 +1,67 @@
|
|
1
|
+
from typing import TypeVar, Callable, List, Any
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from .take_snapshot import SnapshotRestorer, take_snapshot
|
4
|
+
from gltest.exceptions import (
|
5
|
+
FixtureSnapshotError,
|
6
|
+
InvalidSnapshotError,
|
7
|
+
FixtureAnonymousFunctionError,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
T = TypeVar("T")
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class Snapshot:
|
16
|
+
"""Represents a snapshot of the blockchain state."""
|
17
|
+
|
18
|
+
restorer: SnapshotRestorer
|
19
|
+
fixture: Callable[[], Any]
|
20
|
+
data: Any
|
21
|
+
|
22
|
+
|
23
|
+
# Global storage for snapshots
|
24
|
+
_snapshots: List[Snapshot] = []
|
25
|
+
|
26
|
+
|
27
|
+
def load_fixture(fixture: Callable[[], T]) -> T:
|
28
|
+
"""
|
29
|
+
Useful in tests for setting up the desired state of the network.
|
30
|
+
"""
|
31
|
+
if fixture.__name__ == "<lambda>":
|
32
|
+
raise FixtureAnonymousFunctionError("Fixtures must be named functions")
|
33
|
+
|
34
|
+
# Find existing snapshot for this fixture
|
35
|
+
global _snapshots
|
36
|
+
snapshot = next((s for s in _snapshots if s.fixture == fixture), None)
|
37
|
+
|
38
|
+
if snapshot is not None:
|
39
|
+
try:
|
40
|
+
snapshot.restorer.restore()
|
41
|
+
# Remove snapshots that were taken after this one
|
42
|
+
|
43
|
+
_snapshots = [
|
44
|
+
s
|
45
|
+
for s in _snapshots
|
46
|
+
if int(s.restorer.snapshot_id) <= int(snapshot.restorer.snapshot_id)
|
47
|
+
]
|
48
|
+
except Exception as e:
|
49
|
+
if isinstance(e, InvalidSnapshotError):
|
50
|
+
raise FixtureSnapshotError(e) from e
|
51
|
+
raise e
|
52
|
+
|
53
|
+
return snapshot.data
|
54
|
+
else:
|
55
|
+
# Execute the fixture and take a snapshot
|
56
|
+
data = fixture()
|
57
|
+
restorer = take_snapshot()
|
58
|
+
|
59
|
+
_snapshots.append(Snapshot(restorer=restorer, fixture=fixture, data=data))
|
60
|
+
|
61
|
+
return data
|
62
|
+
|
63
|
+
|
64
|
+
def clear_snapshots() -> None:
|
65
|
+
"""Clears every existing snapshot."""
|
66
|
+
global _snapshots
|
67
|
+
_snapshots = []
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from gltest.glchain import get_gl_provider
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Callable
|
4
|
+
from gltest.exceptions import HelperError, InvalidSnapshotError
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass
|
8
|
+
class SnapshotRestorer:
|
9
|
+
"""Class responsible for restoring blockchain state to a snapshot."""
|
10
|
+
|
11
|
+
restore: Callable[[], None]
|
12
|
+
snapshot_id: int
|
13
|
+
|
14
|
+
|
15
|
+
def take_snapshot() -> SnapshotRestorer:
|
16
|
+
"""
|
17
|
+
Take a snapshot of the current blockchain state and return a function to restore the state and the snapshot ID.
|
18
|
+
"""
|
19
|
+
provider = get_gl_provider()
|
20
|
+
snapshot_id = provider.make_request(method="sim_createSnapshot", params=[])[
|
21
|
+
"result"
|
22
|
+
]
|
23
|
+
if not isinstance(snapshot_id, int):
|
24
|
+
raise HelperError(
|
25
|
+
"Assertion error: the value returned by evm_snapshot should be a int"
|
26
|
+
)
|
27
|
+
|
28
|
+
def restore() -> None:
|
29
|
+
reverted = provider.make_request(
|
30
|
+
method="sim_restoreSnapshot", params=[snapshot_id]
|
31
|
+
)["result"]
|
32
|
+
|
33
|
+
if not isinstance(reverted, bool):
|
34
|
+
raise HelperError(
|
35
|
+
"Assertion error: the value returned by evm_revert should be a boolean"
|
36
|
+
)
|
37
|
+
|
38
|
+
if not reverted:
|
39
|
+
raise InvalidSnapshotError("")
|
40
|
+
|
41
|
+
return SnapshotRestorer(restore=restore, snapshot_id=snapshot_id)
|
@@ -12,7 +12,7 @@ def test_help_message(pytester):
|
|
12
12
|
"*Default wait interval for waiting transaction receipts",
|
13
13
|
"*--default-wait-retries=DEFAULT_WAIT_RETRIES",
|
14
14
|
"*Default wait retries for waiting transaction receipts",
|
15
|
-
"*--rpc-url=RPC_URL*
|
15
|
+
"*--rpc-url=RPC_URL*RPC URL for the genlayer network",
|
16
16
|
]
|
17
17
|
)
|
18
18
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|