genlayer-test 0.7.0__py3-none-any.whl → 0.9.0__py3-none-any.whl

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 (58) hide show
  1. {genlayer_test-0.7.0.dist-info → genlayer_test-0.9.0.dist-info}/METADATA +245 -4
  2. genlayer_test-0.9.0.dist-info/RECORD +38 -0
  3. {genlayer_test-0.7.0.dist-info → genlayer_test-0.9.0.dist-info}/top_level.txt +0 -1
  4. gltest/__init__.py +3 -0
  5. gltest/types.py +12 -1
  6. gltest/validators/__init__.py +3 -0
  7. gltest/validators/validator_factory.py +136 -0
  8. gltest_cli/config/constants.py +7 -0
  9. gltest_cli/config/plugin.py +22 -4
  10. gltest_cli/config/types.py +81 -46
  11. gltest_cli/config/user.py +95 -7
  12. genlayer_test-0.7.0.dist-info/RECORD +0 -79
  13. tests/__init__.py +0 -0
  14. tests/conftest.py +0 -1
  15. tests/examples/contracts/football_prediction_market.py +0 -100
  16. tests/examples/contracts/intelligent_oracle.py +0 -370
  17. tests/examples/contracts/intelligent_oracle_factory.py +0 -49
  18. tests/examples/contracts/invalid_deploy.py +0 -10
  19. tests/examples/contracts/llm_erc20.py +0 -70
  20. tests/examples/contracts/log_indexer.py +0 -69
  21. tests/examples/contracts/multi_file_contract/__init__.py +0 -24
  22. tests/examples/contracts/multi_file_contract/other.py +0 -14
  23. tests/examples/contracts/multi_read_erc20.py +0 -29
  24. tests/examples/contracts/multi_tenant_storage.py +0 -51
  25. tests/examples/contracts/read_erc20.py +0 -19
  26. tests/examples/contracts/simple_time_contract.py +0 -85
  27. tests/examples/contracts/storage.py +0 -23
  28. tests/examples/contracts/user_storage.py +0 -25
  29. tests/examples/contracts/wizard_of_coin.py +0 -57
  30. tests/examples/tests/test_football_prediction_market.py +0 -38
  31. tests/examples/tests/test_intelligent_oracle_factory.py +0 -162
  32. tests/examples/tests/test_invalid_deploy.py +0 -24
  33. tests/examples/tests/test_llm_erc20.py +0 -60
  34. tests/examples/tests/test_llm_erc20_analyze.py +0 -54
  35. tests/examples/tests/test_log_indexer.py +0 -76
  36. tests/examples/tests/test_multi_file_contract.py +0 -15
  37. tests/examples/tests/test_multi_read_erc20.py +0 -103
  38. tests/examples/tests/test_multi_tenant_storage.py +0 -76
  39. tests/examples/tests/test_read_erc20.py +0 -38
  40. tests/examples/tests/test_simple_time_contract.py +0 -90
  41. tests/examples/tests/test_storage.py +0 -26
  42. tests/examples/tests/test_user_storage.py +0 -87
  43. tests/examples/tests/test_wizard_of_coin.py +0 -27
  44. tests/gltest/__init__.py +0 -0
  45. tests/gltest/artifact/__init__.py +0 -0
  46. tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +0 -22
  47. tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +0 -22
  48. tests/gltest/artifact/contracts/not_ic_contract.py +0 -22
  49. tests/gltest/artifact/test_contract_definition.py +0 -55
  50. tests/gltest/assertions/test_assertions.py +0 -344
  51. tests/gltest_cli/__init__.py +0 -0
  52. tests/gltest_cli/config/test_config_integration.py +0 -432
  53. tests/gltest_cli/config/test_general_config.py +0 -406
  54. tests/gltest_cli/config/test_plugin.py +0 -290
  55. tests/gltest_cli/config/test_user.py +0 -411
  56. {genlayer_test-0.7.0.dist-info → genlayer_test-0.9.0.dist-info}/WHEEL +0 -0
  57. {genlayer_test-0.7.0.dist-info → genlayer_test-0.9.0.dist-info}/entry_points.txt +0 -0
  58. {genlayer_test-0.7.0.dist-info → genlayer_test-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.7.0
3
+ Version: 0.9.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.8.1
18
+ Requires-Dist: genlayer-py==0.9.0
19
19
  Requires-Dist: colorama>=0.4.6
20
20
  Requires-Dist: pyyaml
21
21
  Requires-Dist: python-dotenv
@@ -140,6 +140,7 @@ networks:
140
140
  custom_network: # Custom network configuration
141
141
  id: 1234
142
142
  url: "http://custom.network:8545"
143
+ chain_type: "localnet" # Required for custom networks: localnet, studionet, or testnet_asimov
143
144
  accounts:
144
145
  - "${CUSTOM_ACCOUNT_1}"
145
146
  - "${CUSTOM_ACCOUNT_2}"
@@ -163,10 +164,11 @@ Key configuration sections:
163
164
  - Network configurations can include:
164
165
  - `url`: The RPC endpoint for the network (optional for pre-configured networks)
165
166
  - `id`: Chain ID (optional for pre-configured networks)
167
+ - `chain_type`: Chain type - one of: `localnet`, `studionet`, or `testnet_asimov` (required for custom networks)
166
168
  - `accounts`: List of account private keys (using environment variables)
167
169
  - `from`: Specify which account to use as the default for transactions (optional, defaults to first account)
168
170
  - `leader_only`: Leader only mode
169
- - For custom networks (non-pre-configured), `id`, `url`, and `accounts` are required fields
171
+ - For custom networks (non-pre-configured), `id`, `url`, `chain_type`, and `accounts` are required fields
170
172
 
171
173
  **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
174
 
@@ -182,6 +184,13 @@ testnet_asimov:
182
184
  from: "${ADMIN_KEY}" # Use ADMIN_KEY as default instead of DEPLOYER_KEY
183
185
  ```
184
186
 
187
+ **Chain vs Network**:
188
+ - **Network**: Defines the connection details (URL, accounts, etc.) for a specific environment
189
+ - **Chain**: Defines the genlayer chain type and its associated behaviors (localnet, studionet, or testnet_asimov)
190
+ - Pre-configured networks automatically have the correct chain type set
191
+ - Custom networks must specify the chain type explicitly
192
+ - The `--chain-type` CLI flag can override the chain type for any network, allowing you to test different chain behaviors with the same network configuration
193
+
185
194
  2. **Paths**: Define important directory paths
186
195
  - `contracts`: Location of your contract files
187
196
  - `artifacts`: Location of your artifacts files (analysis results will be stored here)
@@ -299,6 +308,24 @@ When this flag is enabled, all contracts deployed and all write transactions wil
299
308
 
300
309
  **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
310
 
311
+ 12. Override the chain type
312
+ ```bash
313
+ $ gltest --chain-type localnet
314
+ $ gltest --chain-type studionet
315
+ $ gltest --chain-type testnet_asimov
316
+ ```
317
+ The `--chain-type` flag allows you to override the chain type configured for the network. This is useful when:
318
+ - Testing different chain behaviors without changing network configuration
319
+ - Switching between chain types for testing purposes
320
+ - Using a custom network URL with a specific chain type
321
+
322
+ Available chain types:
323
+ - `localnet`: Local development chain
324
+ - `studionet`: Studio-based chain
325
+ - `testnet_asimov`: Testnet Asimov chain
326
+
327
+ The chain type determines various behaviors including RPC endpoints, consensus mechanisms, and available features. When specified, this flag overrides the chain type configured in your network settings.
328
+
302
329
  ## 🚀 Key Features
303
330
 
304
331
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -308,6 +335,7 @@ When this flag is enabled, all contracts deployed and all write transactions wil
308
335
  - **State Injection & Consensus Simulation** – Modify contract states dynamically and simulate consensus scenarios for advanced testing.
309
336
  - **Prompt Testing & Statistical Analysis** – Evaluate and statistically test prompts for AI-driven contract execution.
310
337
  - **Scalability to Security & Audit Tools** – Designed to extend into security testing and smart contract auditing.
338
+ - **Custom Transaction Context** – Set custom validators with specific LLM providers and models, and configure GenVM datetime for deterministic testing scenarios.
311
339
 
312
340
  ## 📚 Examples
313
341
 
@@ -387,6 +415,7 @@ def test_deployment():
387
415
  args=["initial_value"], # Constructor arguments
388
416
  account=get_default_account(), # Account to deploy from
389
417
  consensus_max_rotations=3, # Optional: max consensus rotations
418
+ transaction_context=None, # Optional: custom transaction context
390
419
  )
391
420
 
392
421
  # Contract is now deployed and ready to use
@@ -419,7 +448,9 @@ def test_read_methods():
419
448
  contract = factory.deploy()
420
449
 
421
450
  # Call a read-only method
422
- result = contract.get_storage(args=[]).call()
451
+ result = contract.get_storage(args=[]).call(
452
+ transaction_context=None, # Optional: custom transaction context
453
+ )
423
454
 
424
455
  # Assert the result matches the initial value
425
456
  assert result == "initial_value"
@@ -446,6 +477,7 @@ def test_write_methods():
446
477
  consensus_max_rotations=3, # Optional: max consensus rotations
447
478
  wait_interval=1, # Optional: seconds between status checks
448
479
  wait_retries=10, # Optional: max number of retries
480
+ transaction_context=None, # Optional: custom transaction context
449
481
  )
450
482
 
451
483
  # Verify the transaction was successful
@@ -609,6 +641,7 @@ def test_analyze_method():
609
641
  config=None, # Optional: provider-specific config
610
642
  plugin=None, # Optional: plugin name
611
643
  plugin_config=None, # Optional: plugin configuration
644
+ genvm_datetime="2024-01-15T10:30:00Z", # Optional: GenVM datetime in ISO format
612
645
  )
613
646
 
614
647
  # Access analysis results
@@ -757,6 +790,214 @@ def test_with_mocked_llm(setup_validators):
757
790
  - The `setup_validators` fixture handles the mock setup when provided with a mock_response
758
791
  - Mocking is particularly useful for CI/CD pipelines where deterministic results are required
759
792
 
793
+ ### Custom Transaction Context
794
+
795
+ The GenLayer Testing Suite allows you to customize the transaction execution environment by providing a `transaction_context` parameter with custom validators and GenVM datetime settings.
796
+
797
+ #### Using Transaction Context
798
+
799
+ Set custom validators and GenVM datetime for deterministic testing:
800
+
801
+ ```python
802
+ from gltest import get_contract_factory, get_validator_factory
803
+
804
+ def test_with_custom_transaction_context():
805
+ factory = get_contract_factory("MyContract")
806
+ validator_factory = get_validator_factory()
807
+
808
+ # Create custom validators
809
+ validators = validator_factory.batch_create_validators(
810
+ count=3,
811
+ stake=10,
812
+ provider="openai",
813
+ model="gpt-4o",
814
+ config={"temperature": 0.7, "max_tokens": 1000},
815
+ plugin="openai-compatible",
816
+ plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
817
+ )
818
+
819
+ # Create transaction context with custom validators and datetime
820
+ transaction_context = {
821
+ "validators": [v.to_dict() for v in validators],
822
+ "genvm_datetime": "2024-03-15T14:30:00Z" # ISO format datetime
823
+ }
824
+
825
+ # Deploy with custom context
826
+ contract = factory.deploy(
827
+ args=["initial_value"],
828
+ transaction_context=transaction_context
829
+ )
830
+
831
+ # Call methods with custom context
832
+ result = contract.read_method().call(
833
+ transaction_context=transaction_context
834
+ )
835
+
836
+ # Write operations with custom context
837
+ tx_receipt = contract.write_method(args=["value"]).transact(
838
+ transaction_context=transaction_context
839
+ )
840
+ ```
841
+
842
+ #### Mock Validators with Transaction Context
843
+
844
+ Combine mock validators with custom datetime for fully deterministic tests:
845
+
846
+ ```python
847
+ def test_with_mocked_context():
848
+ factory = get_contract_factory("LLMContract")
849
+ validator_factory = get_validator_factory()
850
+
851
+ # Define mock LLM responses
852
+ mock_response = {
853
+ "nondet_exec_prompt": {
854
+ "analyze this": "positive sentiment"
855
+ },
856
+ "eq_principle_prompt_comparative": {
857
+ "values match": True
858
+ }
859
+ }
860
+
861
+ # Create mock validators
862
+ mock_validators = validator_factory.batch_create_mock_validators(
863
+ count=5,
864
+ mock_llm_response=mock_response
865
+ )
866
+
867
+ # Set up deterministic context
868
+ transaction_context = {
869
+ "validators": [v.to_dict() for v in mock_validators],
870
+ "genvm_datetime": "2024-01-01T00:00:00Z" # Fixed datetime for reproducibility
871
+ }
872
+
873
+ # Deploy and test with deterministic context
874
+ contract = factory.deploy(transaction_context=transaction_context)
875
+
876
+ # All operations will use the same mocked validators and datetime
877
+ result = contract.analyze_text(args=["analyze this"]).transact(
878
+ transaction_context=transaction_context
879
+ )
880
+ # Result will consistently return "positive sentiment"
881
+ ```
882
+
883
+ ### Custom Validators
884
+
885
+ The GenLayer Testing Suite includes a `get_validator_factory()` function that allows you to create custom validators with specific configurations for testing different LLM providers and consensus scenarios.
886
+
887
+ #### Creating Custom Validators
888
+
889
+ ```python
890
+ from gltest import get_validator_factory
891
+
892
+ def test_with_custom_validators():
893
+ factory = get_validator_factory()
894
+
895
+ # Create validators with different LLM providers
896
+ openai_validator = factory.create_validator(
897
+ stake=10,
898
+ provider="openai",
899
+ model="gpt-4o",
900
+ config={"temperature": 0.8, "max_tokens": 2000},
901
+ plugin="openai-compatible",
902
+ plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
903
+ )
904
+
905
+ ollama_validator = factory.create_validator(
906
+ stake=8,
907
+ provider="ollama",
908
+ model="mistral",
909
+ config={"temperature": 0.5},
910
+ plugin="ollama",
911
+ plugin_config={"api_url": "http://localhost:11434"}
912
+ )
913
+
914
+ # Use validators in your tests
915
+ validators = [openai_validator, ollama_validator]
916
+ # Configure your test environment with these validators
917
+ ```
918
+
919
+ #### Batch Creation
920
+
921
+ Create multiple validators with the same configuration:
922
+
923
+ ```python
924
+ def test_batch_validators():
925
+ factory = get_validator_factory()
926
+
927
+ # Create 5 validators with identical configuration
928
+ validators = factory.batch_create_validators(
929
+ count=5,
930
+ stake=8,
931
+ provider="openai",
932
+ model="gpt-4o",
933
+ config={"temperature": 0.7, "max_tokens": 1000},
934
+ plugin="openai-compatible",
935
+ plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
936
+ )
937
+ ```
938
+
939
+ #### Mock Validators
940
+
941
+ For deterministic testing, create mock validators that return predefined responses:
942
+
943
+ ```python
944
+ def test_with_mock_validators():
945
+ factory = get_validator_factory()
946
+
947
+ # Define mock responses
948
+ mock_response = {
949
+ "nondet_exec_prompt": {
950
+ "What is 2+2?": "4",
951
+ "Explain quantum physics": "It's complicated"
952
+ },
953
+ "eq_principle_prompt_comparative": {
954
+ "values must match": True
955
+ },
956
+ "eq_principle_prompt_non_comparative": {
957
+ "Is this valid?": True
958
+ }
959
+ }
960
+
961
+ # Create a single mock validator
962
+ mock_validator = factory.create_mock_validator(mock_response)
963
+
964
+ # Create multiple mock validators
965
+ mock_validators = factory.batch_create_mock_validators(
966
+ count=5,
967
+ mock_llm_response=mock_response
968
+ )
969
+ ```
970
+
971
+ #### Validator Methods
972
+
973
+ Each validator object provides useful methods:
974
+ - `to_dict()`: Convert validator to dictionary format for API calls
975
+ - `clone()`: Create an identical copy of the validator
976
+ - `batch_clone(count)`: Create multiple identical copies
977
+
978
+ Example:
979
+ ```python
980
+ def test_validator_cloning():
981
+ factory = get_validator_factory()
982
+
983
+ # Create a base validator
984
+ base_validator = factory.create_validator(
985
+ stake=10,
986
+ provider="openai",
987
+ model="gpt-4o",
988
+ config={"temperature": 0.7},
989
+ plugin="openai-compatible",
990
+ plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
991
+ )
992
+
993
+ # Clone it to create identical validators
994
+ cloned = base_validator.clone()
995
+ multiple_clones = base_validator.batch_clone(3)
996
+
997
+ # Convert to dictionary for API usage
998
+ validator_dict = base_validator.to_dict()
999
+ ```
1000
+
760
1001
  ## 📝 Best Practices
761
1002
 
762
1003
  1. **Test Organization**
@@ -0,0 +1,38 @@
1
+ genlayer_test-0.9.0.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
2
+ gltest/__init__.py,sha256=49112x2CLdYwvCbBZ1laJmMk0NQ7S3u5YUbxPefqhrk,454
3
+ gltest/accounts.py,sha256=HUmWguJMolggQaZNRPw-LGlRlQCjLLdUanKRowMv6pI,812
4
+ gltest/assertions.py,sha256=0dEk0VxcHK4I7GZPHxJmz-2jaA60V499gOSR74rZbfM,1748
5
+ gltest/clients.py,sha256=1dX6wmG3QCevQRLbSaFlHymZSb-sJ5aYwet1IoX2nbA,1554
6
+ gltest/exceptions.py,sha256=deJPmrTe5gF33qkkKF2IVJY7lc_knI7Ql3N7jZ8aLZs,510
7
+ gltest/fixtures.py,sha256=EJXmqcC3LD03v07mepacFl58lAdhbLj6bP5rtALYISk,2507
8
+ gltest/logging.py,sha256=jAkHsuMm-AEx1Xu1srU6W-0YzTwXJB48mCK-OVzAiN4,342
9
+ gltest/types.py,sha256=H32fHrU5aFMaPHXgEWcHAmLWOZ9pBFVp8PK_ncpVOgM,940
10
+ gltest/utils.py,sha256=-gHhjrS7i_GhDG3sKOq2qsTtYBt4HHgXHEXh-3RB_rI,573
11
+ gltest/artifacts/__init__.py,sha256=qTt3TE19gVNWnQLUlt5aDe4nNvJ2YJ1jzDkMmYIsCG0,194
12
+ gltest/artifacts/contract.py,sha256=KChpmfjZod_0dVB8y-dvWz6IVm7QlIJsgG2ArtvVDaU,6457
13
+ gltest/contracts/__init__.py,sha256=A9bvEtYOoqoHS8TLlFBfmNOnfwdsJPEf-AZuikagCHM,166
14
+ gltest/contracts/contract.py,sha256=jLF_ojSM6IIbdGO2_DhsO79r2wZ2Z8eBAJRrZk2qVTI,7748
15
+ gltest/contracts/contract_factory.py,sha256=PpWh4mKf1hDMv_yms5lwFV_EoXxXiuNfdXbwD74hbAU,8929
16
+ gltest/contracts/contract_functions.py,sha256=W6Dpw1z-n9EeJxlNtIbeVnzpv4BPABhtgmgjnS8-P0w,2573
17
+ gltest/contracts/method_stats.py,sha256=zWWjvf7K5VC4yrHpDIR717VF7LYp1RaZ1Hr_RZvWxJA,5150
18
+ gltest/contracts/stats_collector.py,sha256=iwsnoYo5aZbI4SVMH7dR-5CQgkglExXfsvaUDpwcdss,9286
19
+ gltest/contracts/utils.py,sha256=TTXgcXn9BuRIlKJrjwmU7R3l1IgXsXk2luM-r3lfbbg,296
20
+ gltest/helpers/__init__.py,sha256=I7HiTu_H7_hP65zY6Wl02r-5eAMr2eZvqBVmusuQLX4,180
21
+ gltest/helpers/fixture_snapshot.py,sha256=bMgvlEVQBGIQzj7NOyosXWlphI1H2C1o75Zo0C-kGfQ,1931
22
+ gltest/helpers/take_snapshot.py,sha256=-QkaBvFG4ZsNKv_nCSEsy5Ze1pICOHxVhReSeQmZUlY,1276
23
+ gltest/validators/__init__.py,sha256=AXboXORF5a8MVtG7jWMT1fJcwGXNzcX6txXQstwX2EU,152
24
+ gltest/validators/validator_factory.py,sha256=fpb-YyAKuWo4-pXBjrZ_TApYLsm6HHa6kGpbFByRucs,3886
25
+ gltest_cli/logging.py,sha256=WXVhfq9vT6FtV_jxDqGEGia1ZWSIUKAfmWRnZd_gWQk,1266
26
+ gltest_cli/main.py,sha256=Ti2-0Ev1x5_cM0D1UKqdgaDt80CDHEQGtdRne2qLm4M,53
27
+ gltest_cli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ gltest_cli/config/constants.py,sha256=llQD_yiJDwpohMBWufBKcmY8BXLkBeLe5eTj0QUOxSU,603
29
+ gltest_cli/config/general.py,sha256=ezpoGsT8grO9zQH6RugV14b1GzeFt-htYToHQBJhNvY,186
30
+ gltest_cli/config/plugin.py,sha256=o-tfm0KmbMe4iVLWGWUws5Wg2pwOEnfnASQv4ovXEXQ,7109
31
+ gltest_cli/config/pytest_context.py,sha256=Ze8JSkrwMTCE8jIhpzU_71CEXg92SiEPvSgNTp-gbS4,243
32
+ gltest_cli/config/types.py,sha256=oKRRFvCQESt3oca6T79RATHl9BtLNrVCqGc9tB5hovY,10083
33
+ gltest_cli/config/user.py,sha256=jtqhEkp2pEh67Pk4xcshXNcApeCBRjLesZgpqJQuCYg,13625
34
+ genlayer_test-0.9.0.dist-info/METADATA,sha256=09bCBWnQ0MR5FYhKFqZWgx7-nThb5RgR8xfFhl0nxMs,40707
35
+ genlayer_test-0.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ genlayer_test-0.9.0.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
37
+ genlayer_test-0.9.0.dist-info/top_level.txt,sha256=GSdrnQbiLcZssmtCpbDgBTygsc8Bt_TPeYjwm0FmpdA,18
38
+ genlayer_test-0.9.0.dist-info/RECORD,,
@@ -1,3 +1,2 @@
1
1
  gltest
2
2
  gltest_cli
3
- tests
gltest/__init__.py CHANGED
@@ -8,6 +8,8 @@ from gltest.clients import (
8
8
  get_gl_client,
9
9
  )
10
10
  from gltest.contracts import get_contract_factory
11
+ from gltest.validators import get_validator_factory
12
+
11
13
 
12
14
  __all__ = [
13
15
  "create_account",
@@ -16,4 +18,5 @@ __all__ = [
16
18
  "get_gl_client",
17
19
  "get_accounts",
18
20
  "get_default_account",
21
+ "get_validator_factory",
19
22
  ]
gltest/types.py CHANGED
@@ -9,6 +9,17 @@ from genlayer_py.types import (
9
9
  from typing import List, TypedDict, Dict, Any
10
10
 
11
11
 
12
+ class MockedLLMResponse(TypedDict):
13
+ """Maps prompts to responses"""
14
+
15
+ # Prompt -> raw JSON string response
16
+ nondet_exec_prompt: Dict[str, str]
17
+
18
+ # Principle -> expected boolean
19
+ eq_principle_prompt_comparative: Dict[str, bool]
20
+ eq_principle_prompt_non_comparative: Dict[str, bool]
21
+
22
+
12
23
  class ValidatorConfig(TypedDict):
13
24
  """Validator information."""
14
25
 
@@ -20,7 +31,7 @@ class ValidatorConfig(TypedDict):
20
31
 
21
32
 
22
33
  class TransactionContext(TypedDict, total=False):
23
- """Context for consensus operations."""
34
+ """Context for transaction operations."""
24
35
 
25
36
  validators: List[ValidatorConfig] # List to create virtual validators
26
37
  genvm_datetime: str # ISO format datetime string
@@ -0,0 +1,3 @@
1
+ from .validator_factory import ValidatorFactory, Validator, get_validator_factory
2
+
3
+ __all__ = ["ValidatorFactory", "Validator", "get_validator_factory"]
@@ -0,0 +1,136 @@
1
+ from gltest.types import MockedLLMResponse
2
+ from dataclasses import dataclass
3
+ from typing import Dict, Any, Optional, List
4
+ from copy import deepcopy
5
+
6
+
7
+ @dataclass
8
+ class Validator:
9
+ stake: int
10
+ provider: str
11
+ model: str
12
+ config: Dict[str, Any]
13
+ plugin: str
14
+ plugin_config: Dict[str, Any]
15
+
16
+ # Mock configuration
17
+ mock_enabled: bool
18
+ mock_llm_response: Optional[MockedLLMResponse]
19
+
20
+ def to_dict(self) -> Dict[str, Any]:
21
+ normal_config = {
22
+ "stake": self.stake,
23
+ "provider": self.provider,
24
+ "model": self.model,
25
+ "config": deepcopy(self.config),
26
+ "plugin": self.plugin,
27
+ "plugin_config": deepcopy(self.plugin_config),
28
+ }
29
+ if not self.mock_enabled:
30
+ return normal_config
31
+
32
+ mock = self.mock_llm_response or {}
33
+ mock_config = {
34
+ "response": mock.get("nondet_exec_prompt", {}),
35
+ "eq_principle_prompt_comparative": mock.get(
36
+ "eq_principle_prompt_comparative", {}
37
+ ),
38
+ "eq_principle_prompt_non_comparative": mock.get(
39
+ "eq_principle_prompt_non_comparative", {}
40
+ ),
41
+ }
42
+ return {
43
+ **normal_config,
44
+ "plugin_config": {
45
+ **self.plugin_config,
46
+ "mock_response": mock_config,
47
+ },
48
+ }
49
+
50
+ def batch_clone(self, count: int) -> List["Validator"]:
51
+ return [self.clone() for _ in range(count)]
52
+
53
+ def clone(self) -> "Validator":
54
+ return Validator(
55
+ stake=self.stake,
56
+ provider=self.provider,
57
+ model=self.model,
58
+ config=deepcopy(self.config),
59
+ plugin=self.plugin,
60
+ plugin_config=deepcopy(self.plugin_config),
61
+ mock_enabled=self.mock_enabled,
62
+ mock_llm_response=deepcopy(self.mock_llm_response),
63
+ )
64
+
65
+
66
+ class ValidatorFactory:
67
+ def __init__(self):
68
+ pass
69
+
70
+ def create_validator(
71
+ self,
72
+ stake: int,
73
+ provider: str,
74
+ model: str,
75
+ config: Dict[str, Any],
76
+ plugin: str,
77
+ plugin_config: Dict[str, Any],
78
+ ) -> Validator:
79
+ return Validator(
80
+ stake=stake,
81
+ provider=provider,
82
+ model=model,
83
+ config=deepcopy(config),
84
+ plugin=plugin,
85
+ plugin_config=deepcopy(plugin_config),
86
+ mock_enabled=False,
87
+ mock_llm_response=None,
88
+ )
89
+
90
+ def batch_create_validators(
91
+ self,
92
+ count: int,
93
+ stake: int,
94
+ provider: str,
95
+ model: str,
96
+ config: Dict[str, Any],
97
+ plugin: str,
98
+ plugin_config: Dict[str, Any],
99
+ ) -> List[Validator]:
100
+ return [
101
+ self.create_validator(
102
+ stake=stake,
103
+ provider=provider,
104
+ model=model,
105
+ config=config,
106
+ plugin=plugin,
107
+ plugin_config=plugin_config,
108
+ )
109
+ for _ in range(count)
110
+ ]
111
+
112
+ def create_mock_validator(self, mock_llm_response: MockedLLMResponse) -> Validator:
113
+ return Validator(
114
+ stake=8,
115
+ provider="openai",
116
+ model="gpt-4o",
117
+ config={"temperature": 0.75, "max_tokens": 500},
118
+ plugin="openai-compatible",
119
+ plugin_config={
120
+ "api_key_env_var": "OPENAIKEY",
121
+ "api_url": "https://api.openai.com",
122
+ },
123
+ mock_enabled=True,
124
+ mock_llm_response=deepcopy(mock_llm_response),
125
+ )
126
+
127
+ def batch_create_mock_validators(
128
+ self,
129
+ count: int,
130
+ mock_llm_response: MockedLLMResponse,
131
+ ) -> List[Validator]:
132
+ return [self.create_mock_validator(mock_llm_response) for _ in range(count)]
133
+
134
+
135
+ def get_validator_factory() -> ValidatorFactory:
136
+ return ValidatorFactory()
@@ -5,8 +5,15 @@ from pathlib import Path
5
5
  GLTEST_CONFIG_FILE = "gltest.config.yaml"
6
6
  DEFAULT_NETWORK = "localnet"
7
7
  PRECONFIGURED_NETWORKS = ["localnet", "studionet", "testnet_asimov"]
8
+ CHAINS = ["localnet", "studionet", "testnet_asimov"]
8
9
  DEFAULT_RPC_URL = SIMULATOR_JSON_RPC_URL
9
10
  DEFAULT_ENVIRONMENT = ".env"
10
11
  DEFAULT_CONTRACTS_DIR = Path("contracts")
11
12
  DEFAULT_ARTIFACTS_DIR = Path("artifacts")
12
13
  DEFAULT_NETWORK_ID = 61999
14
+
15
+ # Defaults per network
16
+ DEFAULT_WAIT_INTERVAL = 3000
17
+ DEFAULT_WAIT_RETRIES = 50
18
+ DEFAULT_TEST_WITH_MOCKS = False
19
+ DEFAULT_LEADER_ONLY = False
@@ -12,6 +12,13 @@ from gltest_cli.config.general import (
12
12
  )
13
13
  from gltest_cli.config.types import PluginConfig
14
14
  from gltest_cli.config.pytest_context import _pytest_context
15
+ from gltest_cli.config.constants import (
16
+ DEFAULT_WAIT_INTERVAL,
17
+ DEFAULT_WAIT_RETRIES,
18
+ DEFAULT_TEST_WITH_MOCKS,
19
+ DEFAULT_LEADER_ONLY,
20
+ CHAINS,
21
+ )
15
22
 
16
23
 
17
24
  def pytest_addoption(parser):
@@ -33,14 +40,14 @@ def pytest_addoption(parser):
33
40
  group.addoption(
34
41
  "--default-wait-interval",
35
42
  action="store",
36
- default=3000,
43
+ default=DEFAULT_WAIT_INTERVAL,
37
44
  help="Default interval (ms) between transaction receipt checks",
38
45
  )
39
46
 
40
47
  group.addoption(
41
48
  "--default-wait-retries",
42
49
  action="store",
43
- default=50,
50
+ default=DEFAULT_WAIT_RETRIES,
44
51
  help="Default number of retries for transaction receipt checks",
45
52
  )
46
53
 
@@ -61,17 +68,24 @@ def pytest_addoption(parser):
61
68
  group.addoption(
62
69
  "--test-with-mocks",
63
70
  action="store_true",
64
- default=False,
71
+ default=DEFAULT_TEST_WITH_MOCKS,
65
72
  help="Test with mocks",
66
73
  )
67
74
 
68
75
  group.addoption(
69
76
  "--leader-only",
70
77
  action="store_true",
71
- default=False,
78
+ default=DEFAULT_LEADER_ONLY,
72
79
  help="Run contracts in leader-only mode",
73
80
  )
74
81
 
82
+ group.addoption(
83
+ "--chain-type",
84
+ action="store",
85
+ default=None,
86
+ help=f"Chain type (possible values: {', '.join(CHAINS)})",
87
+ )
88
+
75
89
 
76
90
  def pytest_configure(config):
77
91
  try:
@@ -108,6 +122,7 @@ def pytest_configure(config):
108
122
  network = config.getoption("--network")
109
123
  test_with_mocks = config.getoption("--test-with-mocks")
110
124
  leader_only = config.getoption("--leader-only")
125
+ chain_type = config.getoption("--chain-type")
111
126
 
112
127
  plugin_config = PluginConfig()
113
128
  plugin_config.contracts_dir = (
@@ -122,6 +137,7 @@ def pytest_configure(config):
122
137
  plugin_config.network_name = network
123
138
  plugin_config.test_with_mocks = test_with_mocks
124
139
  plugin_config.leader_only = leader_only
140
+ plugin_config.chain_type = chain_type
125
141
 
126
142
  general_config.plugin_config = plugin_config
127
143
  except Exception as e:
@@ -148,6 +164,8 @@ def pytest_sessionstart(session):
148
164
  # Show available networks including preconfigured ones
149
165
  all_networks = general_config.get_networks_keys()
150
166
  logger.info(f" Available networks: {all_networks}")
167
+ logger.info(f" Selected chain type: {general_config.get_chain_type()}")
168
+ logger.info(f" Available chains: {', '.join(CHAINS)}")
151
169
  logger.info(f" Contracts directory: {general_config.get_contracts_dir()}")
152
170
  logger.info(f" Artifacts directory: {general_config.get_artifacts_dir()}")
153
171
  logger.info(f" Environment: {general_config.user_config.environment}")