Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class PathfindingBlockRequest(

// One set of location by step, each step must be reached in order
@Json(name = "path_items") val pathItems: List<PathItem>,

// Set of authorized track section ids, empty set means no restriction
@Json(name = "allowed_track_sections") val allowedTrackSections: Set<String> = emptySet(),
)

val pathfindingRequestAdapter: JsonAdapter<PathfindingBlockRequest> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fr.sncf.osrd.api.ExceptionHandler
import fr.sncf.osrd.api.FullInfra
import fr.sncf.osrd.api.InfraProvider
import fr.sncf.osrd.api.TrackLocation
import fr.sncf.osrd.api.stdcm.parseTrackSectionIds
import fr.sncf.osrd.cli.Request
import fr.sncf.osrd.cli.Response
import fr.sncf.osrd.cli.RsJson
Expand Down Expand Up @@ -121,13 +122,15 @@ fun runPathfinding(infra: FullInfra, request: PathfindingBlockRequest): Pathfind
targets.add(ExplorerStep(allStarts, canBacktrack = step.canBacktrack))
}
if (targets.size < 2) throw NoPathFoundException(NotEnoughPathItems())
val allowedTrackSectionIds = parseTrackSectionIds(infra, request.allowedTrackSections)
val constraints =
initConstraintsFromRSProps(
infra,
request.rollingStockIsThermal,
request.rollingStockLoadingGauge,
request.rollingStockSupportedElectrifications,
request.rollingStockSupportedSignalingSystems,
allowedTrackSectionIds,
)

// Compute the paths from the entry waypoint to the exit waypoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,11 @@ private fun parseSimulationScheduleItems(
)
}

fun parseTrackSectionIds(infra: FullInfra, trackSectionName: Set<String>?): Set<TrackSectionId>? {
return trackSectionName?.mapNotNull { infra.rawInfra.getTrackSectionFromName(it) }?.toSet()
fun parseTrackSectionIds(infra: FullInfra, trackSectionNames: Set<String>?): Set<TrackSectionId>? {
return trackSectionNames
?.mapNotNull { infra.rawInfra.getTrackSectionFromName(it) }
?.toSet()
?.takeIf { it.isNotEmpty() }
}

private fun progressCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ import fr.sncf.osrd.utils.units.Distance
import fr.sncf.osrd.utils.units.Offset
import fr.sncf.osrd.utils.units.OffsetRange
import fr.sncf.osrd.utils.units.meters
import java.util.stream.Stream
import kotlin.test.assertEquals
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.AssertionsForClassTypes
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource

fun getPathfindingBlockRequest(
rs: RollingStock,
Expand Down Expand Up @@ -610,6 +614,60 @@ class PathfindingTest : ApiTest() {
}
}

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class PathfindingAllowedTrackSectionsTest {
// tiny_infra path: foo_b -> foo_to_bar -> bar_a
private val infra = Helpers.fullInfraFromFile("tiny_infra/infra.json")
private val waypointsStart = listOf(TrackLocation("ne.micro.foo_b", Offset(50.meters)))
private val waypointsEnd = listOf(TrackLocation("ne.micro.bar_a", Offset(100.meters)))
private val pathItems = listOf(PathItem(waypointsStart, false), PathItem(waypointsEnd, false))

private fun makeRequest(allowedTrackSections: Set<String> = emptySet()) =
PathfindingBlockRequest(
rollingStockLoadingGauge = TestTrains.REALISTIC_FAST_TRAIN.loadingGaugeType,
rollingStockIsThermal = TestTrains.REALISTIC_FAST_TRAIN.isThermal,
rollingStockSupportedElectrifications =
TestTrains.REALISTIC_FAST_TRAIN.modeNames.filterNot { it == "thermal" },
rollingStockSupportedSignalingSystems =
TestTrains.REALISTIC_FAST_TRAIN.supportedSignalingSystems.toList(),
rollingStockMaximumSpeed = TestTrains.REALISTIC_FAST_TRAIN.maxSpeed,
rollingStockLength = TestTrains.REALISTIC_FAST_TRAIN.length,
timeout = null,
infra = "tiny_infra/infra.json",
expectedVersion = 1,
pathItems = pathItems,
allowedTrackSections = allowedTrackSections,
)

private fun successCases(): Stream<Arguments> =
Stream.of(
Arguments.of(emptySet<String>()),
Arguments.of(setOf("ne.micro.foo_b", "ne.micro.foo_to_bar", "ne.micro.bar_a")),
)

@ParameterizedTest
@MethodSource("successCases")
fun allowedTrackSectionsSucceeds(allowedTrackSections: Set<String>) {
checkPathfindingSuccess(
runPathfinding(infra, makeRequest(allowedTrackSections)),
10250.meters,
)
}

@Test
fun allowedTrackSectionsFailsWhenRequiredTrackExcluded() {
// omit foo_to_bar
assertThatThrownBy {
runPathfinding(infra, makeRequest(setOf("ne.micro.foo_b", "ne.micro.bar_a")))
}
.isExactlyInstanceOf(NoPathFoundException::class.java)
.satisfies({ e ->
assertThat((e as NoPathFoundException).response)
.isExactlyInstanceOf(NotFoundInBlocks::class.java)
})
}
}

class PathfindingStopsAtEndOfBlock : ApiTest() {
fun callPathfindingEndpoint(
rs: RollingStock,
Expand Down
Loading