genlayer-test 0.3.1__tar.gz → 0.4.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.
Files changed (72) hide show
  1. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/PKG-INFO +124 -4
  2. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/README.md +123 -3
  3. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/PKG-INFO +124 -4
  4. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/SOURCES.txt +1 -0
  5. genlayer_test-0.4.0/gltest/fixtures.py +91 -0
  6. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/helpers/fixture_snapshot.py +1 -6
  7. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/plugin.py +13 -0
  8. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/types.py +11 -0
  9. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/pyproject.toml +1 -1
  10. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/football_prediction_market.py +11 -8
  11. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/intelligent_oracle.py +7 -6
  12. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/intelligent_oracle_factory.py +1 -0
  13. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/llm_erc20.py +3 -2
  14. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/log_indexer.py +7 -5
  15. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/multi_file_contract/__init__.py +5 -2
  16. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/multi_read_erc20.py +2 -1
  17. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/multi_tenant_storage.py +3 -2
  18. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/read_erc20.py +6 -1
  19. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/storage.py +2 -1
  20. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/user_storage.py +2 -1
  21. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/wizard_of_coin.py +4 -3
  22. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_football_prediction_market.py +20 -1
  23. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_intelligent_oracle_factory.py +62 -9
  24. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_llm_erc20.py +20 -1
  25. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_log_indexer.py +2 -1
  26. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_multi_file_contract.py +2 -1
  27. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_multi_file_contract_legacy.py +2 -1
  28. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_multi_read_erc20.py +9 -3
  29. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_multi_tenant_storage.py +2 -1
  30. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_read_erc20.py +2 -1
  31. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_storage.py +2 -1
  32. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_storage_legacy.py +2 -1
  33. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/tests/test_user_storage.py +9 -3
  34. genlayer_test-0.4.0/tests/examples/tests/test_wizard_of_coin.py +27 -0
  35. genlayer_test-0.3.1/tests/examples/tests/test_wizard_of_coin.py +0 -12
  36. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/LICENSE +0 -0
  37. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/dependency_links.txt +0 -0
  38. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/entry_points.txt +0 -0
  39. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/requires.txt +0 -0
  40. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/genlayer_test.egg-info/top_level.txt +0 -0
  41. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/__init__.py +0 -0
  42. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/artifacts/__init__.py +0 -0
  43. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/artifacts/contract.py +0 -0
  44. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/assertions.py +0 -0
  45. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/exceptions.py +0 -0
  46. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/glchain/__init__.py +0 -0
  47. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/glchain/account.py +0 -0
  48. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/glchain/client.py +0 -0
  49. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/glchain/contract.py +0 -0
  50. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/helpers/__init__.py +0 -0
  51. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/helpers/take_snapshot.py +0 -0
  52. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest/types.py +0 -0
  53. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/__init__.py +0 -0
  54. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/constants.py +0 -0
  55. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/general.py +0 -0
  56. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/config/user.py +0 -0
  57. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/logging.py +0 -0
  58. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/gltest_cli/main.py +0 -0
  59. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/setup.cfg +0 -0
  60. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/__init__.py +0 -0
  61. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/conftest.py +0 -0
  62. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/examples/contracts/multi_file_contract/other.py +0 -0
  63. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/__init__.py +0 -0
  64. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/artifact/__init__.py +0 -0
  65. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +0 -0
  66. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +0 -0
  67. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/artifact/contracts/not_ic_contract.py +0 -0
  68. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/artifact/test_contract_definition.py +0 -0
  69. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest/assertions/test_assertions.py +0 -0
  70. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest_cli/__init__.py +0 -0
  71. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest_cli/config/test_plugin.py +0 -0
  72. {genlayer_test-0.3.1 → genlayer_test-0.4.0}/tests/gltest_cli/config/test_user.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -50,7 +50,7 @@ from gltest.assertions import tx_execution_succeeded
50
50
 
51
51
  factory = get_contract_factory("MyContract")
