1
1
import datetime
2
2
import json
3
+ import math
3
4
import random
4
5
import time
5
6
from collections import defaultdict
6
7
from dataclasses import dataclass , field
7
8
from enum import Enum , IntEnum
8
9
from functools import cache
9
10
from pathlib import Path
10
- from typing import Dict , Iterable , List , Optional , Set , Tuple
11
+ from typing import Dict , Iterable , List , Optional , Tuple
11
12
12
13
import requests
13
14
from osrd_schemas .switch_type import builtin_node_types
@@ -119,9 +120,9 @@ def run_test(
119
120
if rolling_stock_name is None
120
121
else get_rolling_stock (editoast_url , rolling_stock_name )
121
122
)
122
- path , path_length = make_valid_path (infra )
123
- if random .randint (0 , 1 ) == 0 :
124
- test_new_train (editoast_url , scenario , rolling_stock .name , path_length , infra_name , path , prelude )
123
+ path = make_valid_path (infra )
124
+ if random .randint (0 , 0 ) == 1 :
125
+ test_new_train (editoast_url , scenario , rolling_stock .name , infra_name , path , prelude )
125
126
else :
126
127
test_stdcm (editoast_url , scenario , rolling_stock .id , infra_name , path , prelude )
127
128
@@ -130,7 +131,6 @@ def test_new_train(
130
131
editoast_url : str ,
131
132
scenario : Scenario ,
132
133
rolling_stock : str ,
133
- path_length : float ,
134
134
infra_name : str ,
135
135
path : List [Tuple [str , float ]],
136
136
prelude : List ,
@@ -179,8 +179,11 @@ def test_stdcm(
179
179
Not finding a path isn't considered as an error, we only look for 500 codes here.
180
180
"""
181
181
print ("testing stdcm" )
182
- stdcm_payload = make_stdcm_payload (scenario , path , rolling_stock )
183
- r = post_with_timeout (editoast_url + "stdcm/" , json = stdcm_payload )
182
+ stdcm_payload = make_stdcm_payload (path , rolling_stock )
183
+ r = post_with_timeout (
184
+ editoast_url + f"v2/timetable/{ scenario .timetable } /stdcm/?infra={ scenario .infra } " ,
185
+ json = stdcm_payload
186
+ )
184
187
if r .status_code // 100 != 2 :
185
188
content = r .content .decode ("utf-8" )
186
189
if r .status_code // 100 == 4 and "No path could be found" in content :
@@ -190,29 +193,24 @@ def test_stdcm(
190
193
print ("test PASSED" )
191
194
192
195
193
- def make_stdcm_payload (scenario : Scenario , path : List [Tuple [str , float ]], rolling_stock : int ) -> Dict :
196
+ def make_stdcm_payload (path : List [Tuple [str , float ]], rolling_stock : int ) -> Dict :
194
197
"""
195
198
Creates a payload for an STDCM request
196
199
"""
197
200
res = {
198
- "infra_id" : scenario .infra ,
199
201
"rolling_stock_id" : rolling_stock ,
200
- "timetable_id" : scenario .timetable ,
201
- "start_time" : random .randint (0 , 3600 * 24 ),
202
- "maximum_departure_delay" : random .randint (0 , 3600 * 4 ),
203
- "maximum_run_time" : random .randint (3600 * 5 , 3600 * 10 ),
204
- "margin_before" : random .randint (0 , 600 ),
205
- "margin_after" : random .randint (0 , 600 ),
206
- "steps" : [convert_stop (stop ) for stop in path ],
202
+ "start_time" : make_random_time (),
203
+ "maximum_departure_delay" : random .randint (0 , 3_600_000 * 4 ),
204
+ "maximum_run_time" : random .randint (3_600_000 * 5 , 3_600_000 * 10 ),
205
+ "time_gap_before" : random .randint (0 , 600_000 ),
206
+ "time_gap_after" : random .randint (0 , 600_000 ),
207
+ "steps" : [convert_stop_stdcm (stop ) for stop in path ],
207
208
"comfort" : "STANDARD" ,
208
- "standard_allowance" : {
209
- "value_type" : "percentage" ,
210
- "percentage" : 0 ,
211
- },
209
+ "margin" : None ,
212
210
}
213
211
res ["steps" ][- 1 ]["duration" ] = 1 # Force a stop at the end
214
- allowance_value = make_random_allowance_value ( 0 )
215
- if allowance_value [ "value_type" ] != "time" and random .randint (0 , 2 ) == 0 :
212
+ allowance_value = make_random_margin_value ( )
213
+ if random .randint (0 , 2 ) == 0 :
216
214
res ["standard_allowance" ] = allowance_value
217
215
return res
218
216
@@ -298,15 +296,6 @@ def get_random_rolling_stock(editoast_url: str) -> RollingStock:
298
296
return RollingStock (rolling_stock ["name" ], rolling_stock ["id" ])
299
297
300
298
301
- def format_route_node (waypoint_id , direction ):
302
- """
303
- Formats a waypoint + track direction into a string, to be used in dicts
304
- :param waypoint_id: waypoint id
305
- :param direction: direction on the track section the waypoint is placed on
306
- """
307
- return f"{ waypoint_id } ;{ direction } "
308
-
309
-
310
299
def make_graph (editoast_url : str , infra : int ) -> InfraGraph :
311
300
"""
312
301
Makes a graph from the infra
@@ -338,20 +327,6 @@ def random_set_element(s: Iterable):
338
327
return random .choice (list (s ))
339
328
340
329
341
- def check_tracks_are_unseen (seen_track_sections : Set [str ], route : Dict ):
342
- """
343
- Checks all tracks in the route, returns true if a track is already part of the path, adds them otherwise
344
- :param seen_track_sections: Set of track sections on the path
345
- :param route: Route to check
346
- """
347
- for track_range in route ["path" ]:
348
- track_id = track_range ["track" ]
349
- if track_id in seen_track_sections :
350
- return False
351
- seen_track_sections .add (track_id )
352
- return True
353
-
354
-
355
330
def make_steps_on_track (track : Dict , endpoint : Endpoint , number : float ) -> List [float ]:
356
331
"""
357
332
Generates a random list of steps on a route
@@ -420,7 +395,7 @@ def make_path(infra: InfraGraph) -> Tuple[List[Tuple[str, float]], float]:
420
395
return res , total_path_length
421
396
422
397
423
- def make_valid_path (infra : InfraGraph ) -> Tuple [ List [Tuple [str , float ]], float ]:
398
+ def make_valid_path (infra : InfraGraph ) -> List [Tuple [str , float ]]:
424
399
"""
425
400
Generates a path with at least two steps
426
401
:param infra: infra graph
@@ -429,29 +404,30 @@ def make_valid_path(infra: InfraGraph) -> Tuple[List[Tuple[str, float]], float]:
429
404
while True :
430
405
path , path_length = make_path (infra )
431
406
if len (path ) > 1 and path_length > 0 :
432
- return path , path_length
407
+ return path
433
408
434
409
435
- def convert_stop (stop : Tuple [str , float ]) -> Dict :
410
+ def convert_stop_stdcm (stop : Tuple [str , float ]) -> Dict :
436
411
"""
437
- Converts a stop to be in the schedule payload
412
+ Converts a stop to be in the stdcm payload
438
413
:param stop: (track, offset)
439
414
"""
440
415
track_section , offset = stop
441
- duration = 0 if random .randint (0 , 1 ) == 0 else random .random () * 1000
416
+ duration = None if random .randint (0 , 1 ) == 0 else to_ms ( random .random () * 1_000 )
442
417
return {
443
418
"duration" : duration ,
444
- "waypoints " : [{ "track_section " : track_section , "offset" : offset }] ,
419
+ "location " : { "track " : track_section , "offset" : to_mm ( offset )} ,
445
420
}
446
421
447
422
448
- def convert_stop_v2 (stop : Tuple [str , float ], i : int ) -> Dict :
423
+ def convert_stop (stop : Tuple [str , float ], i : int ) -> Dict :
449
424
"""
450
425
Converts a stop to be in the schedule payload
451
426
:param stop: (track, offset)
427
+ :param i: index of the stop, included as an id
452
428
"""
453
429
track_section , offset = stop
454
- return {"offset" : round (offset * 1_000 ), "track" : track_section , "id" : str (i )}
430
+ return {"offset" : to_mm (offset ), "track" : track_section , "id" : str (i )}
455
431
456
432
457
433
def create_scenario (editoast_url : str , infra_id : int ) -> Scenario :
@@ -517,7 +493,7 @@ def reset_scenario(editoast_url: str, scenario: Scenario) -> Scenario:
517
493
return Scenario (project_id , study_id , new_id , infra_id , new_timetable_id )
518
494
519
495
520
- def make_random_allowance_value_v2 () -> str :
496
+ def make_random_margin_value () -> str :
521
497
if random .randint (0 , 3 ) == 0 :
522
498
return f"{ random .randint (3 , 20 )} %"
523
499
if random .randint (0 , 3 ) == 0 :
@@ -534,7 +510,7 @@ def make_random_margins(n_steps: int) -> Dict:
534
510
i += 2 # Avoids constraints on very short ranges
535
511
return {
536
512
"boundaries" : transitions ,
537
- "values" : [make_random_allowance_value_v2 () for _ in range (len (transitions ) + 1 )],
513
+ "values" : [make_random_margin_value () for _ in range (len (transitions ) + 1 )],
538
514
}
539
515
540
516
@@ -551,7 +527,7 @@ def make_payload_schedule(
551
527
return [
552
528
{
553
529
"comfort" : "STANDARD" ,
554
- "path" : [convert_stop_v2 (stop , i ) for i , stop in enumerate (path )],
530
+ "path" : [convert_stop (stop , i ) for i , stop in enumerate (path )],
555
531
"initial_speed" : 0 ,
556
532
"labels" : [],
557
533
"constraint_distribution" : random .choice (["STANDARD" , "MARECO" ]),
@@ -566,24 +542,10 @@ def make_payload_schedule(
566
542
]
567
543
568
544
569
- def make_random_allowance_value (allowance_length ) -> Dict :
570
- if random .randint (0 , 3 ) == 0 :
571
- return {
572
- "value_type" : "percentage" ,
573
- "percentage" : random .randint (3 , 20 ) + random .random (),
574
- }
575
- if random .randint (0 , 3 ) == 0 :
576
- return {
577
- "value_type" : "time_per_distance" ,
578
- "minutes" : random .randint (3 , 7 ) + random .random (),
579
- }
580
- return {
581
- "value_type" : "time" ,
582
- "seconds" : (random .randint (3 , 7 ) + random .random ()) * 60 * allowance_length / 100000 ,
583
- }
584
-
585
-
586
545
def make_random_time ():
546
+ """
547
+ Generate a random datetime. All values will be within the same 24h
548
+ """
587
549
start = datetime .datetime (year = 2024 , month = 1 , day = 1 , tzinfo = datetime .timezone .utc ) # Arbitrary date
588
550
date = start + datetime .timedelta (seconds = (random .randint (0 , 3600 * 24 )))
589
551
return date .isoformat ()
@@ -641,6 +603,13 @@ def get_infra(editoast_url: str, infra_name: str) -> int:
641
603
raise ValueError (f"Unable to find infra { infra_name } " )
642
604
643
605
606
+ def to_mm (distance : float ) -> int :
607
+ return math .floor (distance * 1_000 )
608
+
609
+
610
+ to_ms = to_mm
611
+
612
+
644
613
if __name__ == "__main__" :
645
614
infra_id = get_infra (EDITOAST_URL , INFRA_NAME )
646
615
new_scenario = create_scenario (EDITOAST_URL , infra_id )
@@ -653,7 +622,7 @@ def get_infra(editoast_url: str, infra_name: str) -> int:
653
622
EDITOAST_URL ,
654
623
new_scenario ,
655
624
scenario_ttl = 20 ,
656
- n_test = 1000 ,
625
+ n_test = 10 ,
657
626
log_folder = Path (__file__ ).parent / "errors" ,
658
627
infra_name = INFRA_NAME ,
659
628
rolling_stock_name = ROLLING_STOCK_NAME ,
0 commit comments