Bruno automation test code upload: New test cases added: some networking and TR069 test cases.

Change-Id: Ie10f54b238d41c4b05e570a9716890f4fdf7c578
diff --git a/acs.py b/acs.py
index 4025428..8725e02 100755
--- a/acs.py
+++ b/acs.py
@@ -24,6 +24,7 @@
         'url': None,
         # expected image version ID on ACS
         'imageVersion': expected_version,
+        'acs_path': None,
         'outfile': 'cmdOutput.txt'}
     for s in kwargs:
       self.acs_info[s] = kwargs[s]
@@ -47,17 +48,30 @@
     else:
       self.acs_info['imageVersion'] = expected_version
 
-  def SaveConfiguration(self):
+  def ParseAppIDFromACSURL(self, url='https://acs.e2e.gfsvc.com/cwmp'):
+    """Parse app_id from ACS instance host name."""
+    pass
+
+  def SaveConfiguration(self, profile_id, version_id, app_id,
+                        host='https://acs.e2e.gfsvc.com/cwmp'):
     """Run the ACS configuration script from Google3 location."""
+    if not version_id:
+      v_id = self.acs_info['imageVersion']
+    else:
+      v_id = version_id
+
     cur_dir = os.getcwd()
     print '============' + cur_dir
-    os.chdir('/home/lmeng/git_project/google3/isp/'
-             'fiber/testing/automated_tests/bulkupgrade/')
+    # the acs_path is the google3 repository where upgrade_test.py
+    # locates. This test depends on it to modify ACS datastore.
+    os.chdir(self.acs_info['acs_path'])
     print '============' + os.getcwd()
     os.system(
         'blaze test --notest_loasd --test_arg=--imageVersion='
-        + self.acs_info['imageVersion']
-        + ' --test_strategy=local :bulkupgrade_test ')
+        + v_id + ' --test_arg=--profile_id='
+        + profile_id + ' --test_arg=--app_id=' + app_id
+        + ' --test_arg=--host=' + host
+        + ' --test_strategy=local :upgrade_test ')
     os.chdir(cur_dir)
     print '============' + os.getcwd()
 
@@ -71,19 +85,95 @@
       log_list.append(line.strip())
     return log_list
 
-  def ParseParameterNames(self, cmd_list):
-    """Parse the command output from nbi_client, retrieve parameter names."""
+  def ParseParameterAccessStates(self, cmd_list):
+    """Find out if a parameter is 'writable' or 'read-write'.
+
+    This method process the nbi_client getParameterNames() call result
+    to find out the access state of the parameters.
+    Args:
+      cmd_list: the getParameterNames() call returned result list
+    Returns:
+      a dictionary: parameter name as index, and its access state
+      as value.
+    """
     if ('FAILED' in cmd_list[0]) or (not 'SUCCESS' in cmd_list[0]):
       info = self.log.CreateErrorInfo(
-          'Critical', 'nbi_clienet call failed. Check log for details.')
+          'Critical', 'nbi_clienet call failed. ' + str(cmd_list[0]))
       self.log.SendLine(None, info)
       return False
 
+    para_dict = {}
+    for line in cmd_list:
+      if 'name:' in line:
+        name = re.sub('.*name:\s*\"(.*)\".*', r'\1', line)
+        index = cmd_list.index(line)+1
+        access = re.sub('.*writable:\s*([a-zA-Z]+)', r'\1', cmd_list[index])
+        para_dict.update({name: access})
+    return para_dict
+
+  def CheckCmdCall(self, cmd_list):
+    """Check if the RPC call is a success or failure."""
+    if ('FAILED' in cmd_list[0]) or (not 'SUCCESS' in cmd_list[0]):
+      info = self.log.CreateErrorInfo(
+          'Critical', 'nbi_client call failed. ' + str(cmd_list[0]))
+      self.log.SendLine(None, info)
+      return False
+    else:
+      return True
+
+  def ParseManagementURL(self, cmd_list):
+    """Parse Management URL from GetParameterValues query reply message.
+
+    Reply message is in the following format:
+    #########################################################
+    SUCCESS! Response: parameter_value_list {
+    parameter_value_struct {
+    name: "InternetGatewayDevice.ManagementServer.URL"
+    string_value: "https://acs.e2e.gfsvc.com/cwmp"
+       }
+    }
+    #########################################################
+
+    Args:
+      cmd_list: the ACS url information obtained from device log or file
+    Returns:
+      returns the management url found, or return false if url not found
+    """
+    if not cmd_list:
+      return False
+    for line in cmd_list:
+      if ('name:' in line and
+          'InternetGatewayDevice.ManagementServer.URL' in line):
+        s = cmd_list[cmd_list.index(line)+1]
+        m = re.search('http[s]?://(\w*\.)+com/cwmp', s)
+        if not m:
+          info = self.log.CreateErrorInfo(
+              'Warning', 'No management server URL found in GetParameterValues '
+              'query reply.')
+          self.log.SendLine(None, info)
+          return False
+        else:
+          return m.group(0)
+
+  def ParseParameterNames(self, cmd_list, replace_index=False):
+    """Parse the get values RPC call response, retrieve parameter name list.
+
+    Args:
+      cmd_list: the command reply message from nbi_client
+      replace_index: if True, the index digits in parameter names will be
+                     replaced with '.{i}.'
+    Returns:
+      return the parsed parameter name list
+    """
+    if not self.CheckCmdCall(cmd_list):
+      return False
+
     chk_list = []
     for line in cmd_list:
       if 'name:' in line:
         output = re.sub('.*\"(.*)\".*', r'\1', line)
-        output = re.sub(r'(\.)[\d]+(\.)', r'\1{i}\2', output)
+        if replace_index:
+          output = re.sub(r'(\.)[\d]+(\.)', r'\1{i}\2', output)
         if chk_list.count(output) < 1:
           chk_list.append(output)
     return chk_list
diff --git a/config.cfg b/config.cfg
index 602b4d9..ea3fef7 100644
--- a/config.cfg
+++ b/config.cfg
@@ -1,49 +1,126 @@
-##############################################
-# This is the config file for the test cases #
-#                                            #
-# All test cases share the same config file. #
-# Each test case configuration starts with   #
-# the testID of that test case.              #
-#                                            #
-# comment line starts with '#' and will not  #
-# be parsed as configuration information     #
-##############################################
-testID: 11843140
-user = root  #obsoleted 
-addr = 192.168.1.4
-addr_ipv6 = None
-pwd = google  #obsoleted 
-bruno_prompt = gfibertv#
-title =Image_Download
-expected_version_id=716006
-expected_version=bruno-koala-5
-downgrade_version=bruno-koala-4
-downgrade_version_id=728001
-acs_url = https://gfiber-acs-staging.appspot.com/cwmp
-# if authentication server is required to access the device
-jump_server = jmp.googlefiber.net
-# if athena server is required to access the device:
-athena_user = your_uname
-athena_pwd = your_pwd
+{
+      "Image_Download":{
+        "comment":["this is a comment line",
+                   "this configuration profile is for ImageDownload test case",
+                   "the acs_path is the google3 repository where upgrade_test.py locates. This test depends on it to modify ACS datastore."],
+        "testID": ["11843140", "14165036"],
+        "title" : {"11843140":"Image_Download", "14165036":"DownloadInterrupt"},
+        "user" : "root",
+        "addr" : "192.168.1.4",
+        "addr_ipv6" : "2605:a601:fe00:fd18:21a:11ff:fe30:64e6",
+        "pwd" : "google",
+        "bruno_prompt" : "gfibertv#",
+        "expected_version_id": "987010",
+        "expected_version": "bruno-monkey-4",
+        "downgrade_version": "bruno-monkey-3",
+        "downgrade_version_id": "1038003",
+        "acs_url" : "https://gfiber-acs-staging.appspot.com/cwmp",
+        "acs_path": "/home/lmeng/git_project/google3/isp/gfiber/testing/automated_tests/upgrade_test/",
+        "acs_app_id": "gfiber-acs-staging",
+        "acs_host_name": "gfiber-acs-staging.appspot.com",
+        "jump_server" : "jmp.googlefiber.net",
+        "athena_user" : "your_uname",
+        "athena_pwd" : "your_pwd",
+        "profile_id" : "557001"
+      },
+
+      "basic_network_testcases":{
+        "comment":["addr_ipv6_dup: the duplicated address to set on device, in",
+                   "or der to detect the address duplication error."],
+        "testID": ["11874111", "11721378"],
+        "title" : {"11874111":"DuplicateIPv6Addr", "11721378":"DHCPv4OverBruno-IS"},
+        "user" : "root",
+        "addr" : "192.168.1.4",
+        "addr_ipv6" : "2605:a601:fe00:fd18:21a:11ff:fe30:64e6",
+        "bruno_prompt" : "gfibertv#",
+        "expected_version_id": "987010",
+        "expected_version": "bruno-monkey-4",
+        "addr_ipv6_dup":"2605:a601:fe00:fd18:21a:11ff:fe30:6383"
+      },
+      
+      "dataModel":{
+        "testID": ["14187024", "14165033", "14315008", "14165035", "14314007",
+                   "11865133", "14335001", "14266498", "14319149", "14314008",
+                   "11722375", "14315009", "14314009", "14165038", "15643845"],
+        "title" : {"14187024":"TR140_DataModel",
+                   "14165033":"GVSB_DataModel",
+                   "14315008":"TR098_DataModel",
+                   "14165035":"MoCA_DataModel",
+                   "14314007":"TR181_DataModel",
+                   "11865133":"TR135_DataModel",
+                   "14335001":"X_CATAWAMPUS-ORG_DataModel",
+                   "14266498":"FlashDevice_DataModel",
+                   "14319149":"X_GOOGLE-COM_DataModel",
+                   "14314008":"TR157_DataModel",
+                   "11722375":"SetParameterValuesRPC",
+                   "14315009":"ManagementServerURL",
+                   "14314009":"MonitorTemperature",
+                   "14165038":"AutoChannelEnable",
+                   "15643845":"NTPTimeZoneConfig"},
+        "user" : "root",
+        "addr" : "192.168.1.4",
+        "addr_ipv6" : "2605:a601:fe00:fd18:21a:11ff:fe30:64e6",
+        "req_file" : "data/DataModel_requirement.cfg",
+        "bruno_prompt" : "gfibertv#",
+        "expected_version_id": "959004",
+        "expected_version": "bruno-monkey-2",
+        "acs_url" : "https://gfiber-acs-staging.appspot.com/cwmp",
+        "nbi_client_path" : "/home/lmeng/git_project/google3/blaze-bin/java/com/google/fiber/provisioning/acs/client/nbi/nbi_client",
+        "para_tree_file" : "ParameterTree.xml",
+        "from_which_param_to_set": "None",
+        "param_path" : "."
+      },
+      
+      "dataModel_WiFi":{
+        "comment":["wifi_params type: e.g., string_value, is the data type accepted by nbi_client RPC call."],
+        "testID": ["14165034"],
+        "title" : {"14165034":"WiFi_configuration"},
+        "user" : "root",
+        "addr" : "192.168.1.4",
+        "addr_ipv6" : "2605:a601:fe00:fd18:21a:11ff:fe30:64e6",
+        "bruno_prompt" : "gfibertv#",
+        "expected_version_id": "987010",
+        "expected_version": "bruno-monkey-4",
+        "acs_url" : "https://gfiber-acs-staging.appspot.com/cwmp",
+        "nbi_client_path" : "/home/lmeng/git_project/google3/blaze-bin/java/com/google/fiber/provisioning/acs/client/nbi/nbi_client",
+        "account_id":"5438577436",
+        "device_label":"0101209088BC",
+        "wifi_params":{
+            "Google.Wifi.SSID":{"string_value":"Home"},
+            "Google.Wifi.Home.SSID_2GHz":{"string_value":"Home"},
+            "Google.Wifi.Enable":{"boolean_value":"true"},
+            "Google.Wifi.BeaconType":{"string_value": "Basic"},
+            "Google.Wifi.BasicEncryptionModes":{"string_value":"WEPEncryption"}}
+      },
+
+      "basic_tr069_test_case":{
+        "comment":["Factory_reset test case needs to manually reset the device"],
+        "testID": ["11865129", "11721375"],
+        "title" : {"11865129":"IPv6_Connection",
+                   "11721375":"Factory_Reset"
+                  },
+        "user" : "root",
+        "addr" : {"value":"192.168.1.4", "comment":"device ipv4 address"},
+        "expected_version": "bruno-monkey-4",
+        "addr_ipv6" : {"value":"2605:a601:fe00:fd18:21a:11ff:fe30:6383",
+                       "comment":"device ipv6 address"},
+        "acs_ipv6" : "2001:4860:8005::8d",
+        "gvsb_host": "https://gvsb.e2e.gfsvc.com/rpc",
+        "acs_url" : "https://acs.e2e.gfsvc.com/cwmp",
+        "bruno_prompt" : "gfibertv#"
+      },
+      
+      "blocked_test_case":{
+        "testID": ["14314009", "14165038"],
+        "title" : {"14314009":"MonitorTemperature",
+                   "14165038":"AutoChannelEnable"},
+        "user" : "root",
+        "addr" : "192.168.1.4",
+        "addr_ipv6" : "2605:a601:fe00:fd18:21a:11ff:fe30:64e6",
+        "bruno_prompt" : "gfibertv#"
+      }
+}
 
 
 
-testID: 14187024
-title =DataModel
-req_file = DataModel_requirement.cfg
-mis_file = missing_parameters.log
-user = root
-pwd = google
-addr = 192.168.1.4
-addr_ipv6 = 2605:a601:fe00:fd18:21a:11ff:fe30:6383
-serial_num = None
-bruno_prompt = gfibertv#
-expected_version_id=728001
-expected_version=bruno-koala-4
-acs_url = https://gfiber-acs-staging.appspot.com/cwmp
-jump_server = jmp.googlefiber.net
-athena_user = your_uname
-athena_pwd = your_pwd
-nbi_client_path = /home/$your_uname/git_project/google3/blaze-bin/java/com/google/fiber/provisioning/acs/client/nbi/nbi_client
-para_tree_file = tree.xml
 