52
52
  # Deploy a contract with default account
53
- contract = factory.deploy() # This will be deployed with default_account
53
+ contract = factory.deploy() # This will be deployed with the default account
54
54
  assert contract.account == get_default_account()
55
55
 
56
56
  # Deploy a contract with other account
@@ -207,6 +207,30 @@ $ gltest --default-wait-interval <default_wait_interval>
207
207
  $ gltest --default-wait-retries <default_wait_retries>
208
208
  ```
209
209
 
210
+ 10. Run tests with mocked LLM responses (localnet only)
211
+ ```bash
212
+ $ gltest --test-with-mocks
213
+ ```
214
+ The `--test-with-mocks` flag enables mocking of LLM responses when creating validators. This is particularly useful for:
215
+ - Testing without actual LLM API calls
216
+ - Ensuring deterministic test results
217
+ - Faster test execution
218
+ - Testing specific edge cases with controlled responses
219
+
220
+ When using this flag with the `setup_validators` fixture, you can provide custom mock responses:
221
+ ```python
222
+ def test_with_mocked_llm(setup_validators):
223
+ # Setup validators with a specific mock response
224
+ mock_response = {"result": "This is a mocked LLM response"}
225
+ setup_validators(mock_response=mock_response)
226
+
227
+ # Your LLM-based contract will receive the mocked response
228
+ contract = factory.deploy()
229
+ result = contract.llm_method() # Will use the mocked response
230
+ ```
231
+
232
+ Note: This feature is only available when running tests on localnet.
233
+
210
234
  ## 🚀 Key Features
211
235
 
212
236
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -275,7 +299,7 @@ Key features demonstrated in this contract:
275
299
  Here's how to deploy the Storage contract:
276
300
 
277
301
  ```python
278
- from gltest import get_contract_factory, default_account
302
+ from gltest import get_contract_factory, get_default_account
279
303
 
280
304
  def test_deployment():
281
305
  # Get the contract factory for your contract
@@ -285,7 +309,7 @@ def test_deployment():
285
309
  # Deploy the contract with constructor arguments
286
310
  contract = factory.deploy(
287
311
  args=["initial_value"], # Constructor arguments
288
- account=default_account, # Account to deploy from
312
+ account=get_default_account(), # Account to deploy from
289
313
  consensus_max_rotations=3, # Optional: max consensus rotations
290
314
  leader_only=False, # Optional: whether to run only on leader
291
315
  )
@@ -384,6 +408,102 @@ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following par
384
408
 
385
409
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
386
410
 
