@@ -73,7 +73,10 @@ def parse_args():
7373 help = 'Cooldown period in seconds between endpoint tests' )
7474 parser .add_argument ('--max-retries' , dest = 'max_retries' , type = int , default = 2 ,
7575 help = 'Maximum number of retries when an ab command fails' )
76-
76+ parser .add_argument ('--network' , dest = 'network' , default = "mainnet" ,
77+ choices = ['mainnet' , 'preprod' ],
78+ help = 'Network identifier for API requests' )
79+
7780 # Endpoint selection
7881 parser .add_argument ('--endpoints' , dest = 'selected_endpoints' , type = str ,
7982 help = 'Comma-separated list of endpoint names or paths to test (e.g. "Network Status,Block" or "/account/balance,/block"). If not specified, all endpoints will be tested.' )
@@ -104,6 +107,7 @@ def parse_args():
104107VERBOSE = args .verbose
105108COOLDOWN_PERIOD = args .cooldown
106109MAX_RETRIES = args .max_retries
110+ NETWORK_ID = args .network
107111
108112# Global logger variable
109113logger = None
@@ -200,7 +204,6 @@ def parse_ab_output(ab_stdout: str):
200204 requests_per_sec = 0.0
201205 mean_time = 0.0
202206 non_2xx_responses = 0
203- failed_requests = 0
204207
205208 # Parse each metric
206209 for line in ab_stdout .splitlines ():
@@ -234,13 +237,8 @@ def parse_ab_output(ab_stdout: str):
234237 parts = line .split ()
235238 if len (parts ) >= 3 :
236239 non_2xx_responses = int (parts [2 ])
237- # Parse Failed requests
238- elif "Failed requests:" in line :
239- parts = line .split ()
240- if len (parts ) >= 3 :
241- failed_requests = int (parts [2 ])
242240
243- return p95 , p99 , complete_requests , requests_per_sec , mean_time , non_2xx_responses , failed_requests
241+ return p95 , p99 , complete_requests , requests_per_sec , mean_time , non_2xx_responses
244242
245243###############################################################################
246244# PAYLOAD GENERATORS
@@ -252,14 +250,14 @@ def payload_network_status(*_):
252250 """
253251 /network/status does not really need CSV data.
254252 """
255- return dedent ("""\
256- {
257- "network_identifier": {
253+ return dedent (f """\
254+ {{
255+ "network_identifier": {{
258256 "blockchain": "cardano",
259- "network": "mainnet "
260- },
261- "metadata": {}
262- }
257+ "network": "{ NETWORK_ID } "
258+ }} ,
259+ "metadata": {{} }
260+ }}
263261 """ )
264262
265263def payload_account_balance (address , * _ ):
@@ -270,7 +268,7 @@ def payload_account_balance(address, *_):
270268 {{
271269 "network_identifier": {{
272270 "blockchain": "cardano",
273- "network": "mainnet "
271+ "network": "{ NETWORK_ID } "
274272 }},
275273 "account_identifier": {{
276274 "address": "{ address } "
@@ -286,7 +284,7 @@ def payload_account_coins(address, *_):
286284 {{
287285 "network_identifier": {{
288286 "blockchain": "cardano",
289- "network": "mainnet "
287+ "network": "{ NETWORK_ID } "
290288 }},
291289 "account_identifier": {{
292290 "address": "{ address } "
@@ -303,7 +301,7 @@ def payload_block(_addr, block_index, block_hash, *_):
303301 {{
304302 "network_identifier": {{
305303 "blockchain": "cardano",
306- "network": "mainnet "
304+ "network": "{ NETWORK_ID } "
307305 }},
308306 "block_identifier": {{
309307 "index": { block_index } ,
@@ -320,7 +318,7 @@ def payload_block_transaction(_addr, block_index, block_hash, _tx_size, _ttl, tr
320318 {{
321319 "network_identifier": {{
322320 "blockchain": "cardano",
323- "network": "mainnet "
321+ "network": "{ NETWORK_ID } "
324322 }},
325323 "block_identifier": {{
326324 "index": { block_index } ,
@@ -332,22 +330,38 @@ def payload_block_transaction(_addr, block_index, block_hash, _tx_size, _ttl, tr
332330 }}
333331 """ )
334332
335- def payload_search_transactions (_addr , _block_index , _block_hash , _tx_size , _ttl , transaction_hash ):
333+ def payload_search_transactions_by_hash (_addr , _block_index , _block_hash , _tx_size , _ttl , transaction_hash ):
336334 """
337335 /search/transactions requires transaction_hash.
338336 """
339337 return dedent (f"""\
340338 {{
341339 "network_identifier": {{
342340 "blockchain": "cardano",
343- "network": "mainnet "
341+ "network": "{ NETWORK_ID } "
344342 }},
345343 "transaction_identifier": {{
346344 "hash": "{ transaction_hash } "
347345 }}
348346 }}
349347 """ )
350348
349+ def payload_search_transactions_by_address (address , * _ ):
350+ """
351+ /search/transactions with account_identifier (address-based query).
352+ """
353+ return dedent (f"""\
354+ {{
355+ "network_identifier": {{
356+ "blockchain": "cardano",
357+ "network": "{ NETWORK_ID } "
358+ }},
359+ "account_identifier": {{
360+ "address": "{ address } "
361+ }}
362+ }}
363+ """ )
364+
351365def payload_construction_metadata (_addr , _block_index , _block_hash , transaction_size , relative_ttl , _tx_hash ):
352366 """
353367 /construction/metadata requires transaction_size, relative_ttl
@@ -356,7 +370,7 @@ def payload_construction_metadata(_addr, _block_index, _block_hash, transaction_
356370 {{
357371 "network_identifier": {{
358372 "blockchain": "cardano",
359- "network": "mainnet "
373+ "network": "{ NETWORK_ID } "
360374 }},
361375 "options": {{
362376 "transaction_size": { transaction_size } ,
@@ -368,15 +382,16 @@ def payload_construction_metadata(_addr, _block_index, _block_hash, transaction_
368382###############################################################################
369383# ENDPOINT DEFINITION
370384###############################################################################
371- # We'll define 7 endpoints with: (Name, Path, Payload Generator Function)
385+ # We'll define 8 endpoints with: (Name, Path, Payload Generator Function)
372386ENDPOINTS = [
373- ("Network Status" , "/network/status" , payload_network_status ),
374- ("Account Balance" , "/account/balance" , payload_account_balance ),
375- ("Account Coins" , "/account/coins" , payload_account_coins ),
376- ("Block" , "/block" , payload_block ),
377- ("Block Transaction" , "/block/transaction" , payload_block_transaction ),
378- ("Search Transactions" , "/search/transactions" , payload_search_transactions ),
379- ("Construction Metadata" ,"/construction/metadata" , payload_construction_metadata ),
387+ ("Network Status" , "/network/status" , payload_network_status ),
388+ ("Account Balance" , "/account/balance" , payload_account_balance ),
389+ ("Account Coins" , "/account/coins" , payload_account_coins ),
390+ ("Block" , "/block" , payload_block ),
391+ ("Block Transaction" , "/block/transaction" , payload_block_transaction ),
392+ ("Search Transactions by Hash" , "/search/transactions" , payload_search_transactions_by_hash ),
393+ ("Search Transactions by Address" , "/search/transactions" , payload_search_transactions_by_address ),
394+ ("Construction Metadata" , "/construction/metadata" , payload_construction_metadata ),
380395]
381396
382397###############################################################################
@@ -493,7 +508,13 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row):
493508 # Example CSV columns:
494509 # address, block_index, block_hash, transaction_size, relative_ttl, transaction_hash
495510 #
496- # Adjust if your CSV has different columns or order.
511+ # Validate CSV structure
512+ if len (csv_row ) != 6 :
513+ logger .error (f"Invalid CSV format for endpoint { endpoint_name } ." )
514+ logger .error (f"Expected 6 columns (address, block_index, block_hash, transaction_size, relative_ttl, transaction_hash)" )
515+ logger .error (f"Got { len (csv_row )} columns: { csv_row } " )
516+ sys .exit (1 )
517+
497518 address , block_index , block_hash , transaction_size , relative_ttl , transaction_hash = csv_row
498519
499520 # Generate JSON payload
@@ -546,9 +567,13 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row):
546567 if VERBOSE :
547568 # Format each line with box borders
548569 if line_stripped :
549- # Fixed width approach
570+ # Truncate long lines to fit box width
571+ max_content_width = box_width - 4 # 2 for borders, 2 for padding
572+ if len (line_stripped ) > max_content_width :
573+ line_stripped = line_stripped [:max_content_width - 3 ] + "..."
550574 content = "│ " + line_stripped
551- logger .debug (content + " " * (box_width - len (content ) - 1 ) + "│" )
575+ padding = " " * (box_width - len (content ) - 1 )
576+ logger .debug (content + padding + "│" )
552577 else :
553578 logger .debug ("│" + " " * (box_width - 2 ) + "│" )
554579 proc .stdout .close ()
@@ -615,7 +640,7 @@ def test_endpoint(endpoint_name, endpoint_path, payload_func, csv_row):
615640 break
616641
617642 # Parse p95, p99 and additional metrics from the captured stdout
618- p95 , p99 , complete_requests , requests_per_sec , mean_time , non_2xx_responses , failed_requests = parse_ab_output (ab_output )
643+ p95 , p99 , complete_requests , requests_per_sec , mean_time , non_2xx_responses = parse_ab_output (ab_output )
619644
620645 # Calculate error rate as a percentage
621646 error_rate = 0.0
@@ -748,8 +773,9 @@ def main():
748773 logger .debug (f"Data row: { ', ' .join (rows [0 ]) if rows else 'No data available' } " )
749774 logger .debug (f"{ '-' * 80 } " )
750775
751- # For demonstration, pick the *first* row only.
752- # If you want to test multiple rows, you can loop here or adapt logic.
776+ # Use only the first CSV row for consistency across all endpoints and concurrency levels.
777+ # This ensures that performance comparisons are based on the same data characteristics.
778+ # All endpoints will be tested with identical input data to measure their relative performance.
753779 if not rows :
754780 # Use logger.error and exit
755781 logger .error ("No CSV data after skipping header." )
@@ -911,8 +937,8 @@ def main():
911937 logger .warning ("=" * 80 )
912938
913939 current_endpoint = None
914- if 'ep_name' in locals () and 'c' in locals () :
915- current_endpoint = f" { ep_name } at concurrency level { c } "
940+ if 'ep_name' in locals ():
941+ current_endpoint = ep_name
916942
917943 if current_endpoint :
918944 logger .warning (f"Test was interrupted while testing: { current_endpoint } " )
0 commit comments