diff --git a/data/DataModel_requirement_1.cfg b/data/DataModel_requirement_1.cfg
deleted file mode 100644
index c940323..0000000
--- a/data/DataModel_requirement_1.cfg
+++ /dev/null
@@ -1,509 +0,0 @@
-Device.Bridging.
-Device.Bridging.Bridge.{i}.
-Device.Bridging.Bridge.{i}.Port.{i}.
-Device.Bridging.Bridge.{i}.Port.{i}.Stats.
-Device.Bridging.Bridge.{i}.VLANPort.{i}.
-Device.DeviceInfo
-Device.DeviceInfo.AdditionalHardwareVersion
-Device.DeviceInfo.AdditionalSoftwareVersion
-Device.DeviceInfo.Description
-Device.DeviceInfo.HardwareVersion
-Device.DeviceInfo.Manufacturer
-Device.DeviceInfo.ManufacturerOUI
-Device.DeviceInfo.MemoryStatus.
-Device.DeviceInfo.MemoryStatus.Free
-Device.DeviceInfo.MemoryStatus.Total
-Device.DeviceInfo.ModelName
-Device.DeviceInfo.NetworkProperties.
-Device.DeviceInfo.ProcessStatus.
-Device.DeviceInfo.ProcessStatus.CPUUsage
-Device.DeviceInfo.ProcessStatus.Process.{i}.
-Device.DeviceInfo.ProcessStatus.Process.{i}.CPUTime
-Device.DeviceInfo.ProcessStatus.Process.{i}.Command
-Device.DeviceInfo.ProcessStatus.Process.{i}.PID
-Device.DeviceInfo.ProcessStatus.Process.{i}.Priority
-Device.DeviceInfo.ProcessStatus.Process.{i}.Size
-Device.DeviceInfo.ProcessStatus.Process.{i}.State
-Device.DeviceInfo.ProcessStatus.ProcessNumberOfEntries
-Device.DeviceInfo.Processor.{i}.
-Device.DeviceInfo.ProcessorNumberOfEntries
-Device.DeviceInfo.ProductClass
-Device.DeviceInfo.ProxierInfo.
-Device.DeviceInfo.SerialNumber
-Device.DeviceInfo.SoftwareVersion
-Device.DeviceInfo.SupportedDataModel.{i}.
-Device.DeviceInfo.SupportedDataModelNumberOfEntries
-Device.DeviceInfo.TemperatureStatus.
-Device.DeviceInfo.TemperatureStatus.TemperatureSensor.{i}.
-Device.DeviceInfo.TemperatureStatus.TemperatureSensorNumberOfEntries
-Device.DeviceInfo.UpTime
-Device.DeviceInfo.VendorConfigFile.{i}.
-Device.DeviceInfo.VendorConfigFileNumberOfEntries
-Device.DeviceInfo.VendorLogFile.{i}.
-Device.DeviceInfo.VendorLogFileNumberOfEntries
-Device.Ethernet.
-Device.Ethernet.Interface.{i}.
-Device.Ethernet.Interface.{i}.DuplexMode
-Device.Ethernet.Interface.{i}.Enable
-Device.Ethernet.Interface.{i}.LastChange
-Device.Ethernet.Interface.{i}.LowerLayers
-Device.Ethernet.Interface.{i}.MACAddress
-Device.Ethernet.Interface.{i}.MaxBitRate
-Device.Ethernet.Interface.{i}.Name
-Device.Ethernet.Interface.{i}.Stats.
-Device.Ethernet.Interface.{i}.Stats.BroadcastPacketsReceived
-Device.Ethernet.Interface.{i}.Stats.BroadcastPacketsSent
-Device.Ethernet.Interface.{i}.Stats.BytesReceived
-Device.Ethernet.Interface.{i}.Stats.BytesSent
-Device.Ethernet.Interface.{i}.Stats.DiscardPacketsReceived
-Device.Ethernet.Interface.{i}.Stats.DiscardPacketsSent
-Device.Ethernet.Interface.{i}.Stats.ErrorsReceived
-Device.Ethernet.Interface.{i}.Stats.ErrorsSent
-Device.Ethernet.Interface.{i}.Stats.MulticastPacketsReceived
-Device.Ethernet.Interface.{i}.Stats.MulticastPacketsSent
-Device.Ethernet.Interface.{i}.Stats.PacketsReceived
-Device.Ethernet.Interface.{i}.Stats.PacketsSent
-Device.Ethernet.Interface.{i}.Stats.UnicastPacketsReceived
-Device.Ethernet.Interface.{i}.Stats.UnicastPacketsSent
-Device.Ethernet.Interface.{i}.Stats.UnknownProtoPacketsReceived
-Device.Ethernet.Interface.{i}.Status
-Device.Ethernet.Interface.{i}.Upstream
-Device.Ethernet.Interface.{i}.X_CATAWAMPUS-ORG_ActualBitRate
-Device.Ethernet.Interface.{i}.X_CATAWAMPUS-ORG_ActualDuplexMode
-Device.Ethernet.InterfaceNumberOfEntries
-Device.Ethernet.Link.{i}.
-Device.Ethernet.Link.{i}.Stats.
-Device.Ethernet.LinkNumberOfEntries
-Device.Ethernet.RMONStats.{i}.
-Device.Ethernet.VLANTerminationNumberOfEntries
-Device.IP.ActivePort.{i}.
-Device.IP.Diagnostics.DownloadDiagnostics.
-Device.IP.Diagnostics.IPPing.
-Device.IP.Diagnostics.TraceRoute.
-Device.IP.Diagnostics.TraceRoute.RouteHops.{i}.
-Device.IP.Diagnostics.UDPEchoConfig.
-Device.IP.Diagnostics.UploadDiagnostics.
-Device.IP.Interface.{i}.
-Device.IP.Interface.{i}.IPv4Address.{i}.
-Device.IP.Interface.{i}.IPv6Address.{i}.
-Device.IP.Interface.{i}.IPv6Prefix.{i}.
-Device.IP.Interface.{i}.Stats.{i}.
-Device.InterfaceStackNumberOfEntries
-Device.ManagementServer.
-Device.ManagementServer.AutonomousTransferCompletePolicy.
-Device.ManagementServer.CWMPRetryIntervalMultiplier
-Device.ManagementServer.CWMPRetryMinimumWaitInterval
-Device.ManagementServer.ConnectionRequestPassword
-Device.ManagementServer.ConnectionRequestURL
-Device.ManagementServer.ConnectionRequestUsername
-Device.ManagementServer.DUStateChangeComplPolicy.
-Device.ManagementServer.DefaultActiveNotificationThrottle
-Device.ManagementServer.DownloadAvailability.
-Device.ManagementServer.DownloadAvailability.Announcement.
-Device.ManagementServer.DownloadAvailability.Announcement.Group.{i}.
-Device.ManagementServer.DownloadAvailability.Query.
-Device.ManagementServer.EmbeddedDevice.{i}.
-Device.ManagementServer.EnableCWMP
-Device.ManagementServer.ManageableDevice.{i}.
-Device.ManagementServer.ManageableDeviceNumberOfEntries
-Device.ManagementServer.ParameterKey
-Device.ManagementServer.Password
-Device.ManagementServer.PeriodicInformEnable
-Device.ManagementServer.PeriodicInformInterval
-Device.ManagementServer.PeriodicInformTime
-Device.ManagementServer.STUNEnable
-Device.ManagementServer.URL
-Device.ManagementServer.UpgradesManaged
-Device.ManagementServer.Username
-Device.ManagementServer.VirtualDevice.{i}.
-Device.MoCA.
-Device.MoCA.Interface.{i}.AssociatedDeviceNumberOfEntries
-Device.MoCA.Interface.{i}.BackupNC
-Device.MoCA.Interface.{i}.CurrentOperFreq
-Device.MoCA.Interface.{i}.CurrentVersion
-Device.MoCA.Interface.{i}.Enable
-Device.MoCA.Interface.{i}.FirmwareVersion
-Device.MoCA.Interface.{i}.HighestVersion
-Device.MoCA.Interface.{i}.LastChange
-Device.MoCA.Interface.{i}.LastOperFreq
-Device.MoCA.Interface.{i}.LowerLayers
-Device.MoCA.Interface.{i}.MACAddress
-Device.MoCA.Interface.{i}.Name
-Device.MoCA.Interface.{i}.NetworkCoordinator
-Device.MoCA.Interface.{i}.NodeID
-Device.MoCA.Interface.{i}.PacketAggregationCapability
-Device.MoCA.Interface.{i}.PrivacyEnabled
-Device.MoCA.Interface.{i}.QAM256Capable
-Device.MoCA.Interface.{i}.Stats.BroadcastPacketsReceived
-Device.MoCA.Interface.{i}.Stats.BroadcastPacketsSent
-Device.MoCA.Interface.{i}.Stats.BytesReceived
-Device.MoCA.Interface.{i}.Stats.BytesSent
-Device.MoCA.Interface.{i}.Stats.DiscardPacketsReceived
-Device.MoCA.Interface.{i}.Stats.DiscardPacketsSent
-Device.MoCA.Interface.{i}.Stats.ErrorsReceived
-Device.MoCA.Interface.{i}.Stats.ErrorsSent
-Device.MoCA.Interface.{i}.Stats.MulticastPacketsReceived
-Device.MoCA.Interface.{i}.Stats.MulticastPacketsSent
-Device.MoCA.Interface.{i}.Stats.PacketsReceived
-Device.MoCA.Interface.{i}.Stats.PacketsSent
-Device.MoCA.Interface.{i}.Stats.UnicastPacketsReceived
-Device.MoCA.Interface.{i}.Stats.UnicastPacketsSent
-Device.MoCA.Interface.{i}.Stats.UnknownProtoPacketsReceived
-Device.MoCA.Interface.{i}.Status
-Device.MoCA.Interface.{i}.Upstream
-Device.MoCA.InterfaceNumberOfEntries
-Device.MoCA.Interface.{i}.
-Device.MoCA.Interface.{i}.AssociatedDevice.{i}.
-Device.MoCA.Interface.{i}.QoS.
-Device.MoCA.Interface.{i}.QoS.FlowStats.{i}.
-Device.MoCA.Interface.{i}.Stats.
-Device.PeriodicStatistics.MaxReportSamples
-Device.PeriodicStatistics.MinSampleInterval
-Device.PeriodicStatistics.SampleSet.{i}.Enable
-Device.PeriodicStatistics.SampleSet.{i}.FetchSamples
-Device.PeriodicStatistics.SampleSet.{i}.Name
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.CalculationMode
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Enable
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Failures
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.HighThreshold
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.LowThreshold
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Reference
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SampleMode
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SampleSeconds
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SuspectData
-Device.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Values
-Device.PeriodicStatistics.SampleSet.{i}.ParameterNumberOfEntries
-Device.PeriodicStatistics.SampleSet.{i}.ReportEndTime
-Device.PeriodicStatistics.SampleSet.{i}.ReportSamples
-Device.PeriodicStatistics.SampleSet.{i}.ReportStartTime
-Device.PeriodicStatistics.SampleSet.{i}.SampleInterval
-Device.PeriodicStatistics.SampleSet.{i}.SampleSeconds
-Device.PeriodicStatistics.SampleSet.{i}.Status
-Device.PeriodicStatistics.SampleSet.{i}.TimeReference
-Device.PeriodicStatistics.SampleSetNumberOfEntries
-Device.QoS.
-Device.QoS.App.{i}.
-Device.QoS.Classification.{i}.
-Device.QoS.Flow.{i}.
-Device.QoS.Policer.{i}.
-Device.QoS.Queue.{i}.
-Device.QoS.QueueStats.{i}.
-Device.QoS.Shaper.{i}.
-Device.Services.STBService.{i}.
-Device.Services.STBService.{i}.AVPlayers.
-Device.Services.STBService.{i}.AVPlayers.AVPlayer.{i}.
-Device.Services.STBService.{i}.AVStreams.
-Device.Services.STBService.{i}.AVStreams.AVStream{i}.
-Device.Services.STBService.{i}.Applications.
-Device.Services.STBService.{i}.Applications.AudienceStats.
-Device.Services.STBService.{i}.Applications.AudienceStats.Channel.{i}.
-Device.Services.STBService.{i}.Capabilities.AudienceStats.
-Device.Services.STBService.{i}.Capabilities.AudioDecoder.
-Device.Services.STBService.{i}.Capabilities.AudioOutput.
-Device.Services.STBService.{i}.Capabilities.DRM
-Device.Services.STBService.{i}.Capabilities.FrontEnd.
-Device.Services.STBService.{i}.Capabilities.FrontEnd.IP.
-Device.Services.STBService.{i}.Capabilities.PVR.
-Device.Services.STBService.{i}.Capabilities.ServiceMonitoring.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG2Part2.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG2Part2.ProfileLevel.{i}.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG4Part10.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG4Part10.ProfileLevel.{i}.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG4Part2.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.MPEG4Part2.ProfileLevel.{i}.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.SMPTEVC1.
-Device.Services.STBService.{i}.Capabilities.VideoDecoder.SMPTEVC1.ProfileLevel.{i}.
-Device.Services.STBService.{i}.Capabilities.VideoOutput.
-Device.Services.STBService.{i}.Components.
-Device.Services.STBService.{i}.Components.AudioDecoder.{i}.
-Device.Services.STBService.{i}.Components.AudioOutput.{i}.
-Device.Services.STBService.{i}.Components.DRM.{i}.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.Dejittering.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroup.{i}.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroupStats.{i}.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroupStats.{i}.CurrentDay
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroupStats.{i}.QuarterHour.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroupStats.{i}.Total
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroup.{i}.GroupAddress
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.IGMP.ClientGroupNumberOfEntries
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.Inbound.{i}.
-Device.Services.STBService.{i}.Components.FrontEnd.{i}.IP.Outbound.{i}.
-Device.Services.STBService.{i}.Components.FrontEndNumberOfEntries
-Device.Services.STBService.{i}.Components.HDMI.{i}.
-Device.Services.STBService.{i}.Components.HDMI.{i}.DisplayDevice
-Device.Services.STBService.{i}.Components.PVR.
-Device.Services.STBService.{i}.Components.PVR.Storage.{i}.
-Device.Services.STBService.{i}.Components.SPDIF.{i}.
-Device.Services.STBService.{i}.Components.VideoDecoder.{i}.
-Device.Services.STBService.{i}.Components.VideoOutput.{i}.
-Device.Services.STBService.{i}.ServiceMonitoring.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Sample.HighLevelMetricStats.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Sample.VideoResponseStats.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Total.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Total.AudioDecoderStats.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Total.DejitteringStats.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Total.MPEG2TSStats.
-Device.Services.STBService.{i}.ServiceMonitoring.MainStream.{i}.Total.VideoDecoderStats.
-Device.Services.STBServiceNumberOfEntries
-Device.Services.STBService{i}.Capabilities.
-Device.Services.StorageServices.{i}.
-Device.Services.StorageServices.{i}.LogicalVolume.{i}.
-Device.Services.StorageServices.{i}.LogicalVolume.{i}.Folder.{i}.
-Device.Services.StorageServices.{i}.LogicalVolume.{i}.Folder.{i}.Quota.
-Device.Services.StorageServices.{i}.PhysicalMedium.{i}.
-Device.Services.StorageServices.{i}.StorageArray.{i}.
-Device.Services.StorageServices.Capabilities.FTPCapable
-Device.Services.StorageServices.Capabilities.HTTPCapable
-Device.Services.StorageServices.Capabilities.HTTPSCapable
-Device.Services.StorageServices.Capabilities.HTTPWritable
-Device.Services.StorageServices.Capabilities.SFTPCapable
-Device.Services.StorageServices.Capabilities.SupportedFileSystemTypes
-Device.Services.StorageServices.Capabilities.SupportedNetworkProtocols
-Device.Services.StorageServices.Capabilities.SupportedRaidTypes
-Device.Services.StorageServices.Capabilities.VolumeEncryptionCapable
-Device.Services.StorageServices.Enable
-Device.Services.StorageServices.LogicalVolume.{i}.Capacity
-Device.Services.StorageServices.LogicalVolume.{i}.Enable
-Device.Services.StorageServices.LogicalVolume.{i}.FileSystem
-Device.Services.StorageServices.LogicalVolume.{i}.FolderNumberOfEntries
-Device.Services.StorageServices.LogicalVolume.{i}.Name
-Device.Services.StorageServices.LogicalVolume.{i}.Status
-Device.Services.StorageServices.LogicalVolume.{i}.ThresholdLimit
-Device.Services.StorageServices.LogicalVolume.{i}.UsedSpace
-Device.Services.StorageServices.LogicalVolume.{i}.X_CATAWAMPUS-ORG_ReadOnly
-Device.Services.StorageServices.LogicalVolumeNumberOfEntries
-Device.Services.StorageServices.PhysicalMedium.{i}.Capacity
-Device.Services.StorageServices.PhysicalMedium.{i}.ConnectionType
-Device.Services.StorageServices.PhysicalMedium.{i}.FirmwareVersion
-Device.Services.StorageServices.PhysicalMedium.{i}.Health
-Device.Services.StorageServices.PhysicalMedium.{i}.HotSwappable
-Device.Services.StorageServices.PhysicalMedium.{i}.Model
-Device.Services.StorageServices.PhysicalMedium.{i}.Name
-Device.Services.StorageServices.PhysicalMedium.{i}.Removable
-Device.Services.StorageServices.PhysicalMedium.{i}.SMARTCapable
-Device.Services.StorageServices.PhysicalMedium.{i}.SerialNumber
-Device.Services.StorageServices.PhysicalMedium.{i}.Vendor
-Device.Services.StorageServices.PhysicalMediumNumberOfEntries
-Device.Services.StorageServices.StorageArrayNumberOfEntries
-Device.Services.StorageServices.UserAccountNumberOfEntries
-Device.Services.StorageServices.UserGroupNumberOfEntries
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.BadEraseBlocks
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.CorrectedErrors
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.EraseBlockSize
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.IOSize
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.MaxEraseCount
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.Name
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.ReservedEraseBlocks
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.SubVolume.{i}.DataBytes
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.SubVolume.{i}.Name
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.SubVolume.{i}.Status
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.SubVolumeNumberOfEntries
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.TotalEraseBlocks
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMedia.{i}.UncorrectedErrors
-Device.Services.StorageServices.X_CATAWAMPUS-ORG_FlashMediaNumberOfEntries
-Device.USB.
-Device.USB.Interface.{i}.
-Device.USB.Interface.{i}.Stats.
-Device.USB.Port.{i}.
-Device.USB.USBHosts.
-Device.USB.USBHosts.Host.{i}.
-Device.USB.USBHosts.Host.{i}.Device.{i}.
-Device.USB.USBHosts.Host.{i}.Device.{i}.Configuration.{i}.
-Device.USB.USBHosts.Host.{i}.Device.{i}.Configuration.{i}.Interface.{i}.
-Device.WiFi
-Device.WiFi.AccessPoint.{i}.
-Device.WiFi.AccessPoint.{i}.Accounting.
-Device.WiFi.AccessPoint.{i}.AssociatedDevice.{i}.
-Device.WiFi.AccessPoint.{i}.Security.
-Device.WiFi.AccessPoint.{i}.WPS.
-Device.WiFi.EndPoint.{i}.
-Device.WiFi.EndPoint.{i}.Profile.{i}.
-Device.WiFi.EndPoint.{i}.Profile.{i}.Security.
-Device.WiFi.EndPoint.{i}.Profile.{i}.WPS.
-Device.WiFi.EndPoint.{i}.Security
-Device.WiFi.EndPoint.{i}.Stats
-Device.WiFi.Radio.{i}.
-Device.WiFi.Radio.{i}.Antenna.
-Device.WiFi.Radio.{i}.Stats.
-Device.WiFi.SSID.{i}.
-Device.WiFi.SSID.{i}.Stats.
-InternetGatewayDevice.
-InternetGatewayDevice.DeviceConfig.
-InternetGatewayDevice.DeviceInfo.
-InternetGatewayDevice.DeviceInfo.AdditionalHardwareVersion
-InternetGatewayDevice.DeviceInfo.AdditionalSoftwareVersion
-InternetGatewayDevice.DeviceInfo.Description
-InternetGatewayDevice.DeviceInfo.HardwareVersion
-InternetGatewayDevice.DeviceInfo.Manufacturer
-InternetGatewayDevice.DeviceInfo.ManufacturerOUI
-InternetGatewayDevice.DeviceInfo.ModelName
-InternetGatewayDevice.DeviceInfo.ModemFirmwareVersion
-InternetGatewayDevice.DeviceInfo.ProductClass
-InternetGatewayDevice.DeviceInfo.SerialNumber
-InternetGatewayDevice.DeviceInfo.SoftwareVersion
-InternetGatewayDevice.DeviceInfo.SpecVersion
-InternetGatewayDevice.DeviceInfo.UpTime
-InternetGatewayDevice.DeviceInfo.VendorConfigFile.{i}.
-InternetGatewayDevice.DeviceInfo.VendorConfigFileNumberOfEntries
-InternetGatewayDevice.IPPingDiagnostics.
-InternetGatewayDevice.LANConfigSecurity.
-InternetGatewayDevice.LANDevice.{i}.
-InternetGatewayDevice.LANDevice.{i}.Hosts.
-InternetGatewayDevice.LANDevice.{i}.Hosts.Host.{i}.
-InternetGatewayDevice.LANDevice.{i}.LANEthernetInterfaceConfig.{i}.
-InternetGatewayDevice.LANDevice.{i}.LANEthernetInterfaceConfig.{i}.Stats.
-InternetGatewayDevice.LANDevice.{i}.LANEthernetInterfaceNumberOfEntries
-InternetGatewayDevice.LANDevice.{i}.LANHostConfigManagement.
-InternetGatewayDevice.LANDevice.{i}.LANHostConfigManagement.IPInterface.{i}.
-InternetGatewayDevice.LANDevice.{i}.LANUSBInterfaceConfig.{i}.
-InternetGatewayDevice.LANDevice.{i}.LANUSBInterfaceConfig.{i}.Stats.
-InternetGatewayDevice.LANDevice.{i}.LANUSBInterfaceNumberOfEntries
-InternetGatewayDevice.LANDevice.{i}.LANWLANConfigurationNumberOfEntries
-InternetGatewayDevice.LANDevice.{i}.WLANConfiguration.{i}.
-InternetGatewayDevice.LANDevice.{i}.WLANConfiguration.{i}.AssociatedDevice.{i}.
-InternetGatewayDevice.LANDevice.{i}.WLANConfiguration.{i}.PreSharedKey.{i}.
-InternetGatewayDevice.LANDevice.{i}.WLANConfiguration.{i}.WEPKey.{i}.
-InternetGatewayDevice.LANDeviceNumberOfEntries
-InternetGatewayDevice.Layer2Bridging.
-InternetGatewayDevice.Layer2Bridging.AvailableInterface.{i}.
-InternetGatewayDevice.Layer2Bridging.Bridge.{i}.
-InternetGatewayDevice.Layer2Bridging.Filter.{i}.
-InternetGatewayDevice.Layer2Bridging.Marking.{i}.
-InternetGatewayDevice.Layer3Forwarding.
-InternetGatewayDevice.Layer3Forwarding.Forwarding.{i}.
-InternetGatewayDevice.ManagementServer.
-InternetGatewayDevice.ManagementServer.ConnectionRequestPassword
-InternetGatewayDevice.ManagementServer.ConnectionRequestURL
-InternetGatewayDevice.ManagementServer.ConnectionRequestUsername
-InternetGatewayDevice.ManagementServer.DefaultActiveNotificationThrottle
-InternetGatewayDevice.ManagementServer.EnableCWMP
-InternetGatewayDevice.ManagementServer.ManageableDevice.{i}.
-InternetGatewayDevice.ManagementServer.ParameterKey
-InternetGatewayDevice.ManagementServer.Password
-InternetGatewayDevice.ManagementServer.PeriodicInformEnable
-InternetGatewayDevice.ManagementServer.PeriodicInformInterval
-InternetGatewayDevice.ManagementServer.PeriodicInformTime
-InternetGatewayDevice.ManagementServer.URL
-InternetGatewayDevice.ManagementServer.UpgradesManaged
-InternetGatewayDevice.ManagementServer.Username
-InternetGatewayDevice.PeriodicStatistics.MaxReportSamples
-InternetGatewayDevice.PeriodicStatistics.MinSampleInterval
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Enable
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.FetchSamples
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Name
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.CalculationMode
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Enable
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Failures
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.HighThreshold
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.LowThreshold
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Reference
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SampleMode
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SampleSeconds
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.SuspectData
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Parameter.{i}.Values
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.ParameterNumberOfEntries
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.ReportEndTime
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.ReportSamples
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.ReportStartTime
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.SampleInterval
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.SampleSeconds
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.Status
-InternetGatewayDevice.PeriodicStatistics.SampleSet.{i}.TimeReference
-InternetGatewayDevice.PeriodicStatistics.SampleSetNumberOfEntries
-InternetGatewayDevice.QueueManagement.
-InternetGatewayDevice.QueueManagement.App.{i}.
-InternetGatewayDevice.QueueManagement.Classification.{i}.
-InternetGatewayDevice.QueueManagement.Flow.{i}.
-InternetGatewayDevice.QueueManagement.Policer.{i}.
-InternetGatewayDevice.QueueManagement.Queue.{i}.
-InternetGatewayDevice.Services.
-InternetGatewayDevice.Time.
-InternetGatewayDevice.Time.CurrentLocalTime
-InternetGatewayDevice.Time.Enable
-InternetGatewayDevice.Time.LocalTimeZoneName
-InternetGatewayDevice.UserInterface.
-InternetGatewayDevice.WANDevice.{i}.
-InternetGatewayDevice.WANDevice.{i}.WAN-CommonInterfaceConfig.WANAccessType
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.Enable
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.LowerOpticalThreshold
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.LowerTransmitPowerThreshold
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.OpticalSignalLevel
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.Status
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.TransmitOpticalLevel
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.UpperOpticalThreshold
-InternetGatewayDevice.WANDevice.{i}.WAN-OpticalInterfaceConfig.UpperTransmitPowerThreshold
-InternetGatewayDevice.WANDevice.{i}.WANCommonInterfaceConfig.
-InternetGatewayDevice.WANDevice.{i}.WANCommonInterfaceConfig.Connection.{i}.
-InternetGatewayDevice.WANDevice.{i}.WANConnectionDevice.{i}.
-InternetGatewayDevice.WANDevice.{i}.WANConnectionDevice.{i}.WANEthernetLinkConfig.
-InternetGatewayDevice.WANDevice.{i}.WANConnectionDevice.{i}.WANIPConnection.{i}.
-InternetGatewayDevice.WANDevice.{i}.WANConnectionDevice.{i}.WANIPConnection.{i}.PortMapping.{i}.
-InternetGatewayDevice.WANDevice.{i}.WANConnectionDevice.{i}.WANIPConnection.{i}.Stats.
-InternetGatewayDevice.WANDevice.{i}.WANEthernetInterfaceConfig.
-InternetGatewayDevice.WANDevice.{i}.WANEthernetInterfaceConfig.Stats.
-InternetGatewayDevice.WANDeviceNumberOfEntries
-TraceRoute.
-TraceRoute.DSCP
-TraceRoute.DataBlockSize
-TraceRoute.DiagnosticsState
-TraceRoute.Host
-TraceRoute.Interface
-TraceRoute.MaxHopCount
-TraceRoute.NumberOfTries
-TraceRoute.ResponseTime
-TraceRoute.RouteHopsNumberOfEntries
-TraceRoute.Timeout
-VoiceService.{i}.
-VoiceService.{i}.Capabilities.
-VoiceService.{i}.Capabilities.Codecs.{i}.
-VoiceService.{i}.Capabilities.SIP.
-VoiceService.{i}.PhyInterface.{i}.
-VoiceService.{i}.PhyInterface.{i}.Tests.
-VoiceService.{i}.VoiceProfile.{i}.
-VoiceService.{i}.VoiceProfile.{i}.ButtonMap.
-VoiceService.{i}.VoiceProfile.{i}.ButtonMap.Button.{i}.
-VoiceService.{i}.VoiceProfile.{i}.FaxT38.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.CallingFeatures.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Codec.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Codec.List.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Ringer.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Ringer.Description.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Ringer.Event.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Ringer.Pattern.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.SIP.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.SIP.EventSubscribe.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Session.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.Stats.
-VoiceService.{i}.VoiceProfile.{i}.Line.{i}.VoiceProcessing.
-VoiceService.{i}.VoiceProfile.{i}.NumberingPlan.
-VoiceService.{i}.VoiceProfile.{i}.NumberingPlan.PrefixInfo.{i}.
-VoiceService.{i}.VoiceProfile.{i}.RTP.
-VoiceService.{i}.VoiceProfile.{i}.RTP.RTCP.
-VoiceService.{i}.VoiceProfile.{i}.SIP.
-VoiceService.{i}.VoiceProfile.{i}.SIP.EventSubscribe.{i}.
-VoiceService.{i}.VoiceProfile.{i}.SIP.ResponseMap.{i}.
-VoiceService.{i}.VoiceProfile.{i}.ServiceProviderInfo.
-VoiceService.{i}.VoiceProfile.{i}.Tone.
-VoiceService.{i}.VoiceProfile.{i}.Tone.Description.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Tone.Event.{i}.
-VoiceService.{i}.VoiceProfile.{i}.Tone.Pattern.{i}.
-X_CATAWAMPUS-ORG_CATAWAMPUS.
-X_CATAWAMPUS-ORG_CATAWAMPUS.RuntimeEnvInfo
-X_GOOGLE-COM_GFIBERTV.
-X_GOOGLE-COM_GFIBERTV.Mailbox.Name
-X_GOOGLE-COM_GFIBERTV.Mailbox.Node
-X_GOOGLE-COM_GFIBERTV.Mailbox.NodeList
-X_GOOGLE-COM_GFIBERTV.Mailbox.Value
-X_GOOGLE-COM_GVSB.
-X_GOOGLE-COM_GVSB.EpgPrimary
-X_GOOGLE-COM_GVSB.EpgSecondary
-X_GOOGLE-COM_GVSB.GvsbChannelLineup
-X_GOOGLE-COM_GVSB.GvsbKick
-X_GOOGLE-COM_GVSB.GvsbServer
diff --git a/dataModel.py b/dataModel.py
index 73adf5e..af45a0b 100755
--- a/dataModel.py
+++ b/dataModel.py
@@ -17,6 +17,29 @@
        - Data Models for MoCA
        - Data Models for TR140
        - Data Models for TR181
