Merge branch 'master' of https://github.com/opennetworkinglab/ONLabTest into FuncPlatform
diff --git a/TestON/tests/FuncPlatform/Dependency/App.py b/TestON/tests/FuncPlatform/Dependency/App.py
new file mode 100644
index 0000000..f6fecd6
--- /dev/null
+++ b/TestON/tests/FuncPlatform/Dependency/App.py
@@ -0,0 +1,42 @@
+
+def __init__( self ):
+    self.ip = '127.0.0.1'
+
+def activate( apps, nodeToActivateFrom=0 ):
+    """
+    Activate specified applications from node specified
+
+    Ex) apps = ['metrics', 'fwd']
+        nodeToActivateFrom = range( 0, nodes )
+    """
+    if isinstance( apps, ( int, basestring ) ):
+        main.log.error( "Please pass in a list of strings for args" )
+        return main.FALSE
+
+    if not isinstance( nodeToActivateFrom, ( int ) ) or \
+            nodeToActivateFrom < 0:
+        main.log.error( "Incorrect node specified" )
+        return main.FALSE
+
+    for app in apps:
+        # Check if app str in appList is in the main scope
+        # definition main.appList
+        if app not in main.appList:
+            main.log.error( "Invalid app name given" )
+            return main.FALSE
+      
+        # NOTE: assumes node 1 is always activating application
+        appOutput = main.CLIs[nodeToActivateFrom].activateApp( 
+                main.appList[app] ) 
+
+    return main.TRUE
+
+def isAppInstallSuccess():
+    """
+    Check the app list across clusters to determine
+    that apps have been installed successfully
+
+    """
+
+    main.log.report( "isAppInstallSuccess" )
+
diff --git a/TestON/tests/FuncPlatform/Dependency/Startup.py b/TestON/tests/FuncPlatform/Dependency/Startup.py
new file mode 100644
index 0000000..3096eee
--- /dev/null
+++ b/TestON/tests/FuncPlatform/Dependency/Startup.py
@@ -0,0 +1,76 @@
+
+"""
+Startup related methods for ONOS
+
+Guidelines:
+    * Group sequential functionalities together
+    * Methods should not prohibit cross platform execution
+    * Return main.TRUE on success or comprehensive error message 
+      on failure (TBD)
+"""
+import time
+
+def __init__( self ):
+    self.ip = '127.0.0.1' 
+
+def gitPullAndMci( branchName, commitLog=False ):
+    """
+    Pull from branch repository specified and compile changes
+    If commitLog is True, report commit information
+
+    Any errors / warnings will be handled by respective 
+    driver function calls
+    """
+    co = main.ONOSbench.gitCheckout( branchName )
+    gp = main.ONOSbench.gitPull()
+    ci = main.ONOSbench.cleanInstall() 
+
+    if co and gp and ci == main.TRUE:
+        if commitLog:
+            main.log.report( 'Commit information - ' )
+            main.ONOSbench.getVersion(report=True)
+        
+        return main.TRUE
+    
+    else:
+        # TODO: Comprehensive error message
+        return 'git pull and mci failed'
+
+def initOnosStartupSequence( cellName, appStr, benchIp, mnIp, onosIps ):
+    """
+    Startup sequence includes the following:
+        * Create cell file
+        * Set cell variables on ONOS bench
+        * Verify cell
+        * Create ONOS package
+        * Force install ONOS package
+        * Start ONOS service
+        * Start ONOS cli
+    """
+
+    # NOTE: leave out create cell file until bug addressed
+    #cf = main.ONOSbench.createCellFile( benchIp, cellName, mnIp, 
+    #        str(appStr), *onosIps )
+    numNodes = len(onosIps) 
+
+    sc = main.ONOSbench.setCell( cellName )
+    vc = main.ONOSbench.verifyCell()
+    op = main.ONOSbench.onosPackage()
+    for addr in onosIps:
+        oi = main.ONOSbench.onosInstall( node = addr )
+    
+    time.sleep( 5 )
+   
+    iu = main.TRUE
+    for node in onosIps:
+        iu = iu and main.ONOSbench.isup( node )
+   
+    cli = main.TRUE
+    for node in range( 0, numNodes ):
+        cli = cli and main.CLIs[node].startOnosCli( onosIps[node] )
+
+    if sc and vc and op and oi and iu and cli == main.TRUE:
+        return main.TRUE
+    else:
+        return main.FALSE
+
diff --git a/TestON/tests/FuncPlatform/FuncPlatform.params b/TestON/tests/FuncPlatform/FuncPlatform.params
new file mode 100644
index 0000000..eb274ae
--- /dev/null
+++ b/TestON/tests/FuncPlatform/FuncPlatform.params
@@ -0,0 +1,45 @@
+<PARAMS>
+    <testcases>1,2,3</testcases>
+    <DEP>
+        <startupSrc>
+            /home/admin/ONLabTest/TestON/tests/FuncPlatform/Dependency/Startup.py
+        </startupSrc>
+        <startupClassName>
+            Startup
+        </startupClassName>
+        
+        <appSrc>
+            /home/admin/ONLabTest/TestON/tests/FuncPlatform/Dependency/App.py
+        </appSrc>
+        <appClassName>
+            App
+        </appClassName>
+    </DEP> 
+
+    <CTRL>
+        <num>3</num>
+        <port>6633</port>
+        <ip1>10.128.174.1</ip1>
+        <ip2>10.128.174.2</ip2>
+        <ip3>10.128.174.3</ip3>
+    </CTRL>
+  
+    <MN>
+        <ip>10.128.10.90</ip>
+    </MN>
+
+    <BENCH>
+        <ip>10.128.174.10</ip>
+    </BENCH>
+
+    <CELL>
+        <name>func_plat</name>
+        <appStr>"drivers,openflow"</appStr>
+    </CELL>
+
+    <GIT>
+        <branchName>master</branchName>
+        <pull>off</pull>
+    </GIT>
+
+</PARAMS>
diff --git a/TestON/tests/FuncPlatform/FuncPlatform.py b/TestON/tests/FuncPlatform/FuncPlatform.py
new file mode 100644
index 0000000..6bcb06c
--- /dev/null
+++ b/TestON/tests/FuncPlatform/FuncPlatform.py
@@ -0,0 +1,132 @@
+"""
+FuncPlatform
+
+A functional test designed to test the environment and 
+gather information on startup -> shutdown related issues.
+
+Future works may also include security mode startup /
+shutdown check and cfg get and set.
+
+Abstracting the collection of commands that go hand in hand 
+should allow easy rearrangement of steps to replicate or 
+create scenarios. 
+For example:
+    CASE N - Represents a particular scenario
+        Steps - Represents abstraction methods called from 
+                dependency
+        1. Bring ONOS 1 up
+        2. Activate application X
+        3. Activate application Y
+        4. Deactivate application X
+
+contributers to contact for help:
+andrew@onlab.us
+"""
+
+class FuncPlatform:
+    def __init__( self ):
+        self.default = ''
+
+    def CASE1( self, main ):
+        """
+        Main scope initialization case
+        """   
+        main.appList = { 
+            'bgprouter' : 'org.onosproject.bgprouter',
+            'config' : 'org.onosproject.config',
+            'cordfabric' : 'org.onosproject.cordfabric',
+            'demo' : 'org.onosproject.demo',
+            'distributedprimitives' : 'org.onosproject.distributedprimitives',
+            'election' : 'org.onosproject.election',
+            'flowrule' : 'org.onosproject.flowrule',
+            'fwd' : 'org.onosproject.fwd',
+            'intentperf' : 'org.onosproject.intentperf',
+            'messagingperf' : 'org.onosproject.messagingperf',
+            'metrics' : 'org.onosproject.metrics',
+            'mobility' : 'org.onosproject.mobility',
+            'netconf' : 'org.onosproject.netconf', 
+            'null' : 'org.onosproject.null',
+            'optical' : 'org.onosproject.optical'
+            } 
+        # List of ONOS ip's specififed in params
+        main.ONOSips = [] 
+        main.CLIs = []
+
+        for node in range( 0, int(main.params['CTRL']['num']) ):
+            main.ONOSips.append( main.params['CTRL']['ip'+str(node+1)] )
+            main.CLIs.append(
+                    getattr( main, 'ONOS' + str(node+1) + 'cli' ) )
+       
+    def CASE2( self, main ):
+        import time
+        import imp
+
+        startupSrc = main.params['DEP']['startupSrc']
+        startupClassName = main.params['DEP']['startupClassName']
+        cellName = main.params['CELL']['name']
+        appStr = main.params['CELL']['appStr']
+        benchIp = main.params['BENCH']['ip']
+        branchName = main.params['GIT']['branchName']
+        gitPull = main.params['GIT']['pull']
+        mnIp = main.params['MN']['ip']
+
+        # importing dependency class(es)
+        # Refer to source files in Dependency folder to
+        # make changes to its respective methods
+        try:
+            startup = imp.load_source( startupClassName, startupSrc )
+        except ImportError:
+            main.log.error( "Error importing class " +
+                    str(startupClassName) + " from " + str(startupSrc) )
+            main.cleanup()
+            main.exit()
+
+        main.case( 'Setup environment and install ONOS' )
+        if gitPull == 'on': 
+            main.step( 'Git pull and clean install' )
+            gitPullResult = startup.gitPullAndMci( branchName )
+            utilities.assert_equals( expect=main.TRUE,
+                        actual=gitPullResult,
+                        onpass='Git pull and install successful',
+                        onfail='Git pull and install failed: ' +
+                            str(gitPullResult) )
+        
+        main.step( 'Initiate ONOS startup sequence' )    
+        startupResult = startup.initOnosStartupSequence(
+                cellName, appStr, benchIp, mnIp, main.ONOSips )
+        utilities.assert_equals( expect=main.TRUE,
+                        actual=startupResult,
+                        onpass='ONOS startup sequence successful',
+                        onfail='ONOS startup sequence failed: ' +
+                            str(startupResult) )
+        
+    def CASE3( self, main ):
+        import time
+        import imp
+
+        main.case( 'Activate applications and check installation' )
+        # Activate applications and check consistency 
+        # across clusters
+        appClassName = main.params['DEP']['appClassName']
+        appSrc = main.params['DEP']['appSrc']
+
+        # Import application file to use its methods
+        try:
+            app = imp.load_source( appClassName, appSrc )
+        except ImportError:
+            main.log.error( "Error importing class " +
+                    str(startupClassName) + " from " + str(startupSrc) )
+            main.cleanup()
+            main.exit()
+
+        # Sample app activation
+        main.step( 'Activating applications metrics and fwd' ) 
+        appList = ['metrics', 'fwd']
+        appResult = app.activate( appList ) 
+        utilities.assert_equals( expect=main.TRUE,
+                actual=appResult,
+                onpass= 'App activation of ' + str(appList) + ' successful',
+                onfail= 'App activation failed ' + str(appResult) )
+
+
+
diff --git a/TestON/tests/FuncPlatform/FuncPlatform.topo b/TestON/tests/FuncPlatform/FuncPlatform.topo
new file mode 100644
index 0000000..fcc087d
--- /dev/null
+++ b/TestON/tests/FuncPlatform/FuncPlatform.topo
@@ -0,0 +1,82 @@
+<TOPOLOGY>
+    <COMPONENT>
+        
+        <ONOSbench>
+            <host>10.128.174.10</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOSbench>
+        
+        <ONOS1>
+            <host>10.128.174.1</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS1>
+        
+        <ONOS2>
+            <host>10.128.174.2</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>4</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS2>
+
+        <ONOS3>
+            <host>10.128.174.3</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS3>
+   
+        <ONOS1cli>
+            <host>10.128.174.10</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>6</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS1cli>
+        
+        <ONOS2cli>
+            <host>10.128.174.10</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>7</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS2cli>
+
+        <ONOS3cli>
+            <host>10.128.174.10</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>8</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS3cli>
+        
+        <MininetOvs>
+            <host>10.128.10.90</host>
+            <user>admin</user>
+            <password></password>
+            <type>MininetCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS>
+                <arg1> --custom topo-perf-2sw.py </arg1>
+                <arg2> --arp --mac --topo mytopo </arg2>
+                <arg3> </arg3>
+                <controller> remote </controller>
+            </COMPONENTS>
+        </MininetOvs>
+
+    </COMPONENT>
+</TOPOLOGY>