411
+ ### Test Fixtures
412
+
413
+ The GenLayer Testing Suite provides reusable pytest fixtures in `gltest.fixtures` to simplify common testing operations. These fixtures can be imported and used in your test files to avoid repetitive setup code.
414
+
415
+ #### Available Fixtures
416
+
417
+ The following fixtures are available in `gltest.fixtures`:
418
+
419
+ - **`gl_client`** (session scope) - GenLayer client instance for network operations
420
+ - **`default_account`** (session scope) - Default account for testing and deployments
421
+ - **`accounts`** (session scope) - List of test accounts for multi-account scenarios
422
+ - **`setup_validators`** (function scope) - Function to create test validators for LLM operations
423
+
424
+ ##### 1. `gl_client` (session scope)
425
+ Provides a GenLayer PY client instance that's created once per test session. This is useful for operations that interact directly with the GenLayer network.
426
+
427
+ ```python
428
+ def test_client_operations(gl_client):
429
+ # Use the client for network operations
430
+ tx_hash = "0x1234..."
431
+ transaction = gl_client.get_transaction(tx_hash)
432
+ ```
433
+
434
+ ##### 2. `default_account` (session scope)
435
+ Provides the default account used to execute transactions when no account is specified.
436
+
437
+ ```python
438
+ def test_with_default_account(default_account):
439
+ # Use the default account for deployments
440
+ factory = get_contract_factory("MyContract")
441
+ contract = factory.deploy(account=default_account)
442
+ ```
443
+
444
+ ##### 3. `accounts` (session scope)
445
+ Provides a list of account objects loaded from the private keys defined in `gltest.config.yaml` for the current network, or pre-created test accounts if no config is present
446
+
447
+ ```python
448
+ def test_multiple_accounts(accounts):
449
+ # Get multiple accounts for testing
450
+ sender = accounts[0]
451
+ receiver = accounts[1]
452
+
453
+ # Test transfers or multi-party interactions
454
+ contract.transfer(args=[receiver.address, 100], account=sender)
455
+ ```
456
+
457
+ ##### 4. `setup_validators` (function scope)
458
+ Creates test validators for localnet environment. This fixture is particularly useful for testing LLM-based contract methods and consensus behavior. It yields a function that allows you to configure validators with custom settings.
459
+
460
+ ```python
461
+ def test_with_validators(setup_validators):
462
+ # Setup validators with default configuration
463
+ setup_validators()
464
+
465
+ # Or setup with custom mock responses for testing
466
+ mock_response = {"result": "mocked LLM response"}
467
+ setup_validators(mock_response=mock_response, n_validators=3)
468
+
469
+ # Now test your LLM-based contract methods
470
+ contract = factory.deploy()
471
+ result = contract.llm_based_method()
472
+ ```
473
+
474
+ Parameters for `setup_validators`:
475
+ - `mock_response` (dict, optional): Mock validator response when using `--test-with-mocks` flag
476
+ - `n_validators` (int, optional): Number of validators to create (default: 5)
477
+
478
+ #### Using Fixtures in Your Tests
479
+
480
+ To use these fixtures, simply import them and include them as parameters in your test functions:
481
+
482
+ ```python
483
+ from gltest import get_contract_factory
484
+ from gltest.assertions import tx_execution_succeeded
485
+
486
+ def test_complete_workflow(gl_client, default_account, accounts, setup_validators):
487
+ # Setup validators for LLM operations
488
+ setup_validators()
489
+
490
+ # Deploy contract with default account
491
+ factory = get_contract_factory("MyContract")
492
+ contract = factory.deploy(account=default_account)
493
+
494
+ # Interact using other accounts
495
+ other_account = accounts[1]
496
+ tx_receipt = contract.some_method(args=["value"], account=other_account)
497
+
498
+ assert tx_execution_succeeded(tx_receipt)
499
+ ```
500
+
501
+ Fixtures help maintain clean, DRY test code by:
502
+ - Eliminating repetitive setup code
503
+ - Ensuring consistent test environments
504
+ - Managing resource cleanup automatically
505
+ - Providing appropriate scoping for performance
506
+
387
507
  ## 📝 Best Practices
388
508
 
389
509
  1. **Test Organization**
@@ -27,7 +27,7 @@ from gltest.assertions import tx_execution_succeeded
27
27
 
28
28
  factory = get_contract_factory("MyContract")
29
29
  # Deploy a contract with default account
30
- contract = factory.deploy() # This will be deployed with default_account
30
+ contract = factory.deploy() # This will be deployed with the default account
31
31
  assert contract.account == get_default_account()
32
32
 
33
33
  # Deploy a contract with other account
@@ -184,6 +184,30 @@ $ gltest --default-wait-interval <default_wait_interval>
184
184
  $ gltest --default-wait-retries <default_wait_retries>
