Toggle navigation
Toggle navigation
This project
Loading...
Sign in
홍길동
/
onos
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
Thomas Vachuska
2015-06-02 00:42:52 -0700
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
50ec1af6c24ab25052f35d959b708fb1ad7fd5ce
50ec1af6
1 parent
1d126d38
Enhancing STC
Change-Id: If9429cc6a30333bd27b579825fe6b1fac221cf60
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
339 additions
and
45 deletions
tools/test/bin/stc
utils/stc/src/main/java/org/onlab/stc/Coordinator.java
utils/stc/src/main/java/org/onlab/stc/Main.java
utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java
utils/stc/src/main/java/org/onlab/stc/StepEvent.java
utils/stc/src/test/java/org/onlab/stc/CoordinatorTest.java
tools/test/bin/stc
View file @
50ec1af
...
...
@@ -13,4 +13,8 @@ scenario=${1:-smoke}
[
! -f
$scenario
]
&&
scenario
=
$scenario
.xml
[
! -f
$scenario
]
&&
echo
"Scenario
$scenario
file not found"
&&
exit
1
java -jar
$JAR
$scenario
[
$#
-ge 1
]
&&
shift
[
-t 1
]
&&
stcColor
=
true
||
unset
stcColor
java -jar
$JAR
$scenario
"
$@
"
...
...
utils/stc/src/main/java/org/onlab/stc/Coordinator.java
View file @
50ec1af
...
...
@@ -15,9 +15,11 @@
*/
package
org
.
onlab
.
stc
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.Sets
;
import
java.io.File
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.ExecutorService
;
...
...
@@ -36,7 +38,6 @@ public class Coordinator {
private
final
ExecutorService
executor
=
newFixedThreadPool
(
MAX_THREADS
);
private
final
Scenario
scenario
;
private
final
ProcessFlow
processFlow
;
private
final
StepProcessListener
delegate
;
...
...
@@ -57,7 +58,7 @@ public class Coordinator {
* Represents processor state.
*/
public
enum
Status
{
WAITING
,
IN_PROGRESS
,
SUCCEEDED
,
FAILED
WAITING
,
IN_PROGRESS
,
SUCCEEDED
,
FAILED
,
SKIPPED
}
/**
...
...
@@ -68,7 +69,6 @@ public class Coordinator {
* @param logDir scenario log directory
*/
public
Coordinator
(
Scenario
scenario
,
ProcessFlow
processFlow
,
File
logDir
)
{
this
.
scenario
=
scenario
;
this
.
processFlow
=
processFlow
;
this
.
logDir
=
logDir
;
this
.
store
=
new
ScenarioStore
(
processFlow
,
logDir
,
scenario
.
name
());
...
...
@@ -77,6 +77,46 @@ public class Coordinator {
}
/**
* 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 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
()
{
...
...
@@ -104,10 +144,19 @@ public class Coordinator {
}
/**
* Returns the status of the specified test step.
* 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
* @return step status
record
*/
public
Status
getStatus
(
Step
step
)
{
return
store
.
getStatus
(
step
);
...
...
@@ -138,6 +187,7 @@ public class Coordinator {
* @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
->
{
...
...
@@ -155,7 +205,7 @@ public class Coordinator {
private
synchronized
void
execute
(
Step
step
)
{
Directive
directive
=
nextAction
(
step
);
if
(
directive
==
RUN
||
directive
==
SKIP
)
{
store
.
updateStatus
(
step
,
IN_PROGRESS
);
store
.
markStarted
(
step
);
if
(
step
instanceof
Group
)
{
Group
group
=
(
Group
)
step
;
delegate
.
onStart
(
group
);
...
...
@@ -247,7 +297,7 @@ public class Coordinator {
@Override
public
void
onCompletion
(
Step
step
,
int
exitCode
)
{
store
.
updateStatus
(
step
,
exitCode
==
0
?
SUCCEEDED
:
FAILED
);
store
.
markComplete
(
step
,
exitCode
==
0
?
SUCCEEDED
:
FAILED
);
listeners
.
forEach
(
listener
->
listener
.
onCompletion
(
step
,
exitCode
));
executeSucessors
(
step
);
latch
.
countDown
();
...
...
utils/stc/src/main/java/org/onlab/stc/Main.java
View file @
50ec1af
...
...
@@ -15,11 +15,18 @@
*/
package
org
.
onlab
.
stc
;
import
com.google.common.collect.ImmutableList
;
import
org.onlab.stc.Coordinator.Status
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Objects
;
import
static
java
.
lang
.
System
.
currentTimeMillis
;
import
static
org
.
onlab
.
stc
.
Coordinator
.
Status
.*;
import
static
org
.
onlab
.
stc
.
Coordinator
.
print
;
/**
...
...
@@ -27,30 +34,53 @@ import static org.onlab.stc.Coordinator.print;
*/
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
enum
Command
{
LIST
,
RUN
,
RUN_
FROM
,
RUN_TO
LIST
,
RUN
,
RUN_
RANGE
,
HELP
}
private
final
String
[]
args
;
private
final
Command
command
;
private
final
String
scenarioFile
;
private
Scenario
scenario
;
private
Command
command
=
Command
.
HELP
;
private
String
runFromPatterns
=
""
;
private
String
runToPatterns
=
""
;
private
Coordinator
coordinator
;
private
Listener
delegate
=
new
Listener
();
private
static
boolean
useColor
=
Objects
.
equals
(
"true"
,
System
.
getenv
(
"stcColor"
));
// 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
.
args
=
args
;
this
.
scenarioFile
=
args
[
0
];
this
.
command
=
Command
.
valueOf
(
"RUN"
);
}
// usage: stc [<command>] [<scenario-file>]
// --list
// [--run]
// --run-from <step>,...
// --run-to <step>,...
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.
...
...
@@ -62,10 +92,11 @@ public final class Main {
main
.
run
();
}
// Runs the scenario processing
private
void
run
()
{
try
{
// Load scenario
scenario
=
Scenario
.
loadScenario
(
new
FileInputStream
(
scenarioFile
));
Scenario
scenario
=
Scenario
.
loadScenario
(
new
FileInputStream
(
scenarioFile
));
// Elaborate scenario
Compiler
compiler
=
new
Compiler
(
scenario
);
...
...
@@ -82,17 +113,27 @@ public final class Main {
}
}
// 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
"
);
print
(
"Unsupported command
%s"
,
command
);
}
}
// Processes the scenario 'run' command.
private
void
processRun
()
{
try
{
coordinator
.
reset
();
coordinator
.
start
();
int
exitCode
=
coordinator
.
waitFor
();
pause
(
100
);
// allow stdout to flush
...
...
@@ -102,38 +143,85 @@ public final class Main {
}
}
private
void
pause
(
int
ms
)
{
// Processes the scenario 'list' command.
private
void
processList
()
{
coordinator
.
getRecords
()
.
forEach
(
event
->
logStatus
(
event
.
time
(),
event
.
name
(),
event
.
status
()));
}
// Processes the scenario 'run' command for range of steps.
private
void
processRunRange
()
{
try
{
Thread
.
sleep
(
ms
);
coordinator
.
reset
(
list
(
runFromPatterns
),
list
(
runToPatterns
));
coordinator
.
start
();
int
exitCode
=
coordinator
.
waitFor
();
pause
(
100
);
// allow stdout to flush
System
.
exit
(
exitCode
);
}
catch
(
InterruptedException
e
)
{
print
(
"
Interrupted!"
);
print
(
"
Unable to execute scenario %s"
,
scenarioFile
);
}
}
/**
* Internal delegate to monitor the process execution.
*/
private
class
Listener
implements
StepProcessListener
{
private
static
class
Listener
implements
StepProcessListener
{
@Override
public
void
onStart
(
Step
step
)
{
print
(
"%s %s started"
,
now
(),
step
.
name
()
);
logStatus
(
currentTimeMillis
(),
step
.
name
(),
IN_PROGRESS
);
}
@Override
public
void
onCompletion
(
Step
step
,
int
exitCode
)
{
print
(
"%s %s %s"
,
now
(),
step
.
name
(),
exitCode
==
0
?
"completed"
:
"failed"
);
logStatus
(
currentTimeMillis
(),
step
.
name
(),
exitCode
==
0
?
SUCCEEDED
:
FAILED
);
}
@Override
public
void
onOutput
(
Step
step
,
String
line
)
{
}
}
// Logs the step status.
private
static
void
logStatus
(
long
time
,
String
name
,
Status
status
)
{
print
(
"%s %s%s %s%s"
,
time
(
time
),
color
(
status
),
name
,
action
(
status
),
color
(
null
));
}
// 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"
)));
}
private
String
now
()
{
return
new
SimpleDateFormat
(
"YYYY-MM-dd HH:mm:ss"
).
format
(
new
Date
());
// 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!"
);
}
}
}
...
...
utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java
View file @
50ec1af
...
...
@@ -15,18 +15,20 @@
*/
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
.
FAILED
;
import
static
org
.
onlab
.
stc
.
Coordinator
.
Status
.
WAITING
;
import
static
org
.
onlab
.
stc
.
Coordinator
.
Status
.*;
import
static
org
.
onlab
.
stc
.
Coordinator
.
print
;
/**
...
...
@@ -37,7 +39,8 @@ class ScenarioStore {
private
final
ProcessFlow
processFlow
;
private
final
File
storeFile
;
private
final
Map
<
Step
,
Status
>
stepStatus
=
Maps
.
newConcurrentMap
();
private
final
List
<
StepEvent
>
events
=
Lists
.
newArrayList
();
private
final
Map
<
String
,
Status
>
statusMap
=
Maps
.
newConcurrentMap
();
/**
* Creates a new scenario store for the specified process flow.
...
...
@@ -49,9 +52,25 @@ class ScenarioStore {
ScenarioStore
(
ProcessFlow
processFlow
,
File
logDir
,
String
name
)
{
this
.
processFlow
=
processFlow
;
this
.
storeFile
=
new
File
(
logDir
,
name
+
".stc"
);
processFlow
.
getVertexes
().
forEach
(
step
->
stepStatus
.
put
(
step
,
WAITING
)
);
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
{
PropertiesConfiguration
cfg
=
new
PropertiesConfiguration
(
storeFile
);
cfg
.
clear
();
cfg
.
save
();
}
catch
(
ConfigurationException
e
)
{
print
(
"Unable to store file %s"
,
storeFile
);
}
}
/**
* Returns set of all test steps.
...
...
@@ -63,23 +82,42 @@ class ScenarioStore {
}
/**
* Returns the status of the specified test step.
* 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
* @return step status
record
*/
Status
getStatus
(
Step
step
)
{
return
checkNotNull
(
st
epStatus
.
get
(
step
),
"Step %s not found"
,
step
.
name
());
return
checkNotNull
(
st
atusMap
.
get
(
step
.
name
()
),
"Step %s not found"
,
step
.
name
());
}
/**
* Updates the status of the specified test step.
* 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
));
save
();
}
/**
* Marks the specified test step as being complete.
*
* @param step test step or group
* @param status new step status
*/
void
updateStatus
(
Step
step
,
Status
status
)
{
stepStatus
.
put
(
step
,
status
);
synchronized
void
markComplete
(
Step
step
,
Status
status
)
{
add
(
new
StepEvent
(
step
.
name
(),
status
)
);
save
();
}
...
...
@@ -89,7 +127,7 @@ class ScenarioStore {
* @return true if there are failed steps
*/
boolean
hasFailures
()
{
for
(
Status
status
:
st
epStatus
.
values
())
{
for
(
Status
status
:
st
atusMap
.
values
())
{
if
(
status
==
FAILED
)
{
return
true
;
}
...
...
@@ -98,10 +136,26 @@ class ScenarioStore {
}
/**
* Registers a new step record.
*
* @param event step event
*/
private
synchronized
void
add
(
StepEvent
event
)
{
events
.
add
(
event
);
statusMap
.
put
(
event
.
name
(),
event
.
status
());
}
/**
* Loads the states from disk.
*/
private
void
load
()
{
// FIXME: implement this
try
{
PropertiesConfiguration
cfg
=
new
PropertiesConfiguration
(
storeFile
);
cfg
.
getKeys
().
forEachRemaining
(
prop
->
add
(
StepEvent
.
fromString
(
cfg
.
getString
(
prop
))));
cfg
.
save
();
}
catch
(
ConfigurationException
e
)
{
print
(
"Unable to store file %s"
,
storeFile
);
}
}
/**
...
...
@@ -110,7 +164,7 @@ class ScenarioStore {
private
void
save
()
{
try
{
PropertiesConfiguration
cfg
=
new
PropertiesConfiguration
(
storeFile
);
stepStatus
.
forEach
((
step
,
status
)
->
cfg
.
setProperty
(
step
.
name
(),
status
));
events
.
forEach
(
event
->
cfg
.
setProperty
(
"T"
+
event
.
time
(),
event
.
toString
()
));
cfg
.
save
();
}
catch
(
ConfigurationException
e
)
{
print
(
"Unable to store file %s"
,
storeFile
);
...
...
utils/stc/src/main/java/org/onlab/stc/StepEvent.java
0 → 100644
View file @
50ec1af
/*
* 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
;
/**
* Represents an event of execution of a scenario step or group.
*/
public
class
StepEvent
{
private
final
String
name
;
private
final
long
time
;
private
final
Status
status
;
/**
* 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
*/
public
StepEvent
(
String
name
,
long
time
,
Status
status
)
{
this
.
name
=
name
;
this
.
time
=
time
;
this
.
status
=
status
;
}
/**
* Creates a new step record for non-running status.
*
* @param name test step or group name
* @param status status
*/
public
StepEvent
(
String
name
,
Status
status
)
{
this
(
name
,
System
.
currentTimeMillis
(),
status
);
}
/**
* 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
;
}
@Override
public
String
toString
()
{
return
name
+
":"
+
time
+
":"
+
status
;
}
/**
* 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
new
StepEvent
(
fields
[
0
],
parseLong
(
fields
[
1
]),
Status
.
valueOf
(
fields
[
2
]));
}
}
utils/stc/src/test/java/org/onlab/stc/CoordinatorTest.java
View file @
50ec1af
...
...
@@ -55,6 +55,7 @@ public class CoordinatorTest {
compiler
.
compile
();
coordinator
=
new
Coordinator
(
scenario
,
compiler
.
processFlow
(),
compiler
.
logDir
());
coordinator
.
addListener
(
listener
);
coordinator
.
reset
();
coordinator
.
start
();
coordinator
.
waitFor
();
coordinator
.
removeListener
(
listener
);
...
...
Please
register
or
login
to post a comment