Thomas Vachuska

Added check for cyclic dependencies.

Changes intent test scenarios to use the key and added dependencies to make them more robust; h2h still fails intermittently due to a bug.

Increased parallelism of the smoke test scenario.

Change-Id: Ib7fed38d17d1b25c5dd854ef1cd4dc777002c5fc
...@@ -9,16 +9,26 @@ ...@@ -9,16 +9,26 @@
9 aux=/tmp/stc-$$.log 9 aux=/tmp/stc-$$.log
10 trap "rm -f $aux $aux.1 $aux.2 2>/dev/null" EXIT 10 trap "rm -f $aux $aux.1 $aux.2 2>/dev/null" EXIT
11 11
12 -onos ${1:-$OCI} "onos:apps -s -a" | grep -v /bin/client > $aux 12 +for attempt in {1..3}; do
13 -cat $aux 13 + onos ${1:-$OCI} "onos:apps -s -a" | grep -v /bin/client > $aux
14 + cat $aux
14 15
15 -# Normalize the installed apps 16 + # Normalize the installed apps
16 -cut -c7- $aux | grep -v '/bin/client' | cut -d\ -f1 | sort > $aux.1 17 + cut -c7- $aux | grep -v '/bin/client' | cut -d\ -f1 | sort > $aux.1
17 18
18 -# Normalize the expected apps 19 + # Normalize the expected apps
19 -apps=${2:-$ONOS_APPS} 20 + apps=${2:-$ONOS_APPS}
20 -apps=${apps:-drivers,openflow} 21 + apps=${apps:-drivers,openflow}
21 -(for app in ${apps//,/ }; do echo org.onosproject.$app; done) | sort > $aux.2 22 + (for app in ${apps//,/ }; do echo org.onosproject.$app; done) | sort > $aux.2
22 23
23 -# Check for differences 24 + # Check for differences
24 -diff $aux.1 $aux.2 25 + case ${3:-equals} in
26 + equals) diff $aux.1 $aux.2;;
27 + includes) [ $(egrep -c -f $aux.2 $aux.1) -eq $(wc -l $aux.2 | sed "s|$aux.2||g") ];;
28 + excludes) ! egrep -f $aux.2 $aux.1;;
29 + esac
30 +
31 + [ $? -eq 0 ] && exit 0 || sleep 1
32 +done
33 +
34 +exit 1;
......
...@@ -13,9 +13,9 @@ target=${1:-$OCI} ...@@ -13,9 +13,9 @@ target=${1:-$OCI}
13 echo onos-check-intent: $* 13 echo onos-check-intent: $*
14 14
15 set -x 15 set -x
16 -for i in 1 2 3; do 16 +for i in {1..10}; do
17 - onos $target "onos:intents" > $aux 17 + onos $target "onos:intents" | tee $aux
18 - ( cat $aux | grep "id=$2" | grep "state=$3" ) && cat $aux && exit 0 18 + ( cat $aux | grep "key=$2" | grep "state=$3" ) && cat $aux && exit 0
19 sleep 1 19 sleep 1
20 done 20 done
21 21
......
...@@ -18,15 +18,5 @@ arg2=$5 ...@@ -18,15 +18,5 @@ arg2=$5
18 18
19 set -x 19 set -x
20 20
21 -onos $target "onos:add-${type}-intent" "${arg1}" "${arg2}" >> $aux 21 +onos $target "onos:add-${type}-intent" --key $name "${arg1}" "${arg2}"
22 -result=$?
23 -cat $aux
24 -
25 -if [ $result -eq 0 ]; then
26 - id=$(cat $aux | sed -e "1d" | sed -e "s/^[a-zA-Z]*{//" | sed -e "s/,.*$//" | sed -e "s/^...//")
27 - echo @stc ${name}Id=${id}
28 -fi
29 -
30 -
31 -exit $result
32 22
......
...@@ -16,36 +16,44 @@ ...@@ -16,36 +16,44 @@
16 <scenario name="net-host-intent" description="Network host intent connectivity test"> 16 <scenario name="net-host-intent" description="Network host intent connectivity test">
17 <!-- TODO: parametrize this via recipes --> 17 <!-- TODO: parametrize this via recipes -->
18 <group name="Host-Intent-Connectivity"> 18 <group name="Host-Intent-Connectivity">
19 - <step name="Uninstall-Reactive-Forwarding" 19 + <step name="Host-Intent.Uninstall-Reactive-Forwarding"
20 exec="onos ${OC1} app deactivate org.onosproject.fwd org.onosproject.ifwd"/> 20 exec="onos ${OC1} app deactivate org.onosproject.fwd org.onosproject.ifwd"/>
21 + <step name="Host-Intent.Check-Apps" requires="^"
22 + exec="onos-check-apps ${OC1} fwd,ifwd excludes"/>
21 23
22 - <step name="Find-Host-1" requires="^" 24 + <step name="Host-Intent.Find-Host-1" requires="^"
23 - exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect ."/> 25 + exec="onos-mininet sendAndExpect h1 ping -c1 -w1 h4 --expect ."/>
24 - <step name="Find-Host-2" requires="^" 26 + <step name="Host-Intent.Find-Host-2" requires="^"
25 - exec="onos-mininet sendAndExpect h4 ping -c1 h1 --expect ."/> 27 + exec="onos-mininet sendAndExpect h4 ping -c1 -w1 h1 --expect ."/>
26 28
27 - <step name="Create-Intent" requires="^" 29 + <step name="Host-Intent.Create-Intent" requires="^"
28 - exec="onos-create-intent ${OC1} hostToHost host 00:00:00:00:00:01/-1 00:00:00:00:00:04/-1"/> 30 + exec="onos-create-intent ${OC1} h2h host 00:00:00:00:00:01/-1 00:00:00:00:00:04/-1"/>
29 - <step name="Validate-Intent-Installed" exec="onos-check-intent ${OC1} ${hostToHostId} INSTALLED" 31 + <step name="Host-Intent.Validate-Intent-Installed" requires="Host-Intent.Create-Intent"
30 - requires="Create-Intent" /> 32 + exec="onos-check-intent ${OC1} h2h INSTALLED"/>
31 33
32 <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="Host-Intent"/> 34 <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="Host-Intent"/>
33 - <dependency name="Host-Intent.Net-Link-Down-Up" requires="Validate-Intent-Installed"/> 35 + <dependency name="Host-Intent.Net-Link-Down-Up"
36 + requires="Host-Intent.Validate-Intent-Installed"/>
34 37
35 - <step name="Validate-Intent-Installed-Still" exec="onos-check-intent ${OC1} ${hostToHostId} INSTALLED" 38 + <step name="Host-Intent.Validate-Intent-Installed-Still" requires="Host-Intent.Link-1-Down"
36 - requires="Host-Intent.Link-1-Down" /> 39 + exec="onos-check-intent ${OC1} h2h INSTALLED"/>
37 40
38 - <step name="Validate-Intent-Failed" exec="onos-check-intent ${OC1} ${hostToHostId} FAILED" 41 + <dependency name="Host-Intent.Link-2-Down"
39 - requires="Host-Intent.Link-2-Down" /> 42 + requires="~Host-Intent.Validate-Intent-Installed-Still" />
40 43
41 - <step name="Validate-Intent-Installed-Again" exec="onos-check-intent ${OC1} ${hostToHostId} INSTALLED" 44 + <step name="Host-Intent.Validate-Intent-Failed" requires="Host-Intent.Link-2-Down"
42 - requires="Host-Intent.Link-1-Up" /> 45 + exec="onos-check-intent ${OC1} h2h FAILED"/>
43 - <dependency name="Host-Intent.Ping-4" requires="Validate-Intent-Installed-Again" />
44 46
45 - <step name="Remove-Intent" requires="~Host-Intent.Net-Link-Down-Up" 47 + <dependency name="Host-Intent.Link-1-Up"
46 - exec="onos ${OC1} remove-intent -p"/> 48 + requires="~Host-Intent.Validate-Intent-Failed" />
47 49
50 + <step name="Host-Intent.Validate-Intent-Installed-Again" requires="Host-Intent.Link-1-Up"
51 + exec="onos-check-intent ${OC1} h2h INSTALLED"/>
48 52
53 + <dependency name="Host-Intent.Ping-4"
54 + requires="~Host-Intent.Validate-Intent-Installed-Again" />
49 55
56 + <step name="Host-Intent.Remove-Intent" requires="~Host-Intent.Net-Link-Down-Up"
57 + exec="onos ${OC1} remove-intent -p org.onosproject.cli h2h"/>
50 </group> 58 </group>
51 </scenario> 59 </scenario>
......
...@@ -18,21 +18,21 @@ ...@@ -18,21 +18,21 @@
18 <group name="Net-Link-Down-Up"> 18 <group name="Net-Link-Down-Up">
19 <step name="Ping-1" 19 <step name="Ping-1"
20 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/> 20 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
21 - <step name="Link-1-Down" requires="Ping-1" 21 + <step name="Link-1-Down" requires="~Ping-1"
22 exec="onos-mininet sendAndExpect link s4 s7 down --expect ."/> 22 exec="onos-mininet sendAndExpect link s4 s7 down --expect ."/>
23 - <step name="Ping-2" requires="Link-1-Down" 23 + <step name="Ping-2" requires="~Link-1-Down"
24 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/> 24 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
25 - <step name="Link-2-Down" requires="Ping-2" 25 + <step name="Link-2-Down" requires="~Ping-2"
26 exec="onos-mininet sendAndExpect link s4 s5 down --expect ."/> 26 exec="onos-mininet sendAndExpect link s4 s5 down --expect ."/>
27 - <step name="Ping-3" requires="Link-2-Down" 27 + <step name="Ping-3" requires="~Link-2-Down"
28 - exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect 100% packet loss"/> 28 + exec="onos-mininet sendAndExpect h1 ping -c1 -w1 h4 --expect 100% packet loss"/>
29 - <step name="Link-1-Up" requires="Ping-3" 29 + <step name="Link-1-Up" requires="~Ping-3"
30 exec="onos-mininet sendAndExpect link s4 s7 up --expect ."/> 30 exec="onos-mininet sendAndExpect link s4 s7 up --expect ."/>
31 - <step name="Ping-4" requires="Link-1-Up" 31 + <step name="Ping-4" requires="~Link-1-Up"
32 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/> 32 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
33 - <step name="Link-2-Up" requires="Ping-4" 33 + <step name="Link-2-Up" requires="~Ping-4"
34 exec="onos-mininet sendAndExpect link s4 s5 up --expect ."/> 34 exec="onos-mininet sendAndExpect link s4 s5 up --expect ."/>
35 - <step name="Ping-5" requires="Link-2-Up" 35 + <step name="Ping-5" requires="~Link-2-Up"
36 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/> 36 exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
37 </group> 37 </group>
38 </scenario> 38 </scenario>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -18,11 +18,14 @@ ...@@ -18,11 +18,14 @@
18 <group name="Net-Pingall"> 18 <group name="Net-Pingall">
19 <step name="Install-Apps" 19 <step name="Install-Apps"
20 exec="onos ${OC1} app activate org.onosproject.openflow org.onosproject.proxyarp org.onosproject.fwd"/> 20 exec="onos ${OC1} app activate org.onosproject.openflow org.onosproject.proxyarp org.onosproject.fwd"/>
21 + <step name="Check-Apps" requires="^"
22 + exec="onos-check-apps ${OC1} drivers,openflow,proxyarp,fwd includes"/>
21 23
22 - <step name="Check-Apps" requires="Install-Apps" 24 + <!-- TODO: take this out when initial pingall sweep is 100% -->
23 - exec="onos-check-apps ${OC1} drivers,openflow,proxyarp,fwd"/> 25 + <step name="Initial-Ping-All" requires="Check-Apps"
26 + exec="onos-mininet sendAndExpect py net.pingAll(1) --expect 600 received"/>
24 27
25 - <step name="Ping-All-And-Verify" requires="Check-Apps" 28 + <step name="Ping-All-And-Verify" requires="Check-Apps,Initial-Ping-All"
26 exec="onos-mininet sendAndExpect py net.pingAll(1) --expect 600/600 received"/> 29 exec="onos-mininet sendAndExpect py net.pingAll(1) --expect 600/600 received"/>
27 30
28 <step name="Check-Summary-For-Hosts" requires="~Ping-All-And-Verify" 31 <step name="Check-Summary-For-Hosts" requires="~Ping-All-And-Verify"
......
...@@ -13,44 +13,65 @@ ...@@ -13,44 +13,65 @@
13 ~ See the License for the specific language governing permissions and 13 ~ See the License for the specific language governing permissions and
14 ~ limitations under the License. 14 ~ limitations under the License.
15 --> 15 -->
16 -<scenario name="net-point-intent" description="Network point to point intent connectivity test"> 16 +<scenario name="net-point-intent"
17 + description="Network point to point intent connectivity test">
17 <!-- TODO: parametrize this via recipes --> 18 <!-- TODO: parametrize this via recipes -->
18 - <group name="Point-To-Point-Intent-Connectivity"> 19 + <group name="P2P-Intent-Connectivity">
19 - <step name="P2P-Uninstall-Reactive-Forwarding" 20 + <step name="P2P-Intent.Uninstall-Reactive-Forwarding"
20 exec="onos ${OC1} app deactivate org.onosproject.fwd org.onosproject.ifwd"/> 21 exec="onos ${OC1} app deactivate org.onosproject.fwd org.onosproject.ifwd"/>
22 + <step name="P2P-Intent.Check-Apps" requires="^"
23 + exec="onos-check-apps ${OC1} fwd,ifwd excludes"/>
21 24
22 - <step name="P2P-Find-Host-1" requires="^" 25 + <step name="P2P-Intent.Find-Host-1" requires="^"
23 - exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect ."/> 26 + exec="onos-mininet sendAndExpect h1 ping -c1 -w1 h4 --expect ."/>
24 - <step name="P2PFind-Host-2" requires="^" 27 + <step name="P2P-Intent.Find-Host-2" requires="^"
25 - exec="onos-mininet sendAndExpect h4 ping -c1 h1 --expect ."/> 28 + exec="onos-mininet sendAndExpect h4 ping -c1 -w1 h1 --expect ."/>
26 - 29 +
27 - <step name="P2P-Create-Intent-1-To-4" requires="^" 30 + <step name="P2P-Intent.Create-Intent-XY" requires="^"
28 - exec="onos-create-intent ${OC1} oneToFour point of:0000000000000001/1 of:0000000000000004/1"/> 31 + exec="onos-create-intent ${OC1} xy point of:0000000000000001/1 of:0000000000000004/1"/>
29 - <step name="P2P-Create-Intent-4-To-1" requires="^" 32 + <step name="P2P-Intent.Create-Intent-YX" requires="^"
30 - exec="onos-create-intent ${OC1} fourToOne point of:0000000000000004/1 of:0000000000000001/1"/> 33 + exec="onos-create-intent ${OC1} yx point of:0000000000000004/1 of:0000000000000001/1"/>
31 - 34 +
32 - <step name="P2P-Validate-Point-Intents-Installed1" exec="onos-check-intent ${OC1} ${fourToOneId} INSTALLED" 35 + <step name="P2P-Intent.Validate-Intent-XY-Installed" requires="^"
33 - requires="^" /> 36 + exec="onos-check-intent ${OC1} yx INSTALLED"/>
34 - <step name="P2P-Validate-Point-Intents-Installed2" exec="onos-check-intent ${OC1} ${oneToFourId} INSTALLED" 37 + <step name="P2P-Intent.Validate-Intent-YX-Installed" requires="^"
35 - requires="^" /> 38 + exec="onos-check-intent ${OC1} xy INSTALLED"/>
36 - 39 +
37 - <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="Point-To-Point-Intent"/> 40 + <import file="${ONOS_SCENARIOS}/net-link-down-up.xml" namespace="P2P-Intent"/>
38 - <dependency name="Point-To-Point-Intent.Net-Link-Down-Up" requires="P2P-Validate-Point-Intents-Installed2"/> 41 + <dependency name="P2P-Intent.Net-Link-Down-Up"
39 - <step name="P2P-Validate-Intent-Installed-Still" exec="onos-check-intent ${OC1} ${fourToOneId} INSTALLED" 42 + requires="P2P-Intent.Validate-Intent-XY-Installed,
40 - requires="Point-To-Point-Intent.Link-1-Down" /> 43 + P2P-Intent.Validate-Intent-YX-Installed"/>
41 - 44 +
42 - <step name="P2P-Validate-Intent-Failed" exec="onos-check-intent ${OC1} ${fourToOneId} FAILED" 45 + <step name="P2P-Intent.Validate-Intent-XY-Installed-Still" requires="P2P-Intent.Link-1-Down"
43 - requires="Point-To-Point-Intent.Link-2-Down" /> 46 + exec="onos-check-intent ${OC1} xy INSTALLED"/>
44 - <step name="P2P-Validate-Intent-Failed2" exec="onos-check-intent ${OC1} ${oneToFourId} FAILED" 47 + <step name="P2P-Intent.Validate-Intent-YX-Installed-Still" requires="P2P-Intent.Link-1-Down"
45 - requires="Point-To-Point-Intent.Link-2-Down" /> 48 + exec="onos-check-intent ${OC1} yx INSTALLED"/>
46 - 49 +
47 - <step name="P2P-Validate-Intent-Installed-Again" exec="onos-check-intent ${OC1} ${fourToOneId} INSTALLED" 50 + <dependency name="P2P-Intent.Link-2-Down"
48 - requires="Point-To-Point-Intent.Link-1-Up" /> 51 + requires="~P2P-Intent.Validate-Intent-XY-Installed-Still,
49 - <dependency name="Point-To-Point-Intent.Ping-4" requires="P2P-Validate-Intent-Installed-Again" /> 52 + ~P2P-Intent.Validate-Intent-YX-Installed-Still"/>
50 - 53 +
51 - <step name="P2P-Remove-Intent-4-to-1" requires="~Point-To-Point-Intent.Net-Link-Down-Up" 54 + <step name="P2P-Intent.Validate-Intent-XY-Failed" requires="P2P-Intent.Link-2-Down"
52 - exec="onos ${OC1} remove-intent -p org.onosproject.cli ${fourToOneId}"/> 55 + exec="onos-check-intent ${OC1} xy FAILED"/>
53 - <step name="P2P-Remove-Intent-1-to-4" requires="^" 56 + <step name="P2P-Intent.Validate-Intent-YX-Failed" requires="P2P-Intent.Link-2-Down"
54 - exec="onos ${OC1} remove-intent -p org.onosproject.cli ${oneToFourId}"/> 57 + exec="onos-check-intent ${OC1} yx FAILED"/>
58 +
59 + <dependency name="P2P-Intent.Link-1-Up"
60 + requires="~P2P-Intent.Validate-Intent-XY-Failed,
61 + ~P2P-Intent.Validate-Intent-YX-Failed" />
62 +
63 + <step name="P2P-Intent.Validate-Intent-XY-Installed-Again" requires="P2P-Intent.Link-1-Up"
64 + exec="onos-check-intent ${OC1} xy INSTALLED"/>
65 + <step name="P2P-Intent.Validate-Intent-YX-Installed-Again" requires="P2P-Intent.Link-1-Up"
66 + exec="onos-check-intent ${OC1} yx INSTALLED"/>
67 +
68 + <dependency name="P2P-Intent.Ping-4"
69 + requires="~P2P-Intent.Validate-Intent-XY-Installed-Again,
70 + ~P2P-Intent.Validate-Intent-YX-Installed-Again"/>
71 +
72 + <step name="P2P-Intent.Remove-Intent-XY" requires="~P2P-Intent.Net-Link-Down-Up"
73 + exec="onos ${OC1} remove-intent -p org.onosproject.cli xy"/>
74 + <step name="P2P-Intent.Remove-Intent-YX" requires="~P2P-Intent.Net-Link-Down-Up"
75 + exec="onos ${OC1} remove-intent -p org.onosproject.cli yx"/>
55 </group> 76 </group>
56 </scenario> 77 </scenario>
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
29 exec="onos-mininet start topos/topo att-onos.py ${ONOS_INSTANCES}"/> 29 exec="onos-mininet start topos/topo att-onos.py ${ONOS_INSTANCES}"/>
30 30
31 <step name="Wait-For-Mininet" requires="Start-Mininet" 31 <step name="Wait-For-Mininet" requires="Start-Mininet"
32 - exec="onos-mininet wait 20"/> 32 + exec="onos-mininet wait 10"/>
33 33
34 <step name="Check-Summary" requires="Wait-For-Mininet" 34 <step name="Check-Summary" requires="Wait-For-Mininet"
35 exec="onos-check-summary ${OC1} [0-9]* 25 140 0"/> 35 exec="onos-check-summary ${OC1} [0-9]* 25 140 0"/>
......
...@@ -27,9 +27,9 @@ ...@@ -27,9 +27,9 @@
27 <dependency name="Host-Intent-Connectivity" requires="Net-Setup,~Reactive-Forwarding.Net-Link-Down-Up"/> 27 <dependency name="Host-Intent-Connectivity" requires="Net-Setup,~Reactive-Forwarding.Net-Link-Down-Up"/>
28 28
29 <import file="${ONOS_SCENARIOS}/net-point-intent.xml"/> 29 <import file="${ONOS_SCENARIOS}/net-point-intent.xml"/>
30 - <dependency name="Point-To-Point-Intent-Connectivity" requires="Net-Setup,~Reactive-Forwarding.Net-Link-Down-Up,Host-Intent-Connectivity"/> 30 + <dependency name="P2P-Intent-Connectivity" requires="Net-Setup,~Reactive-Forwarding.Net-Link-Down-Up,Host-Intent-Connectivity"/>
31 31
32 <import file="${ONOS_SCENARIOS}/net-teardown.xml"/> 32 <import file="${ONOS_SCENARIOS}/net-teardown.xml"/>
33 - <dependency name="Net-Teardown" requires="~Host-Intent-Connectivity,~Point-To-Point-Intent-Connectivity"/> 33 + <dependency name="Net-Teardown" requires="~Host-Intent-Connectivity,~P2P-Intent-Connectivity"/>
34 </group> 34 </group>
35 </scenario> 35 </scenario>
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 <dependency name="Net-Smoke" requires="Setup"/> 23 <dependency name="Net-Smoke" requires="Setup"/>
24 24
25 <import file="${ONOS_SCENARIOS}/archetypes.xml"/> 25 <import file="${ONOS_SCENARIOS}/archetypes.xml"/>
26 - <dependency name="Archetypes" requires="~Net-Smoke,Setup"/> 26 + <dependency name="Archetypes" requires="Setup"/>
27 27
28 <import file="${ONOS_SCENARIOS}/wrapup.xml"/> 28 <import file="${ONOS_SCENARIOS}/wrapup.xml"/>
29 <dependency name="Wrapup" requires="~Archetypes,~Setup,~Net-Smoke"/> 29 <dependency name="Wrapup" requires="~Archetypes,~Setup,~Net-Smoke"/>
......
...@@ -21,6 +21,7 @@ import com.google.common.collect.Lists; ...@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
21 import com.google.common.collect.Maps; 21 import com.google.common.collect.Maps;
22 import com.google.common.collect.Sets; 22 import com.google.common.collect.Sets;
23 import org.apache.commons.configuration.HierarchicalConfiguration; 23 import org.apache.commons.configuration.HierarchicalConfiguration;
24 +import org.onlab.graph.DepthFirstSearch;
24 25
25 import java.io.File; 26 import java.io.File;
26 import java.io.FileInputStream; 27 import java.io.FileInputStream;
...@@ -29,10 +30,10 @@ import java.util.List; ...@@ -29,10 +30,10 @@ import java.util.List;
29 import java.util.Map; 30 import java.util.Map;
30 import java.util.Set; 31 import java.util.Set;
31 32
32 -import static com.google.common.base.Preconditions.checkArgument; 33 +import static com.google.common.base.Preconditions.*;
33 -import static com.google.common.base.Preconditions.checkNotNull;
34 -import static com.google.common.base.Preconditions.checkState;
35 import static com.google.common.base.Strings.isNullOrEmpty; 34 import static com.google.common.base.Strings.isNullOrEmpty;
35 +import static org.onlab.graph.DepthFirstSearch.EdgeType.BACK_EDGE;
36 +import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
36 import static org.onlab.stc.Scenario.loadScenario; 37 import static org.onlab.stc.Scenario.loadScenario;
37 38
38 /** 39 /**
...@@ -109,6 +110,8 @@ public class Compiler { ...@@ -109,6 +110,8 @@ public class Compiler {
109 processFlow = new ProcessFlow(ImmutableSet.copyOf(steps.values()), 110 processFlow = new ProcessFlow(ImmutableSet.copyOf(steps.values()),
110 ImmutableSet.copyOf(dependencies)); 111 ImmutableSet.copyOf(dependencies));
111 112
113 + scanForCycles();
114 +
112 // Extract the log directory if there was one specified 115 // Extract the log directory if there was one specified
113 String defaultPath = DEFAULT_LOG_DIR + scenario.name(); 116 String defaultPath = DEFAULT_LOG_DIR + scenario.name();
114 String path = scenario.definition().getString(LOG_DIR, defaultPath); 117 String path = scenario.definition().getString(LOG_DIR, defaultPath);
...@@ -449,6 +452,22 @@ public class Compiler { ...@@ -449,6 +452,22 @@ public class Compiler {
449 } 452 }
450 453
451 /** 454 /**
455 + * Scans the process flow graph for cyclic dependencies.
456 + */
457 + private void scanForCycles() {
458 + DepthFirstSearch<Step, Dependency> dfs = new DepthFirstSearch<>();
459 + // Use a brute-force method of searching paths from all vertices.
460 + processFlow().getVertexes().forEach(s -> {
461 + DepthFirstSearch<Step, Dependency>.SpanningTreeResult r =
462 + dfs.search(processFlow, s, null, null, ALL_PATHS);
463 + r.edges().forEach((e, et) -> checkArgument(et != BACK_EDGE,
464 + "Process flow has a cycle involving dependency from %s to %s",
465 + e.src().name, e.dst().name));
466 + });
467 + }
468 +
469 +
470 + /**
452 * Prints formatted output. 471 * Prints formatted output.
453 * 472 *
454 * @param format printf format string 473 * @param format printf format string
......