185
185
  ```
186
186
 
187
+ 10. Run tests with mocked LLM responses (localnet only)
188
+ ```bash
189
+ $ gltest --test-with-mocks
190
+ ```
191
+ The `--test-with-mocks` flag enables mocking of LLM responses when creating validators. This is particularly useful for:
192
+ - Testing without actual LLM API calls
193
+ - Ensuring deterministic test results
194
+ - Faster test execution
195
+ - Testing specific edge cases with controlled responses
196
+
197
+ When using this flag with the `setup_validators` fixture, you can provide custom mock responses:
198
+ ```python
199
+ def test_with_mocked_llm(setup_validators):
200
+ # Setup validators with a specific mock response
201
+ mock_response = {"result": "This is a mocked LLM response"}
202
+ setup_validators(mock_response=mock_response)
203
+
204
+ # Your LLM-based contract will receive the mocked response
205
+ contract = factory.deploy()
206
+ result = contract.llm_method() # Will use the mocked response
207
+ ```
208
+
209
+ Note: This feature is only available when running tests on localnet.
210
+
187
211
  ## 🚀 Key Features
188
212
 
189
213
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -252,7 +276,7 @@ Key features demonstrated in this contract:
252
276
  Here's how to deploy the Storage contract:
253
277
 
254
278
  ```python
255
- from gltest import get_contract_factory, default_account
279
+ from gltest import get_contract_factory, get_default_account
256
280
 
257
281
  def test_deployment():
258
282
  # Get the contract factory for your contract
@@ -262,7 +286,7 @@ def test_deployment():
262
286
  # Deploy the contract with constructor arguments
263
287
  contract = factory.deploy(
264
288
  args=["initial_value"], # Constructor arguments
265
- account=default_account, # Account to deploy from
289
+ account=get_default_account(), # Account to deploy from
266
290
  consensus_max_rotations=3, # Optional: max consensus rotations
267
291
  leader_only=False, # Optional: whether to run only on leader
268
292
  )
@@ -361,6 +385,102 @@ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following par
361
385
 
362
386
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
363
387
 
388
+ ### Test Fixtures
389
+
390
+ The GenLayer Testing Suite provides reusable pytest fixtures in `gltest.fixtures` to simplify common testing operations. These fixtures can be imported and used in your test files to avoid repetitive setup code.
391
+
392
+ #### Available Fixtures
393
+
394
+ The following fixtures are available in `gltest.fixtures`:
395
+
396
+ - **`gl_client`** (session scope) - GenLayer client instance for network operations
397
+ - **`default_account`** (session scope) - Default account for testing and deployments
398
+ - **`accounts`** (session scope) - List of test accounts for multi-account scenarios
399
+ - **`setup_validators`** (function scope) - Function to create test validators for LLM operations
400
+
401
+ ##### 1. `gl_client` (session scope)
402
+ Provides a GenLayer PY client instance that's created once per test session. This is useful for operations that interact directly with the GenLayer network.
403
+
404
+ ```python
405
+ def test_client_operations(gl_client):
406
+ # Use the client for network operations
407
+ tx_hash = "0x1234..."
408
+ transaction = gl_client.get_transaction(tx_hash)
409
+ ```
410
+
411
+ ##### 2. `default_account` (session scope)
412
+ Provides the default account used to execute transactions when no account is specified.
413
+
414
+ ```python
415
+ def test_with_default_account(default_account):
416
+ # Use the default account for deployments
417
+ factory = get_contract_factory("MyContract")
418
+ contract = factory.deploy(account=default_account)
419
+ ```
420
+
421
+ ##### 3. `accounts` (session scope)
422
+ Provides a list of account objects loaded from the private keys defined in `gltest.config.yaml` for the current network, or pre-created test accounts if no config is present
423
+
424
+ ```python
425
+ def test_multiple_accounts(accounts):
426
+ # Get multiple accounts for testing
427
+ sender = accounts[0]
428
+ receiver = accounts[1]
429
+
430
+ # Test transfers or multi-party interactions
431
+ contract.transfer(args=[receiver.address, 100], account=sender)
432
+ ```
433
+
434
+ ##### 4. `setup_validators` (function scope)
435
+ Creates test validators for localnet environment. This fixture is particularly useful for testing LLM-based contract methods and consensus behavior. It yields a function that allows you to configure validators with custom settings.
436
+
437
+ ```python
438
+ def test_with_validators(setup_validators):
439
+ # Setup validators with default configuration
440
+ setup_validators()
441
+
442
+ # Or setup with custom mock responses for testing
443
+ mock_response = {"result": "mocked LLM response"}
444
+ setup_validators(mock_response=mock_response, n_validators=3)
445
+
446
+ # Now test your LLM-based contract methods
447
+ contract = factory.deploy()
448
+ result = contract.llm_based_method()
449
+ ```
450
+
451
+ Parameters for `setup_validators`:
452
+ - `mock_response` (dict, optional): Mock validator response when using `--test-with-mocks` flag
453
+ - `n_validators` (int, optional): Number of validators to create (default: 5)
454
+
455
+ #### Using Fixtures in Your Tests
456
+
457
+ To use these fixtures, simply import them and include them as parameters in your test functions:
458
+
459
+ ```python
460
+ from gltest import get_contract_factory
461
+ from gltest.assertions import tx_execution_succeeded
462
+
463
+ def test_complete_workflow(gl_client, default_account, accounts, setup_validators):
464
+ # Setup validators for LLM operations
465
+ setup_validators()
466
+
467
+ # Deploy contract with default account
468
+ factory = get_contract_factory("MyContract")
469
+ contract = factory.deploy(account=default_account)
470
+
471
+ # Interact using other accounts
472
+ other_account = accounts[1]
473
+ tx_receipt = contract.some_method(args=["value"], account=other_account)
474
+
475
+ assert tx_execution_succeeded(tx_receipt)
476
+ ```
477
+
478
+ Fixtures help maintain clean, DRY test code by:
479
+ - Eliminating repetitive setup code
480
+ - Ensuring consistent test environments
481
+ - Managing resource cleanup automatically
482
+ - Providing appropriate scoping for performance
483
+
364
484
  ## 📝 Best Practices
