Merge "Add KeyError exception handling for compareIntent function in OnosCliDriver"
diff --git a/TestON/core/graph.py b/TestON/core/graph.py
new file mode 100644
index 0000000..c893adc
--- /dev/null
+++ b/TestON/core/graph.py
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+import time
+import random
+
+class Graph:
+ """
+ Graph class provides implementations of graph algorithms.
+ The functions currently supported include:
+ - Comparing two graphs with specified attributes for vertices and edges
+ - Getting DFI (Depth First Index) and back edges during a DFS
+ - Chain decomposition of a graph
+ - Finding (non-)cut-edges and vertices
+ """
+
+ def __init__( self ):
+ # We use a dictionary to store all information about the graph
+ self.graphDict = {}
+ # Depth-first index of each vertex
+ self.DFI = {}
+ self.currentDFI = 0
+ # Parent vertex (and edge to that vertex) of each vertex in depth-first search tree
+ self.parentVertexInDFS = {}
+ self.parentEdgeInDFS = {}
+ # Back edges of the graph generated during DFS
+ self.backEdges = {}
+ # All chains in chain decomposition algorithm
+ self.chains = []
+
+ def update( self, graphDict ):
+ """
+ Update the graph data. The current graph dictionary will be replaced by the
+ new one.
+ graphDict is in a dictionary which maps each vertex to a list of attributes.
+ An example of graphDict:
+ { vertex1: { 'edges': ..., 'name': ..., 'protocol': ... },
+ vertex2: { 'edges': ..., 'name': ..., 'protocol': ... } }
+ Each vertex should at least have an 'edges' attribute which describes the
+ adjacency information. The value of 'edges' attribute is also represented by
+ a dictionary, which maps each edge (identified by the neighbor vertex) to a
+ list of attributes.
+ An example of the edges dictionary:
+ 'edges': { vertex2: { 'port': ..., 'type': ... },
+ vertex3: { 'port': ..., 'type': ... } }
+ """
+ self.graphDict = graphDict
+ return main.TRUE
+
+ def compareGraphs( self, graphDictA, graphDictB, vertexAttributes=['edges'], edgeAttributes=['port'] ):
+ """
+ Compare two graphs.
+ By default only the adjacency relationship, i.e. 'port' attribute in
+ 'edges' attribute for each vertex, is compared, To get other attributes
+ included, attribute name needs to be specified in the args, e.g.
+ vertexAttributes=[ 'edges', 'protocol' ] or
+ edgeAttributes=[ 'port', 'type' ]
+ Return main.TRUE if two graphs are equal, otherwise main.FALSE
+ """
+ try:
+ result = main.TRUE
+ for vertex in set( graphDictA ).difference( graphDictB ):
+ result = main.FALSE
+ main.log.warn( "Graph: graph B: vertex {} not found".format( vertex ) )
+ for vertex in set( graphDictB ).difference( graphDictA ):
+ result = main.FALSE
+ main.log.warn( "Graph: graph A: vertex {} not found".format( vertex ) )
+ for vertex in set( graphDictA ).intersection( graphDictB ):
+ for vertexAttribute in vertexAttributes:
+ attributeFound = True
+ if vertexAttribute not in graphDictA[ vertex ]:
+ main.log.warn( "Graph: graph A -> vertex {}: attribute {} not found".format( vertex, vertexAttribute ) )
+ attributeFound = False
+ if vertexAttribute not in graphDictB[ vertex ]:
+ attributeFound = False
+ main.log.warn( "Graph: graph B -> vertex {}: attribute {} not found".format( vertex, vertexAttribute ) )
+ if not attributeFound:
+ result = main.FALSE
+ continue
+ else:
+ # Compare two attributes
+ attributeValueA = graphDictA[ vertex ][ vertexAttribute ]
+ attributeValueB = graphDictB[ vertex ][ vertexAttribute ]
+ # FIXME: the comparison may not work for (sub)attribute values that are of list type
+ # For attributes except for 'edges', we just rely on '==' for comparison
+ if not vertexAttribute == 'edges':
+ if not attributeValueA == attributeValueB:
+ result = main.FALSE
+ main.log.warn( "Graph: vertex {}: {} does not match: {} and {}".format( vertex,
+ vertexAttribute,
+ attributeValueA,
+ attributeValueB ) )
+ # The structure of 'edges' is similar to that of graphs, so we use the same method for comparison
+ else:
+ edgeDictA = attributeValueA
+ edgeDictB = attributeValueB
+ for neighbor in set( edgeDictA ).difference( edgeDictB ):
+ result = main.FALSE
+ main.log.warn( "Graph: graph B -> vertex {}: neighbor {} not found".format( vertex, neighbor ) )
+ for neighbor in set( edgeDictB ).difference( edgeDictA ):
+ result = main.FALSE
+ main.log.warn( "Graph: graph A -> vertex {}: neighbor {} not found".format( vertex, neighbor ) )
+ for neighbor in set( edgeDictA ).intersection( edgeDictB ):
+ for edgeAttribute in edgeAttributes:
+ attributeFound = True
+ if edgeAttribute not in edgeDictA[ neighbor ]:
+ attributeFound = False
+ main.log.warn( "Graph: graph A -> vertex {} -> neighbor {}: attribute {} not found".format( vertex,
+ neighbor,
+ edgeAttribute ) )
+ if edgeAttribute not in edgeDictB[ neighbor ]:
+ attributeFound = False
+ main.log.warn( "Graph: graph B -> vertex {} -> neighbor {}: attribute {} not found".format( vertex,
+ neighbor,
+ edgeAttribute ) )
+ if not attributeFound:
+ result = main.FALSE
+ continue
+ else:
+ # Compare two attributes
+ attributeValueA = edgeDictA[ neighbor ][ edgeAttribute ]
+ attributeValueB = edgeDictB[ neighbor ][ edgeAttribute ]
+ if not attributeValueA == attributeValueB:
+ result = main.FALSE
+ main.log.warn( "Graph: vertex {} -> neighbor {}: {} does not match: {} and {}".format( vertex,
+ neighbor,
+ edgeAttribute,
+ attributeValueA,
+ attributeValueB ) )
+ if not result:
+ main.log.debug( "Graph: graphDictA: {}".format( graphDictA ) )
+ main.log.debug( "Graph: graphDictB: {}".format( graphDictB ) )
+ return result
+ except TypeError:
+ main.log.exception( "Graph: TypeError exception found" )
+ return main.ERROR
+ except KeyError:
+ main.log.exception( "Graph: KeyError exception found" )
+ return main.ERROR
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return main.ERROR
+
+ def getNonCutEdges( self ):
+ """
+ Get a list of non-cut-edges (non-bridges).
+ The definition of a cut-edge (bridge) is: the deletion of a cut-edge will
+ increase the number of connected component of a graph.
+ The function is realized by impelementing Schmidt's algorithm based on
+ chain decomposition.
+ Returns a list of edges, e.g.
+ [ [ vertex1, vertex2 ], [ vertex2, vertex3 ] ]
+ """
+ try:
+ if not self.depthFirstSearch():
+ return None
+ if not self.findChains():
+ return None
+ nonCutEdges = []
+ for chain in self.chains:
+ for edge in chain:
+ nonCutEdges.append( edge )
+ main.log.debug( 'Non-cut-edges: {}'.format( nonCutEdges ) )
+ return nonCutEdges
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return None
+
+ def getNonCutVertices( self ):
+ """
+ Get a list of non-cut-vertices.
+ The definition of a cut-vertex is: the deletion of a cut-vertex will
+ increase the number of connected component of a graph.
+ The function is realized by impelementing Schmidt's algorithm based on
+ chain decomposition.
+ Returns a list of vertices, e.g. [ vertex1, vertex2, vertex3 ]
+ """
+ try:
+ nonCutEdges = self.getNonCutEdges()
+ # find all cycle chains
+ cycleChains = []
+ for chain in self.chains:
+ # if the source vertex of the first chain equals to the destination vertex of the last
+ # chain, the chain is a cycle chain
+ if chain[ 0 ][ 0 ] == chain[ -1 ][ 1 ]:
+ cycleChains.append( chain )
+ main.log.debug( 'Cycle chains: {}'.format( cycleChains ) )
+ # Get a set of vertices which are the first vertices of a cycle chain (excluding the first
+ # cycle chain), and these vertices are a subset of all cut-vertices
+ subsetOfCutVertices = []
+ if len( cycleChains ) > 1:
+ for cycleChain in cycleChains[ 1: ]:
+ subsetOfCutVertices.append( cycleChain[ 0 ][ 0 ] )
+ main.log.debug( 'Subset of cut vertices: {}'.format( subsetOfCutVertices ) )
+ nonCutVertices = []
+ assert nonCutEdges != None
+ for vertex in self.graphDict.keys():
+ if vertex in subsetOfCutVertices:
+ continue
+ vertexIsNonCut = True
+ for neighbor in self.graphDict[ vertex ][ 'edges' ].keys():
+ edge = [ vertex, neighbor ]
+ backwardEdge = [ neighbor, vertex ]
+ if not edge in nonCutEdges and not backwardEdge in nonCutEdges:
+ vertexIsNonCut = False
+ break
+ if vertexIsNonCut:
+ nonCutVertices.append( vertex )
+ main.log.debug( 'Non-cut-vertices: {}'.format( nonCutVertices ) )
+ return nonCutVertices
+ except KeyError:
+ main.log.exception( "Graph: KeyError exception found" )
+ return None
+ except AssertionError:
+ main.log.exception( "Graph: AssertionError exception found" )
+ return None
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return None
+
+ def depthFirstSearch( self ):
+ """
+ This function runs a depth-first search and gets DFI of each vertex as well
+ as generates the back edges
+ """
+ try:
+ assert self.graphDict != None and len( self.graphDict ) != 0
+ for vertex in self.graphDict.keys():
+ self.DFI[ vertex ] = -1
+ self.parentVertexInDFS[ vertex ] = ''
+ self.parentEdgeInDFS[ vertex ] = None
+ firstVertex = self.graphDict.keys()[ 0 ]
+ self.currentDFI = 0
+ self.backEdges = {}
+ if not self.depthFirstSearchRecursive( firstVertex ):
+ return main.ERROR
+ return main.TRUE
+ except KeyError:
+ main.log.exception( "Graph: KeyError exception found" )
+ return main.ERROR
+ except AssertionError:
+ main.log.exception( "Graph: AssertionError exception found" )
+ return main.ERROR
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return main.ERROR
+
+ def depthFirstSearchRecursive( self, vertex ):
+ """
+ Recursive function for depth-first search
+ """
+ try:
+ self.DFI[ vertex ] = self.currentDFI
+ self.currentDFI += 1
+ for neighbor in self.graphDict[ vertex ][ 'edges' ].keys():
+ edge = [ vertex, neighbor ]
+ backwardEdge = [ neighbor, vertex ]
+ if neighbor == self.parentVertexInDFS[ vertex ]:
+ continue
+ elif self.DFI[ neighbor ] == -1:
+ self.parentVertexInDFS[ neighbor ] = vertex
+ self.parentEdgeInDFS[ neighbor ] = backwardEdge
+ if not self.depthFirstSearchRecursive( neighbor ):
+ return main.ERROR
+ else:
+ key = self.DFI[ neighbor ]
+ if key in self.backEdges.keys():
+ if not edge in self.backEdges[ key ] and\
+ not backwardEdge in self.backEdges[ key ]:
+ self.backEdges[ key ].append( backwardEdge )
+ else:
+ tempKey = self.DFI[ vertex ]
+ if tempKey in self.backEdges.keys():
+ if not edge in self.backEdges[ tempKey ] and\
+ not backwardEdge in self.backEdges[ tempKey ]:
+ self.backEdges[ key ] = [ backwardEdge ]
+ else:
+ self.backEdges[ key ] = [ backwardEdge ]
+ return main.TRUE
+ except KeyError:
+ main.log.exception( "Graph: KeyError exception found" )
+ return main.ERROR
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return main.ERROR
+
+ def findChains( self ):
+ """
+ This function finds all the chains in chain-decomposition algorithm
+ """
+ keyList = self.backEdges.keys()
+ keyList.sort()
+ vertexIsVisited = {}
+ self.chains = []
+ for vertex in self.graphDict.keys():
+ vertexIsVisited[ vertex ] = False
+ try:
+ for key in keyList:
+ backEdgeList = self.backEdges[ key ]
+ for edge in backEdgeList:
+ chain = []
+ currentEdge = edge
+ sourceVertex = edge[ 0 ]
+ while True:
+ currentVertex = currentEdge[ 0 ]
+ nextVertex = currentEdge[ 1 ]
+ vertexIsVisited[ currentVertex ] = True
+ chain.append( currentEdge )
+ if nextVertex == sourceVertex or vertexIsVisited[ nextVertex ] == True:
+ break
+ currentEdge = self.parentEdgeInDFS[ nextVertex ]
+ self.chains.append( chain )
+ return main.TRUE
+ except KeyError:
+ main.log.exception( "Graph: KeyError exception found" )
+ return main.ERROR
+ except Exception:
+ main.log.exception( "Graph: Uncaught exception" )
+ return main.ERROR
diff --git a/TestON/tests/FUNC/FUNCintent/FUNCintent.params b/TestON/tests/FUNC/FUNCintent/FUNCintent.params
index d0fcfa8..c201411 100644
--- a/TestON/tests/FUNC/FUNCintent/FUNCintent.params
+++ b/TestON/tests/FUNC/FUNCintent/FUNCintent.params
@@ -13,6 +13,7 @@
# 16 - Balance ownership of switches
# 17 - Activate Flow Objectives
# 18 - Stop Mininet
+ # 19 - Copy karaf logs from ONOS nodes to TestON log directory
# 1000 - Test host intents
# 2000 - Test point intents
# 3000 - Test single to multi point intents
@@ -20,7 +21,7 @@
# 5000 - Test host mobility
# 6000 - Test Multi Point intent End Point Failure
- <testcases>1,[2,10,12,13,15,16,1000,2000,3000,4000,5000,6000,18]*2,[2,10,12,13,15,16,17,1000,2000,3000,4000,5000,6000,18]*2,[2,11,12,13,15,16,1000,2000,3000,4000,5000,6000,18]*2,[2,11,12,13,15,16,17,1000,2000,3000,4000,5000,6000,18]*2</testcases>
+ <testcases>1,[2,10,12,13,15,16,1000,2000,3000,4000,5000,6000,18,19]*2,[2,10,12,13,15,16,17,1000,2000,3000,4000,5000,6000,18,19]*2,[2,11,12,13,15,16,1000,2000,3000,4000,5000,6000,18,19]*2,[2,11,12,13,15,16,17,1000,2000,3000,4000,5000,6000,18,19]*2</testcases>
<SCALE>
<size>1,3,1,3,1,3,1,3</size>
diff --git a/TestON/tests/FUNC/FUNCintent/FUNCintent.py b/TestON/tests/FUNC/FUNCintent/FUNCintent.py
index e81b5fa..7dc6fb3 100644
--- a/TestON/tests/FUNC/FUNCintent/FUNCintent.py
+++ b/TestON/tests/FUNC/FUNCintent/FUNCintent.py
@@ -59,6 +59,7 @@
main.scapyHostNames = main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
main.scapyHosts = [] # List of scapy hosts for iterating
main.assertReturnString = '' # Assembled assert return string
+ main.cycle = 0 # How many times FUNCintent has run through its tests
main.ONOSip = main.ONOSbench.getOnosIps()
print main.ONOSip
@@ -132,6 +133,8 @@
- Connect to cli
"""
+ main.cycle += 1
+
# main.scale[ 0 ] determines the current number of ONOS controller
main.numCtrls = int( main.scale[ 0 ] )
main.flowCompiler = "Flow Rules"
@@ -655,6 +658,28 @@
main.cleanup()
main.exit()
+ def CASE19( self, main ):
+ """
+ Copy the karaf.log files after each testcase cycle
+ """
+ main.log.report( "Copy karaf logs" )
+ main.case( "Copy karaf logs" )
+ main.caseExplanation = "Copying the karaf logs to preserve them through" +\
+ "reinstalling ONOS"
+ main.step( "Copying karaf logs" )
+ i = 0
+ for cli in main.CLIs:
+ main.node = cli
+ ip = main.ONOSip[ i ]
+ main.node.ip_address = ip
+ main.ONOSbench.scp( main.node ,
+ "/opt/onos/log/karaf.log",
+ "/tmp/karaf.log",
+ direction="from" )
+ main.ONOSbench.cpLogsToDir( "/tmp/karaf.log", main.logdir,
+ copyFileName=( "karaf.log.node{0}.cycle{1}".format( str( i + 1 ), str( main.cycle ) ) ) )
+ i += 1
+
def CASE1000( self, main ):
"""
Add host intents between 2 host:
diff --git a/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.params b/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.params
index b3d3df3..d91559d 100644
--- a/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.params
+++ b/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.params
@@ -13,13 +13,14 @@
# 16 - Balance ownership of switches
# 17 - Activate Flow Objectives
# 18 - Stop Mininet
+ # 19 - Copy karaf logs from ONOS nodes to TestON log directory
# 1000 - Test host intents
# 2000 - Test point intents
# 3000 - Test single to multi point intents
# 4000 - Test multi to single point intents
# 5000 - Test host mobility
- <testcases>1,[2,10,12,13,15,16,1000,2000,5000,18]*2,[2,10,12,13,15,16,17,1000,2000,5000,18]*2,[2,11,12,13,15,16,1000,2000,5000,18]*2,[2,11,12,13,15,16,17,1000,2000,5000,18]*2</testcases>
+ <testcases>1,[2,10,12,13,15,16,1000,2000,5000,18,19]*2,[2,10,12,13,15,16,17,1000,2000,5000,18,19]*2,[2,11,12,13,15,16,1000,2000,5000,18,19]*2,[2,11,12,13,15,16,17,1000,2000,5000,18,19]*2</testcases>
<SCALE>
<size>1,3,1,3,1,3,1,3</size>
diff --git a/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.py b/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.py
index 60fc47f..ec39ceb 100644
--- a/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.py
+++ b/TestON/tests/FUNC/FUNCintentRest/FUNCintentRest.py
@@ -70,6 +70,7 @@
main.scapyHostNames = main.params[ 'SCAPY' ][ 'HOSTNAMES' ].split( ',' )
main.scapyHosts = [] # List of scapy hosts for iterating
main.assertReturnString = '' # Assembled assert return string
+ main.cycle = 0 # How many times FUNCintent has run through its tests
main.ONOSip = main.ONOSbench.getOnosIps()
print main.ONOSip
@@ -152,6 +153,8 @@
- Connect to cli
"""
+ main.cycle += 1
+
# main.scale[ 0 ] determines the current number of ONOS controller
main.numCtrls = int( main.scale[ 0 ] )
main.flowCompiler = "Flow Rules"
@@ -770,6 +773,28 @@
main.cleanup()
main.exit()
+ def CASE19( self, main ):
+ """
+ Copy the karaf.log files after each testcase cycle
+ """
+ main.log.report( "Copy karaf logs" )
+ main.case( "Copy karaf logs" )
+ main.caseExplanation = "Copying the karaf logs to preserve them through" +\
+ "reinstalling ONOS"
+ main.step( "Copying karaf logs" )
+ i = 0
+ for cli in main.CLIs:
+ main.node = cli
+ ip = main.ONOSip[ i ]
+ main.node.ip_address = ip
+ main.ONOSbench.scp( main.node ,
+ "/opt/onos/log/karaf.log",
+ "/tmp/karaf.log",
+ direction="from" )
+ main.ONOSbench.cpLogsToDir( "/tmp/karaf.log", main.logdir,
+ copyFileName=( "karaf.log.node{0}.cycle{1}".format( str( i + 1 ), str( main.cycle ) ) ) )
+ i += 1
+
def CASE1000( self, main ):
"""
Add host intents between 2 host:
diff --git a/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.params b/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.params
index fc296cc..f5339f2 100644
--- a/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.params
+++ b/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.params
@@ -2,12 +2,13 @@
# CASE - Description
# 1 - Variable initialization and optional pull and build ONOS package
# 2 - Install ONOS
+ # 19 - Copy karaf logs from ONOS nodes to TestON log directory
# 100 - Ensure netconf app is running
# 200 - Create or modify a configuration file
# 300 - Push a configuration file to bring up a device
# 400 - Bring down a device (not yet possible)
- <testcases>1,[2,100,200,300]*2</testcases>
+ <testcases>1,[2,100,200,300,19]*2</testcases>
<SCALE>
<size>1,3</size>
diff --git a/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.py b/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.py
index ddd1cd8..6e4ae5a 100644
--- a/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.py
+++ b/TestON/tests/FUNC/FUNCnetconf/FUNCnetconf.py
@@ -55,6 +55,7 @@
main.configName = main.params[ 'CONFIGURE' ][ 'cfgName' ]
main.configPass = main.params[ 'CONFIGURE' ][ 'cfgPass' ]
main.configPort = main.params[ 'CONFIGURE' ][ 'cfgAppPort' ]
+ main.cycle = 0 # How many times FUNCintent has run through its tests
gitPull = main.params[ 'GIT' ][ 'pull' ]
main.cellData = {} # for creating cell file
@@ -139,6 +140,8 @@
- Connect to cli
"""
+ main.cycle += 1
+
# main.scale[ 0 ] determines the current number of ONOS controller
main.numCtrls = int( main.scale[ 0 ] )
@@ -254,6 +257,28 @@
# Remove the first element in main.scale list
main.scale.remove( main.scale[ 0 ] )
+ def CASE19( self, main ):
+ """
+ Copy the karaf.log files after each testcase cycle
+ """
+ main.log.report( "Copy karaf logs" )
+ main.case( "Copy karaf logs" )
+ main.caseExplanation = "Copying the karaf logs to preserve them through" +\
+ "reinstalling ONOS"
+ main.step( "Copying karaf logs" )
+ i = 0
+ for cli in main.CLIs:
+ main.node = cli
+ ip = main.ONOSip[ i ]
+ main.node.ip_address = ip
+ main.ONOSbench.scp( main.node ,
+ "/opt/onos/log/karaf.log",
+ "/tmp/karaf.log",
+ direction="from" )
+ main.ONOSbench.cpLogsToDir( "/tmp/karaf.log", main.logdir,
+ copyFileName=( "karaf.log.node{0}.cycle{1}".format( str( i + 1 ), str( main.cycle ) ) ) )
+ i += 1
+
def CASE100( self, main ):
"""
Start NETCONF app and OFC-Server or make sure that they are already running
diff --git a/TestON/tests/FUNC/FUNCoptical/FUNCoptical.params b/TestON/tests/FUNC/FUNCoptical/FUNCoptical.params
index a906f12..50bb652 100644
--- a/TestON/tests/FUNC/FUNCoptical/FUNCoptical.params
+++ b/TestON/tests/FUNC/FUNCoptical/FUNCoptical.params
@@ -5,13 +5,14 @@
# 10 - Start Mininet opticalTest Topology
# 14 - Stop Mininet
# 17 - Activate Flow Objectives
+ # 19 - Copy karaf logs from ONOS nodes to TestON log directory
# 21 - Run pingall to discover all hosts
# 22 - Send arpings to discover all hosts
# 23 - Compare ONOS Topology to Mininet Topology
# 31 - Add and test bidirectional point intents
# 32 - Add and test bidirectional host intents
- <testcases>1,[2,10,21,22,23,31,32,14,2,10,21,22,23,31,32,14]*1,[2,10,17,21,22,23,31,32,14,2,10,17,21,22,23,31,32,14]*1</testcases>
+ <testcases>1,[2,10,21,22,23,31,32,14,19,2,10,21,22,23,31,32,14,19]*1,[2,10,17,21,22,23,31,32,14,19,2,10,17,21,22,23,31,32,14,19]*1</testcases>
<SCALE>
<size>1,3,1,3</size>
diff --git a/TestON/tests/FUNC/FUNCoptical/FUNCoptical.py b/TestON/tests/FUNC/FUNCoptical/FUNCoptical.py
index c41a740..f4ac6ce 100644
--- a/TestON/tests/FUNC/FUNCoptical/FUNCoptical.py
+++ b/TestON/tests/FUNC/FUNCoptical/FUNCoptical.py
@@ -57,6 +57,7 @@
main.ONOSip = [] # List of IPs of active ONOS nodes. CASE 2
main.activeONOSip = []
main.assertReturnString = '' # Assembled assert return string
+ main.cycle = 0 # How many times FUNCintent has run through its tests
main.ONOSip = main.ONOSbench.getOnosIps()
@@ -124,6 +125,8 @@
- Connect to cli
"""
+ main.cycle += 1
+
# main.scale[ 0 ] determines the current number of ONOS controller
main.numCtrls = int( main.scale[ 0 ] )
main.flowCompiler = "Flow Rules"
@@ -302,6 +305,28 @@
onpass="Successfully activated Flow Objectives",
onfail="Failed to activate Flow Objectives" )
+ def CASE19( self, main ):
+ """
+ Copy the karaf.log files after each testcase cycle
+ """
+ main.log.report( "Copy karaf logs" )
+ main.case( "Copy karaf logs" )
+ main.caseExplanation = "Copying the karaf logs to preserve them through" +\
+ "reinstalling ONOS"
+ main.step( "Copying karaf logs" )
+ i = 0
+ for cli in main.CLIs:
+ main.node = cli
+ ip = main.ONOSip[ i ]
+ main.node.ip_address = ip
+ main.ONOSbench.scp( main.node ,
+ "/opt/onos/log/karaf.log",
+ "/tmp/karaf.log",
+ direction="from" )
+ main.ONOSbench.cpLogsToDir( "/tmp/karaf.log", main.logdir,
+ copyFileName=( "karaf.log.node{0}.cycle{1}".format( str( i + 1 ), str( main.cycle ) ) ) )
+ i += 1
+
def CASE21( self,main ):
"""
Run pingall to discover all hosts
diff --git a/TestON/tests/USECASE/USECASE_SdnipFunction_fsfw/dependencies/fsfw.xml b/TestON/tests/USECASE/USECASE_SdnipFunction_fsfw/dependencies/fsfw.xml
index e792f37..8fee131 100644
--- a/TestON/tests/USECASE/USECASE_SdnipFunction_fsfw/dependencies/fsfw.xml
+++ b/TestON/tests/USECASE/USECASE_SdnipFunction_fsfw/dependencies/fsfw.xml
@@ -434,7 +434,7 @@
</port>
</switch>
- <controller ip_address="10.128.20.11" ssl="false" port="6633"/>
+ <controller ip_address="10.254.1.201" ssl="false" port="6633"/>
</slice>
</flowspace_firewall>
\ No newline at end of file