blob: 0f971b2512a13341cc51fbab90f78fe534d8406f [file] [log] [blame]
#!/usr/bin/python2.7
#
# Copyright (c) 2014, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import sys
import subprocess
from decimal import Decimal
class FixedPointTester():
""" Made for testing a particular Qn.m number
As a convention, we use:
* n is the fractional part
* m is the integral part
This class computes several specific numbers for a given Qn.m number.
For each of those numbers, we run 4 checks:
* Bound check
* Sanity check
* Consistency check
* Bijectivity check
Which are documented below.
"""
def __init__(self, pfwClient, size, integral, fractional):
self._pfwClient = pfwClient
self._paramPath = '/Test/test/%d/q%d.%d' % (size, integral, fractional)
# quantum is the step we have between two numbers
# encoded in Qn.m format
self._quantum = 2 ** -fractional
# The maximum value we can encode for a given Qn.m.
# Since we also need to encode the 0, we have one quantum missing on
# the positive maximum
self._upperAllowedBound = (2 ** integral) - self._quantum
# The minimum value that we can encode for a given Qn.m.
# This one does not need a quantum substraction since we already did
# that on the maximum
self._lowerAllowedBound = -(2 ** integral)
self._shouldWork = [
Decimal(0),
Decimal(self._lowerAllowedBound),
Decimal(self._upperAllowedBound)
]
# bigValue is to be sure a value far out of range is refused
bigValue = (2 * self._quantum)
# little is to be sure a value just out of range is refused
littleValue = 10 ** -fractional
self._shouldBreak = [
Decimal(self._lowerAllowedBound) - Decimal(bigValue),
Decimal(self._upperAllowedBound) + Decimal(bigValue),
Decimal(self._lowerAllowedBound) - Decimal(littleValue),
Decimal(self._upperAllowedBound) + Decimal(littleValue)
]
def run(self):
""" Runs the test suite for a given Qn.m number
"""
for value in self._shouldWork:
print('Testing %s for %s' % (value, self._paramPath))
value, success = self.checkBounds(value)
if not success:
print('Bound ERROR for %s' % self._paramPath)
continue
value, success = self.checkSanity(value)
if not success:
print('Sanity ERROR %s' % self._paramPath)
continue
value, success = self.checkConsistency(value)
if not success:
print('Consistency ERROR %s' % self._paramPath)
continue
value, success = self.checkBijectivity(value)
if not success:
print('Bijectivity ERROR %s' % self._paramPath)
continue
for value in self._shouldBreak:
print('Testing invalid value %s for %s' % (value, self._paramPath))
value, success = self.checkBounds(value)
if success:
print("ERROR: This test should have failed but it has not")
def checkBounds(self, valueToSet):
""" Checks if we are able to set valueToSet via the parameter-framework
valueToSet -- the value we are trying to set
returns: the value we are trying to set
returns: True if we are able to set, False otherwise
"""
returnCode = self._pfwClient.set(self._paramPath, str(valueToSet))
if returnCode != 0:
return (valueToSet, False)
return (valueToSet, True)
def checkSanity(self, valuePreviouslySet):
""" Checks if the value we get is still approximately the same
as we attempted to set. The value can have a slight round error which
is tolerated.
valuePreviouslySet -- the value we had previously set
returns: the value the parameter-framework returns us after the get
returns: True if we are able to set, False otherwise
"""
firstGet = self._pfwClient.get(self._paramPath)
try:
returnValue = Decimal(firstGet)
except ValueError:
print("ERROR: Can't convert %s to a decimal" % firstGet)
return firstGet, False
upperAllowedValue = Decimal(valuePreviouslySet) + (Decimal(self._quantum) / Decimal(2))
lowerAllowedValue = Decimal(valuePreviouslySet) - (Decimal(self._quantum) / Decimal(2))
if not (lowerAllowedValue <= returnValue <= upperAllowedValue):
print('%s <= %s <= %s is not true' %
(lowerAllowedValue, returnValue, upperAllowedValue))
return firstGet, False
return firstGet, True
def checkConsistency(self, valuePreviouslyGotten):
""" Checks if we are able to set the value that the parameter framework
just returned to us.
valuePreviouslyGotten -- the value we are trying to set
valueToSet -- the value we are trying to set
returns: True if we are able to set, False otherwise
"""
returnCode = pfw.set(self._paramPath, valuePreviouslyGotten)
if returnCode != 0:
return valuePreviouslyGotten, False
return valuePreviouslyGotten, True
def checkBijectivity(self, valuePreviouslySet):
""" Checks that the second get value is strictly equivalent to the
consistency set. This ensures that the parameter-framework behaves as
expected.
valuePreviouslySet -- the value we had previously set
returns: value the parameter-framework returns us after the second get
returns: True if we are able to set, False otherwise
"""
secondGet = pfw.get(self._paramPath)
if secondGet != valuePreviouslySet:
return secondGet, False
return secondGet, True
class PfwClient():
def __init__(self, configPath):
self._address = 'localhost'
self._port = '5066'
self._testPlatformPort = '5063'
self._pathToExec = 'remote-process_host'
self._configPath = configPath
def __enter__(self):
# launch test platform in deamon mode
subprocess.call(['test-platform_host', '-d', self._configPath, self._testPlatformPort])
subprocess.call([self._pathToExec, self._address, self._testPlatformPort, 'start'])
self._callCommand(['setTuningMode', 'on'])
return self
def __exit__(self, type, value, traceback):
subprocess.call([self._pathToExec, self._address, self._testPlatformPort, 'exit'])
def _callCommand(self, commandList):
shellCommand = [self._pathToExec, self._address, self._port]
shellCommand.extend(commandList)
# pipes are used to redirect the command output to a variable
subProc = subprocess.Popen(shellCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
commandOutPut, _ = subProc.communicate()
returnCode = subProc.returncode
return commandOutPut, returnCode
def set(self, parameter, value):
print('set %s <--- %s' % (parameter, value))
(returnValue, returnCode) = self._callCommand(['setParameter', parameter, value])
return returnCode
def get(self, parameter):
(returnValue, _) = self._callCommand(['getParameter', parameter])
print('get %s ---> %s' % (parameter, returnValue.strip()))
return returnValue.strip()
if __name__ == '__main__':
# It is necessary to add a ./ in front of the path, otherwise the parameter-framework
# does not recognize the string as a path.
configPath = './ParameterFrameworkConfiguration.xml'
with PfwClient(configPath) as pfw:
for size in [8, 16, 32]:
for integral in range(0, size):
for fractional in range (0, size - integral):
tester = FixedPointTester(pfw, size, integral, fractional)
tester.run()