blob: 475b2874edfae2da3463645599a3a0534325511b [file] [log] [blame]
#!/usr/bin/python
# Copyright 2012 Google Inc. All Rights Reserved.
"""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
"""
__author__ = 'Lehan Meng (lmeng@google.com)'
import os
import re
import time
import acs
import ssh
import testCase
class DownloadTest(testCase.TestCase):
"""Verify Bruno image download from ACS (TestID: 11843140).
Configuration Parameters:
testID: 11843140
user = root
addr = 10.0.28.191
pwd = google
bruno_prompt = (none)#
file=cmdOutput.txt
title =Image_Download
current_version=None
expected_version=bruno-iguana-2-dg
ACS_URL = https://gfiber-acs-staging.appspot.com/cwmp
"""
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)
self.__debug = False
self.__short_delay = 5 #short delay: 5 seconds
self.__delay = 180 #medium delay: 180 seconds
self.__long_delay = 600 #long delay: 600 seconds
def CheckACSUrl(self):
"""Check current ACS URL of the device.
Set it to a default URL if the current URL is not recognized
"""
self.p_ssh.SendCmd('cat /tmp/cwmp/acs_url')
line = self.p_ssh.GetCmdOutput()[1]
m_1 = re.match(self.params['ACS_URL'], line)
if m_1 is None:
info = self.log.CreateErrorInfo(
'intermediate',
'ACS URL unknown! Update ACS URL manually')
self.log.SendLine(self.test_info, info)
self.p_ssh.SendCmd('echo ' + self.params['ACS_URL']
+ ' > /tmp/cwmp/acs_url')
self.AddConfigParams('current_ACS_url', self.params['ACS_URL'])
else:
self.AddConfigParams('current_ACS_url', self.params['ACS_URL'])
def SetACSUrl(self, url='http://acs-sandbox.appspot.com/cwmp'):
"""Set ACS URL on the device."""
self.p_ssh.SendCmd('echo ' + url + ' > /tmp/cwmp/acs_url')
self.p_ssh.SendCmd('cat /tmp/cwmp/acs_url')
info = self.log.CreateProgressInfo('---', 'Set ACS url to: ' + url)
self.log.SendLine(self.test_info, info)
def CheckVersion(self):
"""Check current software version."""
self.p_ssh.SendCmd('more /etc/version')
current_version = self.p_ssh.GetCmdOutput(2)[1].strip()
self.params['current_version'] = current_version
def GetVersion(self):
"""Get current software version."""
self.p_ssh.SendCmd('more /etc/version')
return self.p_ssh.GetCmdOutput(2)[1].strip()
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
def ConfigACS(self):
"""Setup the ACS device profile with expected image.
Then restart the cwmpd process on device to
initiate the inform/download process
Returns:
return the time stamp string if succeed, return -1 otherwise.
"""
#configure ACS:
acs_instance = acs.ACS(self.params['expected_version_id'])
acs_instance.SetLogging(self.log)
acs_instance.SaveConfiguration()
#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
def GetRemoteConnectionURL(self):
"""Get remote connection URL from the cwmp log of the device."""
self.p_ssh.SendCmd('dmesg | grep cwmpd:')
log_list = self.p_ssh.GetCmdOutput()
for line in log_list:
if 'InternetGatewayDevice.ManagementServer.ConnectionRequestURL' in line:
index = log_list.index(line)
index -= 1
if index < 0:
# End of long while download not started, wait 281
info = self.log.createErrorInfo(
'low', 'Can not find ConnectionRequestURL from device log ...')
self.log.sendLine(self.test_info, info)
return None
log_str = log_list[index]
m = re.search('(http://[\d\l:]+)</Value>', log_str)
if m is not None:
# match successful:
return m.group(1)
# No ConnectionRequestURL find:
info = self.log.createErrorInfo(
'low', 'Can not find ConnectionRequestURL from device log ...')
self.log.sendLine(self.test_info, info)
return None
def CheckDownloadFileExists(self):
"""check if a downloaded file is still in the folder.
A file in the folder '/rw/tr69/dnld/' indicates either of the
following:
1. download is in progress
2. download completed, installation is in progress
3. download completed, installation completed, waiting for reboot
the upgrade is not considered as complete until a reboot is done
Returns:
return True if file exists, return False otherwise.
"""
self.p_ssh.SendCmd('ls -l /rw/tr69/dnld/')
latest_log_entry = 4
log_list = self.p_ssh.GetCmdOutput(latest_log_entry)
for line in log_list:
m = re.search(r'[\s]+([\w,\d]{9})', line)
if m is not None:
# download file found
return True
return False
def IsRebooted(self, time_stamp):
"""check if the device rebooted after the software installation.
This method checks device log file, if any event found with smaller time
stamp value than the last known device event, it indicates that the device
has been rebooted since then
Args:
time_stamp: time stamp that the last event recorded on device log
Returns:
return True if rebooted
return False otherwise
"""
s = self.GetTimeStamp()
if float(s) < float(time_stamp):
return True
return False
def CheckImageInstallation(self, time_stamp):
"""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
Returns:
return True if installation succeeded
return False otherwise
"""
self.p_ssh.ExitToAthena()
time.sleep(3*self.__short_delay)
self.p_ssh.SshRetryFromAthena()
count = 0
ts = time_stamp
while not self.IsRebooted(ts):
count +=1
if count*self.__short_delay*3 > self.__long_delay:
info = self.log.CreateErrorInfo(
'critical',
'Error! File download longer than ' + str(self.__long_delay)
+ ' seconds, check network. Exit!')
self.log.SendLine(self.test_info, info)
os.sys.exit(1)
t = self.GetTimeStamp()
if t > ts:
ts = t
self.p_ssh.ExitToAthena()
info = self.log.CreateProgressInfo(
'90%', 'Wait ' + str(3*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()
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']:
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)
max_test_idx = 2
current_test_idx = 1
while current_test_idx < max_test_idx:
self.p_ssh.SshRetryFromAthena()
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()
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: '
+ self.params['ACS_URL'])
self.log.SendLine(self.test_info, info)
self.CheckVersion()
info = self.log.CreateProgressInfo('30%', 'Current Version: '
+ self.params['current_version'])
self.log.SendLine(self.test_info, info)
# Need to do:
# check if the currently version is already expected version,
# if so, downgrade first, then Run this test
#if self.params['current_version'] == self.params['expected_version']:
# info = self.log.createErrorInfo(
# 'low', 'Currently image is expected version, '
# + 'please try other images.')
# self.log.sendLine(self.test_info, info)
self.time_stamp = self.ConfigACS()
info = self.log.CreateProgressInfo('40%', 'Expected Version: '
+ self.params['expected_version'])
self.log.SendLine(self.test_info, info)
info = self.log.CreateProgressInfo(
'40%', 'Successfully configured ACS for expected image version')
self.log.SendLine(self.test_info, info)
time.sleep(self.__short_delay) # time delay for log update
if self.CheckImageInstallation(self.time_stamp):
info = self.log.CreateProgressInfo(
'100%', 'Image successfully upgraded to expected version: '
'from: ' + self.params['current_version']
+ ' to: ' + self.params['expected_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'])
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)
current_test_idx += 1
self.p_ssh.ExitToAthena()
# Need to do:
# downgrade from expected_version
# To verify the capability of the download handling on expected version
# image
print 'Test Completed...'
####### Add your code here -- END #######
def Destructor(self):
"""This is the Destructor function to call for the user extened class."""
# exit the ssh tunnel
self.p_ssh.Close()
if __name__ == '__main__':
DownloadTest(testID='11843140', key_word='Download')