Thomas Vachuska

Adding sequential construct to STC to serially chain sequences based on env properties.

Change-Id: I1df66d2a704309f5450eeca08a6e9b89c02e8346
<!--
~ Copyright 2015 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<scenario name="example" description="sequential scenario example">
<group name="Wrapup">
<!-- 'starts' is a comma-separated list of patterns that name steps starting the current iteration of the sequence -->
<!-- 'ends' is a comma-separated list of patterns that name steps ending the previous iteration of the sequence -->
<!-- In this example each Final-Check-Logs-(N) will become dependent on Fetch-Logs-(N-1), for N > 1 -->
<sequential var="${OC#}" starts="Final-Check-Logs-${#}" ends="Fetch-Logs-${#-1}">
<step name="Final-Check-Logs-${#}" exec="onos-check-logs ${OC#}"/>
<step name="Fetch-Logs-${#}" exec="onos-fetch-logs ${OC#}"
cwd="${WORKSPACE}/tmp/stc" requires="~^"/>
</sequential>
</group>
</scenario>
......@@ -48,6 +48,7 @@ public class Compiler {
private static final String GROUP = "group";
private static final String STEP = "step";
private static final String PARALLEL = "parallel";
private static final String SEQUENTIAL = "sequential";
private static final String DEPENDENCY = "dependency";
private static final String LOG_DIR = "[@logDir]";
......@@ -59,12 +60,16 @@ public class Compiler {
private static final String IF = "[@if]";
private static final String UNLESS = "[@unless]";
private static final String VAR = "[@var]";
private static final String STARTS = "[@starts]";
private static final String ENDS = "[@ends]";
private static final String FILE = "[@file]";
private static final String NAMESPACE = "[@namespace]";
static final String PROP_START = "${";
static final String PROP_END = "}";
private static final String HASH = "#";
private static final String HASH_PREV = "#-1";
private final Scenario scenario;
......@@ -72,7 +77,7 @@ public class Compiler {
private final Map<String, Step> inactiveSteps = Maps.newHashMap();
private final Map<String, String> requirements = Maps.newHashMap();
private final Set<Dependency> dependencies = Sets.newHashSet();
private final List<Integer> parallels = Lists.newArrayList();
private final List<Integer> clonables = Lists.newArrayList();
private ProcessFlow processFlow;
private File logDir;
......@@ -175,6 +180,10 @@ public class Compiler {
cfg.configurationsAt(PARALLEL)
.forEach(c -> processParallelGroup(c, namespace, parentGroup));
// Scan all sequential groups
cfg.configurationsAt(SEQUENTIAL)
.forEach(c -> processSequentialGroup(c, namespace, parentGroup));
// Scan all dependencies
cfg.configurationsAt(DEPENDENCY)
.forEach(c -> processDependency(c, namespace));
......@@ -309,14 +318,62 @@ public class Compiler {
int i = 1;
while (condition(var, i).length() > 0) {
parallels.add(0, i);
clonables.add(0, i);
compile(cfg, namespace, parentGroup);
parallels.remove(0);
clonables.remove(0);
i++;
}
}
/**
* Processes a sequential clone group directive.
*
* @param cfg hierarchical definition
* @param namespace optional namespace
* @param parentGroup optional parent group
*/
private void processSequentialGroup(HierarchicalConfiguration cfg,
String namespace, Group parentGroup) {
String var = cfg.getString(VAR);
String starts = cfg.getString(STARTS);
String ends = cfg.getString(ENDS);
print("sequential var=%s", var);
int i = 1;
while (condition(var, i).length() > 0) {
clonables.add(0, i);
compile(cfg, namespace, parentGroup);
if (i > 1) {
processSequentialRequirements(starts, ends, namespace);
}
clonables.remove(0);
i++;
}
}
/**
* Hooks starts of this sequence tier to the previous tier.
*
* @param starts comma-separated list of start steps
* @param ends comma-separated list of end steps
* @param namespace optional namespace
*/
private void processSequentialRequirements(String starts, String ends,
String namespace) {
for (String s : split(starts)) {
String start = expand(prefix(s, namespace));
String reqs = requirements.get(s);
for (String n : split(ends)) {
boolean isSoft = n.startsWith("~");
String name = n.replaceFirst("^~", "");
name = (isSoft ? "~" : "") + expand(prefix(name, namespace));
reqs = reqs == null ? name : (reqs + "," + name);
}
requirements.put(start, reqs);
}
}
/**
* Returns the elaborated repetition construct conditional.
*
* @param var repetition var property
......@@ -413,9 +470,11 @@ public class Compiler {
String prop = pString.substring(start + PROP_START.length(), end);
String value;
if (prop.equals(HASH)) {
value = parallels.get(0).toString();
value = Integer.toString(clonables.get(0));
} else if (prop.equals(HASH_PREV)) {
value = Integer.toString(clonables.get(0) - 1);
} else if (prop.endsWith(HASH)) {
pString = pString.replaceFirst("#}", parallels.get(0).toString() + "}");
pString = pString.replaceFirst("#}", clonables.get(0) + "}");
last = start;
continue;
} else {
......
......@@ -69,8 +69,8 @@ public class CompilerTest {
ProcessFlow flow = compiler.processFlow();
assertSame("incorrect scenario", scenario, compiler.scenario());
assertEquals("incorrect step count", 24, flow.getVertexes().size());
assertEquals("incorrect dependency count", 16, flow.getEdges().size());
assertEquals("incorrect step count", 33, flow.getVertexes().size());
assertEquals("incorrect dependency count", 26, flow.getEdges().size());
assertEquals("incorrect logDir",
new File(TEST_DIR.getAbsolutePath(), "foo"), compiler.logDir());
......
......@@ -44,4 +44,11 @@
<step name="ding-${#}" exec="asdads" requires="ping-${#},pong-${#}"/>
<dependency name="maybe" requires="ding-${#}"/>
</parallel>
<sequential var="${TOC#}" requires="alpha" starts="fifi-${#},gigi-${#}" ends="gaga-${#-1}">
<step name="fifi-${#}" exec="asdads ${TOC#}"/>
<step name="gigi-${#}" exec="asdads"/>
<step name="gaga-${#}" exec="asdads" requires="fifi-${#},gigi-${#}"/>
<dependency name="maybe" requires="gaga-${#}"/>
</sequential>
</scenario>
\ No newline at end of file
......