genlayer-test 2.1.0__py3-none-any.whl → 2.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -112,17 +112,29 @@ The GenLayer Testing Suite can be configured using an optional but recommended `
112
112
  networks:
113
113
  default: localnet # Default network to use
114
114
 
115
- localnet: # Local development network configuration
115
+ localnet: # Local development network configuration (pre-configured)
116
116
  url: "http://127.0.0.1:4000/api"
117
117
  leader_only: false # Set to true to run all contracts in leader-only mode by default
118
118
 
119
- testnet_asimov: # Test network configuration
120
- id: 4221
121
- url: "http://34.32.169.58:9151"
119
+ studionet: # Studio network configuration (pre-configured)
120
+ # Pre-configured network - accounts are automatically generated
121
+ # You can override any settings if needed
122
+
123
+ testnet_asimov: # Test network configuration (pre-configured)
124
+ # Pre-configured network - requires accounts to be specified
122
125
  accounts:
123
126
  - "${ACCOUNT_PRIVATE_KEY_1}"
124
127
  - "${ACCOUNT_PRIVATE_KEY_2}"
125
128
  - "${ACCOUNT_PRIVATE_KEY_3}"
129
+ from: "${ACCOUNT_PRIVATE_KEY_2}" # Optional: specify default account
130
+
131
+ custom_network: # Custom network configuration
132
+ id: 1234
133
+ url: "http://custom.network:8545"
134
+ accounts:
135
+ - "${CUSTOM_ACCOUNT_1}"
136
+ - "${CUSTOM_ACCOUNT_2}"
137
+ from: "${CUSTOM_ACCOUNT_1}" # Optional: specify default account
126
138
 
127
139
  paths:
128
140
  contracts: "contracts" # Path to your contracts directory
@@ -135,14 +147,31 @@ Key configuration sections:
135
147
 
136
148
  1. **Networks**: Define different network environments
137
149
  - `default`: Specifies which network to use by default
150
+ - **Pre-configured Networks**:
151
+ - `localnet`: Local development network with auto-generated test accounts
152
+ - `studionet`: GenLayer Studio network with auto-generated test accounts
153
+ - `testnet_asimov`: Public testnet (requires account configuration)
138
154
  - Network configurations can include:
139
- - `url`: The RPC endpoint for the network
140
- - `id`: Chain ID
155
+ - `url`: The RPC endpoint for the network (optional for pre-configured networks)
156
+ - `id`: Chain ID (optional for pre-configured networks)
141
157
  - `accounts`: List of account private keys (using environment variables)
158
+ - `from`: Specify which account to use as the default for transactions (optional, defaults to first account)
142
159
  - `leader_only`: Leader only mode
143
- - Special case for `localnet`:
144
- - If a network is named `localnet`, missing fields will be filled with default values
145
- - For all other network names, `id`, `url`, and `accounts` are required fields
160
+ - For custom networks (non-pre-configured), `id`, `url`, and `accounts` are required fields
161
+
162
+ **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.
163
+
164
+ **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.
165
+
166
+ Example:
167
+ ```yaml
168
+ testnet_asimov:
169
+ accounts:
170
+ - "${DEPLOYER_KEY}" # accounts[0]
171
+ - "${USER_KEY}" # accounts[1]
172
+ - "${ADMIN_KEY}" # accounts[2]
173
+ from: "${ADMIN_KEY}" # Use ADMIN_KEY as default instead of DEPLOYER_KEY
174
+ ```
146
175
 
147
176
  2. **Paths**: Define important directory paths
148
177
  - `contracts`: Location of your contract files
@@ -191,11 +220,23 @@ $ gltest --contracts-dir <path_to_contracts>
191
220
  # Run tests on localnet (default)
192
221
  $ gltest --network localnet
193
222
 
194
- # Run tests on testnet
223
+ # Run tests on studionet
224
+ $ gltest --network studionet
225
+
226
+ # Run tests on testnet (requires account configuration)
195
227
  $ gltest --network testnet_asimov
228
+
229
+ # Run tests on a custom network
230
+ $ gltest --network custom_network
196
231
  ```
197
232
  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.
198
233
 