+  5. This file includes the following test cases:
+       (all data models test case are pending on bug: http://b/issue?id=6813492
+        SetParameterValues does not work currently)
+       - testID: 14165033  7.6.13 Support of Data Models for GVSB (TBD)
+       - testID: 14315008  7.6.14 Support of Data Models for TR098
+       - testID: 14165035  7.6.15 Support of Data Models for MoCA
+       - testID: 14187024  7.6.16 Support of Data Models for TR140
+       - testID: 14314007  7.6.17 Support of Data Models for TR181
+       - testID: 11865133  7.6.9.1 Support of Data Models: TR135
+       - testID: 14335001  7.6.31 Implement X_CATAWAMPUS-ORG parameters
+       - testID: 14319149  7.6.29 Implement X_GOOGLE-COM data model for Sage
+                                  information
+       - testID: 14314008  7.6.30 Implement tr-157 PeriodicStatistics
+
+       - testID: 14315009  7.6.20 Support of modification of
+                                  InternetGatewayDevice.ManagementServer.URL
+       - testID: 14314009  7.6.35 Monitor temperature
+       - testID: 14266498  7.6.36 X_CATAWAMPUS-ORG_FlashDevice Storage data
+                                  model (for tracking flash wear)
+       - testID: 14165038  7.6.37 Implement AutoChannelEnable in catawampus
+       - testID: 11722375  7.6.6  TR069 - SetParameter RPC Request
+       - testID: 15643845  7.6.39 NTP-Time zone configuration
+       - testID: 14165034  7.6.14.1 WiFi Test: ACS configuration
 """
 
 __author__ = 'Lehan Meng (lmeng@google.com)'
@@ -49,21 +72,18 @@
     info = self.log.CreateResultInfo(
         '---', 'Data model verification test started...')
     self.log.SendLine(self.test_info, info)
-
     self.bruno = device.Bruno(user=self.params['user'],
                               addr=self.params['addr'],
                               pwd=self.params['pwd'],
                               cmd_prompt=self.params['bruno_prompt'])
-    self.p_ssh = ssh.SSH(user=self.params['user'],
-                         addr=self.params['addr'],
-                         pwd=self.params['pwd'],
-                         bruno_prompt=self.params['bruno_prompt'],
-                         addr_ipv6=self.params['addr_ipv6'],
-                         athena_user=self.params['athena_user'],
-                         athena_pwd=self.params['athena_pwd'],
-                         jump_server=self.params['jump_server'])
-    self.p_ssh.Setlogging(self.log)
-    self.bruno.Setlogging(self.log)
+    if not self.p_ssh:
+      self.p_ssh = ssh.SSH(user=self.params['user'],
+                           addr=self.params['addr'],
+                           pwd=self.params['pwd'],
+                           bruno_prompt=self.params['bruno_prompt'],
+                           addr_ipv6=self.params['addr_ipv6'])
+    self.p_ssh.SetLogging(self.log)
+    self.bruno.SetLogging(self.log)
     self.bruno.dev_ssh = self.p_ssh
 
     self.__short_delay = 30  #short delay: 5 seconds
@@ -72,13 +92,53 @@
 
     self.req_file = open(self.params['req_file'], 'r')
     self.req_tr069_params = []
+    self.acs_instance = acs.ACS()
+    self.acs_instance.SetLogging(self.log)
+
+  def SetACSURL(self, url=None):
+    """Set the ACS URL on device."""
+    if not url:
+      url = self.params['acs_url']
+    self.p_ssh.SendCmd('echo '+ url + ' > /tmp/cwmp/acs_url')
+    self.p_ssh.GetCmdOutput()[1].rstrip()
+
+  def GetACSURL(self):
+    """Get ACS URL from Device."""
+    self.p_ssh.SendCmd(r'cat /tmp/cwmp/acs_url')
+    line = self.p_ssh.GetCmdOutput()[1].strip()
+    m = re.match('http[s]?://([\w-]+\.)+\.com/cwmp', line)
+    if m is None:
+      info = self.log.CreateErrorInfo('Warning',
+                                      'Can not get ACS url')
+      self.log.SendLine(None, info)
+    else:
+      info = self.log.CreateProgressInfo('---',
+                                         'Get ACS URL from device file: '
+                                         + line)
+      self.log.SendLine(None, info)
+    return line
+
+  def GetCurrentVersion(self):
+    """Get current software version."""
+    self.p_ssh.SendCmd('more /etc/version')
+    return self.p_ssh.GetCmdOutput()[1].strip()
 
   def TestEnvCheck(self):
     """Verify device configuration meets the test requirement."""
-    acs_url = self.bruno.GetACSUrl()
-    self.AddConfigParams('acs_url', acs_url)
+    acs_url = self.GetACSURL()
+    if acs_url != self.params['acs_url']:
+      info = self.log.CreateErrorInfo(
+          'Warning', 'ACS URL incorrect!. Expected: '
+          + self.params['acs_url'] + ', Current: '
+          + acs_url)
+      self.log.SendLine(self.test_info, info)
+      #os.sys.exit(1)
+      info = self.log.CreateProgressInfo(
+          '---', 'Reset ACS URL to Expected: ' + self.params['acs_url'])
+      self.log.SendLine(self.test_info, info)
+      self.SetACSURL()
 
-    current_version = self.bruno.getCurrentVersion()
+    current_version = self.GetCurrentVersion()
     if (not current_version
         or current_version != self.params['expected_version']):
       info = self.log.CreateErrorInfo(
@@ -122,28 +182,234 @@
         new_list.append(line)
     return (missing_list, new_list)
 
-  def SetParameterValues(self, param='', value=''):
-    """Set parameter values on Device."""
+  def GetACSAppFromURL(self):
+    """Parse ACS appID from ACS URL string."""
+    return re.sub(r'https?://(.*).appspot.com/cwmp', r'\1',
+                  self.params['acs_url'])
+
+  def GetSerialNumber(self):
+    """This function returns Bruno device serial number."""
+    self.p_ssh.SendCmd('hnvram -r 1st_serial_number')
+    line = self.p_ssh.GetCmdOutput()[1].strip()
+    if line is None:
+      info = self.log.CreateErrorInfo('Warning',
+                                      'Can not get serial number')
+      self.log.SendLine(None, info)
+      return False
+    return re.sub(r'1st_serial_number=([0-9A-Z]{12})', r'\1', line)
+
+  def GetProductClass(self):
+    """Get product class from device system."""
+    self.p_ssh.SendCmd('cat /etc/platform')
+    return self.p_ssh.GetCmdOutput()[1].strip()
+
+  def BatchSetParametersValues(self, tree, param):
+    """Set multiple parameter values in a single nbi_client RPC call.
+
+    Set multiple parameter values
+    Args:
+      tree: the parameter names are in TreeElement structure. It has
+            parameter 'writable' states and test_value to set.
+            Parameter names/paths are sorted in alphabetical order in tree.
+      param: the parameters name list that needs to be set with new value
+    """
     nbi_path = self.params['nbi_client_path']
+    app_id = self.GetACSAppFromURL()
+    product_class = self.GetProductClass()
+    serial_no = self.GetSerialNumber()
+
+    container = tree.findall('parameter_value_struct')
+    batch_size = 1
+    counter = 0
+    parameter_struct = ''
+
+    for node in container:
+      name = node.findtext('name')
+
+      if name in param:
+        nbi_type = node.findtext('nbi_type')
+
+        if not nbi_type:
+          info = self.log.CreateErrorInfo('Warning',
+                                          'Can not determin parameter type!')
+          self.log.SendLine(None, info)
+
+        test_value = node.findtext('test_value')
+        if nbi_type == 'string_value':
+          test_value = '"' + test_value + '"'
+        if (node.findtext('writable') == '1'
+            or node.findtext('writable') == 'true'):
+          parameter_struct += ('parameter_value_struct: <name: "'
+                               + name + '" ' + nbi_type + ': '
+                               + test_value + '> ')
+          counter += 1
+        else:
+          continue
+
+        if counter >= batch_size:
+          counter = 0
+          cmd = (nbi_path
+                 + ' --server /gns/project/apphosting/stubby/prod-appengine/'
+                 '*/' + app_id + '/default/* --service CpeParametersService '
+                 '--method SetParameterValues --request \''
+                 'cpe_id: <oui: "F88FCA" product_class: "' + product_class
+                 + '" serial_no: "' + serial_no
+                 + '"> request: <parameter_list < '
+                 + parameter_struct + ' > parameter_key: "myParamKey">\'')
+          print cmd
+          parameter_struct = ''
+          time_stamp = self.GetTimeStamp()
+          call_result = self.acs_instance.StubbyClientCall(cmd)
+          print call_result
+          if not self.acs_instance.CheckCmdCall(call_result):
+            # command not succeed according to nbi_client reply
+            # However, there is possibility that the request is successful,
+            # nbi_client reports a failure only because the timeout 60s.
+            # check device log to see if this request actually fails
+            self.p_ssh.SendCmd('dmesg | grep cwmpd:')
+            # read the last 500 lines from log
+            log_list = self.p_ssh.GetCmdOutput(500)
+            log_list.reverse()
+            reply_msg = self.ParseDeviceLogForError(
+                time_stamp, log_list, name, 'SetParameterValues')
+            if '<soap:Fault>' in reply_msg[0] or '<soap:fault>' in reply_msg[0]:
+              # failed to set parameter values (on nbi_client and device):
+              info = self.log.CreateErrorInfo(
+                  'Critical', 'Batch SetParameterValues() failed on Parameter: '
+                  + name + '. Parameter type: ' + nbi_type
+                  + '. Set test value: ' + test_value + '. Error message: \n'
+                  + ''.join(reply_msg))
+              self.log.SendLines(self.test_info, info)
+            elif '<cwmp:SetParameterValuesResponse>' in reply_msg[0]:
+              # nbi_reports failure, but success on device
+              info = self.log.CreateResultInfo(
+                  '---', 'Batch SetParameterValues() Succeeded on Parameter: '
+                  + name + '. Parameter type: ' + nbi_type
+                  + '. Set test value: ' + test_value)
+              self.log.SendLine(self.test_info, info)
+            else:
+              info = self.log.CreateErrorInfo(
+                  'Critical', 'Batch SetParameterValues() failed on Parameter: '
+                  + name + '. Parameter type: ' + nbi_type
+                  + '. Set test value: ' + test_value + '. Error message: \n'
+                  + ''.join(reply_msg))
+              self.log.SendLines(self.test_info, info)
+          else:
+            # Succeed, logging to result file:
+            self.log.SendTestData(call_result)
+            info = self.log.CreateResultInfo(
+                '---', 'Batch SetParameterValues() Succeeded on Parameter: '
+                + name + '. Parameter type: ' + nbi_type
+                + '. Set test value: ' + test_value)
+            self.log.SendLine(self.test_info, info)
+
+  def SetParameterValues(self, param='', param_type='', value=''):
+    """Set parameter values on Device.
+
+    Set parameter values
+    Args:
+      param: the parameter name that needs to be set with new value
+      param_type: type of value: string, boolean, long_int, etc
+      value: parameter value
+    Returns:
+      return setParameterValues if succeeded.
+      return error information if failed
+    """
+    nbi_path = self.params['nbi_client_path']
+    app_id = self.GetACSAppFromURL()
+    product_class = self.GetProductClass()
+    serial_no = self.GetSerialNumber()
+    # parse type:
+    if 'string' in param_type:
+      param_type = 'string_value'
+      value = '"' + value + '"'
+    elif 'bool' in param_type:
+      param_type = 'boolean_value'
+    elif 'unsignedInt' in param_type:
+      param_type = 'long_value'
+    else:
+      info = self.log.CreateErrorInfo(
+          'Critical', 'Unknown parameter type: ' + param_type)
+      self.log.SendLines(self.test_info, info)
+      os.sys.exit(1)
+
     cmd = (nbi_path + ' --server /gns/project/apphosting/stubby/prod-appengine/'
-           '*/gfiber-acs-staging/default/* --service CpeParametersService '
+           '*/' + app_id + '/default/* --service CpeParametersService '
            '--method SetParameterValues --request \''
-           'cpe_id: <oui: "F88FCA" product_class: "GFMS100" serial_no: '
-           '"110120906BDE"> request: <parameter_list < '
-           'parameter_value_struct: <name: "'
-           + param +
-           '" string_value: "' + value + '"> > parameter_key: "myParamKey">\'')
-    acs_instance = acs.ACS()
-    acs_instance.SetLogging(self.log)
-    call_result = acs_instance.StubbyClientCall(cmd)
+           'cpe_id: <oui: "F88FCA" product_class: "' + product_class
+           + '" serial_no: "' + serial_no + '"> request: <parameter_list < '
+           'parameter_value_struct: <name: "' + param +
+           '" ' + param_type + ': ' + value
+           + '> > parameter_key: "myParamKey">\'')
+    print cmd
+    call_result = self.acs_instance.StubbyClientCall(cmd)
+    if 'FAILED' in call_result[0]:
+      info = self.log.CreateErrorInfo(
+          'Warning', 'ACS failed on SetParameterValues query: ' + cmd)
+      self.log.SendLines(self.test_info, info)
+      return False
+    else:
+      print call_result
+    return call_result
+
+  def GetParameterNames(self, param='.', next_level=True):
+    """Get next level parameter names of the current queried parameter.
+
+    The next level parameter names will be output to result file
+    Due to the large number of parameter instances, parameters in the same
+    parameter family will be grouped together into a single nbi_client
+    RPC call (getParameterNames() call, this call will feedback the access
+    state information). In order to minimize the total processing time, as
+    well as the number of RPC calls to ACS appEngine. This will greatly
+    reduce the execution time.
+    Each getParameterNames call will be created as an individual thread.
+    And multiple calls are made in parallel.
+
+    Args:
+      param:
+        This is the parameter that is queried for its next level names
+        Note that currently GetParameterNames does not support multiple
+        parameter names in a query command. If parameter name is a dot,
+        and the next level is 'False', then device will return all
+        parameters under the queried parameter path
+      next_level:
+        if this parameter is True:
+          only the next level parameter names are returned
+        if this parameter is False:
+          all parameter in the requested parameter path will be returned
+    Returns:
+      return the nbi_client RPC call response. Response can be used to
+      parse for parameters' name, access attribute, etc.
+    """
+    nbi_path = self.params['nbi_client_path']
+    app_id = self.GetACSAppFromURL()
+    product_class = self.GetProductClass()
+    serial_no = self.GetSerialNumber()
+    if next_level:
+      next_level = 'true'
+    else:
+      next_level = 'false'
+    cmd = (nbi_path + ' --server /gns/project/apphosting/stubby/prod-appengine/'
+           '*/' + app_id + '/default/* --service CpeParametersService '
+           '--method GetParameterNames --request \''
+           'cpe_id: <oui: "F88FCA" product_class: "' + product_class
+           + '" serial_no: "' + serial_no + '"> request: <parameter_path: "'
+           + param + '" next_level: ' + next_level + '>\'')
+    print cmd
+    call_result = self.acs_instance.StubbyClientCall(cmd)
     if 'FAILED' in call_result[0]:
       self.nbi_result = []
+      info = self.log.CreateErrorInfo(
+          'Warning', 'ACS failed on GetParameterNames query: ' + cmd)
+      self.log.SendLines(self.test_info, info)
+      return False
     else:
       self.nbi_result = call_result
     print call_result
+    return call_result
 
   def GetParameterValues(self, param=''):
-    """Get parameter value(s) from the data model tree.
+    """Make a Get parameter value(s) query at ACS to request the device.
 
     This method get value(s) of the designated parameter(s)
     Args:
@@ -156,28 +422,176 @@
       This method returns a list of parameter values and record them to file.
     """
     nbi_path = self.params['nbi_client_path']