365
485
 
366
486
  1. **Test Organization**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -50,7 +50,7 @@ from gltest.assertions import tx_execution_succeeded
50
50
 
51
51
  factory = get_contract_factory("MyContract")
52
52
  # Deploy a contract with default account
53
- contract = factory.deploy() # This will be deployed with default_account
53
+ contract = factory.deploy() # This will be deployed with the default account
54
54
  assert contract.account == get_default_account()
55
55
 
56
56
  # Deploy a contract with other account
@@ -207,6 +207,30 @@ $ gltest --default-wait-interval <default_wait_interval>
207
207
  $ gltest --default-wait-retries <default_wait_retries>
208
208
  ```
209
209
 
210
+ 10. Run tests with mocked LLM responses (localnet only)
211
+ ```bash
212
+ $ gltest --test-with-mocks
213
+ ```
214
+ The `--test-with-mocks` flag enables mocking of LLM responses when creating validators. This is particularly useful for:
215
+ - Testing without actual LLM API calls
216
+ - Ensuring deterministic test results
217
+ - Faster test execution
218
+ - Testing specific edge cases with controlled responses
219
+
220
+ When using this flag with the `setup_validators` fixture, you can provide custom mock responses:
221
+ ```python
222
+ def test_with_mocked_llm(setup_validators):
223
+ # Setup validators with a specific mock response
224
+ mock_response = {"result": "This is a mocked LLM response"}
225
+ setup_validators(mock_response=mock_response)
226
+
227
+ # Your LLM-based contract will receive the mocked response
228
+ contract = factory.deploy()
229
+ result = contract.llm_method() # Will use the mocked response
230
+ ```
231
+
232
+ Note: This feature is only available when running tests on localnet.
233
+
210
234
  ## 🚀 Key Features
211
235
 
212
236
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -275,7 +299,7 @@ Key features demonstrated in this contract:
275
299
  Here's how to deploy the Storage contract:
276
300
 
277
301
  ```python
278
- from gltest import get_contract_factory, default_account
302
+ from gltest import get_contract_factory, get_default_account
279
303
 
280
304
  def test_deployment():
281
305
  # Get the contract factory for your contract
@@ -285,7 +309,7 @@ def test_deployment():
285
309
  # Deploy the contract with constructor arguments
286
310
  contract = factory.deploy(
287
311
  args=["initial_value"], # Constructor arguments
288
- account=default_account, # Account to deploy from
312
+ account=get_default_account(), # Account to deploy from
289
313
  consensus_max_rotations=3, # Optional: max consensus rotations
290
314
  leader_only=False, # Optional: whether to run only on leader
291
315
  )
@@ -384,6 +408,102 @@ Both `tx_execution_succeeded` and `tx_execution_failed` accept the following par
384
408
 
385
409
  For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
386
410
 
411
+ ### Test Fixtures
412
+
413
+ The GenLayer Testing Suite provides reusable pytest fixtures in `gltest.fixtures` to simplify common testing operations. These fixtures can be imported and used in your test files to avoid repetitive setup code.
414
+
415
+ #### Available Fixtures
416
+
417
+ The following fixtures are available in `gltest.fixtures`:
418
+
419
+ - **`gl_client`** (session scope) - GenLayer client instance for network operations
420
+ - **`default_account`** (session scope) - Default account for testing and deployments
421
+ - **`accounts`** (session scope) - List of test accounts for multi-account scenarios
422
+ - **`setup_validators`** (function scope) - Function to create test validators for LLM operations
423
+
424
+ ##### 1. `gl_client` (session scope)
425
+ Provides a GenLayer PY client instance that's created once per test session. This is useful for operations that interact directly with the GenLayer network.
426
+
427
+ ```python
428
+ def test_client_operations(gl_client):
429
+ # Use the client for network operations
430
+ tx_hash = "0x1234..."
431
+ transaction = gl_client.get_transaction(tx_hash)
432
+ ```
433
+
434
+ ##### 2. `default_account` (session scope)
435
+ Provides the default account used to execute transactions when no account is specified.
436
+
437
+ ```python
438
+ def test_with_default_account(default_account):
439
+ # Use the default account for deployments
440
+ factory = get_contract_factory("MyContract")
441
+ contract = factory.deploy(account=default_account)
442
+ ```
443
+
444
+ ##### 3. `accounts` (session scope)
445
+ Provides a list of account objects loaded from the private keys defined in `gltest.config.yaml` for the current network, or pre-created test accounts if no config is present
446
+
447
+ ```python
448
+ def test_multiple_accounts(accounts):
449
+ # Get multiple accounts for testing
450
+ sender = accounts[0]
451
+ receiver = accounts[1]
452
+
453
+ # Test transfers or multi-party interactions
454
+ contract.transfer(args=[receiver.address, 100], account=sender)
455
+ ```
456
+
457
+ ##### 4. `setup_validators` (function scope)
458
+ Creates test validators for localnet environment. This fixture is particularly useful for testing LLM-based contract methods and consensus behavior. It yields a function that allows you to configure validators with custom settings.
459
+
460
+ ```python
461
+ def test_with_validators(setup_validators):
462
+ # Setup validators with default configuration
463
+ setup_validators()
464
+
465
+ # Or setup with custom mock responses for testing
466
+ mock_response = {"result": "mocked LLM response"}
467
+ setup_validators(mock_response=mock_response, n_validators=3)
468
+
469
+ # Now test your LLM-based contract methods
470
+ contract = factory.deploy()
471
+ result = contract.llm_based_method()
472
+ ```
473
+
474
+ Parameters for `setup_validators`:
475
+ - `mock_response` (dict, optional): Mock validator response when using `--test-with-mocks` flag
476
+ - `n_validators` (int, optional): Number of validators to create (default: 5)
477
+
478
+ #### Using Fixtures in Your Tests
479
+
480
+ To use these fixtures, simply import them and include them as parameters in your test functions:
481
+
482
+ ```python
483
+ from gltest import get_contract_factory
484
+ from gltest.assertions import tx_execution_succeeded
485
+
486
+ def test_complete_workflow(gl_client, default_account, accounts, setup_validators):
487
+ # Setup validators for LLM operations
488
+ setup_validators()
489
+
490
+ # Deploy contract with default account
491
+ factory = get_contract_factory("MyContract")
492
+ contract = factory.deploy(account=default_account)
493
+
494
+ # Interact using other accounts
495
+ other_account = accounts[1]
496
+ tx_receipt = contract.some_method(args=["value"], account=other_account)
497
+
498
+ assert tx_execution_succeeded(tx_receipt)
499
+ ```
500
+
501
+ Fixtures help maintain clean, DRY test code by:
502
+ - Eliminating repetitive setup code
503
+ - Ensuring consistent test environments
504
+ - Managing resource cleanup automatically
505
+ - Providing appropriate scoping for performance
506
+
387
507
  ## 📝 Best Practices
