VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/core/failurereason.py@ 61217

Last change on this file since 61217 was 61217, checked in by vboxsync, 9 years ago

testmanager: give reason to failures (quick hack, can do prettier later).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: failurereason.py 61217 2016-05-26 20:04:05Z vboxsync $
3
4"""
5Test Manager - Failure Reasons.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2015 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 61217 $"
30
31
32# Validation Kit imports.
33from testmanager.core.base import ModelDataBase, ModelLogicBase, TMExceptionBase
34from testmanager.core.useraccount import UserAccountLogic;
35
36
37
38class FailureReasonData(ModelDataBase):
39 """
40 Failure Reason Data.
41 """
42
43 ksIdAttr = 'idFailureReason';
44
45 ksParam_idFailureReason = 'FailureReasonData_idFailureReason'
46 ksParam_tsEffective = 'FailureReasonData_tsEffective'
47 ksParam_tsExpire = 'FailureReasonData_tsExpire'
48 ksParam_uidAuthor = 'FailureReasonData_uidAuthor'
49 ksParam_idFailureCategory = 'FailureReasonData_idFailureCategory'
50 ksParam_sShort = 'FailureReasonData_sShort'
51 ksParam_sFull = 'FailureReasonData_sFull'
52 ksParam_iTicket = 'FailureReasonData_iTicket'
53 ksParam_asUrls = 'FailureReasonData_asUrls'
54
55 kasAllowNullAttributes = [ 'idFailureReason', 'tsEffective', 'tsExpire',
56 'uidAuthor', 'iTicket', 'asUrls' ]
57
58 def __init__(self):
59 ModelDataBase.__init__(self);
60
61 #
62 # Initialize with defaults.
63 # See the database for explanations of each of these fields.
64 #
65
66 self.idFailureReason = None
67 self.tsEffective = None
68 self.tsExpire = None
69 self.uidAuthor = None
70 self.idFailureCategory = None
71 self.sShort = None
72 self.sFull = None
73 self.iTicket = None
74 self.asUrls = None
75
76 def initFromDbRow(self, aoRow):
77 """
78 Re-initializes the data with a row from a SELECT * FROM FailureReasons.
79
80 Returns self. Raises exception if the row is None or otherwise invalid.
81 """
82
83 if aoRow is None:
84 raise TMExceptionBase('Failure Reason not found.');
85
86 self.idFailureReason = aoRow[0]
87 self.tsEffective = aoRow[1]
88 self.tsExpire = aoRow[2]
89 self.uidAuthor = aoRow[3]
90 self.idFailureCategory = aoRow[4]
91 self.sShort = aoRow[5]
92 self.sFull = aoRow[6]
93 self.iTicket = aoRow[7]
94 self.asUrls = aoRow[8]
95
96 return self;
97
98
99class FailureReasonDataEx(FailureReasonData):
100 """
101 Failure Reason Data, extended version that includes the category.
102 """
103
104 def __init__(self):
105 FailureReasonData.__init__(self);
106 self.oCategory = None;
107 self.oAuthor = None;
108
109 def initFromDbRowEx(self, aoRow, oCategoryLogic, oUserAccountLogic):
110 """
111 Re-initializes the data with a row from a SELECT * FROM FailureReasons.
112
113 Returns self. Raises exception if the row is None or otherwise invalid.
114 """
115
116 self.initFromDbRow(aoRow);
117 self.oCategory = oCategoryLogic.cachedLookup(self.idFailureCategory);
118 self.oAuthor = oUserAccountLogic.cachedLookup(self.uidAuthor);
119
120 return self;
121
122
123class FailureReasonLogic(ModelLogicBase): # pylint: disable=R0903
124 """
125 Failure Reason logic.
126 """
127
128 def __init__(self, oDb):
129 ModelLogicBase.__init__(self, oDb)
130 self.ahCache = None;
131 self.oCategoryLogic = None;
132 self.oUserAccountLogic = None;
133
134 def fetchForListing(self, iStart, cMaxRows, tsNow):
135 """
136 Fetches Failure Category records.
137
138 Returns an array (list) of FailureReasonData items, empty list if none.
139 Raises exception on error.
140 """
141
142 if tsNow is None:
143 self._oDb.execute('SELECT *\n'
144 'FROM FailureReasons\n'
145 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
146 'ORDER BY idFailureReason DESC\n'
147 'LIMIT %s OFFSET %s\n'
148 , (cMaxRows, iStart,));
149 else:
150 self._oDb.execute('SELECT *\n'
151 'FROM FailureReasons\n'
152 'WHERE tsExpire > %s\n'
153 ' AND tsEffective <= %s\n'
154 'ORDER BY idFailureReason DESC\n'
155 'LIMIT %s OFFSET %s\n'
156 , (tsNow, tsNow, cMaxRows, iStart,));
157
158 aoRows = []
159 for aoRow in self._oDb.fetchAll():
160 aoRows.append(FailureReasonData().initFromDbRow(aoRow))
161 return aoRows
162
163 def fetchForCombo(self, sFirstEntry = 'Select a failure reason', tsEffective = None):
164 """
165 Gets the list of Failure Reasons for a combo box.
166 Returns an array of (value [idFailureReason], drop-down-name [sShort],
167 hover-text [sFull]) tuples.
168 """
169 if tsEffective is None:
170 self._oDb.execute('SELECT fr.idFailureReason, CONCAT(fc.sShort, \' / \', fr.sShort) as sComboText, fr.sFull\n'
171 'FROM FailureReasons fr,\n'
172 ' FailureCategories fc\n'
173 'WHERE fr.idFailureCategory = fc.idFailureCategory\n'
174 ' AND fr.tsExpire = \'infinity\'::TIMESTAMP\n'
175 ' AND fc.tsExpire = \'infinity\'::TIMESTAMP\n'
176 'ORDER BY sComboText')
177 else:
178 self._oDb.execute('SELECT fr.idFailureReason, CONCAT(fc.sShort, \' / \', fr.sShort) as sComboText, fr.sFull\n'
179 'FROM FailureReasons fr,\n'
180 ' FailureCategories fc\n'
181 'WHERE fr.idFailureCategory = fc.idFailureCategory\n'
182 ' AND fr.tsExpire > %s\n'
183 ' AND fr.tsEffective <= %s\n'
184 ' AND fc.tsExpire > %s\n'
185 ' AND fc.tsEffective <= %s\n'
186 'ORDER BY sComboText'
187 , (tsEffective, tsEffective, tsEffective, tsEffective));
188 aoRows = self._oDb.fetchAll();
189 return [(-1, sFirstEntry, '')] + aoRows;
190
191 def getById(self, idFailureReason):
192 """Get Failure Reason data by idFailureReason"""
193
194 self._oDb.execute('SELECT *\n'
195 'FROM FailureReasons\n'
196 'WHERE tsExpire = \'infinity\'::timestamp\n'
197 ' AND idFailureReason = %s;', (idFailureReason,))
198 aRows = self._oDb.fetchAll()
199 if len(aRows) not in (0, 1):
200 raise self._oDb.integrityException(
201 'Found more than one failure reasons with the same credentials. Database structure is corrupted.')
202 try:
203 return FailureReasonData().initFromDbRow(aRows[0])
204 except IndexError:
205 return None
206
207 def getIdsByCategory(self, idFailureCategory, tsEffective=None):
208 """
209 Gets the list of Failure Ressons IDs,
210 all the items belong to @param idFailureCategory
211 """
212 if tsEffective is None:
213 self._oDb.execute('SELECT idFailureReason\n'
214 'FROM FailureReasons\n'
215 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
216 ' AND idFailureCategory = %s\n'
217 'ORDER BY idFailureReason DESC'
218 , (idFailureCategory,))
219 else:
220 self._oDb.execute('SELECT idFailureReason\n'
221 'FROM FailureReasons\n'
222 'WHERE tsExpire > %s\n'
223 ' AND tsEffective <= %s\n'
224 ' AND idFailureCategory = %s\n'
225 'ORDER BY idFailureReason DESC'
226 , (tsEffective, tsEffective, idFailureCategory))
227 return self._oDb.fetchAll()
228
229 def getAll(self, tsEffective=None):
230 """
231 Gets the list of all Failure Reasons.
232 Returns an array of FailureReasonData instances.
233 """
234 if tsEffective is None:
235 self._oDb.execute('SELECT *\n'
236 'FROM FailureReasons\n'
237 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
238 'ORDER BY idFailureReason DESC')
239 else:
240 self._oDb.execute('SELECT *\n'
241 'FROM FailureReasons\n'
242 'WHERE tsExpire > %s\n'
243 ' AND tsEffective <= %s\n'
244 'ORDER BY idFailureReason DESC'
245 , (tsEffective, tsEffective))
246 aoRet = []
247 for aoRow in self._oDb.fetchAll():
248 aoRet.append(FailureReasonData().initFromDbRow(aoRow))
249 return aoRet
250
251 def addEntry(self, oFailureReasonData, uidAuthor, fCommit=True):
252 """Add record to database"""
253
254 # Check if record with the same sShort fiels is already exists
255 self._oDb.execute('SELECT *\n'
256 'FROM FailureReasons\n'
257 'WHERE tsExpire = \'infinity\'::TIMESTAMP\n'
258 ' AND sShort = %s\n',
259 (oFailureReasonData.sShort,))
260 if len(self._oDb.fetchAll()) != 0:
261 raise Exception('Record already exist')
262
263 # Add record
264 self._oDb.execute('INSERT INTO FailureReasons (\n'
265 ' uidAuthor, idFailureCategory,'
266 ' sShort, sFull, iTicket, asUrls'
267 ')\n'
268 'VALUES (%s, %s, %s, %s, %s, %s)',
269 (uidAuthor,
270 oFailureReasonData.idFailureCategory,
271 oFailureReasonData.sShort,
272 oFailureReasonData.sFull,
273 oFailureReasonData.iTicket,
274 oFailureReasonData.asUrls))
275 if fCommit:
276 self._oDb.commit()
277
278 return True
279
280 def remove(self, uidAuthor, idFailureReason, fNeedCommit=True):
281 """
282 Historize record
283 """
284 self._oDb.execute('UPDATE FailureReasons\n'
285 'SET tsExpire = CURRENT_TIMESTAMP,\n'
286 ' uidAuthor = %s\n'
287 'WHERE idFailureReason = %s\n'
288 ' AND tsExpire = \'infinity\'::TIMESTAMP\n',
289 (uidAuthor, idFailureReason))
290
291 # Also historize Black List records
292 self._oDb.execute('UPDATE BuildBlackList\n'
293 'SET tsExpire = CURRENT_TIMESTAMP,\n'
294 ' uidAuthor = %s\n'
295 'WHERE idFailureReason = %s\n'
296 ' AND tsExpire = \'infinity\'::TIMESTAMP\n',
297 (uidAuthor, idFailureReason))
298
299 if fNeedCommit:
300 self._oDb.commit()
301
302 return True
303
304 def editEntry(self, oFailureReasonData, uidAuthor, fCommit=True):
305 """Modify database record"""
306
307 # Check if record exists
308 oFailureReasonDataOld = self.getById(oFailureReasonData.idFailureReason)
309 if oFailureReasonDataOld is None:
310 raise TMExceptionBase(
311 'Failure Reason (id: %d) does not exist'
312 % oFailureReasonData.idFailureReason)
313
314 # Check if anything has been changed
315 if oFailureReasonData.isEqual(oFailureReasonDataOld):
316 return True
317
318 # Historize record
319 self.remove(
320 uidAuthor, oFailureReasonData.idFailureReason, fNeedCommit=False)
321
322
323 # Add new record (keeping its ID)
324 self._oDb.execute('INSERT INTO FailureReasons (\n'
325 ' idFailureReason,'
326 ' uidAuthor,'
327 ' idFailureCategory,'
328 ' sShort,'
329 ' sFull,'
330 ' iTicket,'
331 ' asUrls'
332 ')\n'
333 'VALUES (%s, %s, %s, %s, %s, %s, %s)',
334 (oFailureReasonData.idFailureReason,
335 uidAuthor,
336 oFailureReasonData.idFailureCategory,
337 oFailureReasonData.sShort,
338 oFailureReasonData.sFull,
339 oFailureReasonData.iTicket,
340 oFailureReasonData.asUrls
341 ))
342
343 if fCommit:
344 self._oDb.commit()
345
346 return True
347
348 def cachedLookup(self, idFailureReason):
349 """
350 Looks up the most recent FailureReasonDataEx object for uid idFailureReason
351 an object cache.
352
353 Returns a shared FailureReasonData object. None if not found.
354 Raises exception on DB error.
355 """
356 if self.ahCache is None:
357 self.ahCache = self._oDb.getCache('FailureReasonDataEx');
358 oEntry = self.ahCache.get(idFailureReason, None);
359 if oEntry is None:
360 self._oDb.execute('SELECT *\n'
361 'FROM FailureReasons\n'
362 'WHERE idFailureReason = %s\n'
363 ' AND tsExpire = \'infinity\'::TIMESTAMP\n'
364 , (idFailureReason, ));
365 if self._oDb.getRowCount() == 0:
366 # Maybe it was deleted, try get the last entry.
367 self._oDb.execute('SELECT *\n'
368 'FROM FailureReasons\n'
369 'WHERE idFailureReason = %s\n'
370 'ORDER BY tsExpire\n'
371 'LIMIT 1\n'
372 , (idFailureReason, ));
373 elif self._oDb.getRowCount() > 1:
374 raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idFailureReason));
375
376 if self._oDb.getRowCount() == 1:
377 if self.oCategoryLogic is None:
378 from testmanager.core.failurecategory import FailureCategoryLogic;
379 self.oCategoryLogic = FailureCategoryLogic(self._oDb);
380 if self.oUserAccountLogic is None:
381 self.oUserAccountLogic = UserAccountLogic(self._oDb);
382 oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic,
383 self.oUserAccountLogic);
384 self.ahCache[idFailureReason] = oEntry;
385 return oEntry;
386
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