VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/core/testcaseargs.py@ 106061

Last change on this file since 106061 was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: testcaseargs.py 106061 2024-09-16 14:03:52Z vboxsync $
3
4"""
5Test Manager - Test Case Arguments Variations.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2024 Oracle and/or its affiliates.
11
12This file is part of VirtualBox base platform packages, as
13available from https://www.virtualbox.org.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation, in version 3 of the
18License.
19
20This program is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, see <https://www.gnu.org/licenses>.
27
28The contents of this file may alternatively be used under the terms
29of the Common Development and Distribution License Version 1.0
30(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31in the VirtualBox distribution, in which case the provisions of the
32CDDL are applicable instead of those of the GPL.
33
34You may elect to license modified versions of this file under the
35terms and conditions of either the GPL or the CDDL or both.
36
37SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38"""
39__version__ = "$Revision: 106061 $"
40
41
42# Standard python imports.
43import unittest;
44import sys;
45
46# Validation Kit imports.
47from common import utils;
48from testmanager.core.base import ModelDataBase, ModelDataBaseTestCase, ModelLogicBase, TMExceptionBase, \
49 TMRowNotFound;
50from testmanager.core.testcase import TestCaseData, TestCaseDependencyLogic, TestCaseGlobalRsrcDepLogic;
51
52# Python 3 hacks:
53if sys.version_info[0] >= 3:
54 long = int; # pylint: disable=redefined-builtin,invalid-name
55
56
57class TestCaseArgsData(ModelDataBase):
58 """
59 Test case argument variation.
60 """
61
62 ksIdAttr = 'idTestCaseArgs';
63 ksIdGenAttr = 'idGenTestCaseArgs';
64
65 ksParam_idTestCase = 'TestCaseArgs_idTestCase';
66 ksParam_idTestCaseArgs = 'TestCaseArgs_idTestCaseArgs';
67 ksParam_tsEffective = 'TestCaseArgs_tsEffective';
68 ksParam_tsExpire = 'TestCaseArgs_tsExpire';
69 ksParam_uidAuthor = 'TestCaseArgs_uidAuthor';
70 ksParam_idGenTestCaseArgs = 'TestCaseArgs_idGenTestCaseArgs';
71 ksParam_sArgs = 'TestCaseArgs_sArgs';
72 ksParam_cSecTimeout = 'TestCaseArgs_cSecTimeout';
73 ksParam_sTestBoxReqExpr = 'TestCaseArgs_sTestBoxReqExpr';
74 ksParam_sBuildReqExpr = 'TestCaseArgs_sBuildReqExpr';
75 ksParam_cGangMembers = 'TestCaseArgs_cGangMembers';
76 ksParam_sSubName = 'TestCaseArgs_sSubName';
77
78 kcDbColumns = 12;
79
80 kasAllowNullAttributes = [ 'idTestCase', 'idTestCaseArgs', 'tsEffective', 'tsExpire', 'uidAuthor', 'idGenTestCaseArgs',
81 'cSecTimeout', 'sTestBoxReqExpr', 'sBuildReqExpr', 'sSubName', ];
82
83 def __init__(self):
84 ModelDataBase.__init__(self);
85
86 #
87 # Initialize with defaults.
88 # See the database for explanations of each of these fields.
89 #
90 self.idTestCase = None;
91 self.idTestCaseArgs = None;
92 self.tsEffective = None;
93 self.tsExpire = None;
94 self.uidAuthor = None;
95 self.idGenTestCaseArgs = None;
96 self.sArgs = '';
97 self.cSecTimeout = None;
98 self.sTestBoxReqExpr = None;
99 self.sBuildReqExpr = None;
100 self.cGangMembers = 1;
101 self.sSubName = None;
102
103 def initFromDbRow(self, aoRow):
104 """
105 Re-initializes the object from a SELECT * FROM TestCaseArgs row.
106 Returns self. Raises exception if aoRow is None.
107 """
108 if aoRow is None:
109 raise TMRowNotFound('TestBoxStatus not found.');
110
111 self.idTestCase = aoRow[0];
112 self.idTestCaseArgs = aoRow[1];
113 self.tsEffective = aoRow[2];
114 self.tsExpire = aoRow[3];
115 self.uidAuthor = aoRow[4];
116 self.idGenTestCaseArgs = aoRow[5];
117 self.sArgs = aoRow[6];
118 self.cSecTimeout = aoRow[7];
119 self.sTestBoxReqExpr = aoRow[8];
120 self.sBuildReqExpr = aoRow[9];
121 self.cGangMembers = aoRow[10];
122 self.sSubName = aoRow[11];
123 return self;
124
125 def initFromDbWithId(self, oDb, idTestCaseArgs, tsNow = None, sPeriodBack = None):
126 """
127 Initialize from the database.
128 """
129 oDb.execute(self.formatSimpleNowAndPeriodQuery(oDb,
130 'SELECT *\n'
131 'FROM TestCaseArgs\n'
132 'WHERE idTestCaseArgs = %s\n'
133 , ( idTestCaseArgs,), tsNow, sPeriodBack));
134 aoRow = oDb.fetchOne()
135 if aoRow is None:
136 raise TMRowNotFound('idTestCaseArgs=%s not found (tsNow=%s sPeriodBack=%s)'
137 % (idTestCaseArgs, tsNow, sPeriodBack,));
138 return self.initFromDbRow(aoRow);
139
140 def initFromDbWithGenId(self, oDb, idGenTestCaseArgs):
141 """
142 Initialize from the database, given the generation ID of a row.
143 """
144 oDb.execute('SELECT * FROM TestCaseArgs WHERE idGenTestCaseArgs = %s', (idGenTestCaseArgs,));
145 return self.initFromDbRow(oDb.fetchOne());
146
147 def initFromValues(self, sArgs, cSecTimeout = None, sTestBoxReqExpr = None, sBuildReqExpr = None, # pylint: disable=too-many-arguments
148 cGangMembers = 1, idTestCase = None, idTestCaseArgs = None, tsEffective = None, tsExpire = None,
149 uidAuthor = None, idGenTestCaseArgs = None, sSubName = None):
150 """
151 Reinitialize from values.
152 Returns self.
153 """
154 self.idTestCase = idTestCase;
155 self.idTestCaseArgs = idTestCaseArgs;
156 self.tsEffective = tsEffective;
157 self.tsExpire = tsExpire;
158 self.uidAuthor = uidAuthor;
159 self.idGenTestCaseArgs = idGenTestCaseArgs;
160 self.sArgs = sArgs;
161 self.cSecTimeout = utils.parseIntervalSeconds(cSecTimeout);
162 self.sTestBoxReqExpr = sTestBoxReqExpr;
163 self.sBuildReqExpr = sBuildReqExpr;
164 self.cGangMembers = cGangMembers;
165 self.sSubName = sSubName;
166 return self;
167
168 def getAttributeParamNullValues(self, sAttr):
169 aoNilValues = ModelDataBase.getAttributeParamNullValues(self, sAttr);
170 if sAttr == 'cSecTimeout':
171 aoNilValues.insert(0, ''); # Prettier NULL value for cSecTimeout.
172 elif sAttr == 'sArgs':
173 aoNilValues = []; # No NULL value here, thank you.
174 return aoNilValues;
175
176 def _validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb):
177 if sAttr == 'cSecTimeout' and oValue not in aoNilValues: # Allow human readable interval formats.
178 return utils.parseIntervalSeconds(oValue);
179
180 (oValue, sError) = ModelDataBase._validateAndConvertAttribute(self, sAttr, sParam, oValue, aoNilValues, fAllowNull, oDb);
181 if sError is None:
182 if sAttr == 'sTestBoxReqExpr':
183 sError = TestCaseData.validateTestBoxReqExpr(oValue);
184 elif sAttr == 'sBuildReqExpr':
185 sError = TestCaseData.validateBuildReqExpr(oValue);
186 return (oValue, sError);
187
188
189
190
191class TestCaseArgsDataEx(TestCaseArgsData):
192 """
193 Complete data set.
194 """
195
196 def __init__(self):
197 TestCaseArgsData.__init__(self);
198 self.oTestCase = None;
199 self.aoTestCasePreReqs = [];
200 self.aoGlobalRsrc = [];
201
202 def initFromDbRow(self, aoRow):
203 raise TMExceptionBase('Do not call me: %s' % (aoRow,))
204
205 def initFromDbRowEx(self, aoRow, oDb, tsConfigEff = None, tsRsrcEff = None):
206 """
207 Extended version of initFromDbRow that fills in the rest from the database.
208 """
209 TestCaseArgsData.initFromDbRow(self, aoRow);
210
211 if tsConfigEff is None: tsConfigEff = oDb.getCurrentTimestamp();
212 if tsRsrcEff is None: tsRsrcEff = oDb.getCurrentTimestamp();
213
214 self.oTestCase = TestCaseData().initFromDbWithId(oDb, self.idTestCase, tsConfigEff);
215 self.aoTestCasePreReqs = TestCaseDependencyLogic(oDb).getTestCaseDeps(self.idTestCase, tsConfigEff);
216 self.aoGlobalRsrc = TestCaseGlobalRsrcDepLogic(oDb).getTestCaseDeps(self.idTestCase, tsRsrcEff);
217
218 return self;
219
220 def initFromDbWithId(self, oDb, idTestCaseArgs, tsNow = None, sPeriodBack = None):
221 _ = oDb; _ = idTestCaseArgs; _ = tsNow; _ = sPeriodBack;
222 raise TMExceptionBase('Not supported.');
223
224 def initFromDbWithGenId(self, oDb, idGenTestCaseArgs):
225 _ = oDb; _ = idGenTestCaseArgs;
226 raise TMExceptionBase('Use initFromDbWithGenIdEx...');
227
228 def initFromDbWithGenIdEx(self, oDb, idGenTestCaseArgs, tsConfigEff = None, tsRsrcEff = None):
229 """
230 Initialize from the database, given the ID of a row.
231 """
232 oDb.execute('SELECT *, CURRENT_TIMESTAMP FROM TestCaseArgs WHERE idGenTestCaseArgs = %s', (idGenTestCaseArgs,));
233 aoRow = oDb.fetchOne();
234 return self.initFromDbRowEx(aoRow, oDb, tsConfigEff, tsRsrcEff);
235
236 def convertFromParamNull(self):
237 raise TMExceptionBase('Not implemented');
238
239 def convertToParamNull(self):
240 raise TMExceptionBase('Not implemented');
241
242 def isEqual(self, oOther):
243 raise TMExceptionBase('Not implemented');
244
245 def matchesTestBoxProps(self, oTestBoxData):
246 """
247 Checks if the all of the testbox related test requirements matches the
248 given testbox.
249
250 Returns True or False according to the expression, None on exception or
251 non-boolean expression result.
252 """
253 return TestCaseData.matchesTestBoxPropsEx(oTestBoxData, self.oTestCase.sTestBoxReqExpr) \
254 and TestCaseData.matchesTestBoxPropsEx(oTestBoxData, self.sTestBoxReqExpr);
255
256 def matchesBuildProps(self, oBuildDataEx):
257 """
258 Checks if the all of the build related test requirements matches the
259 given build.
260
261 Returns True or False according to the expression, None on exception or
262 non-boolean expression result.
263 """
264 return TestCaseData.matchesBuildPropsEx(oBuildDataEx, self.oTestCase.sBuildReqExpr) \
265 and TestCaseData.matchesBuildPropsEx(oBuildDataEx, self.sBuildReqExpr);
266
267
268class TestCaseArgsLogic(ModelLogicBase):
269 """
270 TestCaseArgs database logic.
271 """
272
273 def __init__(self, oDb):
274 ModelLogicBase.__init__(self, oDb);
275 self.dCache = None;
276
277
278 def areResourcesFree(self, oDataEx):
279 """
280 Checks if all global resources are currently still in existance and free.
281 Returns True/False. May raise exception on database error.
282 """
283
284 # Create a set of global resource IDs.
285 if not oDataEx.aoGlobalRsrc:
286 return True;
287 asIdRsrcs = [str(oDep.idGlobalRsrc) for oDep, _ in oDataEx.aoGlobalRsrc];
288
289 # A record in the resource status table means it's allocated.
290 self._oDb.execute('SELECT COUNT(*)\n'
291 'FROM GlobalResourceStatuses\n'
292 'WHERE GlobalResourceStatuses.idGlobalRsrc IN (' + ', '.join(asIdRsrcs) + ')\n');
293 if self._oDb.fetchOne()[0] == 0:
294 # Check for disabled or deleted resources (we cannot allocate them).
295 self._oDb.execute('SELECT COUNT(*)\n'
296 'FROM GlobalResources\n'
297 'WHERE GlobalResources.idGlobalRsrc IN (' + ', '.join(asIdRsrcs) + ')\n'
298 ' AND GlobalResources.tsExpire = \'infinity\'::TIMESTAMP\n'
299 ' AND GlobalResources.fEnabled = TRUE\n');
300 if self._oDb.fetchOne()[0] == len(oDataEx.aoGlobalRsrc):
301 return True;
302 return False;
303
304 def getAll(self):
305 """Get list of objects of type TestCaseArgsData"""
306 self._oDb.execute('SELECT *\n'
307 'FROM TestCaseArgs\n'
308 'WHERE tsExpire = \'infinity\'::TIMESTAMP')
309 aaoRows = self._oDb.fetchAll()
310 aoRet = []
311 for aoRow in aaoRows:
312 aoRet.append(TestCaseArgsData().initFromDbRow(aoRow))
313
314 return aoRet
315
316 def getTestCaseArgs(self, idTestCase, tsNow = None, aiWhiteList = None):
317 """Get list of testcase's arguments variations"""
318 if aiWhiteList is None:
319 if tsNow is None:
320 self._oDb.execute('SELECT *\n'
321 'FROM TestCaseArgs\n'
322 'WHERE idTestCase = %s\n'
323 ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
324 'ORDER BY TestCaseArgs.idTestCaseArgs\n'
325 , (idTestCase,));
326 else:
327 self._oDb.execute('SELECT *\n'
328 'FROM TestCaseArgs\n'
329 'WHERE idTestCase = %s\n'
330 ' AND tsExpire > %s\n'
331 ' AND tsEffective <= %s\n'
332 'ORDER BY TestCaseArgs.idTestCaseArgs\n'
333 , (idTestCase, tsNow, tsNow));
334 else:
335 sWhiteList = ','.join((str(x) for x in aiWhiteList));
336 if tsNow is None:
337 self._oDb.execute('SELECT *\n'
338 'FROM TestCaseArgs\n'
339 'WHERE idTestCase = %s\n'
340 ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
341 ' AND idTestCaseArgs IN (' + sWhiteList + ')\n'
342 'ORDER BY TestCaseArgs.idTestCaseArgs\n'
343 , (idTestCase,));
344 else:
345 self._oDb.execute('SELECT *\n'
346 'FROM TestCaseArgs\n'
347 'WHERE idTestCase = %s\n'
348 ' AND tsExpire > %s\n'
349 ' AND tsEffective <= %s\n'
350 ' AND idTestCaseArgs IN (' + sWhiteList + ')\n'
351 'ORDER BY TestCaseArgs.idTestCaseArgs\n'
352 , (idTestCase, tsNow, tsNow));
353
354 aaoRows = self._oDb.fetchAll()
355 aoRet = []
356 for aoRow in aaoRows:
357 aoRet.append(TestCaseArgsData().initFromDbRow(aoRow))
358
359 return aoRet
360
361 def addTestCaseArgs(self, oTestCaseArgsData):
362 """Add Test Case Args record into DB"""
363 pass; # pylint: disable=unnecessary-pass
364
365 def cachedLookup(self, idTestCaseArgs):
366 """
367 Looks up the most recent TestCaseArgsDataEx object for idTestCaseArg
368 via in an object cache.
369
370 Returns a shared TestCaseArgDataEx object. None if not found.
371 Raises exception on DB error.
372 """
373 if self.dCache is None:
374 self.dCache = self._oDb.getCache('TestCaseArgsDataEx');
375 oEntry = self.dCache.get(idTestCaseArgs, None);
376 if oEntry is None:
377 fNeedTsNow = False;
378 self._oDb.execute('SELECT *\n'
379 'FROM TestCaseArgs\n'
380 'WHERE idTestCaseArgs = %s\n'
381 ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
382 , (idTestCaseArgs, ));
383 if self._oDb.getRowCount() == 0:
384 # Maybe it was deleted, try get the last entry.
385 self._oDb.execute('SELECT *\n'
386 'FROM TestCaseArgs\n'
387 'WHERE idTestCaseArgs = %s\n'
388 'ORDER BY tsExpire DESC\n'
389 'LIMIT 1\n'
390 , (idTestCaseArgs, ));
391 fNeedTsNow = True;
392 elif self._oDb.getRowCount() > 1:
393 raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idTestCaseArgs));
394
395 if self._oDb.getRowCount() == 1:
396 aaoRow = self._oDb.fetchOne();
397 oEntry = TestCaseArgsDataEx();
398 tsNow = TestCaseArgsData().initFromDbRow(aaoRow).tsEffective if fNeedTsNow else None;
399 oEntry.initFromDbRowEx(aaoRow, self._oDb, tsNow, tsNow);
400 self.dCache[idTestCaseArgs] = oEntry;
401 return oEntry;
402
403
404#
405# Unit testing.
406#
407
408# pylint: disable=missing-docstring
409class TestCaseArgsDataTestCase(ModelDataBaseTestCase):
410 def setUp(self):
411 self.aoSamples = [TestCaseArgsData(),];
412
413if __name__ == '__main__':
414 unittest.main();
415 # not reached.
416
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette