Merge "Add VLAN Treatment Intent Tests to FUNCintent for Host, Point, MPSP, and SPMP intents."
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 4d8cec7..345e0f9 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -151,7 +151,10 @@
# ONOS didn't fully load, and logout command isn't working
# or the command timed out
self.handle.send( "\x04" ) # send ctrl-d
- self.handle.expect( "\$" )
+ try:
+ self.handle.expect( "\$" )
+ except pexpect.TIMEOUT:
+ main.log.error( "ONOS did not respond to 'logout' or CTRL-d" )
return main.TRUE
else: # some other output
main.log.warn( "Unknown repsonse to logout command: '{}'",
@@ -2039,19 +2042,18 @@
def getIntentState(self, intentsId, intentsJson=None):
"""
- Check intent state.
- Accepts a single intent ID (string type) or a list of intent IDs.
- Returns the state(string type) of the id if a single intent ID is
- accepted.
- Returns a dictionary with intent IDs as the key and its
- corresponding states as the values
- Parameters:
- intentId: intent ID (string type)
+ Description:
+ Gets intent state. Accepts a single intent ID (string type) or a
+ list of intent IDs.
+ Parameters:
+ intentsId: intent ID, both string type and list type are acceptable
intentsJson: parsed json object from the onos:intents api
- Returns:
- state = An intent's state- INSTALL,WITHDRAWN etc.
- stateDict = Dictionary of intent's state. intent ID as the keys and
- state as the values.
+ Returns:
+ Returns the state (string type) of the ID if a single intent ID is
+ accepted.
+ Returns a list of dictionaries if a list of intent IDs is accepted,
+ and each dictionary maps 'id' to the Intent ID and 'state' to
+ corresponding intent state.
"""
try:
state = "State is Undefined"
@@ -2163,6 +2165,52 @@
main.cleanup()
main.exit()
+ def compareIntent( self, intentDict ):
+ """
+ Description:
+ Compare the intent ids and states provided in the argument with all intents in ONOS
+ Return:
+ Returns main.TRUE if the two sets of intents match exactly, otherwise main.FALSE
+ Arguments:
+ intentDict: a dictionary which maps intent ids to intent states
+ """
+ try:
+ intentsRaw = self.intents()
+ intentsJson = json.loads( intentsRaw )
+ intentDictONOS = {}
+ for intent in intentsJson:
+ intentDictONOS[ intent[ 'id' ] ] = intent[ 'state' ]
+ if len( intentDict ) != len( intentDictONOS ):
+ main.log.info( self.name + ": expected intent count does not match that in ONOS, " +
+ str( len( intentDict ) ) + " expected and " +
+ str( len( intentDictONOS ) ) + " actual" )
+ return main.FALSE
+ returnValue = main.TRUE
+ for intentID in intentDict.keys():
+ if not intentID in intentDictONOS.keys():
+ main.log.debug( self.name + ": intent ID - " + intentID + " is not in ONOS" )
+ returnValue = main.FALSE
+ elif intentDict[ intentID ] != intentDictONOS[ intentID ]:
+ main.log.debug( self.name + ": intent ID - " + intentID +
+ " expected state is " + intentDict[ intentID ] +
+ " but actual state is " + intentDictONOS[ intentID ] )
+ returnValue = main.FALSE
+ if returnValue == main.TRUE:
+ main.log.info( self.name + ": all intent IDs and states match that in ONOS" )
+ return returnValue
+ except ( TypeError, ValueError ):
+ main.log.exception( "{}: Object not as expected: {!r}".format( self.name, intentsRaw ) )
+ return None
+ except pexpect.EOF:
+ main.log.error( self.name + ": EOF exception found" )
+ main.log.error( self.name + ": " + self.handle.before )
+ main.cleanup()
+ main.exit()
+ except Exception:
+ main.log.exception( self.name + ": Uncaught exception!" )
+ main.cleanup()
+ main.exit()
+
def checkIntentSummary( self, timeout=60 ):
"""
Description:
@@ -2405,8 +2453,8 @@
return int(totalFlows)
- except TypeError:
- main.log.exception( self.name + ": Object not as expected" )
+ except ( TypeError, ValueError ):
+ main.log.exception( "{}: Object not as expected: {!r}".format( self.name, rawFlows ) )
return None
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
@@ -2435,8 +2483,8 @@
return -1
response = json.loads( response )
return int( response.get("intents") )
- except TypeError:
- main.log.exception( self.name + ": Object not as expected" )
+ except ( TypeError, ValueError ):
+ main.log.exception( "{}: Object not as expected: {!r}".format( self.name, response ) )
return None
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
@@ -2697,6 +2745,9 @@
topology = json.loads(topologyOutput)
main.log.debug( topology )
return topology
+ except ( TypeError, ValueError ):
+ main.log.exception( "{}: Object not as expected: {!r}".format( self.name, topologyOutput ) )
+ return None
except pexpect.EOF:
main.log.error( self.name + ": EOF exception found" )
main.log.error( self.name + ": " + self.handle.before )
diff --git a/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py b/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
index 699a17d..6831811 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/elements/ONOSElement.py
@@ -33,6 +33,7 @@
self.default = ''
self.type = 'INTENT'
self.id = id
+ self.expectedState = 'INSTALLED'
def isHostIntent( self ):
return self.type == 'INTENT_HOST'
@@ -40,12 +41,26 @@
def isPointIntent( self ):
return self.type == 'INTENT_POINT'
+ def isFailed( self ):
+ return self.expectedState == 'FAILED'
+
+ def isInstalled( self ):
+ return self.expectedState == 'INSTALLED'
+
+ def setFailed( self ):
+ self.expectedState = 'FAILED'
+
+ def setInstalled( self ):
+ self.expectedState = 'INSTALLED'
+
class HostIntent( Intent ):
def __init__( self, id, hostA, hostB ):
Intent.__init__( self, id )
self.type = 'INTENT_HOST'
self.hostA = hostA
self.hostB = hostB
+ self.deviceA = hostA.device
+ self.deviceB = hostB.device
def __str__( self ):
return "ID: " + self.id
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
index e48f674..01aa734 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/CheckEvent.py
@@ -25,21 +25,15 @@
def startCheckEvent( self, args=None ):
checkResult = EventStates().PASS
- intentIDs = []
+ # TODO: check intents that are expected in "FAILED" state?
+ installedIntentIDs = []
for intent in main.intents:
- if intent.isHostIntent():
- deviceA = intent.hostA.device
- deviceB = intent.hostB.device
- elif intent.isPointIntent():
- deviceA = intent.deviceA
- deviceB = intent.deviceB
- # Exclude the intents that are to or from removed devices/hosts
- if not deviceA.isRemoved() and not deviceB.isRemoved():
- intentIDs.append( intent.id )
+ if intent.isInstalled():
+ installedIntentIDs.append( intent.id )
for controller in main.controllers:
if controller.isUp():
with controller.CLILock:
- intentState = controller.CLI.checkIntentState( intentsId=intentIDs )
+ intentState = controller.CLI.checkIntentState( intentsId=installedIntentIDs )
if not intentState:
main.log.warn( "Intent Check - Not all intents are in INSTALLED state on ONOS%s" % ( controller.index ) )
checkResult = EventStates().FAIL
@@ -141,10 +135,10 @@
dpidToMaster[ dpid ] = device[ 'master' ]
elif dpidToMaster[ dpid ] != device[ 'master' ]:
checkResult = EventStates().FAIL
- main.log.warn( "ONOS Check - Mastership of %s on ONOS%s is inconsistent with that on ONOS1" % ( device.name, controller.index ) )
+ main.log.warn( "ONOS Check - Mastership of %s on ONOS%s is inconsistent with that on ONOS1" % ( dpid, controller.index ) )
if dpidToAvailability[ dpid ] and device[ 'master' ] == "none":
checkResult = EventStates().FAIL
- main.log.warn( "ONOS Check - Device %s has no master on ONOS%s" % ( device.name, controller.index ) )
+ main.log.warn( "ONOS Check - Device %s has no master on ONOS%s" % ( dpid, controller.index ) )
# Check leaders
with controller.CLILock:
leaders = controller.CLI.leaders()
diff --git a/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py b/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
index 46b37e7..7247ecf 100644
--- a/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
+++ b/TestON/tests/CHOTestMonkey/dependencies/events/NetworkEvent.py
@@ -208,6 +208,9 @@
link.backwardLink.setRemoved()
for host in self.device.hosts:
host.setRemoved()
+ for intent in main.intents:
+ if intent.deviceA == self.device or intent.deviceB == self.device:
+ intent.setFailed()
return EventStates().PASS
class DeviceUp( DeviceEvent ):
@@ -256,6 +259,11 @@
with main.variableLock:
link.bringUp()
link.backwardLink.bringUp()
+ for intent in main.intents:
+ if intent.isFailed():
+ if intent.deviceA == self.device and intent.deviceB.isUp() or\
+ intent.deviceB == self.device and intent.deviceA.isUp():
+ intent.setInstalled()
# Re-assign mastership for the device
with main.mininetLock:
main.Mininet1.assignSwController( sw=self.device.name, ip=main.onosIPs )
diff --git a/TestON/tests/SCPF/SCPFscalingMaxIntents/SCPFscalingMaxIntents.py b/TestON/tests/SCPF/SCPFscalingMaxIntents/SCPFscalingMaxIntents.py
index 6aee29e..608f0e6 100644
--- a/TestON/tests/SCPF/SCPFscalingMaxIntents/SCPFscalingMaxIntents.py
+++ b/TestON/tests/SCPF/SCPFscalingMaxIntents/SCPFscalingMaxIntents.py
@@ -419,6 +419,8 @@
# make sure the checkInterval divisible batchSize
main.checkInterval = int( int( main.checkInterval / main.batchSize ) * main.batchSize )
+ flowTemp=0
+ totalFlows=0
for i in range(limit):
# Threads pool
@@ -463,22 +465,27 @@
temp = 0
intentsState = main.CLIs[0].checkIntentSummary(timeout=600)
if intentsState:
- totalIntents = main.CLIs[0].getTotalIntentsNum(timeout=600)
- if temp < totalIntents:
- temp = totalIntents
+ verifyTotalIntents = main.CLIs[0].getTotalIntentsNum(timeout=600)
+ if temp < verifyTotalIntents:
+ temp = verifyTotalIntents
else:
- totalIntents = temp
+ verifytotalIntents = temp
+ main.log.info("Total Intents: {}".format( verifyTotalIntents ) )
break
- main.log.info("Total Intents: {}".format( totalIntents) )
k = k+1
-
+
+ totalFlows = main.CLIs[0].getTotalFlowsNum( timeout=600, noExit=True )
+ if flowTemp < totalFlows:
+ flowTemp = totalFlows
+ else:
+ totalFlows = flowTemp
+
if not intentsState:
# If some intents are not installed, grep the previous flows list, and finished this test case
main.log.warn( "Some intens did not install" )
- main.log.info("Total Intents: {}".format( totalIntents) )
+ main.log.info("Total Intents: {}".format( verifyTotalIntents) )
break
- totalFlows = main.CLIs[0].getTotalFlowsNum(timeout=600, noExit=True)
del main.scale[0]
utilities.assert_equals( expect = main.TRUE,
actual = intentsState,
@@ -496,7 +503,7 @@
temp = str(main.numCtrls)
temp += ",'" + "baremetal1" + "'"
# how many intents we installed before crash
- temp += "," + str(totalIntents)
+ temp += "," + str(verifyTotalIntents)
# how many flows we installed before crash
temp += "," + str(totalFlows)
# other columns in database, but we didn't use in this test
diff --git a/TestON/tests/SCPF/SCPFscalingMaxIntentsWithFlowObj/SCPFscalingMaxIntentsWithFlowObj.py b/TestON/tests/SCPF/SCPFscalingMaxIntentsWithFlowObj/SCPFscalingMaxIntentsWithFlowObj.py
index 7e6753e..97dc6f3 100644
--- a/TestON/tests/SCPF/SCPFscalingMaxIntentsWithFlowObj/SCPFscalingMaxIntentsWithFlowObj.py
+++ b/TestON/tests/SCPF/SCPFscalingMaxIntentsWithFlowObj/SCPFscalingMaxIntentsWithFlowObj.py
@@ -421,6 +421,9 @@
# make sure the checkInterval divisible batchSize
main.checkInterval = int( int( main.checkInterval / main.batchSize ) * main.batchSize )
+ flowTemp=0
+ totalFlows=0
+ verifyTotalIntents=0
for i in range(limit):
# Threads pool
@@ -465,22 +468,27 @@
temp = 0
intentsState = main.CLIs[0].checkIntentSummary(timeout=600)
if intentsState:
- totalIntents = main.CLIs[0].getTotalIntentsNum(timeout=600)
- if temp < totalIntents:
- temp = totalIntents
+ verifyTotalIntents = main.CLIs[0].getTotalIntentsNum(timeout=600)
+ if temp < verifyTotalIntents:
+ temp = verifyTotalIntents
else:
- totalIntents = temp
+ verifyTotalIntents = temp
break
main.log.info("Total Intents: {}".format( totalIntents) )
k = k+1
-
+
+ totalFlows = main.CLIs[0].getTotalFlowsNum( timeout=600, noExit=True )
+ if flowTemp<totalFlows:
+ flowTemp = totalFlows
+ else:
+ totalFlows = flowTemp
+
if not intentsState:
# If some intents are not installed, grep the previous flows list, and finished this test case
main.log.warn( "Some intens did not install" )
main.log.info("Total Intents: {}".format( totalIntents) )
break
- totalFlows = main.CLIs[0].getTotalFlowsNum(timeout=600, noExit=True)
del main.scale[0]
utilities.assert_equals( expect = main.TRUE,
actual = intentsState,
diff --git a/TestON/tests/USECASE/USECASE_SegmentRouting/USECASE_SegmentRouting.py b/TestON/tests/USECASE/USECASE_SegmentRouting/USECASE_SegmentRouting.py
index 9822b8b..bfdff59 100644
--- a/TestON/tests/USECASE/USECASE_SegmentRouting/USECASE_SegmentRouting.py
+++ b/TestON/tests/USECASE/USECASE_SegmentRouting/USECASE_SegmentRouting.py
@@ -286,21 +286,31 @@
onpass="Flow status is correct!",
onfail="Flow status is wrong!" )
main.ONOSbench.dumpFlows( main.ONOSip[0],
- main.logdir, "flows" + main.jsonFile)
+ main.logdir, "flowsBefore" + main.jsonFile)
#time.sleep( 3*main.startUpSleep)
def CASE4( self, main ):
main.case( "Check full connectivity" )
main.log.report( "Check full connectivity" )
- main.step("Check full connectivity")
+ main.step("1st Check full connectivity")
pa = main.Mininet1.pingall()
utilities.assert_equals( expect=main.TRUE, actual=pa,
onpass="Full connectivity successfully tested",
onfail="Full connectivity failed" )
# cleanup mininet
main.ONOSbench.dumpFlows( main.ONOSip[0],
- main.logdir, "flows" + main.jsonFile)
+ main.logdir, "flowsAfter" + main.jsonFile)
+
+ main.step("2nd Check full connectivity")
+ pa = main.Mininet1.pingall()
+ utilities.assert_equals( expect=main.TRUE, actual=pa,
+ onpass="Full connectivity successfully tested",
+ onfail="Full connectivity failed" )
+
+ main.ONOSbench.dumpFlows( main.ONOSip[0],
+ main.logdir, "flowsAfter2nd" + main.jsonFile)
+
main.ONOSbench.onosStop( main.ONOSip[0] )
main.Mininet1.stopNet()