blob: bcb259de3de5dfd963ea9183d3edcdb9c2f6ece5 [file] [log] [blame]
Thomas Vachuskaf9c84362015-04-15 11:20:45 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.stc;
17
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070018import com.google.common.collect.ImmutableList;
19import org.onlab.stc.Coordinator.Status;
20
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070021import java.io.FileInputStream;
22import java.io.FileNotFoundException;
23import java.text.SimpleDateFormat;
24import java.util.Date;
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070025import java.util.List;
26import java.util.Objects;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070027
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070028import static java.lang.System.currentTimeMillis;
29import static org.onlab.stc.Coordinator.Status.*;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070030import static org.onlab.stc.Coordinator.print;
31
32/**
33 * Main program for executing system test coordinator.
34 */
35public final class Main {
36
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070037 private static final String NONE = "\u001B[0m";
38 private static final String GRAY = "\u001B[30;1m";
39 private static final String RED = "\u001B[31;1m";
40 private static final String GREEN = "\u001B[32;1m";
41 private static final String BLUE = "\u001B[36m";
42
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070043 private enum Command {
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070044 LIST, RUN, RUN_RANGE, HELP
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070045 }
46
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070047 private final String scenarioFile;
48
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070049 private Command command = Command.HELP;
50 private String runFromPatterns = "";
51 private String runToPatterns = "";
52
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070053 private Coordinator coordinator;
54 private Listener delegate = new Listener();
55
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070056 private static boolean useColor = Objects.equals("true", System.getenv("stcColor"));
57
58 // usage: stc [<scenario-file>] [run]
59 // usage: stc [<scenario-file>] run [from <from-patterns>] [to <to-patterns>]]
60 // usage: stc [<scenario-file>] list
61
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070062 // Public construction forbidden
63 private Main(String[] args) {
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070064 this.scenarioFile = args[0];
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070065
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070066 if (args.length <= 1 || args.length == 2 && args[1].equals("run")) {
67 command = Command.RUN;
68 } else if (args.length == 2 && args[1].equals("list")) {
69 command = Command.LIST;
70 } else if (args.length >= 4 && args[1].equals("run")) {
71 int i = 2;
72 if (args[i].equals("from")) {
73 command = Command.RUN_RANGE;
74 runFromPatterns = args[i + 1];
75 i += 2;
76 }
77
78 if (args.length >= i + 2 && args[i].equals("to")) {
79 command = Command.RUN_RANGE;
80 runToPatterns = args[i + 1];
81 }
82 }
83 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070084
85 /**
86 * Main entry point for coordinating test scenario execution.
87 *
88 * @param args command-line arguments
89 */
90 public static void main(String[] args) {
91 Main main = new Main(args);
92 main.run();
93 }
94
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070095 // Runs the scenario processing
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070096 private void run() {
97 try {
98 // Load scenario
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070099 Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile));
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700100
101 // Elaborate scenario
102 Compiler compiler = new Compiler(scenario);
103 compiler.compile();
104
105 // Execute process flow
106 coordinator = new Coordinator(scenario, compiler.processFlow(),
107 compiler.logDir());
108 coordinator.addListener(delegate);
109 processCommand();
110
111 } catch (FileNotFoundException e) {
112 print("Unable to find scenario file %s", scenarioFile);
113 }
114 }
115
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700116 // Processes the appropriate command
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700117 private void processCommand() {
118 switch (command) {
119 case RUN:
120 processRun();
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700121 break;
122 case LIST:
123 processList();
124 break;
125 case RUN_RANGE:
126 processRunRange();
127 break;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700128 default:
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700129 print("Unsupported command %s", command);
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700130 }
131 }
132
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700133 // Processes the scenario 'run' command.
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700134 private void processRun() {
135 try {
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700136 coordinator.reset();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700137 coordinator.start();
138 int exitCode = coordinator.waitFor();
139 pause(100); // allow stdout to flush
140 System.exit(exitCode);
141 } catch (InterruptedException e) {
142 print("Unable to execute scenario %s", scenarioFile);
143 }
144 }
145
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700146 // Processes the scenario 'list' command.
147 private void processList() {
148 coordinator.getRecords()
149 .forEach(event -> logStatus(event.time(), event.name(), event.status()));
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700150 }
151
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700152 // Processes the scenario 'run' command for range of steps.
153 private void processRunRange() {
154 try {
155 coordinator.reset(list(runFromPatterns), list(runToPatterns));
156 coordinator.start();
157 int exitCode = coordinator.waitFor();
158 pause(100); // allow stdout to flush
159 System.exit(exitCode);
160 } catch (InterruptedException e) {
161 print("Unable to execute scenario %s", scenarioFile);
162 }
163 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700164
165 /**
166 * Internal delegate to monitor the process execution.
167 */
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700168 private static class Listener implements StepProcessListener {
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700169 @Override
170 public void onStart(Step step) {
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700171 logStatus(currentTimeMillis(), step.name(), IN_PROGRESS);
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700172 }
173
174 @Override
Thomas Vachuska86439372015-06-05 09:21:32 -0700175 public void onCompletion(Step step, Status status) {
176 logStatus(currentTimeMillis(), step.name(), status);
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700177 }
178
179 @Override
180 public void onOutput(Step step, String line) {
181 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700182 }
183
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700184 // Logs the step status.
185 private static void logStatus(long time, String name, Status status) {
186 print("%s %s%s %s%s", time(time), color(status), name, action(status), color(null));
187 }
188
189 // Produces a description of event using the specified step status.
190 private static String action(Status status) {
191 return status == IN_PROGRESS ? "started" :
192 (status == SUCCEEDED ? "completed" :
193 (status == FAILED ? "failed" :
194 (status == SKIPPED ? "skipped" : "waiting")));
195 }
196
197 // Produces an ANSI escape code for color using the specified step status.
198 private static String color(Status status) {
199 if (!useColor) {
200 return "";
201 }
202 return status == null ? NONE :
203 (status == IN_PROGRESS ? BLUE :
204 (status == SUCCEEDED ? GREEN :
205 (status == FAILED ? RED : GRAY)));
206 }
207
208 // Produces a list from the specified comma-separated string.
209 private static List<String> list(String patterns) {
210 return ImmutableList.copyOf(patterns.split(","));
211 }
212
213 // Produces a formatted time stamp.
214 private static String time(long time) {
215 return new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date(time));
216 }
217
218 // Pauses for the specified number of millis.
219 private static void pause(int ms) {
220 try {
221 Thread.sleep(ms);
222 } catch (InterruptedException e) {
223 print("Interrupted!");
224 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700225 }
226
227}