genlayer-test 0.4.1__tar.gz → 0.5.0__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.4.1 → genlayer_test-0.5.0}/PKG-INFO +257 -24
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/README.md +255 -22
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/PKG-INFO +257 -24
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/SOURCES.txt +13 -4
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/requires.txt +1 -1
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/__init__.py +7 -6
- genlayer_test-0.4.1/gltest/glchain/client.py → genlayer_test-0.5.0/gltest/clients.py +1 -1
- genlayer_test-0.5.0/gltest/contracts/__init__.py +4 -0
- genlayer_test-0.5.0/gltest/contracts/contract.py +205 -0
- genlayer_test-0.4.1/gltest/glchain/contract.py → genlayer_test-0.5.0/gltest/contracts/contract_factory.py +47 -144
- genlayer_test-0.5.0/gltest/contracts/contract_functions.py +62 -0
- genlayer_test-0.5.0/gltest/contracts/method_stats.py +163 -0
- genlayer_test-0.5.0/gltest/contracts/stats_collector.py +259 -0
- genlayer_test-0.5.0/gltest/contracts/utils.py +12 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/fixtures.py +2 -6
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/helpers/take_snapshot.py +1 -1
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/types.py +1 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/config/constants.py +2 -0
- genlayer_test-0.5.0/gltest_cli/config/plugin.py +187 -0
- genlayer_test-0.5.0/gltest_cli/config/pytest_context.py +9 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/config/types.py +73 -8
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/config/user.py +71 -28
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/logging.py +3 -2
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/pyproject.toml +2 -2
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/football_prediction_market.py +1 -1
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_football_prediction_market.py +2 -2
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_intelligent_oracle_factory.py +8 -24
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_llm_erc20.py +5 -5
- genlayer_test-0.5.0/tests/examples/tests/test_llm_erc20_analyze.py +50 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_log_indexer.py +23 -11
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_multi_file_contract.py +2 -2
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_multi_file_contract_legacy.py +2 -2
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_multi_read_erc20.py +14 -12
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_multi_tenant_storage.py +11 -7
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_read_erc20.py +1 -1
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_storage.py +4 -4
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_storage_legacy.py +5 -3
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_user_storage.py +20 -10
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/tests/test_wizard_of_coin.py +1 -1
- genlayer_test-0.5.0/tests/gltest_cli/config/test_config_integration.py +432 -0
- genlayer_test-0.5.0/tests/gltest_cli/config/test_general_config.py +406 -0
- genlayer_test-0.5.0/tests/gltest_cli/config/test_plugin.py +290 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest_cli/config/test_user.py +61 -1
- genlayer_test-0.4.1/gltest/glchain/__init__.py +0 -16
- genlayer_test-0.4.1/gltest_cli/config/plugin.py +0 -115
- genlayer_test-0.4.1/tests/gltest_cli/config/test_plugin.py +0 -127
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/LICENSE +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/dependency_links.txt +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/entry_points.txt +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/genlayer_test.egg-info/top_level.txt +0 -0
- /genlayer_test-0.4.1/gltest/glchain/account.py → /genlayer_test-0.5.0/gltest/accounts.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/artifacts/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/artifacts/contract.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/assertions.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/exceptions.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/helpers/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/helpers/fixture_snapshot.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest/logging.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/config/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/config/general.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/gltest_cli/main.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/setup.cfg +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/conftest.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/intelligent_oracle.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/intelligent_oracle_factory.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/llm_erc20.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/log_indexer.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/multi_file_contract/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/multi_file_contract/other.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/multi_read_erc20.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/multi_tenant_storage.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/read_erc20.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/storage.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/user_storage.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/examples/contracts/wizard_of_coin.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/artifact/__init__.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/artifact/contracts/not_ic_contract.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/artifact/test_contract_definition.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest/assertions/test_assertions.py +0 -0
- {genlayer_test-0.4.1 → genlayer_test-0.5.0}/tests/gltest_cli/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: genlayer-test
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: GenLayer Testing Suite
|
5
5
|
Author: GenLayer
|
6
6
|
License-Expression: MIT
|
@@ -15,7 +15,7 @@ Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
16
16
|
Requires-Dist: pytest
|
17
17
|
Requires-Dist: setuptools>=77.0
|
18
|
-
Requires-Dist: genlayer-py==0.
|
18
|
+
Requires-Dist: genlayer-py==0.7.2
|
19
19
|
Requires-Dist: colorama>=0.4.6
|
20
20
|
Requires-Dist: pyyaml
|
21
21
|
Requires-Dist: python-dotenv
|
@@ -59,8 +59,8 @@ contract = factory.deploy(account=other_account)
|
|
59
59
|
assert contract.account == other_account
|
60
60
|
|
61
61
|
# Interact with the contract
|
62
|
-
result = contract.get_value() # Read method
|
63
|
-
tx_receipt = contract.set_value(args=["new_value"]) # Write method
|
62
|
+
result = contract.get_value().call() # Read method
|
63
|
+
tx_receipt = contract.set_value(args=["new_value"]).transact() # Write method
|
64
64
|
|
65
65
|
assert tx_execution_succeeded(tx_receipt)
|
66
66
|
```
|
@@ -73,6 +73,15 @@ assert tx_execution_succeeded(tx_receipt)
|
|
73
73
|
- [Installation and Usage](#installation-and-usage)
|
74
74
|
- [Key Features](#-key-features)
|
75
75
|
- [Examples](#-examples)
|
76
|
+
- [Project Structure](#project-structure)
|
77
|
+
- [Storage Contract Example](#storage-contract-example)
|
78
|
+
- [Contract Deployment](#contract-deployment)
|
79
|
+
- [Read Methods](#read-methods)
|
80
|
+
- [Write Methods](#write-methods)
|
81
|
+
- [Assertions](#assertions)
|
82
|
+
- [Test Fixtures](#test-fixtures)
|
83
|
+
- [Statistical Analysis with `.analyze()`](#statistical-analysis-with-analyze)
|
84
|
+
- [Mock LLM Responses](#mock-llm-responses)
|
76
85
|
- [Best Practices](#-best-practices)
|
77
86
|
- [Troubleshooting](#-troubleshooting)
|
78
87
|
- [Contributing](#-contributing)
|
@@ -112,19 +121,33 @@ The GenLayer Testing Suite can be configured using an optional but recommended `
|
|
112
121
|
networks:
|
113
122
|
default: localnet # Default network to use
|
114
123
|
|
115
|
-
localnet: # Local development network configuration
|
124
|
+
localnet: # Local development network configuration (pre-configured)
|
116
125
|
url: "http://127.0.0.1:4000/api"
|
126
|
+
leader_only: false # Set to true to run all contracts in leader-only mode by default
|
117
127
|
|
118
|
-
|
119
|
-
|
120
|
-
|
128
|
+
studionet: # Studio network configuration (pre-configured)
|
129
|
+
# Pre-configured network - accounts are automatically generated
|
130
|
+
# You can override any settings if needed
|
131
|
+
|
132
|
+
testnet_asimov: # Test network configuration (pre-configured)
|
133
|
+
# Pre-configured network - requires accounts to be specified
|
121
134
|
accounts:
|
122
135
|
- "${ACCOUNT_PRIVATE_KEY_1}"
|
123
136
|
- "${ACCOUNT_PRIVATE_KEY_2}"
|
124
137
|
- "${ACCOUNT_PRIVATE_KEY_3}"
|
138
|
+
from: "${ACCOUNT_PRIVATE_KEY_2}" # Optional: specify default account
|
139
|
+
|
140
|
+
custom_network: # Custom network configuration
|
141
|
+
id: 1234
|
142
|
+
url: "http://custom.network:8545"
|
143
|
+
accounts:
|
144
|
+
- "${CUSTOM_ACCOUNT_1}"
|
145
|
+
- "${CUSTOM_ACCOUNT_2}"
|
146
|
+
from: "${CUSTOM_ACCOUNT_1}" # Optional: specify default account
|
125
147
|
|
126
148
|
paths:
|
127
149
|
contracts: "contracts" # Path to your contracts directory
|
150
|
+
artifacts: "artifacts" # Path to your artifacts directory
|
128
151
|
|
129
152
|
environment: .env # Path to your environment file containing private keys and other secrets
|
130
153
|
```
|
@@ -133,16 +156,35 @@ Key configuration sections:
|
|
133
156
|
|
134
157
|
1. **Networks**: Define different network environments
|
135
158
|
- `default`: Specifies which network to use by default
|
159
|
+
- **Pre-configured Networks**:
|
160
|
+
- `localnet`: Local development network with auto-generated test accounts
|
161
|
+
- `studionet`: GenLayer Studio network with auto-generated test accounts
|
162
|
+
- `testnet_asimov`: Public testnet (requires account configuration)
|
136
163
|
- Network configurations can include:
|
137
|
-
- `url`: The RPC endpoint for the network
|
138
|
-
- `id`: Chain ID
|
164
|
+
- `url`: The RPC endpoint for the network (optional for pre-configured networks)
|
165
|
+
- `id`: Chain ID (optional for pre-configured networks)
|
139
166
|
- `accounts`: List of account private keys (using environment variables)
|
140
|
-
|
141
|
-
-
|
142
|
-
|
167
|
+
- `from`: Specify which account to use as the default for transactions (optional, defaults to first account)
|
168
|
+
- `leader_only`: Leader only mode
|
169
|
+
- For custom networks (non-pre-configured), `id`, `url`, and `accounts` are required fields
|
170
|
+
|
171
|
+
**Note on Environment Variables**: When using environment variables in your configuration (e.g., `${ACCOUNT_PRIVATE_KEY_1}`), ensure they are properly set in your `environment` file. If an environment variable is not found, the system will raise a clear error message indicating which variable is missing.
|
172
|
+
|
173
|
+
**Default Account Selection**: The `from` field allows you to specify which account from the `accounts` list should be used as the default for deployments and transactions. If not specified, the first account in the list is used by default. This is useful when you want a specific account to be the primary account for your tests without having to specify it in every transaction.
|
174
|
+
|
175
|
+
Example:
|
176
|
+
```yaml
|
177
|
+
testnet_asimov:
|
178
|
+
accounts:
|
179
|
+
- "${DEPLOYER_KEY}" # accounts[0]
|
180
|
+
- "${USER_KEY}" # accounts[1]
|
181
|
+
- "${ADMIN_KEY}" # accounts[2]
|
182
|
+
from: "${ADMIN_KEY}" # Use ADMIN_KEY as default instead of DEPLOYER_KEY
|
183
|
+
```
|
143
184
|
|
144
185
|
2. **Paths**: Define important directory paths
|
145
186
|
- `contracts`: Location of your contract files
|
187
|
+
- `artifacts`: Location of your artifacts files (analysis results will be stored here)
|
146
188
|
|
147
189
|
3. **Environment**: Path to your `.env` file containing sensitive information like private keys
|
148
190
|
|
@@ -187,11 +229,23 @@ $ gltest --contracts-dir <path_to_contracts>
|
|
187
229
|
# Run tests on localnet (default)
|
188
230
|
$ gltest --network localnet
|
189
231
|
|
190
|
-
# Run tests on
|
232
|
+
# Run tests on studionet
|
233
|
+
$ gltest --network studionet
|
234
|
+
|
235
|
+
# Run tests on testnet (requires account configuration)
|
191
236
|
$ gltest --network testnet_asimov
|
237
|
+
|
238
|
+
# Run tests on a custom network
|
239
|
+
$ gltest --network custom_network
|
192
240
|
```
|
193
241
|
The `--network` flag allows you to specify which network configuration to use from your `gltest.config.yaml`. If not specified, it will use the `default` network defined in your config file.
|
194
242
|
|
243
|
+
**Pre-configured Networks**:
|
244
|
+
- `localnet` and `studionet`: Work out of the box with auto-generated test accounts
|
245
|
+
- `testnet_asimov`: Requires account configuration in `gltest.config.yaml`
|
246
|
+
|
247
|
+
When using `testnet_asimov` without proper account configuration, you'll receive a clear error message directing you to configure accounts in your config file.
|
248
|
+
|
195
249
|
7. Run tests with a custom RPC url
|
196
250
|
```bash
|
197
251
|
$ gltest --rpc-url <custom_rpc_url>
|
@@ -231,6 +285,20 @@ def test_with_mocked_llm(setup_validators):
|
|
231
285
|
|
232
286
|
Note: This feature is only available when running tests on localnet.
|
233
287
|
|
288
|
+
11. Run tests with leader-only mode enabled
|
289
|
+
```bash
|
290
|
+
$ gltest --leader-only
|
291
|
+
```
|
292
|
+
The `--leader-only` flag configures all contract deployments and write operations to run only on the leader node. This is useful for:
|
293
|
+
- Faster test execution by avoiding consensus
|
294
|
+
- Testing specific leader-only scenarios
|
295
|
+
- Development and debugging purposes
|
296
|
+
- Reducing computational overhead in test environments
|
297
|
+
|
298
|
+
When this flag is enabled, all contracts deployed and all write transactions will automatically use leader-only mode, regardless of individual method parameters.
|
299
|
+
|
300
|
+
**Note:** Leader-only mode is only available for studio-based networks (localhost, 127.0.0.1, *.genlayer.com, *.genlayerlabs.com). When enabled on other networks, it will have no effect and a warning will be logged.
|
301
|
+
|
234
302
|
## 🚀 Key Features
|
235
303
|
|
236
304
|
- **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
|
@@ -251,8 +319,9 @@ Before diving into the examples, let's understand the basic project structure:
|
|
251
319
|
genlayer-example/
|
252
320
|
├── contracts/ # Contract definitions
|
253
321
|
│ └── storage.py # Example storage contract
|
254
|
-
|
255
|
-
|
322
|
+
├── test/ # Test files
|
323
|
+
│ └── test_contract.py # Contract test cases
|
324
|
+
└── gltest.config.yaml # Configuration file
|
256
325
|
```
|
257
326
|
|
258
327
|
### Storage Contract Example
|
@@ -311,7 +380,6 @@ def test_deployment():
|
|
311
380
|
args=["initial_value"], # Constructor arguments
|
312
381
|
account=get_default_account(), # Account to deploy from
|
313
382
|
consensus_max_rotations=3, # Optional: max consensus rotations
|
314
|
-
leader_only=False, # Optional: whether to run only on leader
|
315
383
|
)
|
316
384
|
|
317
385
|
# Contract is now deployed and ready to use
|
@@ -320,7 +388,7 @@ def test_deployment():
|
|
320
388
|
|
321
389
|
### Read Methods
|
322
390
|
|
323
|
-
Reading from the contract
|
391
|
+
Reading from the contract requires calling `.call()` on the method:
|
324
392
|
|
325
393
|
```python
|
326
394
|
from gltest import get_contract_factory
|
@@ -332,7 +400,7 @@ def test_read_methods():
|
|
332
400
|
contract = factory.deploy()
|
333
401
|
|
334
402
|
# Call a read-only method
|
335
|
-
result = contract.
|
403
|
+
result = contract.get_storage(args=[]).call()
|
336
404
|
|
337
405
|
# Assert the result matches the initial value
|
338
406
|
assert result == "initial_value"
|
@@ -340,7 +408,7 @@ def test_read_methods():
|
|
340
408
|
|
341
409
|
### Write Methods
|
342
410
|
|
343
|
-
Writing to the contract requires transaction
|
411
|
+
Writing to the contract requires calling `.transact()` on the method. Method arguments are passed to the write method, while transaction parameters are passed to `.transact()`:
|
344
412
|
|
345
413
|
```python
|
346
414
|
from gltest import get_contract_factory
|
@@ -354,9 +422,9 @@ def test_write_methods():
|
|
354
422
|
# Call a write method with arguments
|
355
423
|
tx_receipt = contract.update_storage(
|
356
424
|
args=["new_value"], # Method arguments
|
425
|
+
).transact(
|
357
426
|
value=0, # Optional: amount of native currency to send
|
358
427
|
consensus_max_rotations=3, # Optional: max consensus rotations
|
359
|
-
leader_only=False, # Optional: whether to run only on leader
|
360
428
|
wait_interval=1, # Optional: seconds between status checks
|
361
429
|
wait_retries=10, # Optional: max number of retries
|
362
430
|
)
|
@@ -365,7 +433,7 @@ def test_write_methods():
|
|
365
433
|
assert tx_execution_succeeded(tx_receipt)
|
366
434
|
|
367
435
|
# Verify the value was updated
|
368
|
-
assert contract.get_storage() == "new_value"
|
436
|
+
assert contract.get_storage().call() == "new_value"
|
369
437
|
```
|
370
438
|
|
371
439
|
### Assertions
|
@@ -503,6 +571,172 @@ Fixtures help maintain clean, DRY test code by:
|
|
503
571
|
- Ensuring consistent test environments
|
504
572
|
- Managing resource cleanup automatically
|
505
573
|
- Providing appropriate scoping for performance
|
574
|
+
### Statistical Analysis with `.analyze()`
|
575
|
+
|
576
|
+
The GenLayer Testing Suite provides a powerful `.analyze()` method for write operations that performs statistical analysis through multiple simulation runs. This is particularly useful for testing LLM-based contracts where outputs may vary:
|
577
|
+
|
578
|
+
```python
|
579
|
+
from gltest import get_contract_factory
|
580
|
+
|
581
|
+
def test_analyze_method():
|
582
|
+
factory = get_contract_factory("LlmContract")
|
583
|
+
contract = factory.deploy()
|
584
|
+
|
585
|
+
# Analyze a write method's behavior across multiple runs
|
586
|
+
analysis = contract.process_with_llm(args=["input_data"]).analyze(
|
587
|
+
provider="openai", # LLM provider
|
588
|
+
model="gpt-4o", # Model to use
|
589
|
+
runs=100, # Number of simulation runs (default: 100)
|
590
|
+
config=None, # Optional: provider-specific config
|
591
|
+
plugin=None, # Optional: plugin name
|
592
|
+
plugin_config=None, # Optional: plugin configuration
|
593
|
+
)
|
594
|
+
|
595
|
+
# Access analysis results
|
596
|
+
print(f"Method: {analysis.method}")
|
597
|
+
print(f"Success rate: {analysis.success_rate:.2f}%")
|
598
|
+
print(f"Reliability score: {analysis.reliability_score:.2f}%")
|
599
|
+
print(f"Unique states: {analysis.unique_states}")
|
600
|
+
print(f"Execution time: {analysis.execution_time:.1f}s")
|
601
|
+
|
602
|
+
# The analysis returns a MethodStatsSummary object with:
|
603
|
+
# - method: The contract method name
|
604
|
+
# - args: Arguments passed to the method
|
605
|
+
# - total_runs: Total number of simulation runs
|
606
|
+
# - successful_runs: Number of successful executions
|
607
|
+
# - failed_runs: Number of failed executions
|
608
|
+
# - unique_states: Number of unique contract states observed
|
609
|
+
# - reliability_score: Percentage of runs with the most common state
|
610
|
+
# - execution_time: Total time for all simulations
|
611
|
+
```
|
612
|
+
|
613
|
+
The `.analyze()` method helps you:
|
614
|
+
- Test non-deterministic contract methods
|
615
|
+
- Measure consistency of LLM-based operations
|
616
|
+
- Identify edge cases and failure patterns
|
617
|
+
- Benchmark performance across multiple runs
|
618
|
+
|
619
|
+
### Mock LLM Responses
|
620
|
+
|
621
|
+
The Mock LLM system allows you to simulate Large Language Model responses in GenLayer tests. This is essential for creating deterministic tests by providing predefined responses instead of relying on actual LLM calls.
|
622
|
+
|
623
|
+
#### Basic Structure
|
624
|
+
|
625
|
+
The mock system consists of a response dictionary that maps GenLayer methods to their mocked responses:
|
626
|
+
|
627
|
+
```python
|
628
|
+
mock_response = {
|
629
|
+
"response": {}, # Optional: mocks gl.nondet.exec_prompt
|
630
|
+
"eq_principle_prompt_comparative": {}, # Optional: mocks gl.eq_principle.prompt_comparative
|
631
|
+
"eq_principle_prompt_non_comparative": {} # Optional: mocks gl.eq_principle.prompt_non_comparative
|
632
|
+
}
|
633
|
+
|
634
|
+
setup_validators(mock_response)
|
635
|
+
```
|
636
|
+
|
637
|
+
#### Method Mappings
|
638
|
+
|
639
|
+
| Mock Key | GenLayer Method |
|
640
|
+
|----------|----------------|
|
641
|
+
| `"response"` | `gl.nondet.exec_prompt` |
|
642
|
+
| `"eq_principle_prompt_comparative"` | `gl.eq_principle.prompt_comparative` |
|
643
|
+
| `"eq_principle_prompt_non_comparative"` | `gl.eq_principle.prompt_non_comparative` |
|
644
|
+
|
645
|
+
#### How It Works
|
646
|
+
|
647
|
+
The mock system works by pattern matching against the user message that gets built internally. When a GenLayer method is called:
|
648
|
+
|
649
|
+
1. A user message is constructed internally (`<user_message>`)
|
650
|
+
2. The mock system searches for strings within that message
|
651
|
+
3. If a matching string is found in the mock dictionary, the associated response is returned
|
652
|
+
|
653
|
+
##### String Matching Rules
|
654
|
+
|
655
|
+
The system performs **substring matching** on the user message. The key in your mock dictionary must be contained within the actual user message.
|
656
|
+
|
657
|
+
#### Examples
|
658
|
+
|
659
|
+
##### Basic Example
|
660
|
+
|
661
|
+
```python
|
662
|
+
# Mock setup
|
663
|
+
mock_response = {
|
664
|
+
"eq_principle_prompt_comparative": {
|
665
|
+
"The value of give_coin has to match": True
|
666
|
+
}
|
667
|
+
}
|
668
|
+
setup_validators(mock_response)
|
669
|
+
|
670
|
+
# In your contract
|
671
|
+
result = gl.eq_principle.prompt_comparative(
|
672
|
+
get_wizard_answer,
|
673
|
+
"The value of give_coin has to match" # This string will be matched
|
674
|
+
)
|
675
|
+
# result will be True
|
676
|
+
```
|
677
|
+
|
678
|
+
##### Substring Matching Examples
|
679
|
+
|
680
|
+
✅ **Will work** - Partial match:
|
681
|
+
```python
|
682
|
+
"eq_principle_prompt_comparative": {
|
683
|
+
"The value of give_coin": True # Substring of the full message
|
684
|
+
}
|
685
|
+
```
|
686
|
+
|
687
|
+
❌ **Won't work** - Extra words break the match:
|
688
|
+
```python
|
689
|
+
"eq_principle_prompt_comparative": {
|
690
|
+
"The good value of give_coin": True # "good" is not in the actual message
|
691
|
+
}
|
692
|
+
```
|
693
|
+
|
694
|
+
##### Complete Example
|
695
|
+
|
696
|
+
```python
|
697
|
+
from gltest import get_contract_factory
|
698
|
+
from gltest.fixtures import setup_validators
|
699
|
+
|
700
|
+
def test_with_mocked_llm(setup_validators):
|
701
|
+
# Define mock responses
|
702
|
+
mock_response = {
|
703
|
+
"response": {
|
704
|
+
"What is the weather?": "It's sunny today",
|
705
|
+
"Calculate 2+2": "4"
|
706
|
+
},
|
707
|
+
"eq_principle_prompt_comparative": {
|
708
|
+
"values must be equal": True,
|
709
|
+
"amounts should match": False
|
710
|
+
},
|
711
|
+
"eq_principle_prompt_non_comparative": {
|
712
|
+
"Is this valid?": True
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
# Initialize the mock system
|
717
|
+
setup_validators(mock_response)
|
718
|
+
|
719
|
+
# Deploy and test your contract
|
720
|
+
factory = get_contract_factory("MyLLMContract")
|
721
|
+
contract = factory.deploy()
|
722
|
+
|
723
|
+
# Your LLM methods will use the mocked responses
|
724
|
+
result = contract.check_weather() # Uses mocked response
|
725
|
+
```
|
726
|
+
|
727
|
+
#### Best Practices
|
728
|
+
|
729
|
+
1. **Be specific with match strings**: Use unique substrings that won't accidentally match other prompts
|
730
|
+
2. **Test your matches**: Verify that your mock strings actually appear in the generated user messages
|
731
|
+
3. **Keep mocks simple**: Mock responses should be minimal and focused on the test case
|
732
|
+
4. **Document your mocks**: Comment why specific responses are mocked for future reference
|
733
|
+
5. **Use with `--test-with-mocks` flag**: Enable mocking when running tests: `gltest --test-with-mocks`
|
734
|
+
|
735
|
+
#### Notes
|
736
|
+
|
737
|
+
- Mock responses are only available when running tests on localnet
|
738
|
+
- The `setup_validators` fixture handles the mock setup when provided with a mock_response
|
739
|
+
- Mocking is particularly useful for CI/CD pipelines where deterministic results are required
|
506
740
|
|
507
741
|
## 📝 Best Practices
|
508
742
|
|
@@ -546,6 +780,7 @@ Fixtures help maintain clean, DRY test code by:
|
|
546
780
|
```python
|
547
781
|
tx_receipt = contract.set_value(
|
548
782
|
args=["new_value"],
|
783
|
+
).transact(
|
549
784
|
wait_interval=2, # Increase wait interval between status checks
|
550
785
|
wait_retries=20, # Increase number of retry attempts
|
551
786
|
)
|
@@ -558,13 +793,11 @@ Fixtures help maintain clean, DRY test code by:
|
|
558
793
|
# Try with increased consensus parameters
|
559
794
|
contract = factory.deploy(
|
560
795
|
consensus_max_rotations=5, # Increase number of consensus rotations
|
561
|
-
leader_only=True, # Try leader-only mode for faster execution
|
562
796
|
)
|
563
797
|
|
564
798
|
# For critical operations, use more conservative settings
|
565
799
|
contract = factory.deploy(
|
566
800
|
consensus_max_rotations=10, # More rotations for better reliability
|
567
|
-
leader_only=False, # Full consensus for better security
|
568
801
|
wait_interval=3, # Longer wait between checks
|
569
802
|
wait_retries=30 # More retries for consensus
|
570
803
|
)
|