234
+ **Pre-configured Networks**:
235
+ - `localnet` and `studionet`: Work out of the box with auto-generated test accounts
236
+ - `testnet_asimov`: Requires account configuration in `gltest.config.yaml`
237
+
238
+ When using `testnet_asimov` without proper account configuration, you'll receive a clear error message directing you to configure accounts in your config file.
239
+
199
240
  7. Run tests with a custom RPC url
200
241
  ```bash
201
242
  $ gltest --rpc-url <custom_rpc_url>
@@ -1,4 +1,4 @@
1
- genlayer_test-2.1.0.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
1
+ genlayer_test-2.2.0.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
2
2
  gltest/__init__.py,sha256=qoBV3IgDJr8uh9262XsWNMhi-ilkSgMqKVC9FVMk7cw,372
3
3
  gltest/accounts.py,sha256=HUmWguJMolggQaZNRPw-LGlRlQCjLLdUanKRowMv6pI,812
4
4
  gltest/assertions.py,sha256=0dEk0VxcHK4I7GZPHxJmz-2jaA60V499gOSR74rZbfM,1748
@@ -19,15 +19,15 @@ gltest/contracts/utils.py,sha256=TTXgcXn9BuRIlKJrjwmU7R3l1IgXsXk2luM-r3lfbbg,296
19
19
  gltest/helpers/__init__.py,sha256=I7HiTu_H7_hP65zY6Wl02r-5eAMr2eZvqBVmusuQLX4,180
20
20
  gltest/helpers/fixture_snapshot.py,sha256=bMgvlEVQBGIQzj7NOyosXWlphI1H2C1o75Zo0C-kGfQ,1931
21
21
  gltest/helpers/take_snapshot.py,sha256=-QkaBvFG4ZsNKv_nCSEsy5Ze1pICOHxVhReSeQmZUlY,1276
22
- gltest_cli/logging.py,sha256=YRWIGwCJIkaB747oQvmS2tzF-B7zymdEMJznrlfyQYA,1245
22
+ gltest_cli/logging.py,sha256=WXVhfq9vT6FtV_jxDqGEGia1ZWSIUKAfmWRnZd_gWQk,1266
23
23
  gltest_cli/main.py,sha256=Ti2-0Ev1x5_cM0D1UKqdgaDt80CDHEQGtdRne2qLm4M,53
24
24
  gltest_cli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- gltest_cli/config/constants.py,sha256=3iSK337AeupyYl_6Sf8MR_o91XfLmul8m1rVmi3Fvmo,342
25
+ gltest_cli/config/constants.py,sha256=LG74S_65OXhqweL__PGRV6Ms8UkMFYSeK7Sq88viBis,411
26
26
  gltest_cli/config/general.py,sha256=ezpoGsT8grO9zQH6RugV14b1GzeFt-htYToHQBJhNvY,186
27
- gltest_cli/config/plugin.py,sha256=sByVyPt9IikLFg4PiVe7xFrO56mVwyDdn4nzYa_HTNo,5411
27
+ gltest_cli/config/plugin.py,sha256=TsK3JnKKz_9azASHcKKSY5ohCl5TmxVUk_YEGIc4A28,6469
28
28
  gltest_cli/config/pytest_context.py,sha256=Ze8JSkrwMTCE8jIhpzU_71CEXg92SiEPvSgNTp-gbS4,243
29
- gltest_cli/config/types.py,sha256=KDAA_vNqI7o_sYMj21ks3WaIXGrbLVb76E17TSlWUwI,7241
30
- gltest_cli/config/user.py,sha256=WNX_Wi2eJpjW0UstQuQiDjzRpOIOwx9iiXOx4ntt93U,8759
29
+ gltest_cli/config/types.py,sha256=0x8I-Xvzul9lGkPL0GusxJPhJCNajx-ghm0N-V5P594,8206
30
+ gltest_cli/config/user.py,sha256=SXGWQnA6422vRhQ9Xwxuzts7ZARcBIJZcRFSxN56PV4,9970
31
31
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  tests/conftest.py,sha256=RKdoE5_zcMimeojAoA_GSFI9du4pMzMi1vZ1njtfoAs,28
33
33
  tests/examples/contracts/football_prediction_market.py,sha256=9xwU8f3q73Hae-ByHy_wauhMPLRnLZd4XKNrClnjOJM,3248
@@ -67,10 +67,10 @@ tests/gltest/assertions/test_assertions.py,sha256=qzVrOdOM4xYtIy1sFHVAD_-naDHOeq
67
67
  tests/gltest_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  tests/gltest_cli/config/test_config_integration.py,sha256=vPTzr3_h9UMw7m72HogBJE2ZPhRduXoLSq18Z7FoCWQ,10105
69
69
  tests/gltest_cli/config/test_general_config.py,sha256=UHtSwVnso-ZwNtYM0Z4v2sCLKwyrVbHlk6b1leVfV84,14703
70
- tests/gltest_cli/config/test_plugin.py,sha256=87kJpSYcWbNuKDqfc_jiN7hoRnFkMEnOOTINwuXKBY0,7981
70
+ tests/gltest_cli/config/test_plugin.py,sha256=COrEK5tHP1BSzanWbZHmN3EQgE9VuTcPvB95pgOvKS4,7974
71
71
  tests/gltest_cli/config/test_user.py,sha256=JxR655oUFoM9quWQO68CVPKRpT0TMpzS3bF6j6NWyT4,14401
72
- genlayer_test-2.1.0.dist-info/METADATA,sha256=Mj2oQbtObBd2TgEWNPGYIyZKmfnMxswurXuu2tFHas4,24978
73
- genlayer_test-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
- genlayer_test-2.1.0.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
75
- genlayer_test-2.1.0.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
76
- genlayer_test-2.1.0.dist-info/RECORD,,
72
+ genlayer_test-2.2.0.dist-info/METADATA,sha256=FFJ-Iqp1o4mrYhzyYrvGU6N3Fgn0KcfZWhnQjXlXKC0,27320
73
+ genlayer_test-2.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
+ genlayer_test-2.2.0.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
75
+ genlayer_test-2.2.0.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
76
+ genlayer_test-2.2.0.dist-info/RECORD,,
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
 
5
5
  GLTEST_CONFIG_FILE = "gltest.config.yaml"
6
6
  DEFAULT_NETWORK = "localnet"
7
+ PRECONFIGURED_NETWORKS = ["localnet", "studionet", "testnet_asimov"]
7
8
  DEFAULT_RPC_URL = SIMULATOR_JSON_RPC_URL
8
9
  DEFAULT_ENVIRONMENT = ".env"
9
10
  DEFAULT_CONTRACTS_DIR = Path("contracts")
@@ -1,3 +1,4 @@
1
+ import pytest
1
2
  from pathlib import Path
2
3
  import shutil
3
4
  from gltest_cli.logging import logger
@@ -73,85 +74,103 @@ def pytest_addoption(parser):
73
74
 
74
75
 
75
76
  def pytest_configure(config):
76
- general_config = get_general_config()
77
-
78
- # Handle user config from gltest.config.yaml
79
- if not user_config_exists():
80
- logger.warning(
81
- "File `gltest.config.yaml` not found in the current directory, using default config"
77
+ try:
78
+ general_config = get_general_config()
79
+
80
+ network_name = config.getoption("--network")
81
+
82
+ if not user_config_exists():
83
+ logger.warning(
84
+ "File `gltest.config.yaml` not found in the current directory, using default config, create a `gltest.config.yaml` file to manage multiple networks"
85
+ )
86
+ user_config = get_default_user_config()
87
+
88
+ # Special handling for testnet_asimov - check if accounts are configured
89
+ if network_name == "testnet_asimov":
90
+ logger.error(
91
+ "For testnet_asimov, you need to configure accounts in gltest.config.yaml, see https://docs.genlayer.com/api-references/genlayer-test"
92
+ )
93
+ pytest.exit("gltest configuration error")
94
+ else:
95
+ logger.info(
96
+ "File `gltest.config.yaml` found in the current directory, using it"
97
+ )
98
+ user_config = load_user_config("gltest.config.yaml")
99
+
100
+ general_config.user_config = user_config
101
+
102
+ # Handle plugin config from command line
103
+ contracts_dir = config.getoption("--contracts-dir")
104
+ artifacts_dir = config.getoption("--artifacts-dir")
105
+ default_wait_interval = config.getoption("--default-wait-interval")
106
+ default_wait_retries = config.getoption("--default-wait-retries")
107
+ rpc_url = config.getoption("--rpc-url")
108
+ network = config.getoption("--network")
109
+ test_with_mocks = config.getoption("--test-with-mocks")
110
+ leader_only = config.getoption("--leader-only")
111
+
112
+ plugin_config = PluginConfig()
113
+ plugin_config.contracts_dir = (
114
+ Path(contracts_dir) if contracts_dir is not None else None
82
115
  )
83
- logger.info("Create a `gltest.config.yaml` file to manage multiple networks")
84
- user_config = get_default_user_config()
85
- else:
86
- logger.info(
87
- "File `gltest.config.yaml` found in the current directory, using it"
116
+ plugin_config.artifacts_dir = (
117
+ Path(artifacts_dir) if artifacts_dir is not None else None
88
118
  )
89
- user_config = load_user_config("gltest.config.yaml")
90
-
91
- general_config.user_config = user_config
92
-
93
- # Handle plugin config from command line
94
- contracts_dir = config.getoption("--contracts-dir")
95
- artifacts_dir = config.getoption("--artifacts-dir")
96
- default_wait_interval = config.getoption("--default-wait-interval")
97
- default_wait_retries = config.getoption("--default-wait-retries")
98
- rpc_url = config.getoption("--rpc-url")
99
- network = config.getoption("--network")
100
- test_with_mocks = config.getoption("--test-with-mocks")
101
- leader_only = config.getoption("--leader-only")
102
-
103
- plugin_config = PluginConfig()
104
- plugin_config.contracts_dir = (
105
- Path(contracts_dir) if contracts_dir is not None else None
106
- )
107
- plugin_config.artifacts_dir = (
108
- Path(artifacts_dir) if artifacts_dir is not None else None
109
- )
110
- plugin_config.default_wait_interval = int(default_wait_interval)
111
- plugin_config.default_wait_retries = int(default_wait_retries)
112
- plugin_config.rpc_url = rpc_url
113
- plugin_config.network_name = network
114
- plugin_config.test_with_mocks = test_with_mocks
115
- plugin_config.leader_only = leader_only
119
+ plugin_config.default_wait_interval = int(default_wait_interval)
120
+ plugin_config.default_wait_retries = int(default_wait_retries)
121
+ plugin_config.rpc_url = rpc_url
122
+ plugin_config.network_name = network
123
+ plugin_config.test_with_mocks = test_with_mocks
124
+ plugin_config.leader_only = leader_only
116
125
 
117
- general_config.plugin_config = plugin_config
126
+ general_config.plugin_config = plugin_config
127
+ except Exception as e:
128
+ logger.error(f"Gltest configure error: {e}")
129
+ pytest.exit("gltest configuration error")
118
130
 
119
131
 
120
132
  def pytest_sessionstart(session):
121
- general_config = get_general_config()
122
-
123
- artifacts_dir = general_config.get_artifacts_dir()
124
- if artifacts_dir and artifacts_dir.exists():
125
- logger.info(f"Clearing artifacts directory: {artifacts_dir}")
126
- try:
127
- shutil.rmtree(artifacts_dir)
133
+ try:
134
+ general_config = get_general_config()
135
+ artifacts_dir = general_config.get_artifacts_dir()
136
+ if artifacts_dir and artifacts_dir.exists():
137
+ logger.info(f"Clearing artifacts directory: {artifacts_dir}")
138
+ try:
139
+ shutil.rmtree(artifacts_dir)
140
+ artifacts_dir.mkdir(parents=True, exist_ok=True)
141
+ except Exception as e:
142
+ logger.warning(f"Failed to clear artifacts directory: {e}")
143
+ elif artifacts_dir:
128
144
  artifacts_dir.mkdir(parents=True, exist_ok=True)
129
- except Exception as e:
130
- logger.warning(f"Failed to clear artifacts directory: {e}")
131
- elif artifacts_dir:
132
- artifacts_dir.mkdir(parents=True, exist_ok=True)
133
-
134
- logger.info("Using the following configuration:")
135
- logger.info(f" RPC URL: {general_config.get_rpc_url()}")
136
- logger.info(f" Selected Network: {general_config.get_network_name()}")
137
- logger.info(
138
- f" Available networks: {list(general_config.user_config.networks.keys())}"
139
- )
140
- logger.info(f" Contracts directory: {general_config.get_contracts_dir()}")
141
- logger.info(f" Artifacts directory: {general_config.get_artifacts_dir()}")
142
- logger.info(f" Environment: {general_config.user_config.environment}")
143
- logger.info(
144
- f" Default wait interval: {general_config.get_default_wait_interval()} ms"
145
- )
146
- logger.info(f" Default wait retries: {general_config.get_default_wait_retries()}")
147
- logger.info(f" Test with mocks: {general_config.get_test_with_mocks()}")
148
-
149
- if general_config.get_leader_only() and not general_config.check_studio_based_rpc():
150
- logger.warning(
151
- "Leader only mode: True (enabled on non-studio network - will have no effect)"
145
+ logger.info("Using the following configuration:")
146
+ logger.info(f" RPC URL: {general_config.get_rpc_url()}")
147
+ logger.info(f" Selected Network: {general_config.get_network_name()}")
148
+ # Show available networks including preconfigured ones
149
+ all_networks = general_config.get_networks_keys()
150
+ logger.info(f" Available networks: {all_networks}")
151
+ logger.info(f" Contracts directory: {general_config.get_contracts_dir()}")
152
+ logger.info(f" Artifacts directory: {general_config.get_artifacts_dir()}")
153
+ logger.info(f" Environment: {general_config.user_config.environment}")
154
+ logger.info(
155
+ f" Default wait interval: {general_config.get_default_wait_interval()} ms"
156
+ )
157
+ logger.info(
158
+ f" Default wait retries: {general_config.get_default_wait_retries()}"
152
159
  )
153
- else:
154
- logger.info(f" Leader only mode: {general_config.get_leader_only()}")
160
+ logger.info(f" Test with mocks: {general_config.get_test_with_mocks()}")
161
+
162
+ if (
163
+ general_config.get_leader_only()
164
+ and not general_config.check_studio_based_rpc()
165
+ ):
166
+ logger.warning(
167
+ "Leader only mode: True (enabled on non-studio network - will have no effect)"
168
+ )
169
+ else:
170
+ logger.info(f" Leader only mode: {general_config.get_leader_only()}")
171
+ except Exception as e:
172
+ logger.error(f"Gltest session start error: {e}")
173
+ pytest.exit("gltest session start error")
155
174
 
156
175
 
157
176
  def pytest_runtest_setup(item):
@@ -2,14 +2,10 @@ from enum import Enum
2
2
  from dataclasses import dataclass, field
3
3
  from pathlib import Path
4
4
  from typing import Dict, List, Optional
5
- from genlayer_py.chains import localnet, testnet_asimov
5
+ from genlayer_py.chains import localnet, studionet, testnet_asimov
6
6
  from genlayer_py.types import GenLayerChain
7
7
  from urllib.parse import urlparse
8
-
9
-
10
- class NetworkConfig(str, Enum):
11
- LOCALNET = "localnet"
12
- TESTNET_ASIMOV = "testnet_asimov"
8
+ from gltest_cli.config.constants import PRECONFIGURED_NETWORKS
13
9
 
14
10
 
15
11
  @dataclass
@@ -111,10 +107,17 @@ class GeneralConfig:
111
107
  artifacts_dir = self.get_artifacts_dir()
112
108
  return artifacts_dir / "analysis"
113
109
 
110
+ def get_networks_keys(self) -> List[str]:
111
+ return list(self.user_config.networks.keys())
112
+
114
113
  def get_rpc_url(self) -> str:
115
114
  if self.plugin_config.rpc_url is not None:
116
115
  return self.plugin_config.rpc_url
117
116
  network_name = self.get_network_name()
117
+ if network_name not in self.user_config.networks:
118
+ raise ValueError(
119
+ f"Unknown network: {network_name}, possible values: {self.get_networks_keys()}"
120
+ )
118
121
  return self.user_config.networks[network_name].url
119
122
 
120
123
  def get_default_account_key(self, network_name: Optional[str] = None) -> str:
@@ -128,16 +131,37 @@ class GeneralConfig:
128
131
  return self.user_config.networks[self.user_config.default_network].accounts
129
132
 
130
133
  def get_chain(self) -> GenLayerChain:
134
+ network_name = self.get_network_name()
135
+ if network_name not in self.user_config.networks:
136
+ raise ValueError(
137
+ f"Unknown network: {network_name}, possible values: {self.get_networks_keys()}"
138
+ )
139
+
140
+ # Reserved network names
141
+ chain_map_by_name = {
142
+ "localnet": localnet,
143
+ "studionet": studionet,
144
+ "testnet_asimov": testnet_asimov,
145
+ }
146
+
147
+ if network_name in chain_map_by_name:
148
+ return chain_map_by_name[network_name]
149
+
150
+ if network_name in PRECONFIGURED_NETWORKS:
151
+ raise ValueError(
152
+ f"Network {network_name} should be handled by reserved mapping"
153
+ )
154
+
155
+ # Custom networks
131
156
  chain_map_by_id = {
132
157
  61999: localnet,
133
158
  4221: testnet_asimov,
134
159
  }
135
- network_name = self.get_network_name()
136
160
  network_id = self.user_config.networks[network_name].id
137
161
  if network_id not in chain_map_by_id:
138
162
  known = ", ".join(map(str, chain_map_by_id.keys()))
139
163
  raise ValueError(
140
- f"Unknown network: {network_name}, possible values: {known}"
164
+ f"Unknown network id: {network_id}, possible values: {known}"
141
165
  )
142
166
  return chain_map_by_id[network_id]
143
167
 
gltest_cli/config/user.py CHANGED
@@ -8,12 +8,12 @@ from gltest.accounts import create_accounts
8
8
  from gltest_cli.config.constants import (
9
9
  GLTEST_CONFIG_FILE,
10
10
  DEFAULT_NETWORK,
11
- DEFAULT_RPC_URL,
12
11
  DEFAULT_ENVIRONMENT,
13
12
  DEFAULT_CONTRACTS_DIR,
14
13
  DEFAULT_ARTIFACTS_DIR,
15
- DEFAULT_NETWORK_ID,
14
+ PRECONFIGURED_NETWORKS,
16
15
  )
16
+ from genlayer_py.chains import localnet, studionet, testnet_asimov
17
17
  from gltest_cli.config.types import UserConfig, NetworkConfigData, PathConfig
18
18
 
19
19
  VALID_ROOT_KEYS = ["networks", "paths", "environment"]
@@ -26,16 +26,32 @@ def get_default_user_config() -> UserConfig:
26
26
  accounts = create_accounts(n_accounts=10)
27
27
  accounts_private_keys = [account.key.hex() for account in accounts]
28
28
 
29
+ networks = {
30
+ "localnet": NetworkConfigData(
31
+ id=localnet.id,
32
+ url=localnet.rpc_urls["default"]["http"][0],
33
+ accounts=accounts_private_keys,
34
+ from_account=accounts_private_keys[0],
35
+ leader_only=False,
36
+ ),
37
+ "studionet": NetworkConfigData(
38
+ id=studionet.id,
39
+ url=studionet.rpc_urls["default"]["http"][0],
40
+ accounts=accounts_private_keys,
41
+ from_account=accounts_private_keys[0],
42
+ leader_only=False,
43
+ ),
44
+ "testnet_asimov": NetworkConfigData(
45
+ id=testnet_asimov.id,
46
+ url=testnet_asimov.rpc_urls["default"]["http"][0],
47
+ accounts=None,
48
+ from_account=None,
49
+ leader_only=False,
50
+ ),
51
+ }
52
+
29
53
  return UserConfig(
30
- networks={
31
- DEFAULT_NETWORK: NetworkConfigData(
32
- id=DEFAULT_NETWORK_ID,
33
- url=DEFAULT_RPC_URL,
34
- accounts=accounts_private_keys,
35
- from_account=accounts_private_keys[0],
36
- leader_only=False,
37
- ),
38
- },
54
+ networks=networks,
39
55
  paths=PathConfig(
40
56
  contracts=DEFAULT_CONTRACTS_DIR, artifacts=DEFAULT_ARTIFACTS_DIR
41
57
  ),
@@ -46,11 +62,26 @@ def get_default_user_config() -> UserConfig:
46
62
 
47
63
  def resolve_env_vars(obj):
48
64
  if isinstance(obj, str):
49
- return re.sub(
50
- r"\${(\w+)}",
51
- lambda m: os.getenv(m.group(1), f"<UNSET:{m.group(1)}>"),
52
- obj,
53
- )
65
+
66
+ def replace_env_var(m):
67
+ try:
68
+ var_name = m.group(1)
69
+ if var_name is None:
70
+ raise ValueError(
71
+ f"Invalid environment variable pattern: {m.group(0)}"
72
+ )
73
+ var_value = os.getenv(var_name)
74
+ if var_value is None:
75
+ raise ValueError(
76
+ f"Environment variable {var_name} is not set, please check your environment file"
77
+ )
78
+ return var_value
79
+ except IndexError as e:
80
+ raise ValueError(
81
+ f"Invalid environment variable pattern: {m.group(0)}"
82
+ ) from e
83
+
84
+ return re.sub(r"\${(\w+)}", replace_env_var, obj)
54
85
  elif isinstance(obj, dict):
55
86
  return {k: resolve_env_vars(v) for k, v in obj.items()}
56
87
  elif isinstance(obj, list):
@@ -90,8 +121,8 @@ def validate_network_config(network_name: str, network_config: dict):
90
121
  ):
91
122
  raise ValueError(f"network {network_name} leader_only must be a boolean")
92
123
 
93
- # For non-default networks, url and accounts are required
94
- if network_name != DEFAULT_NETWORK:
124
+ # For non-preconfigured networks, url and accounts are required
125
+ if network_name not in PRECONFIGURED_NETWORKS:
95
126
  if "id" not in network_config:
96
127
  raise ValueError(f"network {network_name} must have an id")
97
128
  if "url" not in network_config:
@@ -139,7 +170,6 @@ def validate_raw_user_config(config: dict):
139
170
  def load_user_config(path: str) -> UserConfig:
140
171
  with open(path, "r") as f:
141
172
  raw_config = yaml.safe_load(f) or {}
142
-
143
173
  validate_raw_user_config(raw_config)
144
174
  load_dotenv(
145
175
  dotenv_path=raw_config.get("environment", DEFAULT_ENVIRONMENT), override=True
@@ -176,8 +206,8 @@ def _get_overridden_networks(raw_config: dict) -> tuple[dict, str]:
176
206
 
177
207
  networks_config = {}
178
208
  for network_name, network_config in networks.items():
179
- if network_name == DEFAULT_NETWORK:
180
- networks_config[network_name] = default_config.networks[DEFAULT_NETWORK]
209
+ if network_name in PRECONFIGURED_NETWORKS:
210
+ networks_config[network_name] = default_config.networks[network_name]
181
211
  if network_config is None:
182
212
  continue
183
213
 
gltest_cli/logging.py CHANGED
@@ -31,13 +31,14 @@ class ColoredFormatter(logging.Formatter):
31
31
 
32
32
  def setup_logger():
33
33
  logger = logging.getLogger("gltest_cli")
34
- logger.setLevel(logging.DEBUG)
34
+ log_level = logging.INFO
35
+ logger.setLevel(log_level)
35
36
 
36
37
  if logger.handlers:
37
38
  return logger
38
39
 
39
40
  console_handler = logging.StreamHandler()
40
- console_handler.setLevel(logging.DEBUG)
41
+ console_handler.setLevel(log_level)
41
42
 
42
43
  formatter = ColoredFormatter("%(levelname)s: %(message)s")
43
44
  console_handler.setFormatter(formatter)
@@ -123,12 +123,8 @@ def test_network_testnet(pytester):
123
123
  "--network=testnet_asimov", "--rpc-url=http://test.example.com:9151", "-v"
124
124
  )
125
125
 
126
- result.stdout.fnmatch_lines(
127
- [
128
- "*::test_network PASSED*",
129
- ]
130
- )
131
- assert result.ret == 0
126
+ # The test should exit with an error code when testnet_asimov is used without accounts
127
+ assert result.ret != 0
132
128
 
133
129
 
134
130
  def test_artifacts_dir(pytester):