388
508
 
389
509
  1. **Test Organization**
@@ -10,6 +10,7 @@ genlayer_test.egg-info/top_level.txt
10
10
  gltest/__init__.py
11
11
  gltest/assertions.py
12
12
  gltest/exceptions.py
13
+ gltest/fixtures.py
13
14
  gltest/types.py
14
15
  gltest/artifacts/__init__.py
15
16
  gltest/artifacts/contract.py
@@ -0,0 +1,91 @@
1
+ """
2
+ This module provides reusable pytest fixtures for common gltest operations.
3
+ These fixtures can be imported and used in test files.
4
+ """
5
+
6
+ import pytest
7
+ from gltest.glchain import (
8
+ get_gl_client,
9
+ get_accounts,
10
+ get_default_account,
11
+ get_gl_provider,
12
+ )
13
+ from gltest_cli.config.general import get_general_config
14
+
15
+
16
+ @pytest.fixture(scope="session")
17
+ def gl_client():
18
+ """
19
+ Provides a GenLayer client instance.
20
+
21
+ Scope: session - created once per test session
22
+ """
23
+ return get_gl_client()
24
+
25
+
26
+ @pytest.fixture(scope="session")
27
+ def default_account():
28
+ """
29
+ Provides the default account for testing.
30
+
31
+ Scope: session - created once per test session
32
+ """
33
+ return get_default_account()
34
+
35
+
36
+ @pytest.fixture(scope="session")
37
+ def accounts():
38
+ """
39
+ Provides a list of test accounts.
40
+
41
+ Scope: session - created once per test session
42
+ """
43
+ return get_accounts()
44
+
45
+
46
+ @pytest.fixture(scope="function")
47
+ def setup_validators():
48
+ """
49
+ Creates test validators for localnet environment.
50
+
51
+ Args:
52
+ mock_response (dict, optional): Mock validator response when using --test-with-mocks flag
53
+ n_validators (int, optional): Number of validators to create (default: 5)
54
+
55
+ Scope: function - created fresh for each test
56
+ """
57
+ general_config = get_general_config()
58
+ provider = get_gl_provider()
59
+
60
+ def _setup(mock_response=None, n_validators=5):
61
+ if not general_config.check_local_rpc():
62
+ return
63
+ if general_config.get_test_with_mocks():
64
+ for _ in range(n_validators):
65
+ provider.make_request(
66
+ method="sim_createValidator",
67
+ params=[
68
+ 8,
69
+ "openai",
70
+ "gpt-4o",
71
+ {"temperature": 0.75, "max_tokens": 500},
72
+ "openai-compatible",
73
+ {
74
+ "api_key_env_var": "OPENAIKEY",
75
+ "api_url": "https://api.openai.com",
76
+ "mock_response": mock_response if mock_response else {},
77
+ },
78
+ ],
79
+ )
80
+ else:
81
+ provider.make_request(
82
+ method="sim_createRandomValidators",
83
+ params=[n_validators, 8, 12],
84
+ )
85
+
86
+ yield _setup
87
+
88
+ if not general_config.check_local_rpc():
89
+ return
90
+
91
+ provider.make_request(method="sim_deleteAllValidators", params=[])
@@ -1,6 +1,5 @@
1
1
  from typing import TypeVar, Callable, List, Any
