blob: 8b8e6531532c163bb48912ff1d794bfa5598d380 [file] [log] [blame]
Thomas Vachuskaf9c84362015-04-15 11:20:45 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuskaf9c84362015-04-15 11:20:45 -07003 *
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 com.google.common.collect.Lists;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070020import com.google.common.collect.Maps;
21import org.apache.commons.configuration.ConfigurationException;
22import org.apache.commons.configuration.PropertiesConfiguration;
23import org.onlab.stc.Coordinator.Status;
24
25import java.io.File;
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070026import java.util.List;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070027import java.util.Map;
28import java.util.Set;
29
30import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070031import static org.onlab.stc.Coordinator.Status.*;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070032import static org.onlab.stc.Coordinator.print;
33
34/**
35 * Maintains state of scenario execution.
36 */
37class ScenarioStore {
38
39 private final ProcessFlow processFlow;
40 private final File storeFile;
Thomas Vachuskaa48e3d12015-06-02 09:43:29 -070041 private final File logDir;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070042
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070043 private final List<StepEvent> events = Lists.newArrayList();
44 private final Map<String, Status> statusMap = Maps.newConcurrentMap();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070045
Thomas Vachuskad542cc42015-09-11 16:15:36 -070046 private long startTime = Long.MAX_VALUE;
47 private long endTime = Long.MIN_VALUE;
48
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070049 /**
50 * Creates a new scenario store for the specified process flow.
51 *
52 * @param processFlow scenario process flow
53 * @param logDir scenario log directory
54 * @param name scenario name
55 */
56 ScenarioStore(ProcessFlow processFlow, File logDir, String name) {
57 this.processFlow = processFlow;
Thomas Vachuskaa48e3d12015-06-02 09:43:29 -070058 this.logDir = logDir;
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070059 this.storeFile = new File(logDir, name + ".stc");
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070060 load();
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070061 }
62
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070063 /**
64 * Resets status of all steps to waiting and clears all events.
65 */
66 void reset() {
67 events.clear();
68 statusMap.clear();
69 processFlow.getVertexes().forEach(step -> statusMap.put(step.name(), WAITING));
70 try {
Thomas Vachuskaa48e3d12015-06-02 09:43:29 -070071 removeLogs();
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070072 PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
73 cfg.clear();
74 cfg.save();
Thomas Vachuskad542cc42015-09-11 16:15:36 -070075 startTime = Long.MAX_VALUE;
76 endTime = Long.MIN_VALUE;
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070077 } catch (ConfigurationException e) {
78 print("Unable to store file %s", storeFile);
79 }
80
81 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070082
83 /**
84 * Returns set of all test steps.
85 *
86 * @return set of steps
87 */
88 Set<Step> getSteps() {
89 return processFlow.getVertexes();
90 }
91
92 /**
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070093 * Returns a chronological list of step or group records.
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070094 *
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070095 * @return list of events
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070096 */
Thomas Vachuska50ec1af2015-06-02 00:42:52 -070097 synchronized List<StepEvent> getEvents() {
98 return ImmutableList.copyOf(events);
Thomas Vachuskaf9c84362015-04-15 11:20:45 -070099 }
100
101 /**
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700102 * Returns the status record of the specified test step.
103 *
104 * @param step test step or group
105 * @return step status record
106 */
107 Status getStatus(Step step) {
108 return checkNotNull(statusMap.get(step.name()), "Step %s not found", step.name());
109 }
110
111 /**
112 * Marks the specified test step as being in progress.
113 *
114 * @param step test step or group
115 */
116 synchronized void markStarted(Step step) {
Thomas Vachuska0ec6ff42015-07-17 11:00:02 -0700117 add(new StepEvent(step.name(), IN_PROGRESS, step.command()));
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700118 save();
119 }
120
121 /**
122 * Marks the specified test step as being complete.
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700123 *
124 * @param step test step or group
125 * @param status new step status
126 */
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700127 synchronized void markComplete(Step step, Status status) {
Thomas Vachuska0ec6ff42015-07-17 11:00:02 -0700128 add(new StepEvent(step.name(), status, null));
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700129 save();
130 }
131
132 /**
Thomas Vachuska1b403a52015-08-26 11:30:48 -0700133 * Returns true if all steps in the store have been marked as completed
134 * regardless of the completion status.
135 *
136 * @return true if all steps completed one way or another
137 */
138 synchronized boolean isComplete() {
139 return !statusMap.values().stream().anyMatch(s -> s == WAITING || s == IN_PROGRESS);
140 }
141
142 /**
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700143 * Indicates whether there are any failures.
144 *
145 * @return true if there are failed steps
146 */
147 boolean hasFailures() {
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700148 for (Status status : statusMap.values()) {
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700149 if (status == FAILED) {
150 return true;
151 }
152 }
153 return false;
154 }
155
156 /**
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700157 * Registers a new step record.
158 *
159 * @param event step event
160 */
161 private synchronized void add(StepEvent event) {
162 events.add(event);
163 statusMap.put(event.name(), event.status());
Thomas Vachuskad542cc42015-09-11 16:15:36 -0700164 startTime = Math.min(startTime, event.time());
165 endTime = Math.max(endTime, event.time());
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700166 }
167
168 /**
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700169 * Loads the states from disk.
170 */
171 private void load() {
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700172 try {
173 PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
174 cfg.getKeys().forEachRemaining(prop -> add(StepEvent.fromString(cfg.getString(prop))));
175 cfg.save();
176 } catch (ConfigurationException e) {
Thomas Vachuskae827c0e2015-08-04 16:53:18 -0700177 print("Unable to load file %s", storeFile);
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700178 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700179 }
180
181 /**
182 * Saves the states to disk.
183 */
184 private void save() {
185 try {
186 PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile);
Thomas Vachuska50ec1af2015-06-02 00:42:52 -0700187 events.forEach(event -> cfg.setProperty("T" + event.time(), event.toString()));
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700188 cfg.save();
189 } catch (ConfigurationException e) {
190 print("Unable to store file %s", storeFile);
191 }
192 }
193
Thomas Vachuskaa48e3d12015-06-02 09:43:29 -0700194 /**
195 * Removes all scenario log files.
196 */
197 private void removeLogs() {
198 File[] logFiles = logDir.listFiles();
199 if (logFiles != null && logFiles.length > 0) {
200 for (File file : logFiles) {
201 if (!file.delete()) {
202 print("Unable to delete log file %s", file);
203 }
204 }
205 }
206 }
207
Thomas Vachuskad542cc42015-09-11 16:15:36 -0700208 /**
209 * Returns the scenario run start time.
210 *
211 * @return start time in mills since start of epoch
212 */
213 public long startTime() {
214 return startTime;
215 }
216
217 /**
218 * Returns the scenario run end time or current time if the scenario
219 * is still running.
220 *
221 * @return end time (or current time) in mills since start of epoch
222 */
223 public long endTime() {
224 return endTime > 0 ? endTime : System.currentTimeMillis();
225 }
Thomas Vachuskaf9c84362015-04-15 11:20:45 -0700226}