blob: 73adf5e66f8c922c75ac8f5540b8dddd9e696553 [file] [log] [blame]
#!/usr/bin/python
# Copyright 2012 Google Inc. All Rights Reserved.
"""This test performs TR069 related DataModel verification.
This class extends the TestCase class, it does the following:
1. Configure/Verify Bruno with correct TR69 parameters:
- ACS URL
- Image Version
2. Verify Bruno has connection to ACS (IPv6/IPv4)
3. Set/Get TR69 data model parameters:
- getParameterNames()
- getParameterValues()
4. Data mode:
- Data Models for GVSB
- Data Models for TR098
- Data Models for MoCA
- Data Models for TR140
- Data Models for TR181
"""
__author__ = 'Lehan Meng (lmeng@google.com)'
import os
import re
import string
import time
import xml.etree.ElementTree as ET
import acs
import device
import ssh
import testCase
class DataModelTest(testCase.TestCase):
"""Class for TR69 DataModel and parameter verification test.
Configuration Parameters:
TBD
testID: 14187024
title =DataModel
req_file = 14187024-requirement.req
"""
def Init(self):
"""Initialte the test case."""
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)
self.bruno.dev_ssh = self.p_ssh
self.__short_delay = 30 #short delay: 5 seconds
self.__delay = 80 #medium delay: 180 seconds
self.__long_delay = 120 #long delay: 600 seconds
self.req_file = open(self.params['req_file'], 'r')
self.req_tr069_params = []
def TestEnvCheck(self):
"""Verify device configuration meets the test requirement."""
acs_url = self.bruno.GetACSUrl()
self.AddConfigParams('acs_url', acs_url)
current_version = self.bruno.getCurrentVersion()
if (not current_version
or current_version != self.params['expected_version']):
info = self.log.CreateErrorInfo(
'critical', 'Not expected image version. Expected: '
+ self.params['expected_version'] + ', Current: '
+ current_version)
self.log.SendLine(self.test_info, info)
else:
self.AddConfigParams('current_version', current_version)
def CheckRequirement(self, chk_list, req_list):
"""Check parameter names with parameters in requirement file.
This file will compare the parameters from Device and from requirement
File. The differences between the two will be written to the result log
file
Args:
chk_list: the list of parameters results returned by query
req_list: the list of parameters from requirement
Returns:
missing_list: the list of parameters that is missing from requirement
net_list: the list of parameters that are newly added but not in the
requirement
"""
missing_list = []
new_list = []
#check missing parameters from Requirement
for req_line in req_list:
verify = False
for chk_line in chk_list:
if req_line == chk_line:
verify = True
elif string.find(chk_line, req_line) == 0:
verify = True
if not verify:
missing_list.append(req_line)
#check newly added parameters to Requirement
for line in chk_list:
if req_list.count(line) < 1 and new_list.count(line) < 1:
new_list.append(line)
return (missing_list, new_list)
def SetParameterValues(self, param='', value=''):
"""Set parameter values on Device."""
nbi_path = self.params['nbi_client_path']
cmd = (nbi_path + ' --server /gns/project/apphosting/stubby/prod-appengine/'
'*/gfiber-acs-staging/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)
if 'FAILED' in call_result[0]:
self.nbi_result = []
else:
self.nbi_result = call_result
print call_result
def GetParameterValues(self, param=''):
"""Get parameter value(s) from the data model tree.
This method get value(s) of the designated parameter(s)
Args:
param: this is the parameter (path) that need to get value(s) from.
1. If this path ends with a dot '.', all parameters
under this path will be queried for values.
2. If this path does not end with a '.', the parameter
must be a leaf parameter which has a value.
Returns:
This method returns a list of parameter values and record them to file.
"""
nbi_path = self.params['nbi_client_path']
cmd = (nbi_path + ' --server /gns/project/apphosting/stubby/prod-appengine/'
'*/gfiber-acs-staging/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)
if 'FAILED' in call_result[0]:
self.nbi_result = []
else:
self.nbi_result = call_result
print call_result
return acs_instance.ParseParameterNames(call_result)
def GetParameterNamesFromDeviceLog(self, time_stamp, param=''):
"""Get TR069 data model parameters that are supported by current image."""
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()
log_list.reverse()
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:GetParameterValues>' in line:
# check the parameter query from nbi_client has been answered:
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 '</cwmp:GetParameterValuesResponse>' in line:
if param_list_start:
param_list_end = True
break
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)
if param_list.count(output) < 1:
param_list.append(output)
if (not param_list_start) or (not param_list_end):
return False
return param_list
def CreateElement(self, param_name, param_type, 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
Args:
param_name: the name of the parameter (Path)
param_type: the type of the parameter
param_value: the value of the parameter
Returns:
return the created element node
"""
e = ET.Element('parameter_value_struct')
name = ET.Element('name')
name.text = param_name
e.append(name)
value = ET.Element('value', type=param_type)
value.text = param_value
e.append(value)
test_value = ET.Element('test_value', type=param_type)
test_value.text = param_value
e.append(test_value)
return e
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 != []:
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 != []:
#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
if index >= len(self.device_log_result) or '<Name>' in line:
info = self.log.createErrorInfo(
'Critical', 'Mis-matching name-value pair in log file!')
self.log.sendLine(self.test_info, info)
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))
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()
return tree
def VerifyParameterValues(self, param=None):
"""Verify the designated parameter can be set with expected value.
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
"""
self.para_tree = self.ParseToElementTree()
self.SetParameterValues(param, 'none')
def GetRequirementFromFile(self):
"""Get TR69 data model parameters from requirement file.
The format of the requirement file is as follows:
1. Each line represents a data model parameter
2. If a parameter has indexed nodes, index numbers are replaced by {i}
###### Begin of File ######
Device.Bridging.
Device.Bridging.Bridge.{i}.
Device.Bridging.Bridge.{i}.Port.{i}.
Device.Bridging.Bridge.{i}.Port.{i}.Stats.
... ... ...
Device.DeviceInfo.Manufacturer
Device.DeviceInfo.ManufacturerOUI
X_GOOGLE-COM_GVSB.EpgSecondary
X_GOOGLE-COM_GVSB.GvsbChannelLineup
X_GOOGLE-COM_GVSB.GvsbKick
X_GOOGLE-COM_GVSB.GvsbServer
###### End of File ######
Returns:
return the requirement parameters in a list
"""
req_list = []
for line in self.req_file:
line = line.strip()
if req_list.count(line) < 1:
req_list.append(line)
return req_list
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 line is None:
# get time stamp from Device log file
self.p_ssh.SendCmd('dmesg | grep cwmpd:')
# search the last 30 lines in Device log for time information
latest_log_entry = 30
log_list = self.p_ssh.GetCmdOutput(latest_log_entry)
for line in log_list:
m = re.match('\\[[\s]*(\d*\\.\d{3})\\]', line)
if m is not None:
# 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 is not None:
# 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!')
self.log.SendLine(self.test_info, info)
#self.p_ssh.SshRetryFromAthena()
#info = self.log.CreateProgressInfo(
# '15%', '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(
'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 ...')
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()
if not chk_list:
info = self.log.CreateProgressInfo(
'40%', '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
while not chk_list:
time.sleep(self.__delay)
chk_list = self.GetParameterNamesFromDeviceLog(time_stamp)
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)
req_list = self.GetRequirementFromFile()
(mis_list, new_list) = self.CheckRequirement(chk_list, req_list)
mis_list.sort()
new_list.sort()
self.log.SendTestData(['############# Missing Parameters #############'])
self.log.SendTestData(mis_list)
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.')
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)
#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()
print 'Test Completed...'
####### Add your code here -- END #######
def Destructor(self):
self.p_ssh.Close()
if __name__ == '__main__':
test = DataModelTest(testID='14187024', key_word='DataModel')