Initial implementation of test suite for ONOS NETCONF
functionality using OF-Config
    -for more information please check the README

Change-Id: I631ae8b5de24553899c44a465a604283602a6f27
diff --git a/TestON/tests/FUNCnetconf/Dependency/netconf.py b/TestON/tests/FUNCnetconf/Dependency/netconf.py
new file mode 100644
index 0000000..5ebbea5
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/Dependency/netconf.py
@@ -0,0 +1,141 @@
+"""
+    Wrapper functions for FUNCnetconf
+    This functions include Onosclidriver and Mininetclidriver driver functions
+    Author: Jeremy Songster, jeremy@onlab.us
+"""
+import time
+import json
+
+def __init__( self ):
+    self.default = ''
+
+def startApp( main ):
+    """
+        This function starts the netconf app in all onos nodes and ensures that
+        the OF-Config server is running on the node to be configured
+    """
+
+    startResult = main.FALSE
+    startResult = main.CLIs[ 0 ].activateApp( appName="org.onosproject.netconf" )
+    return startResult
+
+def startOFC( main ):
+    """
+        This function uses pexpect pxssh class to activate the ofc-server daemon on OC2
+    """
+
+    startResult = main.FALSE
+    try:
+        main.ONOSbench.handle.sendline( "" )
+        main.ONOSbench.handle.expect( "\$" )
+        main.ONOSbench.handle.sendline( "ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1 }'" )
+        main.ONOSbench.handle.expect( "\$1 }'" )
+        main.ONOSbench.handle.expect( "\$" )
+        main.configDeviceIp = main.ONOSbench.handle.before
+        main.configDeviceIp = main.configDeviceIp.split()
+        main.configDeviceIp = main.configDeviceIp[ 0 ]
+        main.log.info( "Device to be configured: " + str( main.configDeviceIp ) )
+        main.ONOSbench.handle.sendline( "sudo ofc-server" )
+        main.ONOSbench.handle.expect( "\$" )
+        startResult = main.TRUE
+        return startResult
+    except pexpect.ExceptionPexpect as e:
+        main.log.exception( self.name + ": Pexpect exception found: " )
+        main.log.error( self.name + ":    " + self.handle.before )
+        main.cleanup()
+        main.exit()
+
+def createConfig( main ):
+    """
+        This function writes a configuration file that can later be sent to the
+        REST API to configure a device.
+        The controller device is assumed to be OC1
+        The device to be configured is assumed to be OC2
+    """
+    createCfgResult = main.FALSE
+    # TODO, add ability to set Manufacturer, Hardware and Software versions
+    main.cfgJson = '{ "devices":{ "netconf:'+ main.configDeviceIp + ":" +\
+                    main.configDevicePort + '":' + '{ "basic":{ "driver":"'+\
+                    main.configDriver + '" } } }, "apps": { "' +\
+                    main.configApps + '":{ "devices":[ { "name":' +\
+                    main.configName + ', "password":' + main.configPass +\
+                    ', "ip":"' + main.configDeviceIp + '", "port":' +\
+                    main.configPort + '} ] } } }'
+    try:
+        file = open( "/home/admin/OnosSystemTest/TestON/tests/FUNCnetconf/Dependency/netconfConfig.json", 'w' )
+        main.cfgJson = json.loads( main.cfgJson )
+        main.cfgJson = json.dumps( main.cfgJson, sort_keys=True,
+                               indent=4, separators=(',', ': '))
+        print main.cfgJson
+        file.write( main.cfgJson )
+        if file:
+            createCfgResult = main.TRUE
+            file.close()
+            return createCfgResult
+        else:
+            main.log.error( "There was an error opening the file")
+            return createCfgResult
+    except:
+        main.log.exception( "There was an error opening the file")
+        return createCfgResult
+
+def sendConfig( main ):
+    """
+        This function prepares the command needed to upload the configuration
+        file to the REST API
+    """
+    ip = main.ONOSip[0]
+    port = 8181
+    url = "/network/configuration"
+    method = "POST"
+    data = main.cfgJson
+    configResult = main.FALSE
+    sendResult = main.CLIs[ 0 ].send( ip=ip, port=port, url=url, method=method, data=data )
+    main.log.info( "Device configuration request response code: " + str( sendResult[ 0 ] ) )
+    if ( 200 <= sendResult[ 0 ] <= 299):
+        configResult = main.TRUE
+    else:
+        configResult = main.FALSE
+
+    return configResult
+
+def devices( main ):
+    """
+        This function get the list of devices from the REST API, the ONOS CLI, and
+        the device-controllers command and check to see that each recognizes the
+        device is configured according to the configuration uploaded above.
+    """
+    availResult = main.FALSE
+    typeResult = main.FALSE
+    addressResult = main.FALSE
+    driverResult = main.FALSE
+    try:
+        apiResult = main.CLIs[ 0 ].devices()
+        cliResult = main.CLIs2[ 0 ].devices()
+
+        apiDict = json.loads( apiResult )
+        cliDict = json.loads( cliResult )
+        apiAnnotations = apiDict[ 0 ].get( "annotations" )
+        cliAnnotations = cliDict[ 0 ].get( "annotations" )
+
+        main.log.info( "API device availability result: " + str( apiDict[ 0 ].get( "available" ) ) )
+        main.log.info( "CLI device availability result: " + str( cliDict[ 0 ].get( "available" ) ) )
+        if apiDict[ 0 ].get( "available" ) == True and cliDict[ 0 ].get( "available" ) == True:
+            availResult = main.TRUE
+        main.log.info( "API device type result: " + apiDict[ 0 ].get( "type" ) )
+        main.log.info( "CLI device type result: " + cliDict[ 0 ].get( "type" ) )
+        if apiDict[ 0 ].get( "type" ) == "SWITCH" and cliDict[ 0 ].get( "type" ) == "SWITCH":
+            typeResult = main.TRUE
+        main.log.info( "API device ipaddress: " + apiAnnotations.get( "ipaddress" ) )
+        main.log.info( "CLI device ipaddress: " + apiAnnotations.get( "ipaddress" ) )
+        if str( apiAnnotations.get( "ipaddress" ) ) == main.configDeviceIp and str( cliAnnotations.get( "ipaddress" ) ) == main.configDeviceIp:
+            addressResult = main.TRUE
+        main.log.info( "API device driver: " + apiAnnotations.get( "driver" ) )
+        main.log.info( "CLI device driver: " + cliAnnotations.get( "driver" ) )
+        if apiAnnotations.get( "driver" ) == main.configDriver and cliAnnotations.get( "driver" ) == main.configDriver:
+            driverResult = main.TRUE
+
+        return availResult and typeResult and addressResult and driverResult
+    except TypeError:
+        main.log.error( "Device was not configured correctly" )
+        return main.FALSE
\ No newline at end of file
diff --git a/TestON/tests/FUNCnetconf/Dependency/netconfConfig.json b/TestON/tests/FUNCnetconf/Dependency/netconfConfig.json
new file mode 100644
index 0000000..fc5a231
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/Dependency/netconfConfig.json
@@ -0,0 +1,21 @@
+{
+    "apps": {
+        "org.onosproject.netconf": {
+            "devices": [
+                {
+                    "ip": "10.128.50.10",
+                    "name": "sdn",
+                    "password": "rocks",
+                    "port": 830
+                }
+            ]
+        }
+    },
+    "devices": {
+        "netconf:10.128.50.10:830": {
+            "basic": {
+                "driver": "ovs-netconf"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/TestON/tests/FUNCnetconf/Dependency/startUp.py b/TestON/tests/FUNCnetconf/Dependency/startUp.py
new file mode 100644
index 0000000..bf2a2b6
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/Dependency/startUp.py
@@ -0,0 +1,38 @@
+"""
+    This wrapper function is use for starting up onos instance
+"""
+
+import time
+import os
+import json
+
+def onosBuild( main, gitBranch ):
+    """
+        This includes pulling ONOS and building it using maven install
+    """
+
+    buildResult = main.FALSE
+
+    # Git checkout a branch of ONOS
+    checkOutResult = main.ONOSbench.gitCheckout( gitBranch )
+    # Does the git pull on the branch that was checked out
+    if not checkOutResult:
+        main.log.warn( "Failed to checked out " + gitBranch +
+                                           " branch")
+    else:
+        main.log.info( "Successfully checked out " + gitBranch +
+                                           " branch")
+    gitPullResult = main.ONOSbench.gitPull()
+    if gitPullResult == main.ERROR:
+        main.log.error( "Error pulling git branch" )
+    else:
+        main.log.info( "Successfully pulled " + gitBranch + " branch" )
+
+    # Maven clean install
+    buildResult = main.ONOSbench.cleanInstall()
+
+    return buildResult
+
+
+
+
diff --git a/TestON/tests/FUNCnetconf/Dependency/topo.py b/TestON/tests/FUNCnetconf/Dependency/topo.py
new file mode 100644
index 0000000..b44e3fc
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/Dependency/topo.py
@@ -0,0 +1,100 @@
+"""
+    These functions can be used for topology comparisons
+"""
+
+import time
+import os
+import json
+
+def getAllDevices( main ):
+    """
+        Return a list containing the devices output from each ONOS node
+    """
+    devices = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].devices,
+                         name="devices-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        devices.append( t.result )
+    return devices
+
+def getAllHosts( main ):
+    """
+        Return a list containing the hosts output from each ONOS node
+    """
+    hosts = []
+    ipResult = main.TRUE
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].hosts,
+                         name="hosts-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        hosts.append( t.result )
+    return hosts
+
+def getAllPorts( main ):
+    """
+        Return a list containing the ports output from each ONOS node
+    """
+    ports = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].ports,
+                         name="ports-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        ports.append( t.result )
+    return ports
+
+def getAllLinks( main ):
+    """
+        Return a list containing the links output from each ONOS node
+    """
+    links = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].links,
+                         name="links-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        links.append( t.result )
+    return links
+
+def getAllClusters( main ):
+    """
+        Return a list containing the clusters output from each ONOS node
+    """
+    clusters = []
+    threads = []
+    for i in range( main.numCtrls ):
+        t = main.Thread( target=main.CLIs[i].clusters,
+                         name="clusters-" + str( i ),
+                         args=[ ] )
+        threads.append( t )
+        t.start()
+
+    for t in threads:
+        t.join()
+        clusters.append( t.result )
+    return clusters
+
+
diff --git a/TestON/tests/FUNCnetconf/FUNCnetconf.params b/TestON/tests/FUNCnetconf/FUNCnetconf.params
new file mode 100644
index 0000000..c0fcc5a
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/FUNCnetconf.params
@@ -0,0 +1,53 @@
+<PARAMS>
+    # CASE - Description
+    # 1 - Variable initialization and optional pull and build ONOS package
+    # 2 - Install ONOS
+    # 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>
+
+    <SCALE>
+        <size>1,3</size>
+    </SCALE>
+
+    <DEPENDENCY>
+        <path> /tests/FUNCnetconf/Dependency/</path>
+        <wrapper1>startUp</wrapper1>
+        <wrapper2>netconf</wrapper2>
+        <wrapper3>topo</wrapper3>
+        <topology></topology>
+    </DEPENDENCY>
+
+    <ENV>
+        <cellApps>drivers,openflow,proxyarp,mobility,netconf</cellApps>
+    </ENV>
+
+    <GIT>
+        <pull>False</pull>
+        <branch>master</branch>
+    </GIT>
+
+    <SLEEP>
+        <startup>20</startup>
+        <upSwitch>10</upSwitch>
+        <topoAttempts>3</topoAttempts>
+    </SLEEP>
+
+    <MININET>
+        <switch>0</switch>
+        <links></links>
+    </MININET>
+
+    <CONFIGURE>
+        <cfgDevicePort>830</cfgDevicePort>
+        <cfgDriver>ovs-netconf</cfgDriver>
+        <cfgApps>org.onosproject.netconf</cfgApps>
+        <cfgName>"sdn"</cfgName>
+        <cfgPass>"rocks"</cfgPass>
+        <cfgAppPort>830</cfgAppPort>
+    </CONFIGURE>
+
+</PARAMS>
diff --git a/TestON/tests/FUNCnetconf/FUNCnetconf.py b/TestON/tests/FUNCnetconf/FUNCnetconf.py
new file mode 100644
index 0000000..ddd1cd8
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/FUNCnetconf.py
@@ -0,0 +1,361 @@
+# Testing the NETCONF protocol within ONOS
+
+class FUNCnetconf:
+
+    def __init__( self ):
+        self.default = ''
+
+    def CASE1( self, main ):
+        import time
+        import imp
+        import re
+
+        """
+        - Construct tests variables
+        - GIT ( optional )
+            - Checkout ONOS master branch
+            - Pull latest ONOS code
+        - Building ONOS ( optional )
+            - Install ONOS package
+            - Build ONOS package
+        """
+
+        main.case( "Constructing test variables and building ONOS package" )
+        main.step( "Constructing test variables" )
+        main.caseExplanation = "This test case is mainly for loading " +\
+                               "from params file, and pull and build the " +\
+                               " latest ONOS package"
+        stepResult = main.FALSE
+
+        # Test variables
+        try:
+            main.testOnDirectory = re.sub( "(/tests)$", "", main.testDir )
+            main.apps = main.params[ 'ENV' ][ 'cellApps' ]
+            gitBranch = main.params[ 'GIT' ][ 'branch' ]
+            main.dependencyPath = main.testOnDirectory + \
+                                  main.params[ 'DEPENDENCY' ][ 'path' ]
+            # main.topology = main.params[ 'DEPENDENCY' ][ 'topology' ]
+            main.scale = ( main.params[ 'SCALE' ][ 'size' ] ).split( "," )
+            if main.ONOSbench.maxNodes:
+                main.maxNodes = int( main.ONOSbench.maxNodes )
+            else:
+                main.maxNodes = 0
+            wrapperFile1 = main.params[ 'DEPENDENCY' ][ 'wrapper1' ]
+            wrapperFile2 = main.params[ 'DEPENDENCY' ][ 'wrapper2' ]
+            wrapperFile3 = main.params[ 'DEPENDENCY' ][ 'wrapper3' ]
+            main.startUpSleep = int( main.params[ 'SLEEP' ][ 'startup' ] )
+            main.switchSleep = int( main.params[ 'SLEEP' ][ 'upSwitch' ] )
+            main.checkTopoAttempts = int( main.params[ 'SLEEP' ][ 'topoAttempts' ] )
+            main.numSwitch = int( main.params[ 'MININET' ][ 'switch' ] )
+
+            # Config file parameters
+            main.configDevicePort = main.params[ 'CONFIGURE' ][ 'cfgDevicePort' ]
+            main.configDriver = main.params[ 'CONFIGURE' ][ 'cfgDriver' ]
+            main.configApps = main.params[ 'CONFIGURE' ][ 'cfgApps' ]
+            main.configName = main.params[ 'CONFIGURE' ][ 'cfgName' ]
+            main.configPass = main.params[ 'CONFIGURE' ][ 'cfgPass' ]
+            main.configPort = main.params[ 'CONFIGURE' ][ 'cfgAppPort' ]
+
+            gitPull = main.params[ 'GIT' ][ 'pull' ]
+            main.cellData = {} # for creating cell file
+            main.hostsData = {}
+            main.CLIs = []
+            main.CLIs2 = []
+            main.ONOSip = []
+            main.assertReturnString = ''  # Assembled assert return string
+
+            main.ONOSip = main.ONOSbench.getOnosIps()
+            print main.ONOSip
+
+            # Assigning ONOS cli handles to a list
+            for i in range( 1,  main.maxNodes + 1 ):
+                main.CLIs.append( getattr( main, 'ONOSrest' + str( i ) ) )
+                main.CLIs2.append( getattr( main, 'ONOScli' + str( i ) ) )
+
+            # -- INIT SECTION, ONLY RUNS ONCE -- #
+            main.startUp = imp.load_source( wrapperFile1,
+                                            main.dependencyPath +
+                                            wrapperFile1 +
+                                            ".py" )
+
+            main.netconfFunction = imp.load_source( wrapperFile2,
+                                            main.dependencyPath +
+                                            wrapperFile2 +
+                                            ".py" )
+
+            main.topo = imp.load_source( wrapperFile3,
+                                         main.dependencyPath +
+                                         wrapperFile3 +
+                                         ".py" )
+
+            # Uncomment out the following if a mininet topology is added
+            # copyResult1 = main.ONOSbench.scp( main.Mininet1,
+            #                                   main.dependencyPath +
+            #                                   main.topology,
+            #                                   main.Mininet1.home + "custom/",
+            #                                   direction="to" )
+
+            if main.CLIs and main.CLIs2:
+                stepResult = main.TRUE
+            else:
+                main.log.error( "Did not properly created list of ONOS CLI handle" )
+                stepResult = main.FALSE
+        except Exception as e:
+            main.log.exception(e)
+            main.cleanup()
+            main.exit()
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully construct " +
+                                        "test variables ",
+                                 onfail="Failed to construct test variables" )
+
+        if gitPull == 'True':
+            main.step( "Building ONOS in " + gitBranch + " branch" )
+            onosBuildResult = main.startUp.onosBuild( main, gitBranch )
+            stepResult = onosBuildResult
+            utilities.assert_equals( expect=main.TRUE,
+                                     actual=stepResult,
+                                     onpass="Successfully compiled " +
+                                            "latest ONOS",
+                                     onfail="Failed to compile " +
+                                            "latest ONOS" )
+        else:
+            main.log.warn( "Did not pull new code so skipping mvn " +
+                           "clean install" )
+        main.ONOSbench.getVersion( report=True )
+
+    def CASE2( self, main ):
+        """
+        - Set up cell
+            - Create cell file
+            - Set cell file
+            - Verify cell file
+        - Kill ONOS process
+        - Uninstall ONOS cluster
+        - Verify ONOS start up
+        - Install ONOS cluster
+        - Connect to cli
+        """
+
+        # main.scale[ 0 ] determines the current number of ONOS controller
+        main.numCtrls = int( main.scale[ 0 ] )
+
+        main.case( "Starting up " + str( main.numCtrls ) +
+                   " node(s) ONOS cluster" )
+        main.caseExplanation = "Set up ONOS with " + str( main.numCtrls ) +\
+                                " node(s) ONOS cluster"
+
+
+
+        #kill off all onos processes
+        main.log.info( "Safety check, killing all ONOS processes" +
+                       " before initiating environment setup" )
+
+
+
+        time.sleep( main.startUpSleep )
+        main.step( "Uninstalling ONOS package" )
+        onosUninstallResult = main.TRUE
+        for ip in main.ONOSip:
+            onosUninstallResult = onosUninstallResult and \
+                    main.ONOSbench.onosUninstall( nodeIp=ip )
+        stepResult = onosUninstallResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully uninstalled ONOS package",
+                                 onfail="Failed to uninstall ONOS package" )
+
+        for i in range( main.maxNodes ):
+            main.ONOSbench.onosDie( main.ONOSip[ i ] )
+
+        main.log.info( "NODE COUNT = " + str( main.numCtrls ) )
+
+        tempOnosIp = []
+        for i in range( main.numCtrls ):
+            tempOnosIp.append( main.ONOSip[i] )
+
+        main.ONOSbench.createCellFile( main.ONOSbench.ip_address,
+                                       "temp", main.Mininet1.ip_address,
+                                       main.apps, tempOnosIp )
+
+        main.step( "Apply cell to environment" )
+        cellResult = main.ONOSbench.setCell( "temp" )
+        verifyResult = main.ONOSbench.verifyCell()
+        stepResult = cellResult and verifyResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully applied cell to " + \
+                                        "environment",
+                                 onfail="Failed to apply cell to environment " )
+
+        main.step( "Creating ONOS package" )
+        packageResult = main.ONOSbench.onosPackage()
+        stepResult = packageResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully created ONOS package",
+                                 onfail="Failed to create ONOS package" )
+
+        time.sleep( main.startUpSleep )
+        main.step( "Installing ONOS package" )
+        onosInstallResult = main.TRUE
+        for i in range( main.numCtrls ):
+            onosInstallResult = onosInstallResult and \
+                    main.ONOSbench.onosInstall( node=main.ONOSip[ i ], options="" )
+        stepResult = onosInstallResult
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully installed ONOS package",
+                                 onfail="Failed to install ONOS package" )
+
+        time.sleep( main.startUpSleep )
+        main.step( "Starting ONOS service" )
+        stopResult = main.TRUE
+        startResult = main.TRUE
+        onosIsUp = main.TRUE
+
+        for i in range( main.numCtrls ):
+            onosIsUp = onosIsUp and main.ONOSbench.isup( main.ONOSip[ i ] )
+        if onosIsUp == main.TRUE:
+            main.log.report( "ONOS instance is up and ready" )
+        else:
+            main.log.report( "ONOS instance may not be up, stop and " +
+                             "start ONOS again " )
+            for i in range( main.numCtrls ):
+                stopResult = stopResult and \
+                        main.ONOSbench.onosStop( main.ONOSip[ i ] )
+            for i in range( main.numCtrls ):
+                startResult = startResult and \
+                        main.ONOSbench.onosStart( main.ONOSip[ i ] )
+        stepResult = onosIsUp and stopResult and startResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="ONOS service is ready",
+                                 onfail="ONOS service did not start properly" )
+
+        # Start an ONOS cli to provide functionality that is not currently
+        # supported by the Rest API remove this when Leader Checking is supported
+        # by the REST API
+
+        main.step( "Start ONOS cli" )
+        cliResult = main.TRUE
+        for i in range( main.numCtrls ):
+            cliResult = cliResult and \
+                        main.CLIs2[ i ].startOnosCli( main.ONOSip[ i ] )
+        stepResult = cliResult
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully start ONOS cli",
+                                 onfail="Failed to start ONOS cli" )
+
+        # Remove the first element in main.scale list
+        main.scale.remove( main.scale[ 0 ] )
+
+    def CASE100( self, main ):
+        """
+            Start NETCONF app and OFC-Server or make sure that they are already running
+        """
+        assert main, "There is no main"
+        assert main.CLIs, "There is no main.CLIs"
+        assert main.numCtrls, "Placed the total number of switch topology in \
+                                main.numCtrls"
+
+        testResult = main.FALSE
+        main.testName = "Start up NETCONF app in all nodes"
+        main.case( main.testName + " Test - " + str( main.numCtrls ) +
+                   " NODE(S)" )
+        main.step( "Starting NETCONF app" )
+        main.assertReturnString = "Assertion result for starting NETCONF app"
+        testResult = main.netconfFunction.startApp( main )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=testResult,
+                                 onpass=main.assertReturnString,
+                                 onfail=main.assertReturnString )
+
+        main.step( "Starting OFC-Server" )
+        main.assertReturnString = "Assertion result for starting OFC-Server"
+        testResult = main.netconfFunction.startOFC( main )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=testResult,
+                                 onpass=main.assertReturnString,
+                                 onfail=main.assertReturnString )
+        time.sleep( main.startUpSleep )
+
+    def CASE200( self, main ):
+        """
+            Create or modify a Configuration file
+                -The file is built from information loaded from the .params file
+        """
+        assert main, "There is no main"
+        assert main.CLIs, "There is no main.CLIs"
+        assert main.numCtrls, "Placed the total number of switch topology in \
+                                main.numCtrls"
+
+        main.testName = "Assemble the configuration"
+        main.case( main.testName + " Test - " + str( main.numCtrls ) +
+                   " NODES(S)" )
+        main.step( "Assembling configuration file" )
+        main.assertReturnString = "Assertion result for assembling configuration file"
+        testResult = main.FALSE
+        testResult = main.netconfFunction.createConfig( main )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=testResult,
+                                 onpass=main.assertReturnString,
+                                 onfail=main.assertReturnString )
+        time.sleep( main.startUpSleep )
+
+    def CASE300( self, main ):
+        """
+            Push a configuration and bring up a switch
+        """
+        assert main, "There is no main"
+        assert main.CLIs, "There is no main.CLIs"
+        assert main.numCtrls, "Placed the total number of switch topology in \
+                                main.numCtrls"
+
+        main.testName = "Uploading the configuration"
+        main.case( main.testName + " Test - " + str( main.numCtrls ) +
+                   " NODES(S)" )
+        main.step( "Sending the configuration file")
+        main.assertReturnString = "Assertion result for sending the configuration file"
+        testResult = main.FALSE
+
+        testResult = main.netconfFunction.sendConfig( main )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=testResult,
+                                 onpass=main.assertReturnString,
+                                 onfail=main.assertReturnString )
+
+        time.sleep( main.switchSleep )
+
+        main.step( "Confirming the device was configured" )
+        main.assertReturnString = "Assertion result for confirming a configuration."
+        testResult = main.FALSE
+
+        testResult = main.netconfFunction.devices( main )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=testResult,
+                                 onpass=main.assertReturnString,
+                                 onfail=main.assertReturnString )
+
+    def CASE400( self, main ):
+        """
+            Bring down a switch
+            This test case is not yet possible, but the functionality needed to
+            perform it is planned to be added
+                There is a message that is sent "Device () has closed session"
+                when the device disconnects from onos for some reason.
+                    Because of the triggers for this message are not practical
+                    to activate this will likely not be used to implement the test
+                    case at this time
+            Possible ways to do this may include bringing down mininet then checking
+            ONOS to see if it was recongnized the device being disconnected
+        """
diff --git a/TestON/tests/FUNCnetconf/FUNCnetconf.topo b/TestON/tests/FUNCnetconf/FUNCnetconf.topo
new file mode 100644
index 0000000..a5a836f
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/FUNCnetconf.topo
@@ -0,0 +1,87 @@
+<TOPOLOGY>
+    <COMPONENT>
+
+        <ONOSbench>
+            <host>localhost</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS>
+                <nodes>3</nodes>
+            </COMPONENTS>
+        </ONOSbench>
+
+        <ONOSrest1>
+            <host>OC1</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest1>
+
+        <ONOSrest2>
+            <host>OC2</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest2>
+
+        <ONOSrest3>
+            <host>OC3</host>
+            <port>8181</port>
+            <user>onos</user>
+            <password>rocks</password>
+            <type>OnosRestDriver</type>
+            <connect_order>4</connect_order>
+            <COMPONENTS>
+            </COMPONENTS>
+        </ONOSrest3>
+
+        <ONOScli1>
+            <host>localhost</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli1>
+
+        <ONOScli2>
+            <host>localhost</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>6</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli2>
+
+         <ONOScli3>
+            <host>localhost</host>
+            <user>admin</user>
+            <password></password>
+            <type>OnosCliDriver</type>
+            <connect_order>7</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli3>
+
+        <Mininet1>
+            <host>OCN</host>
+            <user>admin</user>
+            <password></password>
+            <type>MininetCliDriver</type>
+            <connect_order>8</connect_order>
+            <COMPONENTS>
+                <home>~/mininet/</home>
+            </COMPONENTS>
+        </Mininet1>
+
+    </COMPONENT>
+</TOPOLOGY>
\ No newline at end of file
diff --git a/TestON/tests/FUNCnetconf/README b/TestON/tests/FUNCnetconf/README
new file mode 100644
index 0000000..dbf51c0
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/README
@@ -0,0 +1,29 @@
+Summary:
+        This test suite consists of generic NETCONF protocol testing within ONOS
+        using OF-Config to translate NETCONF requests for OVSDB.
+        The following is an overview of how the NETCONF protocol is tested
+        Steps:
+            - Start NETCONF App in all currently running nodes
+            - Start OF-Config server on device to be configured
+            - Create configuration file
+            - Upload the configuration file to the device to be configured
+            - Verify that the device was configured successfully
+
+Required:
+        Make sure that OF-Config, https://github.com/openvswitch/of-config, is
+        installed on the device that is to be configured, the test assumes this
+        device is the machine running TestON.
+        Ensure that <cfgName> and <cfgPass> in the params file are the username
+        and password required to ssh into the desired machine and account that
+        of-config is to be run on.
+        The netconfConfig.json file contains the configuration that was
+        generated by the test.  The test also relies on the existence of this
+        file and will missbehave if it is removed entirely.  The contents of the
+        file are overwritten everytime the test suite runs through Test Case 200
+
+TODO:
+Extend configuration to allow for specification of
+    - Vendor name
+    - Hardware version
+    - Software version
+    - Serial Number
\ No newline at end of file
diff --git a/TestON/tests/FUNCnetconf/__init__.py b/TestON/tests/FUNCnetconf/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/TestON/tests/FUNCnetconf/__init__.py