1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
#!/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, integral, fractional):
self._pfwClient = pfwClient
self._paramPath = '/Test/test/q%d.%d' % (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 integral in range(0, 31):
for fractional in range (0, 31 - integral):
tester = FixedPointTester(pfw, integral, fractional)
tester.run()
|