2
2
  from dataclasses import dataclass
3
- from urllib.parse import urlparse
4
3
  from .take_snapshot import SnapshotRestorer, take_snapshot
5
4
  from gltest.exceptions import (
6
5
  FixtureSnapshotError,
@@ -9,8 +8,6 @@ from gltest.exceptions import (
9
8
  )
10
9
  from gltest_cli.config.general import get_general_config
11
10
 
12
- SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
13
-
14
11
  T = TypeVar("T")
15
12
 
16
13
 
@@ -35,9 +32,7 @@ def load_fixture(fixture: Callable[[], T]) -> T:
35
32
  raise FixtureAnonymousFunctionError("Fixtures must be named functions")
36
33
 
37
34
  general_config = get_general_config()
38
- rpc_url = general_config.get_rpc_url()
39
- domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
40
- if domain not in SUPPORTED_RPC_DOMAINS:
35
+ if not general_config.check_local_rpc():
41
36
  return fixture()
42
37
 
43
38
  # Find existing snapshot for this fixture
@@ -48,6 +48,13 @@ def pytest_addoption(parser):
48
48
  help="Target network (defaults to 'localnet' if no config file)",
49
49
  )
50
50
 
51
+ group.addoption(
52
+ "--test-with-mocks",
53
+ action="store_true",
54
+ default=False,
55
+ help="Test with mocks",
56
+ )
57
+
51
58
 
52
59
  def pytest_configure(config):
53
60
  general_config = get_general_config()
@@ -73,6 +80,7 @@ def pytest_configure(config):
73
80
  default_wait_retries = config.getoption("--default-wait-retries")
74
81
  rpc_url = config.getoption("--rpc-url")
75
82
  network = config.getoption("--network")
83
+ test_with_mocks = config.getoption("--test-with-mocks")
76
84
 
77
85
  plugin_config = PluginConfig()
78
86
  plugin_config.contracts_dir = (
@@ -82,6 +90,7 @@ def pytest_configure(config):
82
90
  plugin_config.default_wait_retries = int(default_wait_retries)
83
91
  plugin_config.rpc_url = rpc_url
84
92
  plugin_config.network_name = network
93
+ plugin_config.test_with_mocks = test_with_mocks
85
94
 
86
95
  general_config.plugin_config = plugin_config
87
96
 
@@ -100,3 +109,7 @@ def pytest_sessionstart(session):
100
109
  f" Default wait interval: {general_config.get_default_wait_interval()} ms"
101
110
  )
102
111
  logger.info(f" Default wait retries: {general_config.get_default_wait_retries()}")
112
+ logger.info(f" Test with mocks: {general_config.get_test_with_mocks()}")
113
+
114
+
115
+ pytest_plugins = ["gltest.fixtures"]
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
  from typing import Dict, List, Optional
5
5
  from genlayer_py.chains import localnet, testnet_asimov
6
6
  from genlayer_py.types import GenLayerChain
7
+ from urllib.parse import urlparse
7
8
 
8
9
 
9
10
  class NetworkConfig(str, Enum):
@@ -18,6 +19,7 @@ class PluginConfig:
18
19
  default_wait_interval: Optional[int] = None
19
20
  default_wait_retries: Optional[int] = None
20
21
  network_name: Optional[str] = None
22
+ test_with_mocks: bool = False
21
23
 
22
24
 
23
25
  @dataclass
@@ -135,3 +137,12 @@ class GeneralConfig:
135
137
  if self.plugin_config.network_name is not None:
136
138
  return self.plugin_config.network_name
137
139
  return self.user_config.default_network
140
+
141
+ def get_test_with_mocks(self) -> bool:
142
+ return self.plugin_config.test_with_mocks
143
+
144
+ def check_local_rpc(self) -> bool:
145
+ SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
146
+ rpc_url = self.get_rpc_url()
147
+ domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
148
+ return domain in SUPPORTED_RPC_DOMAINS