summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/stc/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/utils/stc/src/main/java/org')
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java541
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java387
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java77
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java60
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java387
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java154
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java31
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java307
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java149
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java137
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java37
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java106
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java226
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java129
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java116
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java50
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java141
-rw-r--r--framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java20
18 files changed, 0 insertions, 3055 deletions
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java
deleted file mode 100644
index 919cbd5b..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.apache.commons.configuration.HierarchicalConfiguration;
-import org.onlab.graph.DepthFirstSearch;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.*;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onlab.graph.DepthFirstSearch.EdgeType.BACK_EDGE;
-import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
-import static org.onlab.stc.Scenario.loadScenario;
-
-/**
- * Entity responsible for loading a scenario and producing a redy-to-execute
- * process flow graph.
- */
-public class Compiler {
-
- private static final String DEFAULT_LOG_DIR = "${WORKSPACE}/tmp/stc/";
-
- private static final String IMPORT = "import";
- 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]";
- private static final String NAME = "[@name]";
- private static final String COMMAND = "[@exec]";
- private static final String ENV = "[@env]";
- private static final String CWD = "[@cwd]";
- private static final String REQUIRES = "[@requires]";
- 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;
-
- private final Map<String, Step> steps = Maps.newHashMap();
- 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> clonables = Lists.newArrayList();
-
- private ProcessFlow processFlow;
- private File logDir;
-
- private String previous = null;
- private String pfx = "";
- private boolean debugOn = System.getenv("debug") != null;
-
- /**
- * Creates a new compiler for the specified scenario.
- *
- * @param scenario scenario to be compiled
- */
- public Compiler(Scenario scenario) {
- this.scenario = scenario;
- }
-
- /**
- * Returns the scenario being compiled.
- *
- * @return test scenario
- */
- public Scenario scenario() {
- return scenario;
- }
-
- /**
- * Compiles the specified scenario to produce a final process flow graph.
- */
- public void compile() {
- compile(scenario.definition(), null, null);
- compileRequirements();
-
- // Produce the process flow
- processFlow = new ProcessFlow(ImmutableSet.copyOf(steps.values()),
- ImmutableSet.copyOf(dependencies));
-
- scanForCycles();
-
- // Extract the log directory if there was one specified
- String defaultPath = DEFAULT_LOG_DIR + scenario.name();
- String path = scenario.definition().getString(LOG_DIR, defaultPath);
- logDir = new File(expand(path));
- }
-
- /**
- * Returns the step with the specified name.
- *
- * @param name step or group name
- * @return test step or group
- */
- public Step getStep(String name) {
- return steps.get(name);
- }
-
- /**
- * Returns the process flow generated from this scenario definition.
- *
- * @return process flow as a graph
- */
- public ProcessFlow processFlow() {
- return processFlow;
- }
-
- /**
- * Returns the log directory where scenario logs should be kept.
- *
- * @return scenario logs directory
- */
- public File logDir() {
- return logDir;
- }
-
- /**
- * Recursively elaborates this definition to produce a final process flow graph.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- */
- private void compile(HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- String opfx = pfx;
- pfx = pfx + ">";
- print("pfx=%s namespace=%s", pfx, namespace);
-
- // Scan all imports
- cfg.configurationsAt(IMPORT)
- .forEach(c -> processImport(c, namespace, parentGroup));
-
- // Scan all steps
- cfg.configurationsAt(STEP)
- .forEach(c -> processStep(c, namespace, parentGroup));
-
- // Scan all groups
- cfg.configurationsAt(GROUP)
- .forEach(c -> processGroup(c, namespace, parentGroup));
-
- // Scan all parallel groups
- 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));
-
- pfx = opfx;
- }
-
- /**
- * Compiles requirements for all steps and groups accrued during the
- * overall compilation process.
- */
- private void compileRequirements() {
- requirements.forEach((name, requires) ->
- compileRequirements(getStep(name), requires));
- }
-
- private void compileRequirements(Step src, String requires) {
- split(requires).forEach(n -> {
- boolean isSoft = n.startsWith("~");
- String name = n.replaceFirst("^~", "");
- Step dst = getStep(name);
- if (dst != null) {
- dependencies.add(new Dependency(src, dst, isSoft));
- }
- });
- }
-
- /**
- * Processes an import directive.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- */
- private void processImport(HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- String file = checkNotNull(expand(cfg.getString(FILE)),
- "Import directive must specify 'file'");
- String newNamespace = expand(prefix(cfg.getString(NAMESPACE), namespace));
- print("import file=%s namespace=%s", file, newNamespace);
- try {
- Scenario importScenario = loadScenario(new FileInputStream(file));
- compile(importScenario.definition(), newNamespace, parentGroup);
- } catch (IOException e) {
- throw new IllegalArgumentException("Unable to import scenario", e);
- }
- }
-
- /**
- * Processes a step directive.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- */
- private void processStep(HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- String name = expand(prefix(cfg.getString(NAME), namespace));
- String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true);
- String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
- String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
-
- print("step name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
- Step step = new Step(name, command, env, cwd, parentGroup);
- registerStep(step, cfg, namespace, parentGroup);
- }
-
- /**
- * Processes a group directive.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- */
- private void processGroup(HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- String name = expand(prefix(cfg.getString(NAME), namespace));
- String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true);
- String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
- String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
-
- print("group name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
- Group group = new Group(name, command, env, cwd, parentGroup);
- if (registerStep(group, cfg, namespace, parentGroup)) {
- compile(cfg, namespace, group);
- }
- }
-
- /**
- * Registers the specified step or group.
- *
- * @param step step or group
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- * @return true of the step or group was registered as active
- */
- private boolean registerStep(Step step, HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- checkState(!steps.containsKey(step.name()), "Step %s already exists", step.name());
- String ifClause = expand(cfg.getString(IF));
- String unlessClause = expand(cfg.getString(UNLESS));
-
- if ((ifClause != null && ifClause.length() == 0) ||
- (unlessClause != null && unlessClause.length() > 0) ||
- (parentGroup != null && inactiveSteps.containsValue(parentGroup))) {
- inactiveSteps.put(step.name(), step);
- return false;
- }
-
- if (parentGroup != null) {
- parentGroup.addChild(step);
- }
-
- steps.put(step.name(), step);
- processRequirements(step, expand(cfg.getString(REQUIRES)), namespace);
- previous = step.name();
- return true;
- }
-
- /**
- * Processes a parallel clone group directive.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- * @param parentGroup optional parent group
- */
- private void processParallelGroup(HierarchicalConfiguration cfg,
- String namespace, Group parentGroup) {
- String var = cfg.getString(VAR);
- print("parallel var=%s", var);
-
- int i = 1;
- while (condition(var, i).length() > 0) {
- clonables.add(0, i);
- compile(cfg, namespace, parentGroup);
- 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
- * @param i index to elaborate
- * @return elaborated string
- */
- private String condition(String var, Integer i) {
- return expand(var.replaceFirst("#", i.toString())).trim();
- }
-
- /**
- * Processes a dependency directive.
- *
- * @param cfg hierarchical definition
- * @param namespace optional namespace
- */
- private void processDependency(HierarchicalConfiguration cfg, String namespace) {
- String name = expand(prefix(cfg.getString(NAME), namespace));
- String requires = expand(cfg.getString(REQUIRES));
-
- print("dependency name=%s requires=%s", name, requires);
- Step step = getStep(name, namespace);
- if (!inactiveSteps.containsValue(step)) {
- processRequirements(step, requires, namespace);
- }
- }
-
- /**
- * Processes the specified requiremenst string and adds dependency for
- * each requirement of the given step.
- *
- * @param src source step
- * @param requires comma-separated list of required steps
- * @param namespace optional namespace
- */
- private void processRequirements(Step src, String requires, String namespace) {
- String reqs = requirements.get(src.name());
- for (String n : split(requires)) {
- boolean isSoft = n.startsWith("~");
- String name = n.replaceFirst("^~", "");
- name = previous != null && name.equals("^") ? previous : name;
- name = (isSoft ? "~" : "") + expand(prefix(name, namespace));
- reqs = reqs == null ? name : (reqs + "," + name);
- }
- requirements.put(src.name(), reqs);
- }
-
- /**
- * Retrieves the step or group with the specified name.
- *
- * @param name step or group name
- * @param namespace optional namespace
- * @return step or group; null if none found in active or inactive steps
- */
- private Step getStep(String name, String namespace) {
- String dName = prefix(name, namespace);
- Step step = steps.get(dName);
- step = step != null ? step : inactiveSteps.get(dName);
- checkArgument(step != null, "Unknown step %s", dName);
- return step;
- }
-
- /**
- * Prefixes the specified name with the given namespace.
- *
- * @param name name of a step or a group
- * @param namespace optional namespace
- * @return composite name
- */
- private String prefix(String name, String namespace) {
- return isNullOrEmpty(namespace) ? name : namespace + "." + name;
- }
-
- /**
- * Expands any environment variables in the specified string. These are
- * specified as ${property} tokens.
- *
- * @param string string to be processed
- * @param keepTokens true if the original unresolved tokens should be kept
- * @return original string with expanded substitutions
- */
- private String expand(String string, boolean... keepTokens) {
- if (string == null) {
- return null;
- }
-
- String pString = string;
- StringBuilder sb = new StringBuilder();
- int start, end, last = 0;
- while ((start = pString.indexOf(PROP_START, last)) >= 0) {
- end = pString.indexOf(PROP_END, start + PROP_START.length());
- checkArgument(end > start, "Malformed property in %s", pString);
- sb.append(pString.substring(last, start));
- String prop = pString.substring(start + PROP_START.length(), end);
- String value;
- if (prop.equals(HASH)) {
- 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("#}", clonables.get(0) + "}");
- last = start;
- continue;
- } else {
- // Try system property first, then fall back to env. variable.
- value = System.getProperty(prop);
- if (value == null) {
- value = System.getenv(prop);
- }
- }
- if (value == null && keepTokens.length == 1 && keepTokens[0]) {
- sb.append("${").append(prop).append("}");
- } else {
- sb.append(value != null ? value : "");
- }
- last = end + 1;
- }
- sb.append(pString.substring(last));
- return sb.toString().replace('\n', ' ').replace('\r', ' ');
- }
-
- /**
- * Splits the comma-separated string into a list of strings.
- *
- * @param string string to split
- * @return list of strings
- */
- private List<String> split(String string) {
- ImmutableList.Builder<String> builder = ImmutableList.builder();
- String[] fields = string != null ? string.split(",") : new String[0];
- for (String field : fields) {
- builder.add(field.trim());
- }
- return builder.build();
- }
-
- /**
- * Scans the process flow graph for cyclic dependencies.
- */
- private void scanForCycles() {
- DepthFirstSearch<Step, Dependency> dfs = new DepthFirstSearch<>();
- // Use a brute-force method of searching paths from all vertices.
- processFlow().getVertexes().forEach(s -> {
- DepthFirstSearch<Step, Dependency>.SpanningTreeResult r =
- dfs.search(processFlow, s, null, null, ALL_PATHS);
- r.edges().forEach((e, et) -> checkArgument(et != BACK_EDGE,
- "Process flow has a cycle involving dependency from %s to %s",
- e.src().name, e.dst().name));
- });
- }
-
-
- /**
- * Prints formatted output.
- *
- * @param format printf format string
- * @param args arguments to be printed
- */
- private void print(String format, Object... args) {
- if (debugOn) {
- System.err.println(pfx + String.format(format, args));
- }
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java
deleted file mode 100644
index 228e7834..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newFixedThreadPool;
-import static org.onlab.stc.Compiler.PROP_END;
-import static org.onlab.stc.Compiler.PROP_START;
-import static org.onlab.stc.Coordinator.Directive.*;
-import static org.onlab.stc.Coordinator.Status.*;
-
-/**
- * Coordinates execution of a scenario process flow.
- */
-public class Coordinator {
-
- private static final int MAX_THREADS = 64;
-
- private final ExecutorService executor = newFixedThreadPool(MAX_THREADS);
-
- private final ProcessFlow processFlow;
-
- private final StepProcessListener delegate;
- private final CountDownLatch latch;
- private final ScenarioStore store;
-
- private static final Pattern PROP_ERE = Pattern.compile("^@stc ([a-zA-Z0-9_.]+)=(.*$)");
- private final Map<String, String> properties = Maps.newConcurrentMap();
-
- private final Set<StepProcessListener> listeners = Sets.newConcurrentHashSet();
- private File logDir;
-
- /**
- * Represents action to be taken on a test step.
- */
- public enum Directive {
- NOOP, RUN, SKIP
- }
-
- /**
- * Represents processor state.
- */
- public enum Status {
- WAITING, IN_PROGRESS, SUCCEEDED, FAILED, SKIPPED
- }
-
- /**
- * Creates a process flow coordinator.
- *
- * @param scenario test scenario to coordinate
- * @param processFlow process flow to coordinate
- * @param logDir scenario log directory
- */
- public Coordinator(Scenario scenario, ProcessFlow processFlow, File logDir) {
- this.processFlow = processFlow;
- this.logDir = logDir;
- this.store = new ScenarioStore(processFlow, logDir, scenario.name());
- this.delegate = new Delegate();
- this.latch = new CountDownLatch(1);
- }
-
- /**
- * Resets any previously accrued status and events.
- */
- public void reset() {
- store.reset();
- }
-
- /**
- * Resets all previously accrued status and events for steps that lie
- * in the range between the steps or groups whose names match the specified
- * patterns.
- *
- * @param runFromPatterns list of starting step patterns
- * @param runToPatterns list of ending step patterns
- */
- public void reset(List<String> runFromPatterns, List<String> runToPatterns) {
- List<Step> fromSteps = matchSteps(runFromPatterns);
- List<Step> toSteps = matchSteps(runToPatterns);
-
- // FIXME: implement this
- }
-
- /**
- * Returns number of milliseconds it took to execute.
- *
- * @return number of millis elapsed during the run
- */
- public long duration() {
- return store.endTime() - store.startTime();
- }
-
- /**
- * Returns a list of steps that match the specified list of patterns.
- *
- * @param runToPatterns list of patterns
- * @return list of steps with matching names
- */
- private List<Step> matchSteps(List<String> runToPatterns) {
- ImmutableList.Builder<Step> builder = ImmutableList.builder();
- store.getSteps().forEach(step -> {
- runToPatterns.forEach(p -> {
- if (step.name().matches(p)) {
- builder.add(step);
- }
- });
- });
- return builder.build();
- }
-
- /**
- * Starts execution of the process flow graph.
- */
- public void start() {
- executeRoots(null);
- }
-
- /**
- * Waits for completion of the entire process flow.
- *
- * @return exit code to use
- * @throws InterruptedException if interrupted while waiting for completion
- */
- public int waitFor() throws InterruptedException {
- while (!store.isComplete()) {
- latch.await(1, TimeUnit.SECONDS);
- }
- return store.hasFailures() ? 1 : 0;
- }
-
- /**
- * Returns set of all test steps.
- *
- * @return set of steps
- */
- public Set<Step> getSteps() {
- return store.getSteps();
- }
-
- /**
- * Returns a chronological list of step or group records.
- *
- * @return list of events
- */
- List<StepEvent> getRecords() {
- return store.getEvents();
- }
-
- /**
- * Returns the status record of the specified test step.
- *
- * @param step test step or group
- * @return step status record
- */
- public Status getStatus(Step step) {
- return store.getStatus(step);
- }
-
- /**
- * Adds the specified listener.
- *
- * @param listener step process listener
- */
- public void addListener(StepProcessListener listener) {
- listeners.add(checkNotNull(listener, "Listener cannot be null"));
- }
-
- /**
- * Removes the specified listener.
- *
- * @param listener step process listener
- */
- public void removeListener(StepProcessListener listener) {
- listeners.remove(checkNotNull(listener, "Listener cannot be null"));
- }
-
- /**
- * Executes the set of roots in the scope of the specified group or globally
- * if no group is given.
- *
- * @param group optional group
- */
- private void executeRoots(Group group) {
- // FIXME: add ability to skip past completed steps
- Set<Step> steps =
- group != null ? group.children() : processFlow.getVertexes();
- steps.forEach(step -> {
- if (processFlow.getEdgesFrom(step).isEmpty() && step.group() == group) {
- execute(step);
- }
- });
- }
-
- /**
- * Executes the specified step.
- *
- * @param step step to execute
- */
- private synchronized void execute(Step step) {
- Directive directive = nextAction(step);
- if (directive == RUN) {
- store.markStarted(step);
- if (step instanceof Group) {
- Group group = (Group) step;
- delegate.onStart(group, null);
- executeRoots(group);
- } else {
- executor.execute(new StepProcessor(step, logDir, delegate,
- substitute(step.command())));
- }
- } else if (directive == SKIP) {
- skipStep(step);
- }
- }
-
- /**
- * Recursively skips the specified step or group and any steps/groups within.
- *
- * @param step step or group
- */
- private void skipStep(Step step) {
- if (step instanceof Group) {
- Group group = (Group) step;
- store.markComplete(step, SKIPPED);
- group.children().forEach(this::skipStep);
- }
- delegate.onCompletion(step, SKIPPED);
-
- }
-
- /**
- * Determines the state of the specified step.
- *
- * @param step test step
- * @return state of the step process
- */
- private Directive nextAction(Step step) {
- Status status = store.getStatus(step);
- if (status != WAITING) {
- return NOOP;
- }
-
- for (Dependency dependency : processFlow.getEdgesFrom(step)) {
- Status depStatus = store.getStatus(dependency.dst());
- if (depStatus == WAITING || depStatus == IN_PROGRESS) {
- return NOOP;
- } else if (((depStatus == FAILED || depStatus == SKIPPED) && !dependency.isSoft()) ||
- (step.group() != null && store.getStatus(step.group()) == SKIPPED)) {
- return SKIP;
- }
- }
- return RUN;
- }
-
- /**
- * Executes the successors to the specified step.
- *
- * @param step step whose successors are to be executed
- */
- private void executeSucessors(Step step) {
- processFlow.getEdgesTo(step).forEach(dependency -> execute(dependency.src()));
- completeParentIfNeeded(step.group());
- }
-
- /**
- * Checks whether the specified parent group, if any, should be marked
- * as complete.
- *
- * @param group parent group that should be checked
- */
- private synchronized void completeParentIfNeeded(Group group) {
- if (group != null && getStatus(group) == IN_PROGRESS) {
- boolean done = true;
- boolean failed = false;
- for (Step child : group.children()) {
- Status status = store.getStatus(child);
- done = done && (status == SUCCEEDED || status == FAILED || status == SKIPPED);
- failed = failed || status == FAILED;
- }
- if (done) {
- delegate.onCompletion(group, failed ? FAILED : SUCCEEDED);
- }
- }
- }
-
- /**
- * Expands the var references with values from the properties map.
- *
- * @param string string to perform substitutions on
- */
- private String substitute(String string) {
- StringBuilder sb = new StringBuilder();
- int start, end, last = 0;
- while ((start = string.indexOf(PROP_START, last)) >= 0) {
- end = string.indexOf(PROP_END, start + PROP_START.length());
- checkArgument(end > start, "Malformed property in %s", string);
- sb.append(string.substring(last, start));
- String prop = string.substring(start + PROP_START.length(), end);
- String value = properties.get(prop);
- sb.append(value != null ? value : "");
- last = end + 1;
- }
- sb.append(string.substring(last));
- return sb.toString().replace('\n', ' ').replace('\r', ' ');
- }
-
- /**
- * Scrapes the line of output for any variables to be captured and posted
- * in the properties for later use.
- *
- * @param line line of output to scrape for property exports
- */
- private void scrapeForVariables(String line) {
- Matcher matcher = PROP_ERE.matcher(line);
- if (matcher.matches()) {
- String prop = matcher.group(1);
- String value = matcher.group(2);
- properties.put(prop, value);
- }
- }
-
-
- /**
- * Prints formatted output.
- *
- * @param format printf format string
- * @param args arguments to be printed
- */
- public static void print(String format, Object... args) {
- System.out.println(String.format(format, args));
- }
-
- /**
- * Internal delegate to monitor the process execution.
- */
- private class Delegate implements StepProcessListener {
- @Override
- public void onStart(Step step, String command) {
- listeners.forEach(listener -> listener.onStart(step, command));
- }
-
- @Override
- public void onCompletion(Step step, Status status) {
- store.markComplete(step, status);
- listeners.forEach(listener -> listener.onCompletion(step, status));
- executeSucessors(step);
- if (store.isComplete()) {
- latch.countDown();
- }
- }
-
- @Override
- public void onOutput(Step step, String line) {
- scrapeForVariables(line);
- listeners.forEach(listener -> listener.onOutput(step, line));
- }
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java
deleted file mode 100644
index 9025d2e5..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.base.MoreObjects;
-import org.onlab.graph.AbstractEdge;
-
-import java.util.Objects;
-
-/**
- * Representation of a dependency from one step on completion of another.
- */
-public class Dependency extends AbstractEdge<Step> {
-
- private boolean isSoft;
-
- /**
- * Creates a new edge between the specified source and destination vertexes.
- *
- * @param src source vertex
- * @param dst destination vertex
- * @param isSoft indicates whether this is a hard or soft dependency
- */
- public Dependency(Step src, Step dst, boolean isSoft) {
- super(src, dst);
- this.isSoft = isSoft;
- }
-
- /**
- * Indicates whether this is a soft or hard dependency, i.e. one that
- * requires successful completion of the dependency or just any completion.
- *
- * @return true if dependency is a soft one
- */
- public boolean isSoft() {
- return isSoft;
- }
-
- @Override
- public int hashCode() {
- return 31 * super.hashCode() + Objects.hash(isSoft);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof Dependency) {
- final Dependency other = (Dependency) obj;
- return super.equals(other) && Objects.equals(this.isSoft, other.isSoft);
- }
- return false;
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("name", src().name())
- .add("requires", dst().name())
- .add("isSoft", isSoft)
- .toString();
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java
deleted file mode 100644
index 0281c364..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-import java.util.Set;
-
-/**
- * Represenation of a related group of steps.
- */
-public class Group extends Step {
-
- private final Set<Step> children = Sets.newHashSet();
-
- /**
- * Creates a new test step.
- *
- * @param name group name
- * @param command default command
- * @param env default path to file to be sourced into the environment
- * @param cwd default path to current working directory for the step
- * @param group optional group to which this step belongs
- */
- public Group(String name, String command, String env, String cwd, Group group) {
- super(name, command, env, cwd, group);
- }
-
- /**
- * Returns the set of child steps and groups contained within this group.
- *
- * @return set of children
- */
- public Set<Step> children() {
- return ImmutableSet.copyOf(children);
- }
-
- /**
- * Adds the specified step or group as a child of this group.
- *
- * @param child child step or group to add
- */
- public void addChild(Step child) {
- children.add(child);
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java
deleted file mode 100644
index ca04a7c2..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Files;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.util.log.Logger;
-import org.onlab.stc.Coordinator.Status;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-import static java.lang.System.currentTimeMillis;
-import static org.onlab.stc.Coordinator.Status.*;
-import static org.onlab.stc.Coordinator.print;
-
-/**
- * Main program for executing system test coordinator.
- */
-public final class Main {
-
- private static final String NONE = "\u001B[0m";
- private static final String GRAY = "\u001B[30;1m";
- private static final String RED = "\u001B[31;1m";
- private static final String GREEN = "\u001B[32;1m";
- private static final String BLUE = "\u001B[36m";
-
- private static final String SUCCESS_SUMMARY =
- "%s %sPassed! %d steps succeeded%s";
- private static final String MIXED_SUMMARY =
- "%s%d steps succeeded; %s%d steps failed; %s%d steps skipped%s";
- private static final String FAILURE_SUMMARY = "%s %sFailed! " + MIXED_SUMMARY;
- private static final String ABORTED_SUMMARY = "%s %sAborted! " + MIXED_SUMMARY;
-
- private boolean isReported = false;
-
- private enum Command {
- LIST, RUN, RUN_RANGE, HELP
- }
-
- private final String scenarioFile;
-
- private Command command = Command.HELP;
- private String runFromPatterns = "";
- private String runToPatterns = "";
-
- private Coordinator coordinator;
- private Compiler compiler;
- private Monitor monitor;
- private Listener delegate = new Listener();
-
- private static boolean useColor = Objects.equals("true", System.getenv("stcColor"));
- private static boolean dumpLogs = Objects.equals("true", System.getenv("stcDumpLogs"));
-
- // usage: stc [<scenario-file>] [run]
- // usage: stc [<scenario-file>] run [from <from-patterns>] [to <to-patterns>]]
- // usage: stc [<scenario-file>] list
-
- // Public construction forbidden
- private Main(String[] args) {
- this.scenarioFile = args[0];
-
- if (args.length <= 1 || args.length == 2 && args[1].equals("run")) {
- command = Command.RUN;
- } else if (args.length == 2 && args[1].equals("list")) {
- command = Command.LIST;
- } else if (args.length >= 4 && args[1].equals("run")) {
- int i = 2;
- if (args[i].equals("from")) {
- command = Command.RUN_RANGE;
- runFromPatterns = args[i + 1];
- i += 2;
- }
-
- if (args.length >= i + 2 && args[i].equals("to")) {
- command = Command.RUN_RANGE;
- runToPatterns = args[i + 1];
- }
- }
- }
-
- /**
- * Main entry point for coordinating test scenario execution.
- *
- * @param args command-line arguments
- */
- public static void main(String[] args) {
- Main main = new Main(args);
- main.run();
- }
-
- // Runs the scenario processing
- private void run() {
- try {
- // Load scenario
- Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile));
-
- // Elaborate scenario
- compiler = new Compiler(scenario);
- compiler.compile();
-
- // Setup the process flow coordinator
- coordinator = new Coordinator(scenario, compiler.processFlow(),
- compiler.logDir());
- coordinator.addListener(delegate);
-
- // Prepare the GUI monitor
- monitor = new Monitor(coordinator, compiler);
- startMonitorServer(monitor);
-
- // Execute process flow
- processCommand();
-
- } catch (FileNotFoundException e) {
- print("Unable to find scenario file %s", scenarioFile);
- }
- }
-
- // Initiates a web-server for the monitor GUI.
- private static void startMonitorServer(Monitor monitor) {
- org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
- Server server = new Server(9999);
- ServletHandler handler = new ServletHandler();
- server.setHandler(handler);
- MonitorWebSocketServlet.setMonitor(monitor);
- handler.addServletWithMapping(MonitorWebSocketServlet.class, "/*");
- try {
- server.start();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // Processes the appropriate command
- private void processCommand() {
- switch (command) {
- case RUN:
- processRun();
- break;
- case LIST:
- processList();
- break;
- case RUN_RANGE:
- processRunRange();
- break;
- default:
- print("Unsupported command %s", command);
- }
- }
-
- // Processes the scenario 'run' command.
- private void processRun() {
- coordinator.reset();
- runCoordinator();
- }
-
- // Processes the scenario 'run' command for range of steps.
- private void processRunRange() {
- coordinator.reset(list(runFromPatterns), list(runToPatterns));
- runCoordinator();
- }
-
- // Processes the scenario 'list' command.
- private void processList() {
- coordinator.getRecords()
- .forEach(event -> logStatus(event.time(), event.name(), event.status(), event.command()));
- printSummary(0, false);
- System.exit(0);
- }
-
- // Runs the coordinator and waits for it to finish.
- private void runCoordinator() {
- try {
- Runtime.getRuntime().addShutdownHook(new ShutdownHook());
- coordinator.start();
- int exitCode = coordinator.waitFor();
- pause(100); // allow stdout to flush
- printSummary(exitCode, false);
- System.exit(exitCode);
- } catch (InterruptedException e) {
- print("Unable to execute scenario %s", scenarioFile);
- }
- }
-
- private synchronized void printSummary(int exitCode, boolean isAborted) {
- if (!isReported) {
- isReported = true;
- Set<Step> steps = coordinator.getSteps();
- String duration = formatDuration((int) (coordinator.duration() / 1_000));
- int count = steps.size();
- if (exitCode == 0) {
- print(SUCCESS_SUMMARY, duration, color(SUCCEEDED), count, color(null));
- } else {
- long success = steps.stream().filter(s -> coordinator.getStatus(s) == SUCCEEDED).count();
- long failed = steps.stream().filter(s -> coordinator.getStatus(s) == FAILED).count();
- long skipped = steps.stream().filter(s -> coordinator.getStatus(s) == SKIPPED).count();
- print(isAborted ? ABORTED_SUMMARY : FAILURE_SUMMARY, duration,
- color(FAILED), color(SUCCEEDED), success,
- color(FAILED), failed, color(SKIPPED), skipped, color(null));
- }
- }
- }
-
- /**
- * Internal delegate to monitor the process execution.
- */
- private class Listener implements StepProcessListener {
- @Override
- public void onStart(Step step, String command) {
- logStatus(currentTimeMillis(), step.name(), IN_PROGRESS, command);
- }
-
- @Override
- public void onCompletion(Step step, Status status) {
- logStatus(currentTimeMillis(), step.name(), status, null);
- if (dumpLogs && !(step instanceof Group) && status == FAILED) {
- dumpLogs(step);
- }
- }
-
- @Override
- public void onOutput(Step step, String line) {
- }
- }
-
- // Logs the step status.
- private static void logStatus(long time, String name, Status status, String cmd) {
- if (cmd != null) {
- print("%s %s%s %s%s -- %s", time(time), color(status), name, action(status), color(null), cmd);
- } else {
- print("%s %s%s %s%s", time(time), color(status), name, action(status), color(null));
- }
- }
-
- // Dumps the step logs to standard output.
- private void dumpLogs(Step step) {
- File logFile = new File(compiler.logDir(), step.name() + ".log");
- try {
- print(">>>>>");
- Files.copy(logFile, System.out);
- print("<<<<<");
- } catch (IOException e) {
- print("Unable to dump log file %s", logFile.getName());
- }
- }
-
- // Produces a description of event using the specified step status.
- private static String action(Status status) {
- return status == IN_PROGRESS ? "started" :
- (status == SUCCEEDED ? "completed" :
- (status == FAILED ? "failed" :
- (status == SKIPPED ? "skipped" : "waiting")));
- }
-
- // Produces an ANSI escape code for color using the specified step status.
- private static String color(Status status) {
- if (!useColor) {
- return "";
- }
- return status == null ? NONE :
- (status == IN_PROGRESS ? BLUE :
- (status == SUCCEEDED ? GREEN :
- (status == FAILED ? RED : GRAY)));
- }
-
- // Produces a list from the specified comma-separated string.
- private static List<String> list(String patterns) {
- return ImmutableList.copyOf(patterns.split(","));
- }
-
- // Produces a formatted time stamp.
- private static String time(long time) {
- return new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date(time));
- }
-
- // Pauses for the specified number of millis.
- private static void pause(int ms) {
- try {
- Thread.sleep(ms);
- } catch (InterruptedException e) {
- print("Interrupted!");
- }
- }
-
- // Formats time duration
- private static String formatDuration(int totalSeconds) {
- int seconds = totalSeconds % 60;
- int totalMinutes = totalSeconds / 60;
- int minutes = totalMinutes % 60;
- int hours = totalMinutes / 60;
- return hours > 0 ?
- String.format("%d:%02d:%02d", hours, minutes, seconds) :
- String.format("%d:%02d", minutes, seconds);
- }
-
- // Shutdown hook to report status even when aborted.
- private class ShutdownHook extends Thread {
- @Override
- public void run() {
- printSummary(1, true);
- }
- }
-
- // Logger to quiet Jetty down
- private static class NullLogger implements Logger {
- @Override
- public String getName() {
- return "quiet";
- }
-
- @Override
- public void warn(String msg, Object... args) {
- }
-
- @Override
- public void warn(Throwable thrown) {
- }
-
- @Override
- public void warn(String msg, Throwable thrown) {
- }
-
- @Override
- public void info(String msg, Object... args) {
- }
-
- @Override
- public void info(Throwable thrown) {
- }
-
- @Override
- public void info(String msg, Throwable thrown) {
- }
-
- @Override
- public boolean isDebugEnabled() {
- return false;
- }
-
- @Override
- public void setDebugEnabled(boolean enabled) {
- }
-
- @Override
- public void debug(String msg, Object... args) {
- }
-
- @Override
- public void debug(Throwable thrown) {
- }
-
- @Override
- public void debug(String msg, Throwable thrown) {
- }
-
- @Override
- public Logger getLogger(String name) {
- return this;
- }
-
- @Override
- public void ignore(Throwable ignored) {
- }
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java
deleted file mode 100644
index 4e6f63fa..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Maps;
-import org.onlab.stc.MonitorLayout.Box;
-
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Map;
-
-import static org.onlab.stc.Coordinator.Status.IN_PROGRESS;
-
-/**
- * Scenario test monitor.
- */
-public class Monitor implements StepProcessListener {
-
- private final ObjectMapper mapper = new ObjectMapper();
-
- private final Coordinator coordinator;
- private final Compiler compiler;
- private final MonitorLayout layout;
-
- private MonitorDelegate delegate;
-
- private Map<Step, Box> boxes = Maps.newHashMap();
-
- /**
- * Creates a new shared process flow monitor.
- *
- * @param coordinator process flow coordinator
- * @param compiler scenario compiler
- */
- Monitor(Coordinator coordinator, Compiler compiler) {
- this.coordinator = coordinator;
- this.compiler = compiler;
- this.layout = new MonitorLayout(compiler);
- coordinator.addListener(this);
- }
-
- /**
- * Sets the process monitor delegate.
- *
- * @param delegate process monitor delegate
- */
- void setDelegate(MonitorDelegate delegate) {
- this.delegate = delegate;
- }
-
- /**
- * Notifies the process monitor delegate with the specified event.
- *
- * @param event JSON event data
- */
- public void notify(ObjectNode event) {
- if (delegate != null) {
- delegate.notify(event);
- }
- }
-
- /**
- * Returns the scenario process flow as JSON data.
- *
- * @return scenario process flow data
- */
- ObjectNode scenarioData() {
- ObjectNode root = mapper.createObjectNode();
- ArrayNode steps = mapper.createArrayNode();
- ArrayNode requirements = mapper.createArrayNode();
-
- ProcessFlow pf = compiler.processFlow();
- pf.getVertexes().forEach(step -> add(step, steps));
- pf.getEdges().forEach(requirement -> add(requirement, requirements));
-
- root.set("steps", steps);
- root.set("requirements", requirements);
-
- try (FileWriter fw = new FileWriter("/tmp/data.json");
- PrintWriter pw = new PrintWriter(fw)) {
- pw.println(root.toString());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return root;
- }
-
-
- private void add(Step step, ArrayNode steps) {
- Box box = layout.get(step);
- ObjectNode sn = mapper.createObjectNode()
- .put("name", step.name())
- .put("isGroup", step instanceof Group)
- .put("status", status(coordinator.getStatus(step)))
- .put("tier", box.tier())
- .put("depth", box.depth());
- if (step.group() != null) {
- sn.put("group", step.group().name());
- }
- steps.add(sn);
- }
-
- private String status(Coordinator.Status status) {
- return status.toString().toLowerCase();
- }
-
- private void add(Dependency requirement, ArrayNode requirements) {
- ObjectNode rn = mapper.createObjectNode();
- rn.put("src", requirement.src().name())
- .put("dst", requirement.dst().name())
- .put("isSoft", requirement.isSoft());
- requirements.add(rn);
- }
-
- @Override
- public void onStart(Step step, String command) {
- notify(event(step, status(IN_PROGRESS)));
- }
-
- @Override
- public void onCompletion(Step step, Coordinator.Status status) {
- notify(event(step, status(status)));
- }
-
- @Override
- public void onOutput(Step step, String line) {
-
- }
-
- private ObjectNode event(Step step, String status) {
- ObjectNode event = mapper.createObjectNode()
- .put("name", step.name())
- .put("status", status);
- return event;
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java
deleted file mode 100644
index d11542a7..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-/**
- * Delegate to which monitor can send notifications.
- */
-public interface MonitorDelegate {
-
- /**
- * Issues JSON event to be sent to any connected monitor clients.
- *
- * @param event JSON event data
- */
- void notify(ObjectNode event);
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java
deleted file mode 100644
index 1c0e7313..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-/**
- * Computes scenario process flow layout for the Monitor GUI.
- */
-public class MonitorLayout {
-
- public static final int WIDTH = 210;
- public static final int HEIGHT = 30;
- public static final int W_GAP = 40;
- public static final int H_GAP = 50;
- public static final int SLOT_WIDTH = WIDTH + H_GAP;
-
- private final Compiler compiler;
- private final ProcessFlow flow;
-
- private Map<Step, Box> boxes = Maps.newHashMap();
-
- /**
- * Creates a new shared process flow monitor.
- *
- * @param compiler scenario compiler
- */
- MonitorLayout(Compiler compiler) {
- this.compiler = compiler;
- this.flow = compiler.processFlow();
-
- // Extract the flow and create initial bounding boxes.
- boxes.put(null, new Box(null, 0));
- flow.getVertexes().forEach(this::createBox);
-
- computeLayout(null, 0, 1);
- }
-
- // Computes the graph layout giving preference to group associations.
- private void computeLayout(Group group, int absoluteTier, int tier) {
- Box box = boxes.get(group);
-
- // Find all children of the group, or items with no group if at top.
- Set<Step> children = group != null ? group.children() :
- flow.getVertexes().stream().filter(s -> s.group() == null)
- .collect(Collectors.toSet());
-
- children.forEach(s -> visit(s, absoluteTier, 1, group));
-
- // Figure out what the group root vertexes are.
- Set<Step> roots = findRoots(group);
-
- // Compute the boxes for each of the roots.
- roots.forEach(s -> updateBox(s, absoluteTier + 1, 1, group));
-
- // Update the tier and depth of the group bounding box.
- computeTiersAndDepth(group, box, absoluteTier, tier, children);
-
- // Compute the minimum breadth of this group's bounding box.
- computeBreadth(group, box, children);
-
- // Compute child placements
- computeChildPlacements(group, box, children);
- }
-
- // Updates the box for the specified step, given the tier number, which
- // is relative to the parent.
- private Box updateBox(Step step, int absoluteTier, int tier, Group group) {
- Box box = boxes.get(step);
- if (step instanceof Group) {
- computeLayout((Group) step, absoluteTier, tier);
- } else {
- box.setTierAndDepth(absoluteTier, tier, 1, group);
- }
-
- // Follow the steps downstream of this one.
- follow(step, absoluteTier + box.depth(), box.tier() + box.depth());
- return box;
- }
-
- // Backwards follows edges leading towards the specified step to visit
- // the source vertex and compute layout of those vertices that had
- // sufficient number of visits to compute their tier.
- private void follow(Step step, int absoluteTier, int tier) {
- Group from = step.group();
- flow.getEdgesTo(step).stream()
- .filter(d -> visit(d.src(), absoluteTier, tier, from))
- .forEach(d -> updateBox(d.src(), absoluteTier, tier, from));
- }
-
- // Visits each step, records maximum tier and returns true if this
- // was the last expected visit.
- private boolean visit(Step step, int absoluteTier, int tier, Group from) {
- Box box = boxes.get(step);
- return box.visitAndLatchMaxTier(absoluteTier, tier, from);
- }
-
- // Computes the absolute and relative tiers and the depth of the group
- // bounding box.
- private void computeTiersAndDepth(Group group, Box box,
- int absoluteTier, int tier, Set<Step> children) {
- int depth = children.stream().mapToInt(this::bottomMostTier).max().getAsInt();
- box.setTierAndDepth(absoluteTier, tier, depth, group);
- }
-
- // Returns the bottom-most tier this step occupies relative to its parent.
- private int bottomMostTier(Step step) {
- Box box = boxes.get(step);
- return box.tier() + box.depth();
- }
-
- // Computes breadth of the specified group.
- private void computeBreadth(Group group, Box box, Set<Step> children) {
- if (box.breadth() == 0) {
- // Scan through all tiers and determine the maximum breadth of each.
- IntStream.range(1, box.depth)
- .forEach(t -> computeTierBreadth(t, box, children));
- box.latchBreadth(children.stream()
- .mapToInt(s -> boxes.get(s).breadth())
- .max().getAsInt());
- }
- }
-
- // Computes tier width.
- private void computeTierBreadth(int t, Box box, Set<Step> children) {
- box.latchBreadth(children.stream().map(boxes::get)
- .filter(b -> isSpanningTier(b, t))
- .mapToInt(Box::breadth).sum());
- }
-
- // Computes the actual child box placements relative to the parent using
- // the previously established tier, depth and breadth attributes.
- private void computeChildPlacements(Group group, Box box,
- Set<Step> children) {
- // Order the root-nodes in alphanumeric order first.
- List<Box> tierBoxes = Lists.newArrayList(boxesOnTier(1, children));
- tierBoxes.sort((a, b) -> a.step().name().compareTo(b.step().name()));
-
- // Place the boxes centered on the parent box; left to right.
- int tierBreadth = tierBoxes.stream().mapToInt(Box::breadth).sum();
- int slot = 1;
- for (Box b : tierBoxes) {
- b.updateCenter(1, slot(slot, tierBreadth));
- slot += b.breadth();
- }
- }
-
- // Returns the horizontal offset off the parent center.
- private int slot(int slot, int tierBreadth) {
- boolean even = tierBreadth % 2 == 0;
- int multiplier = -tierBreadth / 2 + slot - 1;
- return even ? multiplier * SLOT_WIDTH + SLOT_WIDTH / 2 : multiplier * SLOT_WIDTH;
- }
-
- // Returns a list of all child step boxes that start on the specified tier.
- private List<Box> boxesOnTier(int tier, Set<Step> children) {
- return boxes.values().stream()
- .filter(b -> b.tier() == tier && children.contains(b.step()))
- .collect(Collectors.toList());
- }
-
- // Determines whether the specified box spans, or occupies a tier.
- private boolean isSpanningTier(Box b, int tier) {
- return (b.depth() == 1 && b.tier() == tier) ||
- (b.tier() <= tier && tier < b.tier() + b.depth());
- }
-
-
- // Determines roots of the specified group or of the entire graph.
- private Set<Step> findRoots(Group group) {
- Set<Step> steps = group != null ? group.children() : flow.getVertexes();
- return steps.stream().filter(s -> isRoot(s, group)).collect(Collectors.toSet());
- }
-
- private boolean isRoot(Step step, Group group) {
- if (step.group() != group) {
- return false;
- }
-
- Set<Dependency> requirements = flow.getEdgesFrom(step);
- return requirements.stream().filter(r -> r.dst().group() == group)
- .collect(Collectors.toSet()).isEmpty();
- }
-
- /**
- * Returns the bounding box for the specified step. If null is given, it
- * returns the overall bounding box.
- *
- * @param step step or group; null for the overall bounding box
- * @return bounding box
- */
- public Box get(Step step) {
- return boxes.get(step);
- }
-
- /**
- * Returns the bounding box for the specified step name. If null is given,
- * it returns the overall bounding box.
- *
- * @param name name of step or group; null for the overall bounding box
- * @return bounding box
- */
- public Box get(String name) {
- return get(name == null ? null : compiler.getStep(name));
- }
-
- // Creates a bounding box for the specified step or group.
- private void createBox(Step step) {
- boxes.put(step, new Box(step, flow.getEdgesFrom(step).size()));
- }
-
- /**
- * Bounding box data for a step or group.
- */
- final class Box {
-
- private Step step;
- private int remainingRequirements;
-
- private int absoluteTier = 0;
- private int tier;
- private int depth = 1;
- private int breadth;
- private int center, top;
-
- private Box(Step step, int remainingRequirements) {
- this.step = step;
- this.remainingRequirements = remainingRequirements + 1;
- breadth = step == null || step instanceof Group ? 0 : 1;
- }
-
- private void latchTiers(int absoluteTier, int tier, Group from) {
- this.absoluteTier = Math.max(this.absoluteTier, absoluteTier);
- if (step == null || step.group() == from) {
- this.tier = Math.max(this.tier, tier);
- }
- }
-
- public void latchBreadth(int breadth) {
- this.breadth = Math.max(this.breadth, breadth);
- }
-
- void setTierAndDepth(int absoluteTier, int tier, int depth, Group from) {
- latchTiers(absoluteTier, tier, from);
- this.depth = depth;
- }
-
- boolean visitAndLatchMaxTier(int absoluteTier, int tier, Group from) {
- latchTiers(absoluteTier, tier, from);
- --remainingRequirements;
- return remainingRequirements == 0;
- }
-
- Step step() {
- return step;
- }
-
- public int absoluteTier() {
- return absoluteTier;
- }
-
- int tier() {
- return tier;
- }
-
- int depth() {
- return depth;
- }
-
- int breadth() {
- return breadth;
- }
-
- int top() {
- return top;
- }
-
- int center() {
- return center;
- }
-
- public void updateCenter(int top, int center) {
- this.top = top;
- this.center = center;
- }
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java
deleted file mode 100644
index cd146070..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.eclipse.jetty.websocket.WebSocket;
-
-import java.io.IOException;
-
-import static org.onlab.stc.Coordinator.print;
-
-/**
- * Web socket capable of interacting with the STC monitor GUI.
- */
-public class MonitorWebSocket implements WebSocket.OnTextMessage, WebSocket.OnControl {
-
- private static final long MAX_AGE_MS = 30_000;
-
- private static final byte PING = 0x9;
- private static final byte PONG = 0xA;
- private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
-
- private final Monitor monitor;
-
- private Connection connection;
- private FrameConnection control;
-
- private final ObjectMapper mapper = new ObjectMapper();
-
- private long lastActive = System.currentTimeMillis();
-
- /**
- * Creates a new monitor client GUI web-socket.
- *
- * @param monitor shared process flow monitor
- */
- MonitorWebSocket(Monitor monitor) {
- this.monitor = monitor;
- }
-
- /**
- * Issues a close on the connection.
- */
- synchronized void close() {
- destroyHandlers();
- if (connection.isOpen()) {
- connection.close();
- }
- }
-
- /**
- * Indicates if this connection is idle.
- *
- * @return true if idle or closed
- */
- synchronized boolean isIdle() {
- long quietFor = System.currentTimeMillis() - lastActive;
- boolean idle = quietFor > MAX_AGE_MS;
- if (idle || (connection != null && !connection.isOpen())) {
- return true;
- } else if (connection != null) {
- try {
- control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
- } catch (IOException e) {
- print("Unable to send ping message due to: %s", e);
- }
- }
- return false;
- }
-
- @Override
- public void onOpen(Connection connection) {
- this.connection = connection;
- this.control = (FrameConnection) connection;
- try {
- createHandlers();
- sendMessage(message("flow", monitor.scenarioData()));
-
- } catch (Exception e) {
- print("Unable to open monitor connection: %s", e);
- this.connection.close();
- this.connection = null;
- this.control = null;
- }
- }
-
- @Override
- public synchronized void onClose(int closeCode, String message) {
- destroyHandlers();
- }
-
- @Override
- public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
- lastActive = System.currentTimeMillis();
- return true;
- }
-
- @Override
- public void onMessage(String data) {
- lastActive = System.currentTimeMillis();
- try {
- ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
- // TODO:
- print("Got message: %s", message);
- } catch (Exception e) {
- print("Unable to parse GUI message %s due to %s", data, e);
- }
- }
-
- public synchronized void sendMessage(ObjectNode message) {
- try {
- if (connection.isOpen()) {
- connection.sendMessage(message.toString());
- }
- } catch (IOException e) {
- print("Unable to send message %s to GUI due to %s", message, e);
- }
- }
-
- public ObjectNode message(String type, ObjectNode payload) {
- ObjectNode message = mapper.createObjectNode().put("event", type);
- message.set("payload", payload);
- return message;
- }
-
- // Creates new message handlers.
- private synchronized void createHandlers() {
- }
-
- // Destroys message handlers.
- private synchronized void destroyHandlers() {
- }
-
-}
-
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java
deleted file mode 100644
index a8705003..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.io.ByteStreams;
-import com.google.common.net.MediaType;
-import org.eclipse.jetty.websocket.WebSocket;
-import org.eclipse.jetty.websocket.WebSocketServlet;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * Web socket servlet capable of creating web sockets for the STC monitor.
- */
-public class MonitorWebSocketServlet extends WebSocketServlet
- implements MonitorDelegate {
-
- private static final long PING_DELAY_MS = 5000;
- private static final String DOT = ".";
-
- private static Monitor monitor;
- private static MonitorWebSocketServlet instance;
-
- private final Set<MonitorWebSocket> sockets = new HashSet<>();
- private final Timer timer = new Timer();
- private final TimerTask pruner = new Pruner();
-
- /**
- * Binds the shared process flow monitor.
- *
- * @param m process monitor reference
- */
- public static void setMonitor(Monitor m) {
- monitor = m;
- }
-
- /**
- * Closes all currently open monitor web-sockets.
- */
- public static void closeAll() {
- if (instance != null) {
- instance.sockets.forEach(MonitorWebSocket::close);
- instance.sockets.clear();
- }
- }
-
- @Override
- public void init() throws ServletException {
- super.init();
- instance = this;
- monitor.setDelegate(this);
- timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS);
- }
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- String uri = req.getRequestURI();
- uri = uri.length() <= 1 ? "/index.html" : uri;
- InputStream resource = getClass().getResourceAsStream(uri);
- if (resource == null) {
- resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
- } else {
- byte[] entity = ByteStreams.toByteArray(resource);
- resp.setStatus(HttpServletResponse.SC_OK);
- resp.setContentType(contentType(uri).toString());
- resp.setContentLength(entity.length);
- resp.getOutputStream().write(entity);
- }
- }
-
- private MediaType contentType(String uri) {
- int sep = uri.lastIndexOf(DOT);
- String ext = sep > 0 ? uri.substring(sep + 1) : null;
- return ext == null ? MediaType.APPLICATION_BINARY :
- ext.equals("html") ? MediaType.HTML_UTF_8 :
- ext.equals("js") ? MediaType.JAVASCRIPT_UTF_8 :
- ext.equals("css") ? MediaType.CSS_UTF_8 :
- MediaType.APPLICATION_BINARY;
- }
-
- @Override
- public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
- MonitorWebSocket socket = new MonitorWebSocket(monitor);
- synchronized (sockets) {
- sockets.add(socket);
- }
- return socket;
- }
-
- @Override
- public void notify(ObjectNode event) {
- if (instance != null) {
- instance.sockets.forEach(ws -> ws.sendMessage(event));
- }
- }
-
- // Task for pruning web-sockets that are idle.
- private class Pruner extends TimerTask {
- @Override
- public void run() {
- synchronized (sockets) {
- Iterator<MonitorWebSocket> it = sockets.iterator();
- while (it.hasNext()) {
- MonitorWebSocket socket = it.next();
- if (socket.isIdle()) {
- it.remove();
- socket.close();
- }
- }
- }
- }
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java
deleted file mode 100644
index 4d99b339..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import org.onlab.graph.MutableAdjacencyListsGraph;
-
-import java.util.Set;
-
-/**
- * Graph representation of a test process flow.
- */
-public class ProcessFlow extends MutableAdjacencyListsGraph<Step, Dependency> {
-
- /**
- * Creates a graph comprising of the specified vertexes and edges.
- *
- * @param vertexes set of graph vertexes
- * @param edges set of graph edges
- */
- public ProcessFlow(Set<Step> vertexes, Set<Dependency> edges) {
- super(vertexes, edges);
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java
deleted file mode 100644
index fd2cd62d..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.HierarchicalConfiguration;
-import org.apache.commons.configuration.XMLConfiguration;
-
-import java.io.InputStream;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-/**
- * Representation of a re-usable test scenario.
- */
-public final class Scenario {
-
- private static final String SCENARIO = "scenario";
- private static final String NAME = "[@name]";
- private static final String DESCRIPTION = "[@description]";
-
- private final String name;
- private final String description;
- private final HierarchicalConfiguration definition;
-
- // Creates a new scenario from the specified definition.
- private Scenario(String name, String description, HierarchicalConfiguration definition) {
- this.name = checkNotNull(name, "Name cannot be null");
- this.description = checkNotNull(description, "Description cannot be null");
- this.definition = checkNotNull(definition, "Definition cannot be null");
- }
-
- /**
- * Loads a new scenario from the specified hierarchical configuration.
- *
- * @param definition scenario definition
- * @return loaded scenario
- */
- public static Scenario loadScenario(HierarchicalConfiguration definition) {
- String name = definition.getString(NAME);
- String description = definition.getString(DESCRIPTION, "");
- checkState(name != null, "Scenario name must be specified");
- return new Scenario(name, description, definition);
- }
-
- /**
- * Loads a new scenario from the specified input stream.
- *
- * @param stream scenario definition stream
- * @return loaded scenario
- */
- public static Scenario loadScenario(InputStream stream) {
- XMLConfiguration cfg = new XMLConfiguration();
- cfg.setAttributeSplittingDisabled(true);
- cfg.setDelimiterParsingDisabled(true);
- cfg.setRootElementName(SCENARIO);
- try {
- cfg.load(stream);
- return loadScenario(cfg);
- } catch (ConfigurationException e) {
- throw new IllegalArgumentException("Unable to load scenario from the stream", e);
- }
- }
-
- /**
- * Returns the scenario name.
- *
- * @return scenario name
- */
- public String name() {
- return name;
- }
-
- /**
- * Returns the scenario description.
- *
- * @return scenario description
- */
- public String description() {
- return description;
- }
-
- /**
- * Returns the scenario definition.
- *
- * @return scenario definition
- */
- public HierarchicalConfiguration definition() {
- return definition;
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java
deleted file mode 100644
index 7313462e..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.onlab.stc.Coordinator.Status;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onlab.stc.Coordinator.Status.*;
-import static org.onlab.stc.Coordinator.print;
-
-/**
- * Maintains state of scenario execution.
- */
-class ScenarioStore {
-
- private final ProcessFlow processFlow;
- private final File storeFile;
- private final File logDir;
-
- private final List<StepEvent> events = Lists.newArrayList();
- private final Map<String, Status> statusMap = Maps.newConcurrentMap();
-
- private long startTime = Long.MAX_VALUE;
- private long endTime = Long.MIN_VALUE;
-
- /**
- * Creates a new scenario store for the specified process flow.
- *
- * @param processFlow scenario process flow
- * @param logDir scenario log directory
- * @param name scenario name
- */
- ScenarioStore(ProcessFlow processFlow, File logDir, String name) {
- this.processFlow = processFlow;
- this.logDir = logDir;
- this.storeFile = new File(logDir, name + ".stc");
- load();
- }
-
- /**
- * Resets status of all steps to waiting and clears all events.
- */
- void reset() {
- events.clear();
- statusMap.clear();
- processFlow.getVertexes().forEach(step -> statusMap.put(step.name(), WAITING));
- try {
- removeLogs();
- PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
- cfg.clear();
- cfg.save();
- startTime = Long.MAX_VALUE;
- endTime = Long.MIN_VALUE;
- } catch (ConfigurationException e) {
- print("Unable to store file %s", storeFile);
- }
-
- }
-
- /**
- * Returns set of all test steps.
- *
- * @return set of steps
- */
- Set<Step> getSteps() {
- return processFlow.getVertexes();
- }
-
- /**
- * Returns a chronological list of step or group records.
- *
- * @return list of events
- */
- synchronized List<StepEvent> getEvents() {
- return ImmutableList.copyOf(events);
- }
-
- /**
- * Returns the status record of the specified test step.
- *
- * @param step test step or group
- * @return step status record
- */
- Status getStatus(Step step) {
- return checkNotNull(statusMap.get(step.name()), "Step %s not found", step.name());
- }
-
- /**
- * Marks the specified test step as being in progress.
- *
- * @param step test step or group
- */
- synchronized void markStarted(Step step) {
- add(new StepEvent(step.name(), IN_PROGRESS, step.command()));
- save();
- }
-
- /**
- * Marks the specified test step as being complete.
- *
- * @param step test step or group
- * @param status new step status
- */
- synchronized void markComplete(Step step, Status status) {
- add(new StepEvent(step.name(), status, null));
- save();
- }
-
- /**
- * Returns true if all steps in the store have been marked as completed
- * regardless of the completion status.
- *
- * @return true if all steps completed one way or another
- */
- synchronized boolean isComplete() {
- return !statusMap.values().stream().anyMatch(s -> s == WAITING || s == IN_PROGRESS);
- }
-
- /**
- * Indicates whether there are any failures.
- *
- * @return true if there are failed steps
- */
- boolean hasFailures() {
- for (Status status : statusMap.values()) {
- if (status == FAILED) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Registers a new step record.
- *
- * @param event step event
- */
- private synchronized void add(StepEvent event) {
- events.add(event);
- statusMap.put(event.name(), event.status());
- startTime = Math.min(startTime, event.time());
- endTime = Math.max(endTime, event.time());
- }
-
- /**
- * Loads the states from disk.
- */
- private void load() {
- try {
- PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
- cfg.getKeys().forEachRemaining(prop -> add(StepEvent.fromString(cfg.getString(prop))));
- cfg.save();
- } catch (ConfigurationException e) {
- print("Unable to load file %s", storeFile);
- }
- }
-
- /**
- * Saves the states to disk.
- */
- private void save() {
- try {
- PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
- events.forEach(event -> cfg.setProperty("T" + event.time(), event.toString()));
- cfg.save();
- } catch (ConfigurationException e) {
- print("Unable to store file %s", storeFile);
- }
- }
-
- /**
- * Removes all scenario log files.
- */
- private void removeLogs() {
- File[] logFiles = logDir.listFiles();
- if (logFiles != null && logFiles.length > 0) {
- for (File file : logFiles) {
- if (!file.delete()) {
- print("Unable to delete log file %s", file);
- }
- }
- }
- }
-
- /**
- * Returns the scenario run start time.
- *
- * @return start time in mills since start of epoch
- */
- public long startTime() {
- return startTime;
- }
-
- /**
- * Returns the scenario run end time or current time if the scenario
- * is still running.
- *
- * @return end time (or current time) in mills since start of epoch
- */
- public long endTime() {
- return endTime > 0 ? endTime : System.currentTimeMillis();
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java
deleted file mode 100644
index e14addb5..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import com.google.common.base.MoreObjects;
-import org.onlab.graph.Vertex;
-
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Representation of a test step.
- */
-public class Step implements Vertex {
-
- protected final String name;
- protected final String command;
- protected final String env;
- protected final String cwd;
- protected final Group group;
-
- /**
- * Creates a new test step.
- *
- * @param name step name
- * @param command step command to execute
- * @param env path to file to be sourced into the environment
- * @param cwd path to current working directory for the step
- * @param group optional group to which this step belongs
- */
- public Step(String name, String command, String env, String cwd, Group group) {
- this.name = checkNotNull(name, "Name cannot be null");
- this.group = group;
-
- // Set the command, environment and cwd
- // If one is not given use the value from the enclosing group
- this.command = command != null ? command : group != null && group.command != null ? group.command : null;
- this.env = env != null ? env : group != null && group.env != null ? group.env : null;
- this.cwd = cwd != null ? cwd : group != null && group.cwd != null ? group.cwd : null;
- }
-
- /**
- * Returns the step name.
- *
- * @return step name
- */
- public String name() {
- return name;
- }
-
- /**
- * Returns the step command string.
- *
- * @return command string
- */
- public String command() {
- return command;
- }
-
- /**
- * Returns the step environment script path.
- *
- * @return env script path
- */
- public String env() {
- return env;
- }
-
- /**
- * Returns the step current working directory path.
- *
- * @return current working dir path
- */
- public String cwd() {
- return cwd;
- }
-
- /**
- * Returns the enclosing group; null if none.
- *
- * @return enclosing group or null
- */
- public Group group() {
- return group;
- }
-
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof Step) {
- final Step other = (Step) obj;
- return Objects.equals(this.name, other.name);
- }
- return false;
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("name", name)
- .add("command", command)
- .add("env", env)
- .add("cwd", cwd)
- .add("group", group)
- .toString();
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java
deleted file mode 100644
index c9b81a24..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import org.onlab.stc.Coordinator.Status;
-
-import static java.lang.Long.parseLong;
-import static org.onlab.stc.Coordinator.Status.valueOf;
-
-/**
- * Represents an event of execution of a scenario step or group.
- */
-public class StepEvent {
-
- private static final String SEP = "~";
-
- private final String name;
- private final long time;
- private final Status status;
- private final String command;
-
- /**
- * Creates a new step record.
- *
- * @param name test step or group name
- * @param time time in millis since start of epoch
- * @param status step completion status
- * @param command step command
- */
- public StepEvent(String name, long time, Status status, String command) {
- this.name = name;
- this.time = time;
- this.status = status;
- this.command = command;
- }
-
- /**
- * Creates a new step record for non-running status.
- *
- * @param name test step or group name
- * @param status status
- * @param command step command
- */
- public StepEvent(String name, Status status, String command) {
- this(name, System.currentTimeMillis(), status, command);
- }
-
- /**
- * Returns the test step or test group name.
- *
- * @return step or group name
- */
- public String name() {
- return name;
- }
-
- /**
- * Returns the step event time.
- *
- * @return time in millis since start of epoch
- */
- public long time() {
- return time;
- }
-
- /**
- * Returns the step completion status.
- *
- * @return completion status
- */
- public Status status() {
- return status;
- }
-
- /**
- * Returns the step command.
- *
- * @return step command
- */
- public String command() {
- return command;
- }
-
-
- @Override
- public String toString() {
- return name + SEP + time + SEP + status + SEP + command;
- }
-
- /**
- * Returns a record parsed from the specified string.
- *
- * @param string string encoding
- * @return step record
- */
- public static StepEvent fromString(String string) {
- String[] fields = string.split("~");
- return fields.length == 4 ?
- new StepEvent(fields[0], parseLong(fields[1]), valueOf(fields[2]),
- fields[3].equals("null") ? null : fields[3]) :
- new StepEvent(fields[0], 0, Status.WAITING, null);
- }
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java
deleted file mode 100644
index a8222d0b..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-/**
- * Entity capable of receiving notifications of process step execution events.
- */
-public interface StepProcessListener {
-
- /**
- * Indicates that process step has started.
- *
- * @param step subject step
- * @param command actual command executed; includes run-time substitutions
- */
- default void onStart(Step step, String command) {
- }
-
- /**
- * Indicates that process step has completed.
- *
- * @param step subject step
- * @param status step completion status
- */
- default void onCompletion(Step step, Coordinator.Status status) {
- }
-
- /**
- * Notifies when a new line of output becomes available.
- *
- * @param step subject step
- * @param line line of output
- */
- default void onOutput(Step step, String line) {
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
deleted file mode 100644
index 49943691..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.
- */
-package org.onlab.stc;
-
-import org.onlab.stc.Coordinator.Status;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-
-import static java.lang.String.format;
-import static org.onlab.stc.Coordinator.Status.FAILED;
-import static org.onlab.stc.Coordinator.Status.SUCCEEDED;
-import static org.onlab.stc.Coordinator.print;
-
-/**
- * Manages execution of the specified step or a group.
- */
-class StepProcessor implements Runnable {
-
- private static final String IGNORE_CODE = "~";
- private static final String NEGATE_CODE = "!";
-
- private static final int FAIL = -1;
-
- static String launcher = "stc-launcher ";
-
- private final Step step;
- private final File logDir;
- private String command;
-
- private Process process;
- private StepProcessListener delegate;
-
- /**
- * Creates a process monitor.
- *
- * @param step step or group to be executed
- * @param logDir directory where step process log should be stored
- * @param delegate process lifecycle listener
- * @param command actual command to execute
- */
- StepProcessor(Step step, File logDir, StepProcessListener delegate,
- String command) {
- this.step = step;
- this.logDir = logDir;
- this.delegate = delegate;
- this.command = command;
- }
-
- @Override
- public void run() {
- delegate.onStart(step, command);
- int code = execute();
- boolean ignoreCode = step.env() != null && step.env.equals(IGNORE_CODE);
- boolean negateCode = step.env() != null && step.env.equals(NEGATE_CODE);
- Status status = ignoreCode || code == 0 && !negateCode || code != 0 && negateCode ?
- SUCCEEDED : FAILED;
- delegate.onCompletion(step, status);
- }
-
- /**
- * Executes the step process.
- *
- * @return exit code
- */
- private int execute() {
- try (PrintWriter pw = new PrintWriter(logFile())) {
- process = Runtime.getRuntime().exec(command());
- processOutput(pw);
-
- // Wait for the process to complete and get its exit code.
- if (process.isAlive()) {
- process.waitFor();
- }
- return process.exitValue();
-
- } catch (IOException e) {
- print("Unable to run step %s using command %s", step.name(), step.command());
- } catch (InterruptedException e) {
- print("Step %s interrupted", step.name());
- }
- return FAIL;
- }
-
- /**
- * Returns ready-to-run command for the step.
- *
- * @return command to execute
- */
- private String command() {
- return format("%s %s %s %s", launcher,
- step.env() != null ? step.env() : "-",
- step.cwd() != null ? step.cwd() : "-",
- command);
- }
-
- /**
- * Captures output of the step process.
- *
- * @param pw print writer to send output to
- * @throws IOException if unable to read output or write logs
- */
- private void processOutput(PrintWriter pw) throws IOException {
- InputStream out = process.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(out));
-
- // Slurp its combined stderr/stdout
- String line;
- while ((line = br.readLine()) != null) {
- pw.println(line);
- delegate.onOutput(step, line);
- }
- }
-
- /**
- * Returns the log file for the step output.
- *
- * @return log file
- */
- private File logFile() {
- return new File(logDir, step.name() + ".log");
- }
-
-}
diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java
deleted file mode 100644
index 56145899..00000000
--- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * System Test Coordinator tool for modular scenario-based testing.
- */
-package org.onlab.stc; \ No newline at end of file