Composition operators
Composition operators invoke lower-level scenarios that serve as operands. These scenarios sometimes enforce implicit constraints on their operands. Composition operators have all the attributes of any scenario, such as start, end and fail events.
The serial operator is an example of a composition operator. It takes as operands one or more scenarios and executes them in sequence.
Most operators have an implicit serial operator. In other words, if they have more than one invocation in them, the invocations are put inside an implicit serial. Only parallel and first_of do not have implicit an serial operator.
first_of
Run multiple scenarios in parallel until the first one terminates
Composition operator
first_of
<scenario-list>
[<with-block>]
<scenario-list>- (Required) Is a list of two or more scenarios. Each scenario is on a separate line, indented consistently from the previous line.
<with-block>- (Optional) Is a list of one or more keep() constraints or scenario modifiers, where the members are listed on separate lines as a block or on the same line as with: and separated by semi-colons.
This operator runs multiple scenarios in parallel until the first one terminates. The other members, if any, are abandoned, meaning they are stopped without emitting the end event or collecting coverage.
This scenario uses first_of to set two trucks moving towards each other in parallel. Two wait actions are kicked off at the same time to end the scenario if truck1 passes through the meeting point without meeting truck2 or if it stops before the meeting point.
do first_of:
parallel(overlap: any):
truck1_drive: truck1.drive(duration: truck1_drive_duration) with:
along(truck1_path)
serial:
truck2_wait: truck2.drive(duration: truck2_wait_duration) with:
along(truck2_path)
speed(0kph)
truck2_startup: truck2.drive(duration: truck2_startup_duration)
truck2_drive: truck2.drive(duration: truck2_drive_duration) with:
speed([10kph..15kph], at: start)
avoid_collisions(false)
serial:
wait @passed_meeting
log_info("truck1 passed meeting point.")
serial:
wait @truck1_stopped
log_info("truck1 stopped before meeting point.")
See complete example.
parallel
Execute one or more secondary scenarios in parallel with a primary scenario
Composition operator
parallel[([[overlap: ] <mix-overlap-enum>][,
[start_to_start: ] <time-exp>][,
[end_to_end: ] <time-exp>][,
[duration: ] <time-exp>])]:
<invocation-list>
[<with-block>]
<invocation-list>-
(Required) Is a list of the scenarios that you want to invoke in parallel. The first scenario listed is the primary scenario, and it determines the time and context.
These invocations can have the full syntax including argument list and member block.
<with-block>- (Optional) Is a list of one or more keep() constraints or scenario modifiers, where the members are listed on separate lines as a block or on the same line as with: and separated by semi-colons.
If no parameters are specified, the parentheses are optional.
overlap-
Specifies the overlap between the primary scenario (the first scenario in the invocation list) and the other scenarios in the list. Overlap is one of the following:
- any specifies that there is no constraint on the amount of overlap between the primary and secondary scenarios.
- full specifies that the secondary scenarios fully overlap the primary one. In other words, the secondary scenarios do not start later than or end earlier than the primary scenario: start_to_start <= 0, end_to_end >= 0.
- equal specifies that all scenarios start and end at the same point in time: start_to_start = 0 and end_to_end = 0.
- inside specifies that the secondary scenarios are fully overlapped by the primary scenario. In other words, the secondary scenarios do not start earlier or end later than the primary scenario: start_to_start >= 0, end_to_end =< 0.
- initial specifies that the secondary scenarios cover at least the start of the primary scenario. In other words, the secondary scenarios do not start later than the primary scenario: start_to_start <= 0, end_to_end can be anything.
- final specifies that the secondary scenarios cover at least the end of the primary scenario. In other words, the secondary scenarios do not end earlier than the primary scenario: end_to_end >= 0, start_to_start can be anything.
- start (default) specifies that all scenarios start together: start_to_start = 0.
- end specifies that all scenarios end together: end_to_end = 0.
Note
The various overlap parameters apply separately for each secondary scenario. The secondary scenarios do not have to overlap each another in the manner described. For example, parallel(a,b,c,d) is really parallel(parallel(parallel(a,b),c),d). The image below shows the various types of overlap between the primary scenario and a secondary one.
start_to_start, end_to_end- Are the time offsets of the secondary scenarios relative to the primary one.
<time-exp>- Is an expression of type time. It may be a single value or a range of values.
The parallel operator describes the activities of two or more actors that overlap in some way. For example:
extend top.main:
do p1: parallel(overlap:equal):
car1.drive()
environment.weather(kind: clear)
See complete example.
To describe consecutive activities of multiple actors, invoke parallel multiple times from within the serial operator. For example:
extend top.main:
do s1: serial:
p1: parallel(overlap:equal):
car1.drive()
environment.weather(kind: clear)
p2: parallel(overlap:equal):
car1.drive()
environment.weather(kind: rain)
See complete example.
Each invocation of parallel is referred to informally as a phase. Each activity (or nested scenario) commences at the start of a phase. A phase ends when any of the following conditions is met:
- If all of the scenario’s nested scenarios end, the scenario ends.
- If a duration parameter is specified for a phase, then it ends when the specified duration has been reached.
Failure of any member causes parallel to fail.
parallel() is non-symmetrical: the first scenario is primary. For example, given the following definition of the sut.cut_in_with_rain() scenario, rainstorm and cut_in begin at the same time, but rainstorm may end first.
scenario sut.cut_in_with_rain:
do parallel(overlap:equal):
cut_in()
rainstorm()
See complete example.
However, given the following definition, cut_in may end first.
scenario sut.cut_in_with_rain:
do parallel(overlap:any):
rainstorm()
cut_in()
See complete example.
Note
Scenarios with zero time are not allowed within parallel operators.
serial
Execute two or more scenarios in a serial fashion
Composition operator
serial[([duration: ]<time-exp>)]:
<scenario>+
[<with-block>]
<scenario>+- (Required) Is a list of the scenarios that you want to invoke.
<with-block>- (Optional) Is a list of one or more keep() constraints or scenario modifiers, where the members are listed on separate lines as a block or on the same line as with: and separated by semi-colons.
<time-exp>-
(Optional) Is an expression of type time specifying how long the activities occur.
If no parameters are specified, the parentheses are optional.
In serial execution mode, each member starts when its predecessor ends. The scenario ends when the last member ends. Failure of any member causes serial to fail.
The default execution for all scenarios you create is serial, with no gaps. You can add gaps between scenarios using the wait or wait_time scenarios.
In the following example, a gap of 3 to 5 seconds is added between the execution of first_scenario() and second_scenario().
scenario sut.my_scenario:
do serial():
fs: top.first_scenario()
w1: wait elapsed([3..5]second)
ss: top.second_scenario()
See complete example.