+    if param == '.':
+      param = ''
+    app_id = self.GetACSAppFromURL()
+    product_class = self.GetProductClass()
+    serial_no = self.GetSerialNumber()
     cmd = (nbi_path + ' --server /gns/project/apphosting/stubby/prod-appengine/'
-           '*/gfiber-acs-staging/default/* --service CpeParametersService '
+           '*/' + app_id + '/default/* --service CpeParametersService '
            '--method GetParameterValues --request \''
-           'cpe_id: <oui: "F88FCA" product_class: "GFMS100" serial_no: '
-           '"110120906BDE"> request: <parameter_names: "' +param + '">\'')
-    acs_instance = acs.ACS()
-    acs_instance.SetLogging(self.log)
-    call_result = acs_instance.StubbyClientCall(cmd)
+           'cpe_id: <oui: "F88FCA" product_class: "' + product_class
+           + '" serial_no: "' + serial_no + '"> request: <parameter_names: "'
+           +param + '">\'')
+
+    print cmd
+    call_result = self.acs_instance.StubbyClientCall(cmd)
     if 'FAILED' in call_result[0]:
       self.nbi_result = []
+      info = self.log.CreateErrorInfo(
+          'Warning', 'ACS failed on GetParameterValues query: ' + cmd)
+      self.log.SendLines(self.test_info, info)
+      return False
     else:
       self.nbi_result = call_result
     print call_result
-    return acs_instance.ParseParameterNames(call_result)
+    return call_result
 
-  def GetParameterNamesFromDeviceLog(self, time_stamp, param=''):
-    """Get TR069 data model parameters that are supported by current image."""
+  def FindEndofRequest(self, log_list, index, pattern):
+    """Find the end of a request string from device log.
+
+    Some times the close tag, for example: </cwmp:SetParameterValues> is
+    separated to two consecutive log lines, due to the line length limitation.
+    This method try to search the request closing tag on separate lines
+
+    Args:
+      log_list: the device log list.
+      index: the index of the line to search for tag
+      pattern: the closing tag that need to be searched in log file
+    Returns:
+      True: if pattern find in log
+      False: if pattern not find in log
+    """
+    if index >= len(log_list)-1:
+      if pattern in log_list[index]:
+        return True
+      else:
+        return False
+
+    s = re.sub(r'\[\s*\d*\.\d*\]\s*cwmpd:\s*(.*)', r'\1', log_list[index + 1])
+    s = log_list[index].strip() + s.strip()
+
+    if pattern in s:
+      return True
+    return False
+
+  def MatchParameterName(self, line, param_name, rpc):
+    """Match rpc request logs to a parameter name."""
+    if rpc == 'GetParameterNames':
+      m = re.search(r'.*<ParameterPath>(.*)</ParameterPath>.*', line)
+      if m is not None and param_name in m.group(1):
+        return True
+      else:
+        return False
+    elif rpc == 'GetParameterValues':
+      m = re.search(r'.*<cwmp:GetParameterValues>.*<ParameterNames.*>(.*)'
+                    '</ParameterNames></cwmp:GetParameterValues>.*', line)
+      if m is not None and param_name in m.group(1):
+        return True
+      else:
+        return False
+    elif rpc == 'SetParameterValues':
+      m = re.search(r'.*<Name>(.*)</Name><Value.*', line)
+      if m is not None and param_name in m.group(1):
+        return True
+      else:
+        return False
+    else:
+      return False
+
+  def ParseDeviceLogForError(self, time_stamp, log_list, param, rpc):
+    """Parse the log information from device, Looking for cwmp errors.
+
+    Args:
+      time_stamp: looking for log events that happened only after this time
+      log_list: the cwmp event information obtained from device log
+      param: the parameter name to get value from
+      rpc: the rpc function name to search in log
+    Returns:
+      return cwmp error message found in device log.
+    """
+
+    reply_msg = []
+    start_of_rpc_reply = False
+    end_of_rpc_reply = False
+    start_of_rpc_request = False
+    end_of_rpc_request = False
+    param_matching = False
+    current_index = 0
+
+    for line in log_list:
+      # check only the getParameter query starts after the specified time:
+      if float(self.GetTimeStamp(line)) > float(time_stamp):
+        if 'CPE RECEIVED (at' in line and not start_of_rpc_request:
+          index = log_list.index(line)
+          # macthing the request query in log messages
+          for i in range(index+1, len(log_list)-1):
+            if i < len(log_list):
+              # match rpc request string
+              if '<cwmp:' + rpc + '>' in log_list[i]:
+                start_of_rpc_request = True
+              # match rpc request string end
+              if (self.FindEndofRequest(log_list, i, '</cwmp:' + rpc + '>')
+                  and start_of_rpc_request):
+                if (start_of_rpc_request and end_of_rpc_request
+                    and not param in log_list[i]):
+                  end_of_rpc_request = True
+                  # rpc request scan completed, requested parameter not matched
+                  # this request is not request of interest
+                  start_of_rpc_request = False
+                  end_of_rpc_request = False
+                  break
+              # match queried parameter in rpc request
+              if start_of_rpc_request and not end_of_rpc_request:
+                if self.MatchParameterName(log_list[i], param, rpc):
+                  param_matching = True
+                  current_index = i
+                  break
+
+        # search for end of rpc request command
+        if param_matching and not end_of_rpc_request:
+          for i in range(current_index, len(log_list)-1):
+            if i < len(log_list):
+              # match rpc request string end
+              if self.FindEndofRequest(log_list, i, '</cwmp:' + rpc + '>'):
+                end_of_rpc_request = True
+                current_index = i
+                break
+
+        # search for rpc request reply message
+        if param_matching and end_of_rpc_request:
+          for i in range(current_index, len(log_list)-1):
+            if i < len(log_list):
+              if ('<soap:Fault>' in log_list[i] or '<soap:fault>' in log_list[i]
+                  or '<cwmp:' + rpc + 'Response>' in log_list[i]):
+                start_of_rpc_reply = True
+              if (' </soap:Fault>' in log_list[i]
+                  or ' </soap:fault>' in log_list[i]
+                  or '</cwmp:' + rpc + 'Response>' in log_list[i]):
+                end_of_rpc_reply = True
+                reply_msg.append(log_list[i].strip()+'\n')
+              if start_of_rpc_reply and not end_of_rpc_reply:
+                reply_msg.append(log_list[i].strip()+'\n')
+              if start_of_rpc_reply and end_of_rpc_reply:
+                return reply_msg
+    return ['No rpc message is available in device log']
+
+  def GetParameterListFromDeviceLog(self, time_stamp, param=''):
+    """Parse TR069 data model parameters from Device log information.
+
+    Args:
+      time_stamp: looking for log events that happened only after this time
+      param: the cwmp parameter to search in device log
+    Returns:
+      return parameter list if succeeded
+      return false otherwise
+    """
+    if param == '.':
+      param = ''
     param_list = []
     param_list_start = False
     param_list_end = False
     self.device_log_result = []
-    num_of_params = 0
 
     self.p_ssh.SendCmd('dmesg | grep cwmpd:')
     log_list = self.p_ssh.GetCmdOutput()
@@ -188,15 +602,15 @@
       if float(self.GetTimeStamp(line)) > float(time_stamp):
         if '<cwmp:GetParameterValues>' in line:
           # check the parameter query from nbi_client has been answered:
-          m = re.search(r'.*<cwmp:GetParameterValues>.*<ParameterNames.*/>(.*)'
+          m = re.search(r'.*<cwmp:GetParameterValues>.*<ParameterNames.*>(.*)'
                         '</ParameterNames></cwmp:GetParameterValues>.*', line)
-          if m is not None:
-            output = re.sub(r'.*<cwmp:GetParameterValues>.*<ParameterNames.*/>'
-                            '(.*)</ParameterNames></cwmp:GetParameterValues>.*',
-                            r'\1', line)
-            if output.strip() == param:
-              param_list_start = True
-              continue
+          if m is not None and param in m.group(1):
+            index = log_list.index(line)
+            for i in range(index+1, index+50):
+              if '<cwmp:GetParameterValuesResponse>' in log_list[i]:
+                param_list_start = True
+                break
+            continue
 
       if '</cwmp:GetParameterValuesResponse>' in line:
         if param_list_start:
@@ -206,7 +620,6 @@
       if param_list_start:
         self.device_log_result.append(line.strip())
         if '<Name>' in line:
-          num_of_params += 1
           output = re.sub(r'.*(<Name>)(.*)(</Name>)', r'\2', line)
           output = output.strip()
           output = re.sub(r'(\.)[\d]+(\.)', r'\1{i}\2', output)
@@ -214,16 +627,31 @@
             param_list.append(output)
 
     if (not param_list_start) or (not param_list_end):
-      return False
+      error_msg = self.ParseDeviceLogForError(
+          time_stamp, log_list, param, 'GetParameterValues')
+      if 'fault' in error_msg[0] or 'Fault' in error_msg[0]:
+        # error occurred in rpc request
+        info = self.log.CreateErrorInfo(
+          'Critical', 'Exit! Error while get values: ' + ''.join(error_msg))
+        self.log.SendLines(self.test_info, info)
+        os.sys.exit(1)
+      else:
+        # no error in request, request still in progress
+        return False
     return param_list
 
-  def CreateElement(self, param_name, param_type, param_value):
+  def CreateElement(self, param_name, param_type_device,
+                    param_type_nbi, param_value):
     """Create a new parameter node that contains parameter name and value.
 
-    Currently try to set the same value as being read from the device
+    Currently try to set the same value as being read from the device.
+    Parameter type may have different representations on different platforms.
+    E.g.: type 'long_value' on nbi_client is 'unsignedInt' on bruno.
+          type 'string_value' on nbi_client is 'string' on bruno
     Args:
       param_name: the name of the parameter (Path)
-      param_type: the type of the parameter
+      param_type_device: the type of the parameter represented by device format
+      param_type_nbi: the type of parameter, represented by nbi_client format
       param_value: the value of the parameter
     Returns:
       return the created element node
@@ -232,33 +660,78 @@
     name = ET.Element('name')
     name.text = param_name
     e.append(name)
-    value = ET.Element('value', type=param_type)
+    device_type = ET.Element('device_type')
+    device_type.text = param_type_device
+    e.append(device_type)
+    nbi_type = ET.Element('nbi_type')
+    if not param_type_nbi:
+      if param_type_device == 'unsignedInt':
+        param_type_nbi = 'long_value'
+      elif param_type_device == 'boolean':
+        param_type_nbi = 'boolean_value'
+      elif param_type_device == 'string':
+        param_type_nbi = 'string_value'
+      else:
+        info = self.log.CreateErrorInfo(
+            'Critical', 'Exit! Unknown (new) Parameter types found from device:'
+            ': ' + param_type_device + '. Define as string_value')
+        self.log.SendLine(self.test_info, info)
+        param_type_nbi = 'string_value'
+    nbi_type.text = param_type_nbi
+    e.append(nbi_type)
+    value = ET.Element('value')
     value.text = param_value
     e.append(value)
-    test_value = ET.Element('test_value', type=param_type)
+    test_value = ET.Element('test_value')
     test_value.text = param_value
     e.append(test_value)
+    access_state = ET.Element('writable')
+    access_state.text = 'true'
+    e.append(access_state)
     return e
 
+  def SortElementTree(self, tree):
+    """Sort the parameters in element tree, in alphabetical order of names.
+
+    Args:
+      tree: the ElementTree data structure that holds the parameter list
+    Returns:
+      return the sorted tree data structure
+    """
+    data = []
+    container = tree.findall('parameter_value_struct')
+    for node in container:
+      key = node.findtext('name')
+      data.append((key, node))
+
+    root = ET.Element(tree.getroot().tag, tree.getroot().attrib)
+    root.text = tree.getroot().text
+    data.sort()
+    for node in data:
+      root.append(node[1])
+    return ET.ElementTree(root)
+
   def ParseToElementTree(self):
     """Parse the parameter list to Element Tree structure."""
     root = ET.Element('Bruno_Automation_Test', name='Set_Parameter_Value_Test',
                       testCases=self.test_info['testID'])
     root.text = 'This structure stores all parameters and values for this test'
 
-    if self.nbi_result != []:
+    if self.nbi_result:
       for line in self.nbi_result:
         if 'name:' in line:
           param_name = re.sub('.*\"(.*)\".*', r'\1', line).strip()
           index = self.nbi_result.index(line)
           param_type = self.nbi_result[index+1].split(':')[0].strip()
           param_value = self.nbi_result[index+1].split(':')[1].strip()
-          root.append(self.CreateElement(param_name, param_type, param_value))
-    elif self.device_log_result != []:
+          root.append(self.CreateElement(param_name, None,
+                                         param_type, param_value))
+    elif self.device_log_result:
       #self.device_log_result.reverse()
       for line in self.device_log_result:
         if '<Name>' in line:
           param_name = re.sub(r'.*(<Name>)(.*)(</Name>)', r'\2', line).strip()
+
           index = self.device_log_result.index(line) + 1
           while not 'Value' in self.device_log_result[index]:
             index += 1
@@ -269,36 +742,93 @@
               return False
 
           line = self.device_log_result[index]
-          param_type = re.sub('.*type\w*=\w*\".*:(.*)\".*', r'\1', line).strip()
-          param_value = re.sub('.*<.*type.*>(.*)</Value>', r'\1', line).strip()
-          root.append(self.CreateElement(param_name, param_type, param_value))
+          # In case value string spans multiple lines:
+          while '</Value>' not in line:
+            index +=1
+            if index >= len(self.device_log_result):
+              info = self.log.CreateErrorInfo(
+                  'Critical', 'Exit! Cannot find matching </Value> tag in log!')
+              self.log.SendLine(self.test_info, info)
+              os.sys.exit(1)
+            new_line = self.device_log_result[index]
+            # if <Name> or EOF reached before a matching </Value> is found
+            if '<Name>' in new_line:
+              info = self.log.CreateErrorInfo(
+                  'Critical', 'Exit! Cannot find matching </Value> tag in log!')
+              self.log.SendLine(self.test_info, info)
+              os.sys.exit(1)
+            new_line = re.sub('\[\s*\d*\.\d{3}\]\s*cwmpd:\s*(.*)',
+                              r'\1', new_line).strip()
+            line += new_line.strip()
+
+          param_type = re.search('.*type\s*=\s*\"[a-zA-Z]*:([a-zA-Z]*)\">.*',
+                                 line, re.DOTALL).group(1)
+          param_value = re.search('.*<Value\s*[a-zA-Z]*:type="[a-zA-Z]*:'
+                                  '[a-zA-Z]*">(.*)</Value>',
+                                  line, re.DOTALL).group(1)
+          root.append(self.CreateElement(param_name, param_type,
+                                         None, param_value))
     else:
       info = self.log.CreateErrorInfo(
           'Critical', 'Failed to get parameter list from device!')
       self.log.SendLine(self.test_info, info)
       return False
+
     tree = ET.ElementTree(root)
-    fout = open(self.params['para_tree_file'], 'w')
-    tree.write(fout)
-    fout.close()
+    tree = self.SortElementTree(tree)
     return tree
 
-  def VerifyParameterValues(self, param=None):
-    """Verify the designated parameter can be set with expected value.
+  def ParametersFromXMLFile(self, file_path=None):
+    """Read parameter data from an XML format file.
 
-    Test results will be written to XML formated file, with test value
-    that has been set for the parameter(s)
-    For those parameters that failed to set value, they are recorded in
-    the result file specified by self.log instance.
     Args:
-      param:
-        1. if parameter is given, this method will set the value of this
-           parameter
-        2. if the parameter is not given, this method will set all parameters
-           that the device currently supports
+      file_path: file path to the xml file
+    Returns:
+      return the parameter list stored in the file, in the format of ElementTree
     """
-    self.para_tree = self.ParseToElementTree()
-    self.SetParameterValues(param, 'none')
+    f = None
+    try:
+      if not file_path:
+        f = open(self.params['para_tree_file'], 'r')
+      else:
+        f = open(file_path, 'r')
+      tree = ET.parse(f)
+    except IOError, inst:
+      err_string = ('Exit! Unexpected error opening '
+                    + str(f.name) + '. ' + str(inst))
+      info = self.log.CreateErrorInfo('Critical', err_string)
+      self.log.SendLine(self.test_info, info)
+      os.sys.exit(1)
+    return tree
+
+  def ParametersToXMLFile(self, tree=None, file_path=None):
+    """Output the available parameter instance tree to XML format file.
+
+    Parameter instance results will be written to XML formated file,
+    with test value that has been set for the parameter(s)
+    For those parameters that failed to set value, they are recorded in
+    the result file.
+
+    Args:
+      tree: the parameters structure to parse to file
+      file_path: path to the output file
+    """
+    if not tree:
+      tree = self.para_tree
+    if not file_path:
+      fout = open(self.params['para_tree_file'], 'w')
+    else:
+      fout = open(file_path, 'w')
+
+    try:
+      tree.write(fout)
+    except IOError, inst:
+      err_string = ('Exit! Unexpected error writing to file '
+                    + fout.name() + str(inst))
+      info = self.log.CreateErrorInfo('Critical', err_string)
+      self.log.SendLine(self.test_info, info)
+      os.sys.exit(1)
+    fout.close()
 
   def GetRequirementFromFile(self):
     """Get TR69 data model parameters from requirement file.
@@ -359,60 +889,59 @@
       # Match, return the time stamp
         return m.group(1)
     # No time stamp found
-    return -1
-
-  #################### for Data Model Test Case  ####################
-  def Run(self):
-    """Run the test case."""
-    ####### Add your code here -- BEGIN #######
-    print 'Test Started...'
-    self.Init()
-    self.p_ssh.SshRetry(5, 15)
-    #self.p_ssh.SshToAthena()
-    info = self.log.CreateProgressInfo(
-        '5%', 'SSH session to Athena server successfully established!')
+    info = self.log.CreateErrorInfo(
+        'Critical', 'Cannot get time information from Device log!')
     self.log.SendLine(self.test_info, info)
+    os.sys.exit(1)
 
-    #self.p_ssh.SshRetryFromAthena()
-    #info = self.log.CreateProgressInfo(
-    #    '15%', 'SSH session to Device successfully established!')
-    #self.log.SendLine(self.test_info, info)
+  def VerifyAllReqParameters(self):
+    """Check available parameters and compare to requirement list.
 
-    #check device profile/image is as erquired management url from ACS
-    self.TestEnvCheck()
+    This method checks all available parameters on current image, and
+    compare the list with requirement list. It will find out:
+      1. the parameters that are missing from the requirement list.
+      2. the newly added parameters that are not in the requirement list.
+    Both lists are written to the result file.
+
+    This method also output all parameter instances on current device to
+    a xml formated file, together with their types and values
+    """
+    # get parameter name lists, compare with requirement list
     info = self.log.CreateProgressInfo(
-        '25%', 'Check device test setup completed!')
-    self.log.SendLine(self.test_info, info)
-
-    # get parameter name lists, compare with requirement
-    info = self.log.CreateProgressInfo(
-        '35%', 'Get parameters from nbi_client ...')
+        '30%', 'Get parameters from nbi_client ...')
     self.log.SendLine(self.test_info, info)
     time_stamp = self.GetTimeStamp()
-    if time_stamp == -1:
-      info = self.log.CreateErrorInfo(
-          'Critical', 'Cannot get time information from Device log!')
-      self.log.SendLine(self.test_info, info)
-      os.sys.exit(1)
-    chk_list = self.GetParameterValues()
+    chk_list = self.acs_instance.ParseParameterNames(self.GetParameterValues(),
+                                                     True)
 
     if not chk_list:
       info = self.log.CreateProgressInfo(
-        '40%', 'Get parameters from device log ...')
+        '35%', 'ACS failed to reply, get parameters from device log ...')
       self.log.SendLine(self.test_info, info)
       # nbi client may fail because of timeout
-      # then get parameter list from device log
+      # if that is the case, then get parameter list from device log
+      count = 0
       while not chk_list:
         time.sleep(self.__delay)
-        chk_list = self.GetParameterNamesFromDeviceLog(time_stamp)
+        chk_list = self.GetParameterListFromDeviceLog(time_stamp)
+        count += 1
+        if count*self.__delay >= self.__long_delay:
+          info = self.log.CreateErrorInfo(
+              'Critical', 'Can not retrieve complete log info from device')
+          self.log.SendLine(self.test_info, info)
+          os.sys.exit(1)
+
+        if not chk_list:
+          info = self.log.CreateProgressInfo(
+              '40%', 'GetParameterValue query in progress, retry after '
+              + str(self.__delay) + ' seconds.')
+          self.log.SendLine(self.test_info, info)
       chk_list.sort()
 
-      if not chk_list:
-        info = self.log.CreateErrorInfo(
-            'Critical', 'Cannot find parameter list requirement from log file!')
-        self.log.SendLine(self.test_info, info)
-        os.sys.exit(1)
-
+    info = self.log.CreateProgressInfo(
+        '55%', 'GetParameterValue query completed, verify parameter list '
+        'with parameter requirement document.')
+    self.log.SendLine(self.test_info, info)
     req_list = self.GetRequirementFromFile()
     (mis_list, new_list) = self.CheckRequirement(chk_list, req_list)
     mis_list.sort()
@@ -422,24 +951,465 @@
 
     self.log.SendTestData(['############ Newly Added Parameters ############'])
     self.log.SendTestData(new_list)
+
     info = self.log.CreateProgressInfo(
-        '50%', 'Get parameter names completed. Check '
-        + self.log.params['f_result'] + ' file for missing parameters.')
+        '75%', 'Verify current parameter list with requirement completed. '
+        'Check result file:' + self.log.params['f_error'] + ' for details.')
     self.log.SendLine(self.test_info, info)
 
-    # TODO(lmeng):
-    #set parameter values:
-    #self.VerifyParameterValues('X_GOOGLE-COM_GVSB.GvsbKick')
-    #info = self.log.CreateProgressInfo(
-    #    '60%', 'Set parameter values completed. Check '
-    #    + self.log.params['f_result'] + ' file for missing parameters.')
-    #self.log.SendLine(self.test_info, info)
+    # write parameter instance to file
+    self.para_tree = self.ParseToElementTree()
+    self.ParametersToXMLFile()
+    info = self.log.CreateProgressInfo(
+        '100%', 'Update parameter file: ' + self.params['para_tree_file']
+        + ' completed.')
+    self.log.SendLine(self.test_info, info)
+    info = self.log.CreateResultInfo(
+        'Pass', 'Verification completed. '
+        'Check result file: ' + self.log.params['f_result'] + ' for missing '
+        'parameters and new parameters.')
+    self.log.SendLine(self.test_info, info)
 
-    #self.SetParameterValues('X_GOOGLE-COM_GVSB.GvsbKick', 'arp')
-    #self.GetParameterValues('X_GOOGLE-COM_GVSB.GvsbKick')
-    #self.SetParameterValues('X_GOOGLE-COM_GVSB.GvsbKick', 'none')
-    #self.GetParameterValues('X_GOOGLE-COM_GVSB.GvsbKick')
-    #self.p_ssh.ExitToAthena()
+  def GetParameterAccessStateFromDeviceLog(self, time_stamp=None, param='.'):
+    """Get parameter access state from device logs.
+
+    Args:
+      time_stamp: search events only after this time in log file
+      param: the parameter to search in device log
+    Returns:
+      return dictionary: parameter names as key, and writable status as value
+    """
+    self.p_ssh.SendCmd('dmesg | grep cwmpd:')
+    log_list = self.p_ssh.GetCmdOutput()
+    log_list.reverse()
+
+    param_state_dict = {}
+    param_list_start = False
+    param_list_end = False
+
+    for line in log_list:
+      # check only the getParameter query starts after the last known event:
+      if float(self.GetTimeStamp(line)) > float(time_stamp):
+        if '<cwmp:GetParameterNames>' in line:
+          # check the parameter query from nbi_client has been answered:
+          m = re.search(
+              r'.*<cwmp:GetParameterNames>.*<ParameterPath>(.*)'
+              '</ParameterPath>.*<NextLevel>false</NextLevel>.*'
+              '</cwmp:GetParameterNames>.*', line)
+          if m and param in line:
+            index = log_list.index(line)
+            for i in range(index+1, index+30):
+              if i < len(log_list):
+                if '<cwmp:GetParameterNamesResponse>' in log_list[i]:
+                  param_list_start = True
+                  break
+            continue
+
+      if '</cwmp:GetParameterNamesResponse>' in line:
+        if param_list_start:
+          param_list_end = True
+          break
+
+      if param_list_start:
+        if '<Name>' in line:
+          name = re.search(r'.*<Name>(.*)</Name>', line).group(1).strip()
+          index = log_list.index(line)+1
+          if '<Writable>' in log_list[index]:
+            access = re.sub(r'.*<Writable>(.*)</Writable>',
+                            r'\1', log_list[index]).strip()
+            if access == '1':
+              access = 'true'
+            else:
+              access = 'false'
+            param_state_dict.update({name: access})
+
+    if (not param_list_start) or (not param_list_end):
+      error_msg = self.ParseDeviceLogForError(
+          time_stamp, log_list, param, 'GetParameterNames')
+      if 'fault' in error_msg[0] or 'Fault' in error_msg[0]:
+        info = self.log.CreateErrorInfo(
+          'Critical', 'Exit! Error while get values: ' + ''.join(error_msg))
+        self.log.SendLines(self.test_info, info)
+        os.sys.exit(1)
+      else:
+        return False
+    return param_state_dict
+
+  def UpdateParameterAccessState(self, tree, param_name='.'):
+    """Update parameters' access state (read-only, read-write status).
+
+    TR69 parameters could be either in a read-only state, or a writable
+    state. The setParameterValues() test only verifies those parameters
+    in the 'writable' state. Try to set them with new values.
+    This method is called to determine the state of each supported parameter
+
+    Args:
+      tree:
+        the ElementTree data structure that holds the parameter attribute
+        list in XML format. This tree needs to be sorted before passed to
+        this function, according to the alphabetical order of parameter
+        names.
+      param_name:
+        the parameter name to update the access state
+    Returns:
+      returns this tree with updated parameter access state information
+    """
+    time_stamp = self.GetTimeStamp()
+    cmd_list = self.GetParameterNames(param_name, False)
+    if not self.acs_instance.CheckCmdCall(cmd_list):
+      info = self.log.CreateProgressInfo(
+            '---', 'GetParameterNames() query failed on ACS. Analyzing device'
+            ' logs...')
+      self.log.SendLine(self.test_info, info)
+
+      param_dict = self.GetParameterAccessStateFromDeviceLog(time_stamp,
+                                                             param_name)
+      while not param_dict:
+        info = self.log.CreateProgressInfo(
+            '---', 'GetParameterNames() analyze in progress, wait for '
+            + str(self.__short_delay) + ' seconds.')
+        self.log.SendLine(self.test_info, info)
+        time.sleep(self.__short_delay)
+        param_dict = self.GetParameterAccessStateFromDeviceLog(time_stamp,
+                                                               param_name)
+    else:
+      param_dict = self.acs_instance.ParseParameterAccessStates(cmd_list)
+      for key in param_dict.keys():
+        if param_name.endswith('.') and param_name != '.':
+          param_dict[param_name + key] = param_dict.pop(key)
+        else:
+          param_dict[param_name + '.' + key] = param_dict.pop(key)
+
+    container = tree.findall('parameter_value_struct')
+
+    for node in container:
+      name = node.findtext('name')
+      if name in param_dict.keys():
+        e = node.find('writable')
+        if not e:
+          # Create this tag:
+          e = ET.Element('writable')
+          e.text = param_dict[name]
+          node.append(e)
+        else:
+          e.text = param_dict[name]
+      else:
+        continue
+    return tree
+
+  def MarkParametersToSet(self, param_list, param):
+    """In the sorted tree, mark all parameters before param to read-only."""
+    if not param:
+      return param_list
+
+    ls = list(param_list)
+    for name in param_list:
+      if name != param:
+        ls.remove(name)
+      else:
+        break
+    return ls
+
+  def VerifySetAllParameterValues(self):
+    """This verifies the setParameterValues() on all supported parameters.
+
+    This method tests the 'set' capability on all parameters. According
+    to the data type, the value will be set as 'string', 'long_int', 'boolean',
+    etc. Note the current test only verify the 'set' action is supported by
+    each parameter. Therefore, it will try to set the same default value on each
+    parameter (it does not change the default value of each parameter).
+
+    This test assumes that the parameter list has already been retrieved from
+    device by 'GetparameterValues', and has been written to the parameter XML
+    file.
+    """
+    tree = self.ParametersFromXMLFile()
+    #tree = self.UpdateParameterAccessState(tree)
+    tree = self.SortElementTree(tree)
+    param_list = []
+    # Currently Assume all parameters are read-write
+    container = tree.findall('parameter_value_struct')
+
+    for node in container:
+      #name = node.findtext('name')
+      #test_value = node.findtext('test_value')
+      dev_type = node.findtext('device_type')
+      nbi_type = None
+      if dev_type == 'unsignedInt':
+        nbi_type = 'long_value'
+      elif dev_type == 'boolean':
+        nbi_type = 'boolean_value'
+      elif dev_type == 'string':
+        nbi_type = 'string_value'
+      else:
+        info = self.log.CreateErrorInfo(
+            'Critical', 'Exit! Unknown (new) Parameter types found from device:'
+            ': ' + dev_type)
+        self.log.SendLine(self.test_info, info)
+        os.sys.exit(1)
+      node.find('nbi_type').text = nbi_type
+      param_list.append(node.findtext('name'))
+      e = node.find('writable')
+      if not e:
+        access_state = ET.Element('writable')
+        access_state.text = 'true'
+        node.append(access_state)
+    param_list.sort()
+    param_list = self.MarkParametersToSet(
+        param_list, self.params['from_which_param_to_set'])
+    self.BatchSetParametersValues(tree, param_list)
+
+  def VerifyNTPTimeZoneConfig(self):
+    """Verify the Time zone configuration is received and processed by Device.
+
+    Check the log of device, to find TR69 parameter:
+    InternetGatewayDevice.Time.
+    is pushed down to device. Also verify the device correctly updated local
+    time information.
+    """
+    ## Blocked by bug: http://b/issue?id=6804551
+    ## TODO(lmeng): add set values and verify set values succeeded
+    self.p_ssh.SendCmd('dmesg | grep cwmpd:')
+    log_list = self.p_ssh.GetCmdOutput()
+    time_stamp = self.GetTimeStamp()
+    log_list = self.ParseDeviceLogForError(time_stamp, log_list,
+                                           'InternetGatewayDevice.Time',
+                                           'SetParameterValues')
+    if 'No rpc message is available in device log' in log_list[0]:
+      info = self.log.CreateResultInfo(
+        '---', 'Failed. Can not find TR69 Time zone information in device log')
+      self.log.SendLine(self.test_info, info)
+    elif 'fault' in log_list[0]:
+      info = self.log.CreateResultInfo(
+        '---', 'Failed to apply Time zone configuration on device.')
+      self.log.SendLine(self.test_info, info)
+    else:
+      info = self.log.CreateResultInfo(
+        '---', 'Succeed to setup Time zone on deivce.')
+      self.log.SendLine(self.test_info, info)
+
+  def VerifyManagementServerURL(self):
+    """Verify set and get Management Server URL from device."""
+    # This test is blocked by bug: http://b/issue?id=6813492
+    mngmt_url_param = 'InternetGatewayDevice.ManagementServer.URL'
+    url_from_dev_param = self.acs_instance.ParseManagementURL(
+        self.GetParameterValues(mngmt_url_param))
+    info = self.log.CreateProgressInfo(
+            '15%', 'Get management url from TR069 parameter: '
+            + mngmt_url_param + '. Value: ' + url_from_dev_param)
+    self.log.SendLine(self.test_info, info)
+    if not url_from_dev_param:
+      info = self.log.CreateProgressInfo(
+            '30%', 'Can not found Value for: '
+            'InternetGatewayDevice.ManagementServer.URL'
+            '. Verify to set default URL: ' + self.params['default_url'])
+      self.log.SendLine(self.test_info, info)
+      url_from_dev_param = self.params['default_url']
+
+    info = self.log.CreateProgressInfo(
+            '50%', 'Set parameter value for: '
+            'InternetGatewayDevice.ManagementServer.URL'
+            '. Value: ' + url_from_dev_param)
+    self.log.SendLine(self.test_info, info)
+    result = self.SetParameterValues(mngmt_url_param, 'string',
+                                     url_from_dev_param)
+    if not result:
+      info = self.log.CreateErrorInfo(
+          'Critical', 'Failed to set parameter: '
+          'InternetGatewayDevice.ManagementServer.URL')
+      self.log.SendLine(self.test_info, info)
+      info = self.log.CreateResultInfo(
+          'Failed', 'Failed to set parameter: '
+          'InternetGatewayDevice.ManagementServer.URL')
+      self.log.SendLine(self.test_info, info)
+    else:
+      info = self.log.CreateProgressInfo(
+          '100%', 'Succeeded to set parameter: '
+          'InternetGatewayDevice.ManagementServer.URL')
+      self.log.SendLine(self.test_info, info)
+      info = self.log.CreateResultInfo(
+          'Pass', 'Succeeded to set parameter: '
+          'InternetGatewayDevice.ManagementServer.URL')
+      self.log.SendLine(self.test_info, info)
+
+  def VerifySetParameterValuesRPC(self):
+    """Test case: 11722375. To verify SetParameterValues RPC.
+
+    To verify SetParametersRPC, this methond also try to set all parameters
+    which have 'write-able' status, with test value.
+    """
+    # update parameter access state:
+    info = self.log.CreateProgressInfo(
+        '20%', 'Read Parameters read/write status from file.')
+    self.log.SendLine(self.test_info, info)
+    tree = self.ParametersFromXMLFile()
+    info = self.log.CreateProgressInfo(
+        '50%', 'Update parameters read/write status from Device.')
+    self.log.SendLine(self.test_info, info)
+    tree = self.UpdateParameterAccessState(tree, self.params['param_path'])
+    self.ParametersToXMLFile(tree)
+    # set parameter values:
+    self.VerifySetAllParameterValues()
+    info = self.log.CreateProgressInfo(
+        '100%', 'Verify: Set values for all parameters completed.')
+    self.log.SendLine(self.test_info, info)
+    info = self.log.CreateResultInfo(
+        'Pass', 'Verification: set parameter '
+        'values completed. '
+        'Check result file: ' + self.log.params['f_result'] + ' for details.')
+    self.log.SendLine(self.test_info, info)
+
+  def VerifyMonitorTemperature(self):
+    """Test the temperature monitor on device.
+
+    This feature is not available for first launch.
+    """
+    info = self.log.CreateResultInfo(
+        'Block', 'This feature is not availalbe '
+        'on the first launch images.')
+    self.log.SendLine(self.test_info, info)
+
+  def VerifyAutoChannelEnable(self):
+    """Test AutoChannelEnable on device.
+
+    This feature is not available for first launch.
+    """
+    info = self.log.CreateResultInfo(
+        'Block', 'This feature is not availalbe '
+        'on the first launch images.')
+    self.log.SendLine(self.test_info, info)
+
+  def SetServiceConfigs(self, param_dict):
+    """Set service parameter profile on ACS.
+
+    This method sets the service configurations on ACS, and returns the
+    SetServiceConfigs result.
+    Args:
+      param_dict:
+        it is in this format in config file:
+        "wifi_params":{
+            "Google.Wifi.SSID":{"string_value":"Home"},
+            "Google.Wifi.Home.SSID_2GHz":{"string_value":"Home"},
+            "Google.Wifi.Enable":{"boolean_value":"true"},
+            "Google.Wifi.BeaconType":{"string_value": "Basic"},
+            "Google.Wifi.BasicEncryptionModes":{"string_value":"WEPEncryption"}
+    Returns:
+      True: if set succeeded
+      False: otherwise
+    """
+    app_id = self.GetACSAppFromURL()
+    nbi_path = self.params['nbi_client_path']
+    account_id = self.params['account_id']
+    device_label = self.params['device_label']
+    parameter_value_struct = ''
+
+    # parameter_value_struct: <name: "Google.Wifi.BasicEncryptionModes"
+    # string_value: "WEPEncryption">
+    for key in param_dict.iterkeys():
+      name = key
+      param_type = param_dict[key].keys()[0]
+      value = None
+      if 'string' in param_type:
+        value = '"' + param_dict[key].values()[0] + '"'
+      else:
+        value = param_dict[key].values()[0]
+      parameter_value_struct += (
+          ' parameter_value_struct: <name: "'
+          + name + '" ' + param_type +': ' + value + '> ')
+
+    parameter_value_struct = None
+    cmd = (nbi_path
+           + ' --server /gns/project/apphosting/stubby/prod-appengine/'
+           '*/' + app_id + '/default/* --service AccountService '
+           '--method SetServiceConfigs --request \''
+           'account_device_id: <account_id: "' + account_id
+           + '" device_label: "' + device_label + '"> parameter_list: < '
+           + parameter_value_struct + ' > async_apply_now: false\'')
+    print cmd
+    call_result = self.acs_instance.StubbyClientCall(cmd)
+    if 'FAILED' in call_result[0]:
+      info = self.log.CreateErrorInfo(
+          'Warning', 'ACS failed on SetServiceConfigs query: ' + cmd)
+      self.log.SendLines(self.test_info, info)
+      return False
+    else:
+      print call_result
+    return call_result
+
+  def VerifyWiFiConfiguration(self):
+    """Test case: 14165034, WiFi configuration verification.
+
+    This test case will set WiFi parameters on ACS, and verify
+    that the service profile is correctly pushed to device.
+    Thin Bruno is configured with correct WiFi network.
+
+    The WiFi parameters and values in specified in config file
+    in JSON format, e.g.:
+    "Google.Wifi.SSID":{"string_value":"Home"},
+    "Google.Wifi.Home.SSID_2GHz":{"string_value":"Home"},
+    "Google.Wifi.Enable":{"boolean_value":"true"},
+    "Google.Wifi.BeaconType":{string_value: "Basic"},
+    "Google.Wifi.BasicEncryptionModes":{"string_value":"WEPEncryption"}
+
+    Returns:
+      return False if test failed
+    """
+    info = self.log.CreateProgressInfo(
+          '10%', 'Setup SetServiceConfigs on ACS...')
+    self.log.SendLine(self.test_info, info)
+    if not self.SetServiceConfigs(self.params['wifi_params']):
+      return False
+    else:
+      info = self.log.CreateProgressInfo(
+          '20%', 'Setup SetServiceConfigs on ACS succeed.')
+      self.log.SendLine(self.test_info, info)
+
+    # Verify if the service is pushed to device
+    # TODO(lmeng): what parameters to set and to verify
+
+  #################### for Data Model Test Case  ####################
+
+  def Run(self):
+    """Run the test case."""
+    ####### Add your code here -- BEGIN #######
+    print 'Test Started...'
+    self.Init()
+    self.p_ssh.SshRetry(5, 15)
+    info = self.log.CreateProgressInfo(
+        '5%', 'SSH session to device successfully established!')
+    self.log.SendLine(self.test_info, info)
+
+    #check device profile/image is as erquired management url from ACS
+    self.TestEnvCheck()
+    info = self.log.CreateProgressInfo(
+        '10%', 'Check device test setup completed!')
+    self.log.SendLine(self.test_info, info)
+
+    if (self.test_info['testID'] == '14187024'
+        or self.test_info['testID'] == '14165033'
+        or self.test_info['testID'] == '14315008'
+        or self.test_info['testID'] == '14165035'
+        or self.test_info['testID'] == '14314007'
+        or self.test_info['testID'] == '11865133'
+        or self.test_info['testID'] == '14335001'
+        or self.test_info['testID'] == '14266498'
+        or self.test_info['testID'] == '14319149'
+        or self.test_info['testID'] == '14314008'):
+      self.VerifyAllReqParameters()
+    elif self.test_info['testID'] == '11722375':
+      self.VerifySetParameterValuesRPC()
+    elif self.test_info['testID'] == '14315009':
+      self.VerifyManagementServerURL()
+    elif self.test_info['testID'] == '14314009':
+      self.VerifyMonitorTemperature()
+    elif self.test_info['testID'] == '14165038':
+      self.VerifyAutoChannelEnable()
+    elif self.test_info['testID'] == '15643845':
+      self.VerifyNTPTimeZoneConfig()
+    elif self.test_info['testID'] == '14165034':
+      self.VerifyWiFiConfiguration()
+    else:
+      return
     print 'Test Completed...'
     ####### Add your code here -- END   #######
 
@@ -447,4 +1417,14 @@
     self.p_ssh.Close()
 
 if __name__ == '__main__':
-  test = DataModelTest(testID='14187024', key_word='DataModel')
+  # Test cases defined in this file:
+  test_defined = ['14187024', '14165033', '14315008', '14165035', '14314007',
+                  '11865133', '14335001', '14266498', '14319149', '14314008',
+                  '11722375', '14315009', '14314009', '14165038', '15643845',
+                  '14165034']
+  # To execute test cases that defined in config file:
+  test = DataModelTest(testID='14165034')
+  test_to_execute = testCase.TestCase.FindTestCaseToExecute('config.cfg')
+  for test_id in test_to_execute:
+    if test_id in test_defined:
+      test = DataModelTest(testID=test_id)
diff --git a/device.py b/device.py
index c02fa33..f3eb65c 100644
--- a/device.py
+++ b/device.py
@@ -1,17 +1,24 @@
 #!/usr/bin/python
 # Copyright 2012 Google Inc. All Rights Reserved.
 
-"""This class defines devices."""
+"""This class defines devices.
 
-__author__ = 'Lin Xue (linxue@google.com)'
-
-"""This file defines the base class of all devices,
+   This file defines the base class of all devices,
    and specific device classes, such as Bruno, Spirent, etc.
 """
 
+__author__ = 'Lin Xue (linxue@google.com)'
+__author__ = 'Lehan Meng (lmeng@google.com)'
+
+
+import re
+
+import ip
+
 
 class Device(object):
   """Base class of all devices.
+
      information of device class:
      addr: address of device
      user: user name of device
@@ -23,24 +30,14 @@
      other: other information of device
   """
 
-  dev_info = {'addr': 'None',
-              'user': 'None',
-              'pwd': 'None',
-              'dev_name': 'None',
-              'cmd_prompt': 'None',
-              'other': 'None'}
-
   def GetDevInfo(self):
     """This function returns device information."""
-
     return (self.dev_info['dev_name'], self.dev_info['other'])
 
   def SetLogging(self, logging):
-    """This function set logging for device"""
-
+    """This function set logging for device."""
     self.log = logging
     return
-
 # End of Device class
 
 
@@ -48,13 +45,20 @@
   """Bruno device class."""
 
   def __init__(self, **kwargs):
-    """ Constructor for Bruno device
-        device name: Bruno, and other device informations
+    """Constructor for Bruno device.
+
+    device name: Bruno, and other device informations
     """
+    self.dev_info = {'addr': 'None',
+                     'user': 'None',
+                     'pwd': 'None',
+                     'dev_name': 'None',
+                     'cmd_prompt': 'None',
+                     'other': 'None'}
+
     self.dev_info['dev_name'] = 'Bruno'
     for s in kwargs:
-        self.dev_info[s] = kwargs[s]
-
+      self.dev_info[s] = kwargs[s]
     self.dev_ssh = None
 
     # Bruno Device attributes
@@ -76,26 +80,26 @@
     self.dev_epgpri = None
     # EPG secondary
     self.dev_epgsec = None
-
     return
 
   def GetDevCmd(self, cmd='', dev_attr='', dev_log=''):
     """This function sends command to Bruno.
+
        Then it gets back the results
        If success, save the results and write log
        If fail, show Warning message
-       Args:
-            cmd:
-                the command sent to Bruno system
-                to query the device information
-            dev_attr:
-                the device attribute
-                which can be get from this command
-            dev_log:
-                the logging message to be shown in log
-
+    Args:
+      cmd:
+        the command sent to Bruno system
+        to query the device information
+      dev_attr:
+        the device attribute
+        which can be get from this command
+      dev_log:
+        the logging message to be shown in log
+    Returns:
+      return the command results
     """
-
     # Send command to query Bruno device information
     self.dev_ssh.SendCmd(cmd)
 
@@ -111,8 +115,7 @@
                                          'Get ' + dev_log + ': ' + line)
       self.log.SendLine(None, info)
       dev_attr = line
-
-    return line
+    return line.strip()
 
   def GetSerialNumber(self):
     """This function returns Bruno device serial number."""
@@ -130,20 +133,107 @@
 
     return result
 
-  def GetIPAddress(self):
-    """This function returns Bruno device IP address."""
+  def VerifyCurrentVersion(self, version):
+    """Check if the current software version matches the given version.
 
+    Args:
+      version: the expected version string to check with device software
+    Returns:
+      True: if the current version matches the given version
+      False: if otherwise
+    """
+    if version == self.GetCurrentVersion():
+      return True
+    else:
+      return False
+
+  def GetIPaddress(self):
+    """This function returns Bruno device IP address."""
+    # Obsoleted
     result = self.GetDevCmd(r'ifconfig br0', self.dev_ip,
                             'IP address')
 
     return result
 
+  def GetDNSServer(self):
+    """This function returns device DNS server name."""
+    self.dev_ssh.SendCmd('cat /etc/resolv.conf')
+    cmd_list = self.dev_ssh.GetCmdOutput()
+    dns = None
+    for line in cmd_list:
+      m = re.search('nameserver (.*)', line)
+      if m:
+        dns = m.group(1)
+        break
+    return dns
+
+  def GetTimeServer(self):
+    """This function returns device DNS server name."""
+    self.dev_ssh.SendCmd('cat /etc/ntpd.conf')
+    cmd_list = self.dev_ssh.GetCmdOutput()
+    ts = None
+    for line in cmd_list:
+      m = re.search('server (.*)', line)
+      if m:
+        ts = m.group(1)
+        break
+    return ts
+
+  def GetGVSBHost(self):
+    """This function returns device GVSB host server name."""
+    self.dev_ssh.SendCmd('cat /tmp/gvsbhost')
+    cmd_line = self.dev_ssh.GetCmdOutput(2)[0]
+    m = re.search('http[s]?://[\w\d\./-]*', cmd_line)
+    if m:
+      return m.group(0)
+    return None
+
+  def GetIPv4Address(self):
+    """This function returns Bruno device IPv4 address."""
+    self.dev_ssh.SendCmd('ip addr show dev br0')
+    cmd_list = self.dev_ssh.GetCmdOutput()
+    address = None
+    for line in cmd_list:
+      if 'inet ' in line and 'scope global' in line:
+        address = ip.IPADDR(line).IsLikeIpv4Address()
+
+    if not address:
+      info = self.log.CreateErrorInfo('critical',
+                                      'Can not detect IPv4 address on device!')
+      self.log.SendLine(None, info)
+    return address
+
+  def GetIPv6Address(self):
+    """This function returns Bruno device IPv6 address.
+
+    This function will return a list of addresses. Sometimes device may
+    have multiple IPv6 addresses.
+
+    Returns:
+      return the obtained IPv6 address
+    """
+    self.dev_ssh.SendCmd('ip addr show dev br0')
+    cmd_list = self.dev_ssh.GetCmdOutput()
+    address = []
+    for line in cmd_list:
+      if 'inet6 ' in line and 'scope global' in line:
+        print line
+        m = re.match('inet6 ([\da-f:]+)/\d+ scope global \w*', line.strip())
+        if not m:
+          info = self.log.CreateErrorInfo(
+              'critical', 'Can not detect valid IPv6 address '
+              'on device! ' + line)
+          self.log.SendLine(None, info)
+          return address
+        addr = m.group(1)
+        address.append(addr)
+    return address
+
   def GetDevTime(self):
     """This function returns Bruno device current date."""
 
     result = self.GetDevCmd(r'date', self.dev_time,
                             'current date')
-
     return result
 
   def GetACSUrl(self):
@@ -151,9 +241,22 @@
 
     result = self.GetDevCmd(r'cat /tmp/cwmp/acs_url', self.dev_acs,
                             'ACS URL')
-
     return result
 
+  def VerifyCurrentACSURL(self, url):
+    """Check if the current ACS URL matches the given URL.
+
+    Args:
+      url: the expected url string to check with device ACS URL
+    Returns:
+      True: if the current url matches the given url
+      False: otherwise
+    """
+    if url == self.GetACSUrl():
+      return True
+    else:
+      return False
+
   def GetDnldImage(self):
     """This function returns Bruno device current downloading image."""
 
@@ -163,7 +266,7 @@
     return result
 
   def GetProductClass(self):
-    """This function returns Bruno device product class"""
+    """This function returns Bruno device product class."""
 
     result = self.GetDevCmd(r'cat /etc/platform', self.dev_class,
                             'product class')
@@ -171,7 +274,7 @@
     return result
 
   def GetEpgPrimary(self):
-    """This function returns Bruno device primary EPG"""
+    """This function returns Bruno device primary EPG."""
 
     result = self.GetDevCmd(r'cat /tmp/epgprimary', self.dev_epgpri,
                             'EPG primary')
@@ -179,7 +282,7 @@
     return result
 
   def GetEpgSecond(self):
-    """This function returns Bruno device secondary EPG"""
+    """This function returns Bruno device secondary EPG."""
 
     result = self.GetDevCmd(r'cat /tmp/epgsecondary', self.dev_epgsec,
                             'EPG secondary')
@@ -197,7 +300,7 @@
     # Other device informations
     self.GetSerialNumber()
     self.GetCurrentVersion()
-    self.GetIPAddress()
+    self.GetIPv4Address()
     self.GetDevTime()
     self.GetACSUrl()
     self.GetDnldImage()
@@ -207,6 +310,59 @@
 
     return
 
+  def GetTimeStamp(self, line=None):
+    """Extract the time information of most current event from Device log.
+
+    i.e., the time that the last event happens since reboot (in seconds)
+    Args:
+      line: a line of device log which contains event time information.
+            If it has value of 'None', then retrieve the last a few lines from
+            device log to extract time information.
+    Returns:
+      return the time stamp string if succeed, return -1 otherwise.
+    """
+    if not line:
+      # get time stamp from Device log file
+      self.dev_ssh.SendCmd('dmesg | grep cwmpd:')
+      log_list = self.dev_ssh.GetCmdOutput()
+
+      for line in log_list:
+        m = re.match('\\[[\s]*(\d*\\.\d{3})\\]', line)
+        if m:
+          # Match, return the time stamp
+          return m.group(1)
+    else:
+      # get time stamp from a Device log line
+      m = re.match('\\[[\s]*(\d*\\.\d{3})\\]', line)
+      if m:
+      # Match, return the time stamp
+        return m.group(1)
+    # No time stamp found
+    return -1
+
+  def FindLineInLog(self, log_list, time_stamp, pattern_line):
+    """Match a particular string from device logs.
+
+    Find a particular string or line from device log
+    Args:
+      log_list: the device log to search from
+      time_stamp: to search events that are after this time
+      pattern_line: the string or line that need to be matched in device log
+    Returns:
+      True: if 'line' matched
+      False: 'line' not found in device log
+    """
+    m = re.compile(pattern_line)
+    for line in log_list:
+      if float(self.GetTimeStamp(line)) > float(time_stamp):
+        #Debug
+        if 'detected' in line:
+          print 'here'
+
+        matching = m.search(line)
+        if matching:
+          return True
+    return False
 # End of Bruno device class
 
 
@@ -214,7 +370,8 @@
   """Spirent device class."""
 
   def __init__(self, **kwargs):
-    """ Constructor for Spirent device
+    """Constructor for Spirent device.
+
         device name: Spirent, and other device informations
     """
 
diff --git a/download.py b/download.py
index 2bfdc7f..d39b6e4 100755
--- a/download.py
+++ b/download.py
@@ -4,18 +4,11 @@
 """This class defines the test case "image download" from ACS.
 
 This class extends the TestCase Class.
-testID: 11843140
-This test does the following tasks:
-  - check current image version
-    - if the current version is the same as expected version,
-      this test will first to try to downgrade it to the downgrade_version.
-    - Then, it will Run image download test
-    - Fianlly, it will downgrade to downgrade_version if this has not been
-      done. This is to test the download handling capabilities of the
-      expected_version
-  - configure ACS instance with these software versions
-  - verify image download and installation to be complete and successful, by
-    observing a successfully reboot after installation
+This file includes the following test cases:
+  - testID: 11843140  7.6.11 Verify firmware upgrade/downgrade by ACS
+  - testID: 14165036  7.6.18 Negative test: Bruno Image download interruption
+  - testID: 14334001  7.6.25.3 File Transfer (File upload is optional, this is
+                               then basically the same test case as download.)
 """
 
 __author__ = 'Lehan Meng (lmeng@google.com)'
@@ -48,15 +41,12 @@
 
   def Init(self):
     """Initialte the DownloadTest instance."""
-    self.p_ssh = ssh.SSH(user=self.params['user'],
-                         addr=self.params['addr'],
-                         pwd=self.params['pwd'],
-                         bruno_prompt=self.params['bruno_prompt'],
-                         addr_ipv6=self.params['addr_ipv6'],
-                         athena_user=self.params['athena_user'],
-                         athena_pwd=self.params['athena_pwd'],
-                         jump_server=self.params['jump_server'])
-    self.p_ssh.Setlogging(self.log)
+    if not self.p_ssh:
+      self.p_ssh = ssh.SSH(user=self.params['user'],
+                           addr=self.params['addr'],
+                           bruno_prompt=self.params['bruno_prompt'],
+                           addr_ipv6=self.params['addr_ipv6'])
+      self.p_ssh.SetLogging(self.log)
     self.__debug = False
     self.__short_delay = 5  #short delay: 5 seconds
     self.__delay = 180  #medium delay: 180 seconds
@@ -130,9 +120,13 @@
         return m.group(1)
 
     # No time stamp found
-    return -1
+    info = self.log.createErrorInfo(
+              'Critical', 'Exit! Can not find time information from '
+              'device log ...')
+    self.log.sendLine(self.test_info, info)
+    return os.sys.exit(1)
 
-  def ConfigACS(self, version_id=None):
+  def ConfigACS(self, version_id):
     """Setup the ACS device profile with expected image.
 
     Then restart the cwmpd process on device to
@@ -143,19 +137,12 @@
       return the time stamp string if succeed, return -1 otherwise.
     """
     #configure ACS:
-    acs_instance = acs.ACS(version_id)
+    acs_instance = acs.ACS(acs_path=self.params['acs_path'])
     acs_instance.SetLogging(self.log)
-    acs_instance.SaveConfiguration()
+    acs_instance.SaveConfiguration(
+        self.params['profile_id'], version_id, self.params['acs_app_id'],
+        self.params['acs_host_name'])
 
-    #self.p_ssh.SendCmd('/etc/Init.d/S85catawampus restart')
-    # To setup any device service parameter using nbi_client will trigger
-    # ACS to make a remote connection request to the device.
-    # However, currently ACS does not provide separate stubby call to
-    # only request a remote connection.
-    # As walk around:
-    #   1. call remote management URL locally to initiate Inform immediately
-    #   2. wait for the next periodic inform to initiate download
-    # Here go for the 2nd option.
     time_stamp = self.GetTimeStamp()
     return time_stamp
 
@@ -223,29 +210,32 @@
     """
     time.sleep(5)
     s = self.GetTimeStamp()
+    print 'previous time stamp: ' + time_stamp
+    print 'current time stamp: ' + s
     if float(s) < float(time_stamp) and s is not -1:
       return True
     return False
 
-  def CheckImageInstallation(self, time_stamp):
+  def CheckImageInstallation(self, time_stamp, version):
     """Check if the Image installation and Device reboot is successful.
 
     An upgrade is considered complete only after the device is rebooted
     after image installation
     Args:
       time_stamp: check if a reboot is done after this time
+      version: the image version that needs to be installed
     Returns:
       return True if installation succeeded
       return False otherwise
     """
-    self.p_ssh.ExitToAthena()
-    time.sleep(3*self.__short_delay)
-    self.p_ssh.SshRetryFromAthena(set_key=False)
+    self.p_ssh.Close()
+    time.sleep(6*self.__short_delay)
+    self.p_ssh.SshRetry()
     count = 0
     ts = time_stamp
     while not self.IsRebooted(ts):
       count +=1
-      if count*self.__short_delay*3 > self.__long_delay:
+      if count*self.__short_delay*6 > self.__long_delay:
         info = self.log.CreateErrorInfo(
             'critical',
             'Error! File download longer than ' + str(self.__long_delay)
@@ -256,56 +246,50 @@
       t = self.GetTimeStamp()
       if float(t) > float(ts):
         ts = t
-      self.p_ssh.ExitToAthena()
+      self.p_ssh.Close()
       info = self.log.CreateProgressInfo(
-          '90%', 'Wait ' + str(3*self.__short_delay)
+          '---', 'Wait ' + str(6*self.__short_delay)
           + ' seconds for image installation and device reboot...')
       self.log.SendLine(self.test_info, info)
-      time.sleep(3*self.__short_delay)
-      self.p_ssh.SshRetryFromAthena(set_key=False)
+      time.sleep(6*self.__short_delay)
+      self.p_ssh.SshRetry()
 
     time.sleep(2*self.__short_delay)
     self.p_ssh.SendCmd('more /etc/version')
     line = self.p_ssh.GetCmdOutput()[1]
     crt_version = line.strip()
-    print crt_version + '########' + self.params['expected_version']
-    if crt_version == self.params['expected_version']:
+    print crt_version + '########' + version
+    if crt_version == version:
       return True
     else:
       return False
 
-  def Run(self):
-    """Run the test case."""
-    ####### Add your code here -- BEGIN #######
-    print 'Test Started...'
-    self.Init()
-    self.p_ssh.SshToAthena()
-    info = self.log.CreateProgressInfo(
-        '5%', 'SSH session to Athena server successfully established!')
-    self.log.SendLine(self.test_info, info)
+  def VerifyImageDownload(self):
+    """Verify image download and upgrade.
 
+    This test checks the following:
+      - check current image version
+      - if current_version is not expected_version as defined in config file:
+        - Upgrade to expected_version (verify expected version can boot up)
+        - Downgrade from expected_version to downgrade_version
+          (verify downgrade handling capability of expected_version image)
+        - Finally upgrade to expected_version, and keep device in this state.
+      - if the current version is already the expected_version,
+        - Downgrade from expected_version to downgrade_version
+          (verify downgrade handling capability of expected_version image)
+        - Finally upgrade to expected_version, and keep device in this state.
+
+    At the same time, it also verifies:
+      - configure ACS with these software versions
+    """
     max_test_idx = 3
     current_test_idx = 1
     upgrade = True
 
-    while current_test_idx < max_test_idx:
-      self.p_ssh.SshRetryFromAthena(set_key=True)
+    while current_test_idx <= max_test_idx:
       info = self.log.CreateResultInfo(
           '---', 'Test Sequence Number: ' + str(current_test_idx))
       self.log.SendLine(self.test_info, info)
-      while self.CheckDownloadFileExists():
-        # current in download
-        info = self.log.CreateProgressInfo(
-            '10%', 'Another downloading in progress, retry after '
-            + str(self.__short_delay) + 'seconds...')
-        self.log.SendLine(self.test_info, info)
-        self.p_ssh.ExitToAthena()
-        time.sleep(self.__short_delay)
-        self.p_ssh.SshRetryFromAthena(set_key=False)
-
-      info = self.log.CreateProgressInfo(
-          '15%', 'SSH session to device successfully established!')
-      self.log.SendLine(self.test_info, info)
 
       self.CheckACSUrl()
       info = self.log.CreateProgressInfo('20%', 'Current ACS url: '
@@ -317,45 +301,199 @@
                                          + self.params['current_version'])
       self.log.SendLine(self.test_info, info)
 
-      if upgrade == True:
+      if self.params['current_version'] == self.params['expected_version']:
+        if current_test_idx == 1:
+          current_test_idx += 1
+          upgrade = False
+          continue
+
+      version = None
+      if upgrade:
         self.time_stamp = self.ConfigACS(self.params['expected_version_id'])
         info = self.log.CreateProgressInfo('40%', 'Expected Version: '
                                            + self.params['expected_version'])
         self.log.SendLine(self.test_info, info)
+        version = self.params['expected_version']
       else:
         self.time_stamp = self.ConfigACS(self.params['downgrade_version_id'])
-        self.params['expected_version'] = self.params['downgrade_version']
-        self.params['expected_version_id'] = self.params['downgrade_version_id']
         info = self.log.CreateProgressInfo('40%', 'Downgrade Version: '
                                            + self.params['downgrade_version'])
         self.log.SendLine(self.test_info, info)
+        version = self.params['downgrade_version']
 
       info = self.log.CreateProgressInfo(
-          '40%', 'Successfully configured ACS for image version')
+          '50%', 'Successfully configured ACS for image version: ' + version)
       self.log.SendLine(self.test_info, info)
 
       time.sleep(self.__short_delay)  # time delay for log update
       self.time_stamp = self.GetTimeStamp()
-      if self.CheckImageInstallation(self.time_stamp):
+      if self.CheckImageInstallation(self.time_stamp, version):
         info = self.log.CreateProgressInfo(
             '100%', 'Image successfully upgraded to expected version: '
             'from: ' + self.params['current_version']
-            + ' to: ' + self.params['expected_version'])
+            + ' to: ' + version)
         self.log.SendLine(self.test_info, info)
         info = self.log.CreateResultInfo(
             'Pass', 'Image successfully upgraded to expected version: '
             'from: ' + self.params['current_version']
-            + ' to: ' + self.params['expected_version'])
+            + ' to: ' + version)
         self.log.SendLine(self.test_info, info)
       else:
         info = self.log.CreateErrorInfo(
             'critical',
             'Error! Image version does not match expected version!')
         self.log.SendLine(self.test_info, info)
+        info = self.log.CreateResultInfo(
+            'Failed', 'Image failed to upgraded to expected version: '
+            'from: ' + self.params['current_version']
+            + ' to: ' + version)
+        self.log.SendLine(self.test_info, info)
 
       current_test_idx += 1
-      self.p_ssh.ExitToAthena()
-      upgrade = False
+      if upgrade:
+        upgrade = False
+      else:
+        upgrade = True
+
+  def ImageUpgrade(self, expected_version, expected_version_id):
+    """This function upgrade device image to expected version.
+
+    Args:
+      expected_version: the version to be upgraded to
+      expected_version_id: the id of the expected version
+    Returns:
+      True if upgrade succeeds
+      False if upgrade fails
+    """
+    version = self.GetVersion()
+    if version == expected_version:
+      info = self.log.CreateProgressInfo(
+            '---', 'Image is already expected versioin: '
+            + expected_version)
+      self.log.SendLine(self.test_info, info)
+      return True
+    self.time_stamp = self.ConfigACS(expected_version_id)
+    info = self.log.CreateProgressInfo(
+          '---', 'Successfully configured ACS for image version: '
+          + expected_version)
+    self.log.SendLine(self.test_info, info)
+
+    time.sleep(self.__short_delay)  # time delay for log update
+    self.time_stamp = self.GetTimeStamp()
+    if self.CheckImageInstallation(self.time_stamp, expected_version):
+      info = self.log.CreateProgressInfo(
+            '---', 'Image successfully upgraded to expected version: '
+            'from: ' + version + ' to: ' + expected_version)
+      self.log.SendLine(self.test_info, info)
+      return True
+    else:
+      info = self.log.CreateErrorInfo(
+          'critical',
+          'Error! Image version does not match expected version!')
+      self.log.SendLine(self.test_info, info)
+      return False
+
+  def VerifyDownloadInterrupt(self):
+    """Negative test case: verify image download interruption.
+
+    This case tests device's capability of image upgrade in case of
+    power loss, power cycle, or multiple download requests from ACS.
+    The device should finally be able to complete the download and
+    image upgrade process from expected_version to downgrade_version.
+
+    Returns:
+      return: False if the verification fails
+      return: True otherwise
+    """
+    self.CheckVersion()
+    if self.params['current_version'] != self.params['expected_version']:
+      info = self.log.CreateProgressInfo(
+          '5%', 'Current version is not expected version to test, upgrade to: '
+          + self.params['expected_version'])
+      self.log.SendLine(self.test_info, info)
+      if not self.ImageUpgrade(self.params['expected_version'],
+                               self.params['expected_version_id']):
+        info = self.log.CreateErrorInfo(
+            'critical',
+            'Failed to upgrade version to: '
+            + self.params['expected_version'])
+        self.log.SendLine(self.test_info, info)
+        return False
+    self.ConfigACS(self.params['downgrade_version_id'])
+    info = self.log.CreateProgressInfo(
+          '10%', 'Successfully configured ACS for image version: '
+          + self.params['downgrade_version'])
+    self.log.SendLine(self.test_info, info)
+
+    time.sleep(6*self.__short_delay)
+
+    info = self.log.CreateProgressInfo(
+          '40%', 'Download started, reboot the device.')
+    self.log.SendLine(self.test_info, info)
+    time_stamp = self.GetTimeStamp()
+    self.p_ssh.SendCmd('reboot')
+    self.p_ssh.GetCmdOutput()
+    while not self.IsRebooted(time_stamp):
+      self.p_ssh.Close()
+      time.sleep(self.__short_delay*3)
+      self.p_ssh.SshRetry()
+      info = self.log.CreateProgressInfo(
+          '60%', 'Downloading interrupted, waiting for device boot up.')
+      self.log.SendLine(self.test_info, info)
+
+    time_stamp = self.GetTimeStamp()
+    version = self.GetVersion()
+    if version != self.params['downgrade_version']:
+      count = 0
+      while not self.IsRebooted(time_stamp):
+        count += 1
+        if count*self.__short_delay > self.__long_delay:
+          info = self.log.CreateErrorInfo(
+              'critical',
+              'Error! Image downloading is not successful after interruption!')
+          self.log.SendLine(self.test_info, info)
+          info = self.log.CreateResultInfo(
+              'Failed',
+              'Image failed to upgraded to version: '
+              + self.params['downgrade_version'] + ' ('
+              + self.__long_delay + ' seconds) after interrupted.')
+          self.log.SendLine(self.test_info, info)
+          return False
+        time_stamp = self.GetTimeStamp()
+        info = self.log.CreateProgressInfo(
+          '80%', 'Waiting for downloading complete after interruption.')
+        self.log.SendLine(self.test_info, info)
+        time.sleep(self.__short_delay*5)
+
+    info = self.log.CreateProgressInfo(
+        '100%', 'Image successfully upgraded to version: '
+        + self.params['downgrade_version'] + ' after interrupted.')
+    self.log.SendLine(self.test_info, info)
+    info = self.log.CreateResultInfo(
+        'Pass', 'Image successfully upgraded to version: '
+        + self.params['downgrade_version'] + ' after interrupted.')
+    self.log.SendLine(self.test_info, info)
+    return True
+
+  def Run(self):
+    """Run the test case."""
+    ####### Add your code here -- BEGIN #######
+    print 'Test Started...'
+    self.Init()
+    self.p_ssh.SshRetry()
+    info = self.log.CreateProgressInfo(
+        '5%', 'SSH session to device successfully established!')
+    self.log.SendLine(self.test_info, info)
+
+    if self.test_info['testID'] == '11843140':
+      self.VerifyImageDownload()
+      info = self.log.CreateResultInfo(
+        '----', 'For file transfer test, refer to image download test result:'
+        ' testID: 11843140.')
+      self.log.SendLine(self.test_info, info)
+    elif self.test_info['testID'] == '14165036':
+      self.VerifyDownloadInterrupt()
+
     print 'Test Completed...'
     ####### Add your code here -- END   #######
 
@@ -366,4 +504,10 @@
 
 
 if __name__ == '__main__':
-  DownloadTest(testID='11843140', key_word='Download')
+  # Test cases defined in this file:
+  test_defined = ['11843140', '14165036', '14334001']
+  # To execute test cases that defined in config file:
+  test_to_execute = testCase.TestCase.FindTestCaseToExecute('config.cfg')
+  for test_id in test_to_execute:
+    if test_id in test_defined:
+      test = DownloadTest(testID=test_id)
diff --git a/logging.py b/logging.py
index da14edb..dd1654a 100755
--- a/logging.py
+++ b/logging.py
@@ -16,17 +16,13 @@
 
 
 import datetime
+import errno
+import os
 
 
 class Logging(object):
   """This Class collects and writes test information to log files."""
 
-  params = {'std_out': '1',
-            'f_result': 'result.log',
-            'f_error': 'error.log',
-            'f_progress': 'progress.log',
-            'delimiter': '\t'}
-
   def __init__(self, **kwargs):
     """initiate the logging instance.
 
@@ -36,15 +32,129 @@
       kwargs['f_progres']: file name for test progres
       kwargs['std_out']: by default, send a copy of the log info to stdout
     """
-    for s in ('f_result', 'f_error', 'f_progress', 'std_out'):
-      if s in kwargs:
-        self.params[s] = kwargs[s]
 
-    self.rst_file = open(self.params['f_result'], 'w')
-    self.err_file = open(self.params['f_error'], 'w')
-    self.prg_file = open(self.params['f_progress'], 'w')
+    self.params = {'std_out': '1',
+                   'f_result': 'result.log',
+                   'f_error': 'error.log',
+                   'f_progress': 'progress.log',
+                   'delimiter': '\t',
+                   'out_folder': 'log',
+                   'in_folder': 'data'}
+    for s in kwargs:
+      self.params[s] = kwargs[s]
+
+    try:
+      os.makedirs(self.params['out_folder'])
+    except OSError, e:
+      if e.errno != errno.EEXIST:
+        raise
+
+    now = datetime.datetime.now()
+    s_time = now.strftime('%Y-%m-%d_%H:%M:%S.%f')
+    for f_name in ['f_result', 'f_error', 'f_progress']:
+      name = self.ParseLogFileName(self.params[f_name], 'w', s_time)
+      if name:
+        self.params[f_name] = name
+      else:
+        print 'Error! Fail to create log File.'
+    self.rst_file = open(self.params['f_result'], 'w+')
+    self.err_file = open(self.params['f_error'], 'w+')
+    self.prg_file = open(self.params['f_progress'], 'w+')
     self.NewTestStart()
 
+  def CreateFile(self, f_name, access='r'):
+    """Create a file for read/write.
+
+    Args:
+      f_name: the file name that needs to be created
+      access: 'r': read, input file
+              'w': write, output file
+              'rw': read and write
+    Returns:
+      f_obj: return the file object
+             if not succeed, return False
+    """
+    f_obj = None
+    if access == 'r':
+      # for input file
+      try:
+        f_obj = open(f_name, 'r')
+      except IOError:
+        print 'Cannot open the input file, return'
+        return False
+    elif access == 'w':
+      # for input file
+      try:
+        os.makedirs(self.params['out_folder'])
+      except OSError, e:
+        if e.errno != errno.EEXIST:
+          print 'Cannot create folder! Return'
+          return False
+      full_path = self.ParseLogFileName(f_name, access)
+      if full_path:
+        try:
+          f_obj = open(full_path, 'w+')
+        except IOError:
+          print 'Cannot open the given file, return'
+          return False
+      else:
+        # Can not parse file name
+        print 'Cannot parse given file name'
+        return False
+    else:
+      # read-write file:
+      try:
+        f_obj = open(f_name, 'r')
+      except IOError:
+        print 'Cannot open the input file, return'
+        return False
+    return f_obj
+
+  def ParseLogFileName(self, f_name, access='r', time_stamp=None):
+    """Generate an uniq log file name for each test case instance.
+
+    Args:
+      f_name: file name
+      access: 'r': read mode
+              'w': write mode
+              'rw': read-write
+      time_stamp: the time tag used for file name
+                  if None, create a new tag using current time
+    Returns:
+      return the parsed file name
+    """
+    if not f_name:
+      f_name = 'logFile.log'
+    if not time_stamp:
+      now = datetime.datetime.now()
+      s_time = now.strftime('%Y-%m-%d_%H:%M:%S.%f')
+    else:
+      s_time = time_stamp
+
+    ls = f_name.split('.')
+    ext_name = ''
+    name = ''
+    if len(ls) == 1:
+      name = ls[0]
+    else:
+      ext_name = ls.pop(-1)
+      for s in ls:
+        name += (s+'.')
+      name = name.rstrip('.')
+
+    if not ext_name:
+      ext_name = 'log'
+    folder = None
+    if access == 'r':
+      folder = self.params['in_folder']
+    elif access == 'w':
+      folder = self.params['out_folder']
+    else:
+      folder = self.params['in_folder']
+    name = (folder + '/' + name + '_testID-' + self.params['testID']
+            + '_'+ s_time + '.' + ext_name)
+    return name
+
   def SendLineToResult(self, test_info, result_info):
     """Send test result (one-line) information to the result file.
 
@@ -56,7 +166,7 @@
     """
     now = datetime.datetime.now()
     if test_info is not None:
-      line = (now.strftime('%Y-%m-%d %H:%M') + self.params['delimiter']
+      line = (now.strftime('%Y-%m-%d %H:%M:%S.%f') + self.params['delimiter']
               + 'testID:' + test_info['testID']
               + self.params['delimiter'] + 'TestStartAt:'
               + test_info['start_time']
@@ -69,7 +179,8 @@
 
     if self.params['std_out'] > 0:
       print line
-    return self.rst_file.write(line)
+    self.rst_file.write(line)
+    self.rst_file.flush()
 
   def NewTestStart(self):
     """Mark the start of a new test in the file."""
@@ -91,7 +202,7 @@
     """
     now = datetime.datetime.now()
     if test_info is not None:
-      line = (now.strftime('%Y-%m-%d %H:%M') + self.params['delimiter']
+      line = (now.strftime('%Y-%m-%d %H:%M:%S.%f') + self.params['delimiter']
               + 'testID:' + test_info['testID'] + self.params['delimiter']
               + 'TestStartAt:' + test_info['start_time']
               + self.params['delimiter'] + 'Keyword:'
@@ -99,13 +210,14 @@
               + error_info['severity'] + self.params['delimiter']
               + error_info['note'] + '\n')
     else:
-      line = (now.strftime('%Y-%m-%d %H:%M') + self.params['delimiter'] +
+      line = (now.strftime('%Y-%m-%d %H:%M:%S.%f') + self.params['delimiter'] +
               error_info['severity'] + self.params['delimiter']
               + error_info['note'] + '\n')
 
     if self.params['std_out'] > 0:
       print line
-    return self.err_file.write(line)
+    self.err_file.write(line)
+    self.err_file.flush()
 
   def SendLineToProgress(self, test_info, progress_info):
     """Send test progress (one-line) information to the progress file.
@@ -119,20 +231,21 @@
     """
     now = datetime.datetime.now()
     if test_info is not None:
-      line = (now.strftime('%Y-%m-%d %H:%M') + self.params['delimiter']
+      line = (now.strftime('%Y-%m-%d %H:%M:%S.%f') + self.params['delimiter']
               + 'testID:' + test_info['testID'] + self.params['delimiter']
               + 'TestStartAt:'+ test_info['start_time']
               + self.params['delimiter'] + 'Keyword:' + test_info['key_word']
               + self.params['delimiter'] + progress_info['percent']
               + self.params['delimiter'] + progress_info['note'] + '\n')
     else:
-      line = (now.strftime('%Y-%m-%d %H:%M') + self.params['delimiter']
+      line = (now.strftime('%Y-%m-%d %H:%M:%S.%f') + self.params['delimiter']
               + progress_info['percent'] + self.params['delimiter']
               + progress_info['note'] + '\n')
 
     if self.params['std_out'] > 0:
       print line
-    return self.prg_file.write(line)
+    self.prg_file.write(line)
+    self.prg_file.flush()
 
   def SendLine(self, test_info, info):
     """Send test (one-line) information to the corresponding log file.
@@ -162,7 +275,7 @@
 
     Args:
       test_info: test case related info: testID, start_time, key_word, etc
-      info: test results/error/progress information (single line)
+      info: test results/error/progress information
             test_info could be "None" for class other than TestCase
     Returns:
       return 1 when succeed
diff --git a/ssh.py b/ssh.py
index e721058..7232542 100755
--- a/ssh.py
+++ b/ssh.py
@@ -54,9 +54,10 @@
       'bruno_prompt': '\(none\)#',
       'jump_server': 'jmp.googlefiber.net',
       'jump_prompt': None,
-      'athena_user': None,
-      'athena_pwd': None,
-      'athena_prompt': None}
+      'athena_user': 'lmeng',
+      'athena_pwd': 'changeme',
+      'athena_prompt': None,
+      'ssh_use_athena': False}
 
     self.tmp_file = tempfile.TemporaryFile(mode='w+t')
 
@@ -66,19 +67,13 @@
 
     for s in kwargs:
       self.params[s] = kwargs[s]
-
     #populate prompt on jump and athena server:
-    if self.params['athena_user'] is not 'None':
+    if self.params['athena_user']:
       self.params['jump_prompt'] = self.params['athena_user'] + '@jmp101.nuq1:'
       self.params['athena_prompt'] = ('[' + self.params['athena_user']
                                       + '@athenasrv3 ~]$')
 
-    if dev is not None:
-      # parameters used to open an ssh tunnel to this device
-      for s in ('user', 'addr', 'pwd', 'bruno_prompt', 'addr_ipv6'):
-        self.params[s] = kwargs[s]
-
-  def Setlogging(self, logging):
+  def SetLogging(self, logging):
     """Setup the logging file(s)."""
     self.log = logging
 
@@ -102,7 +97,7 @@
     p_ssh = pexpect.spawn('ssh '+self.params['user']+'@'+addr)
     i = p_ssh.expect(
         [ssh_newkey, 'password:', self.params['bruno_prompt'], pexpect.EOF,
-         '\(none\)#', 'gfibertv#', pexpect.TIMEOUT], 20)
+         '\(none\)#', 'gfibertv#', pexpect.TIMEOUT], self.__long_delay)
 
     while 1:
       if i == 0:
@@ -123,7 +118,7 @@
         if i == 5: self.params['bruno_prompt'] = 'gfibertv#'
         return True
       if i == 3 or i == 6:
-        print 'Key or connection timeout'
+        print 'ssh did not respond, or connection timeout'
         return False
       if i < 0 or i > 6:
         print 'Error, quit'
@@ -210,6 +205,7 @@
     Returns:
       return True upon success
     """
+    self.params['ssh_use_athena'] = True
     p_ssh = pexpect.spawn('ssh -a ' + self.params['jump_server'])
     print 'ssh -a jmp.googlefiber.net ...'
     #p_ssh.expect('lmeng@jmp101.nuq1:.*[\\$]')
@@ -294,7 +290,7 @@
             + str(delay) + ' seconds')
         self.log.SendLine(None, info)
         time.sleep(delay)
-        tunnel = self.SshFromAthena(set_key)
+        tunnel = self.SshFromAthena()
         retry += 1
 
       if retry >= max_retry:
@@ -309,11 +305,19 @@
         '---', 'ssh session to Device successfully established!')
     self.log.SendLine(None, info)
 
-  def SendCmd(self, cmd):
-    """Send a command to the Device over ssh tunnel."""
+  def SendCmd(self, cmd, delay=10):
+    """Send a command to the Device over ssh tunnel.
+
+    Args:
+      cmd: the shell command to execute
+      delay: time delay while waiting for shell prompt after command is
+             executed
+    Returns:
+      return True if send command succeeded
+    """
     self.p_ssh.sendline(cmd)
     i = self.p_ssh.expect(
-        [self.params['bruno_prompt'], pexpect.EOF, pexpect.TIMEOUT], 10)
+        [self.params['bruno_prompt'], pexpect.EOF, pexpect.TIMEOUT], delay)
 
     while 1:
       if i == 0:
@@ -323,13 +327,16 @@
         # prompt not returned
         info = self.log.CreateErrorInfo(
             'Warning', 'Device not responding to shell command or timeout.'
-            ' Connect after 3 seconds ...')
+            ' Connect after 10 seconds ...')
         self.log.SendLine(None, info)
-        time.sleep(3)
-        self.SshRetryFromAthena()
+        time.sleep(10)
+        if self.params['ssh_use_athena']:
+          self.SshRetryFromAthena()
+        else:
+          self.SshRetry()
         self.p_ssh.sendline(cmd)
         i = self.p_ssh.expect(
-            [self.params['bruno_prompt'], pexpect.EOF, pexpect.TIMEOUT], 5)
+            [self.params['bruno_prompt'], pexpect.EOF, pexpect.TIMEOUT], delay)
 
   def GetCmdOutput(self, buff_size=0):
     """Get lines from the command output of the device, in a bottom up manner.
@@ -375,18 +382,18 @@
   def Close(self):
     # exit the ssh tunnel
     self.p_ssh.sendline('exit')
-    i = self.expect([self.p_ssh.params['athena_prompt'],
-                     self.p_ssh.params['jump_prompt'],
-                     self.p_ssh.params['bruno_prompt'],
-                     pexpect.EOF, pexpect.TIMEOUT])
+    i = self.p_ssh.expect([self.params['athena_prompt'],
+                           self.params['jump_prompt'],
+                           self.params['bruno_prompt'],
+                           pexpect.EOF, pexpect.TIMEOUT])
     while 1:
       if i == 0:
         # now at athena server:
         self.p_ssh.sendline('exit')
-        i = self.expect([self.p_ssh.params['athena_prompt'],
-                         self.p_ssh.params['jump_prompt'],
-                         self.p_ssh.params['bruno_prompt'],
-                         pexpect.EOF, pexpect.TIMEOUT])
+        i = self.p_ssh.expect([self.params['athena_prompt'],
+                               self.params['jump_prompt'],
+                               self.params['bruno_prompt'],
+                               pexpect.EOF, pexpect.TIMEOUT])
       elif i == 1:
         # now at jump server:
         self.p_ssh.sendline('exit')
@@ -394,16 +401,15 @@
       elif i == 2:
         # now at bruno:
         self.p_ssh.sendline('exit')
-        i = self.expect([self.p_ssh.params['athena_prompt'],
-                         self.p_ssh.params['jump_prompt'],
-                         self.p_ssh.params['bruno_prompt'],
+        i = self.expect([self.params['athena_prompt'],
+                         self.params['jump_prompt'],
+                         self.params['bruno_prompt'],
                          pexpect.EOF, pexpect.TIMEOUT])
       elif i == 3 or i == 4:
         # time out:
-        print 'Timeout when closing the ssh tunnel!'
+        print 'Exit from Device.'
         break
       else:
-        print 'Error'
         break
 
   def __del__(self):
diff --git a/testCase.py b/testCase.py
index 2fee061..bd2932e 100755
--- a/testCase.py
+++ b/testCase.py
@@ -11,8 +11,11 @@
 __author__ = 'Lehan Meng (lmeng@google.com)'
 
 import datetime
+import json
 import logging
+import os
 import re
+
 import device
 
 
@@ -29,12 +32,13 @@
   placed in here.
   """
 
-  def __init__(self, **kwargs):
+  def __init__(self, ssh=None, **kwargs):
     """Initiate a test class instance.
 
     Args:
+      ssh: ssh tunnel to device
       kwargs['testID']: The assigned test ID on TCM
-      kwargs['title']: Title (section number) of the test case
+      kwargs['title']: Title (keyword) of the test case
       kwargs['start_time']: Start time of the test case (for statistic purpose)
       kwargs['key_word']: the label of the test case
       kwargs['description']: description if required
@@ -49,17 +53,165 @@
                       'configFile': 'config.cfg'}
     self.params = {}
 
-    for s in ('testID', 'title', 'start_time', 'key_word',
-              'description', 'configFile'):
-      if s in kwargs:
-        self.test_info[s] = kwargs[s]
+    for s in kwargs:
+      self.test_info[s] = kwargs[s]
 
     self.device = device.Device()
 
-    self.log = logging.Logging()
-    self.ParseConfig()
+    self.log = logging.Logging(testID=self.test_info['testID'])
+    self.ParseJSONConfigFile()
+    #self.ParseConfig()
+    if ssh:
+      self.p_ssh = ssh
+    else:
+      self.p_ssh = None
     self.Run()
 
+  @staticmethod
+  def FindTestCaseID(file_name):
+    """Parse the configuration file for test case.
+
+    Find test ids in the configuration file.
+    Args:
+      file_name: the configure file to parse
+    Returns:
+      return the test case ids that needs to run the test
+    """
+    test_id_list = []
+    cfg_file = open(file_name, 'r')
+    cfg_list = cfg_file.readlines()
+    for line in cfg_list:
+      s = line.strip().strip('\n')
+      m = re.match(r'testID\s*:\s*(\d*)\s*$', s)
+      if (m is not None) and not s.startswith('#'):
+        test_id_list.append(m.group(1))
+    cfg_file.close()
+    return test_id_list
+
+  @staticmethod
+  def FindTestCaseToExecute(file_name):
+    """Parse the configuration file for test case.
+
+    Find test ids in the configuration file.
+    Args:
+      file_name: the configure file to parse
+    Returns:
+      return the test case ids that needs to run the test
+    """
+    test_id_list = []
+    try:
+      cfg_file = open(file_name, 'r')
+    except IOError:
+      print 'Cannot open the input file, return'
+      return os.sys.exit(1)
+    data = json.load(cfg_file)
+    cfg_file.close()
+
+    for test_case in data.iterkeys():
+      for key in data[test_case].iterkeys():
+        if isinstance(data[test_case][key], list) and key == 'testID':
+          for i in range(0, len(data[test_case][key])):
+            test_id_list.append(data[test_case][key][i])
+    return test_id_list
+
+  def ConfigForThisTestCase(self, data):
+    """Match if the configuration data is for current test case.
+
+    Args:
+      data: configuration data
+    Returns:
+      True: if the data is for current test case
+      False: if otherwise
+    """
+    for key in data.iterkeys():
+      if key == 'testID':
+        if self.test_info['testID'] in data[key]:
+          return True
+        else:
+          return False
+    return False
+
+  def ParseJSONConfigFile(self):
+    """Parse the JSON format configuration file.
+
+    The sturcture of a JSON file is as follows:
+    File format: parameter_names: string_values (or lists of values)
+                 comment is defined in the comment tag (JSON does not support
+                 comment).
+     'Test_Case_Description' : {
+     'comment': ['comments'],
+     'testID': ['11843140', '111111', '222222'],
+     'user' : 'root',
+     'addr' : '192.168.1.4',
+     'addr_ipv6' : 'None',
+     'pwd' : 'google',
+     'bruno_prompt' : 'gfibertv#',
+     'title' : 'Download',
+     'expected_version_id': '716006',
+     'expected_version': 'bruno-koala-5',
+     'downgrade_version': 'bruno-koala-4',
+     'downgrade_version_id': '728001',
+     'acs_url' : 'https://gfiber-acs-staging.appspot.com/cwmp',
+     'jump_server' : 'jmp.googlefiber.net',
+     'athena_user' : 'your_uname',
+     'athena_pwd' : 'your_pwd'
+    }
+
+    Returns:
+      return True if configure file parsed successfully
+    """
+    try:
+      self.cfg_file = open(self.test_info['configFile'], 'r')
+    except IOError:
+      print 'Cannot open the input file, return'
+      return os.sys.exit(1)
+    data = json.load(self.cfg_file)
+    self.cfg_file.close()
+
+    test_id_matched = False
+    for test_case in data.iterkeys():
+      if not self.ConfigForThisTestCase(data[test_case]):
+        continue
+      for key in data[test_case].iterkeys():
+        if isinstance(data[test_case][key], (str, unicode)):
+          value = data[test_case][key]
+          if not value or value == 'None':
+            self.params[key] = None
+          else:
+            self.params[key] = value
+        elif isinstance(data[test_case][key], dict):
+          if (key == 'title' and
+              self.test_info['testID'] in data[test_case][key]):
+            self.params[key] = data[test_case][key][self.test_info['testID']]
+            self.test_info['key_word'] = self.params[key]
+          else:
+            self.params[key] = data[test_case][key]
+        elif isinstance(data[test_case][key], list):
+          if key == 'testID':
+            for i in range(0, len(data[test_case][key])):
+              test_id = data[test_case][key][i]
+              if str(self.test_info['testID']) == test_id:
+                test_id_matched = True
+          elif key == 'comment':
+            # do not process comment lines
+            continue
+          else:
+            self.params[key] = data[test_case][key]
+        else:
+          info = self.log.CreateErrorInfo(
+              'Low', 'Warning: Configuration Parameter type unknown '
+              'in file ' + self.test_info['configFile'] + ': '
+              + test_case + ':' + key)
+          self.log.SendLine(self.test_info, info)
+
+    if not test_id_matched:
+      info = self.log.CreateErrorInfo(
+          'Low', 'Warning: No configuration found for this test '
+          'case in file: ' + self.test_info['configFile'])
+      self.log.SendLine(self.test_info, info)
+      os.sys.exit(1)
+    return True
+
   def ParseConfig(self):
     """Parse the configuration file for test case.
 
@@ -85,11 +237,14 @@
       reuturn 1 if succeed
     """
     # dictionary for params
-    self.cfg_file = open(self.test_info['configFile'], 'r')
+    try:
+      self.cfg_file = open(self.test_info['configFile'], 'r')
+    except IOError:
+      print 'Cannot open the input file, return'
+      return os.sys.exit(1)
 
     cfg_list = self.cfg_file.readlines()
     test_id_matched = False
-
     for line in cfg_list:
       s = line.strip().strip('\n')
       m = re.match('testID: ' + str(self.test_info['testID']), s)
@@ -138,6 +293,7 @@
           'Low', 'Warning: No configuration found for this test case in file: '
           + self.test_info['configFile'])
       self.log.SendLine(self.test_info, info)
+      os.sys.exit(1)
     return True
 
   def AddConfigParams(self, par='par', value='value'):