Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1from flask_login import UserMixin 

2#from flask import current_app 

3from werkzeug.security import generate_password_hash, check_password_hash 

4from datetime import datetime 

5from app import app, db, login_manager 

6import uuid 

7import re 

8import json 

9from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION 

10 

11# 

12# Handling sclalchemy dialects 

13# 

14dialect = re.search(r'(?<=\()\w+', str(db.get_engine()).lower()) 

15# binary fields 

16if dialect.group() == 'mysql': 

17 from sqlalchemy.dialects.mysql import BINARY 

18else: 

19 BINARY = db.LargeBinary 

20# double precision 

21if dialect and dialect.group() == 'postgresql': 

22 from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION 

23else: 

24 DOUBLE_PRECISION = db.Float 

25 

26 

27# 

28# UUID as bytes 

29# 

30def uuidAsBytes(): 

31 return uuid.uuid4().bytes 

32 

33# 

34# user Model 

35# TODO: extend user Model 

36# 

37class User(UserMixin, db.Model): 

38 __tablename__ = 'users' 

39 id = db.Column(db.Integer, primary_key=True) 

40 username = db.Column(db.String(64), unique=True, nullable=False) 

41 password = db.Column(db.String(128), nullable=False) 

42 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

43 lastlogin = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

44 

45 def __str__(self): 

46 return self.username 

47 

48 def set_password(self, password): 

49 self.password = generate_password_hash(password) 

50 

51 def verify_password(self, password): 

52 return check_password_hash(self.password, password) 

53 

54@login_manager.user_loader 

55def load_user(id): 

56 return User.query.get(int(id)) 

57 

58# 

59# relation tables 

60# 

61 

62testrun_casesequence = db.Table( 

63 'testrun_casesequence', 

64 db.Column('testrun_id', BINARY(16), db.ForeignKey('testruns.id'), primary_key=True), 

65 db.Column('testcase_sequence_id', BINARY(16), db.ForeignKey('testcase_sequences.id'), primary_key=True) 

66) 

67 

68testcase_sequence_datafile = db.Table( 

69 'testcase_sequence_datafile', 

70 db.Column('testcase_sequence_id', BINARY(16), db.ForeignKey('testcase_sequences.id'), primary_key=True), 

71 db.Column('datafile_id', BINARY(16), db.ForeignKey('datafiles.id'), primary_key=True) 

72) 

73 

74testcase_sequence_case = db.Table( 

75 'testcase_sequence_case', 

76 db.Column('testcase_sequence_id', BINARY(16), db.ForeignKey('testcase_sequences.id'), primary_key=True), 

77 db.Column('testcase_id', BINARY(16), db.ForeignKey('testcases.id'), primary_key=True) 

78) 

79 

80testcase_stepsequence = db.Table( 

81 'testcase_stepsequence', 

82 db.Column('testcase_id', BINARY(16), db.ForeignKey('testcases.id'), primary_key=True), 

83 db.Column('teststep_sequence_id', BINARY(16), db.ForeignKey('teststep_sequences.id'), primary_key=True) 

84) 

85 

86 

87# 

88# main entities 

89# 

90class Testrun(db.Model): 

91 # 

92 # Testrun object 

93 # 

94 

95 __tablename__ = 'testruns' 

96 

97 # fields 

98 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

99 name = db.Column(db.String(64), nullable=False) 

100 description = db.Column(db.String(512), nullable=False) 

101 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

102 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

103 edited = db.Column(db.DateTime, nullable=True) 

104 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

105 

106 # globals 

107 global_settings = db.Column(db.String(2048), nullable=True) 

108 

109 # realshinships 

110 creator = db.relationship( 

111 'User', 

112 backref=db.backref('created_testruns', order_by='desc(Testrun.created)'), 

113 lazy='select', 

114 foreign_keys=[creator_id], 

115 ) 

116 editor = db.relationship('User', backref='edited_testruns', lazy='select', foreign_keys=[editor_id]) 

117 

118 @property 

119 def uuid(self): 

120 return str(uuid.UUID(bytes=self.id)) 

121 

122 def __str__(self): 

123 return self.name 

124 

125 def __repr__(self): 

126 return f'<Testrun: {self.uuid}>' 

127 

128 def finished_calls(self, stage=None): 

129 if stage == 'None': 

130 return [call for call in self.calls if (call.is_finished and call.stage == None)] 

131 if stage: 

132 return [call for call in self.calls if (call.is_finished and call.stage == stage)] 

133 

134 return [call for call in self.calls if call.is_finished] 

135 

136 

137 def to_json(self): 

138 # 

139 # returns item as JSON 

140 # 

141 

142 return { 

143 'name': self.name, 

144 'testrun': { 

145 'GC.KWARGS_TESTRUNATTRIBUTES': { 

146 'GC.EXPORT_FORMAT': { 

147 'GC.EXPORT_FORMAT': None, 

148 'GC.EXP_FIELDLIST': [], 

149 }, 

150 'GC.STRUCTURE_TESTCASESEQUENCE': { 

151 i+1: self.testcase_sequences[i].to_json(i+1) for i in range(len(self.testcase_sequences)) 

152 }, 

153 } 

154 }, 

155 'globals' : json.loads(self.global_settings) if self.global_settings else None, 

156 } 

157 

158 def get_status(self): 

159 # 

160 # check for item completeness 

161 # returns tuple: (status, message) 

162 # 

163 

164 # check for TestCaseSequences 

165 if len(self.testcase_sequences) == 0: 

166 return False, f'Testrun {self} does not contain TestCaseSequences' 

167 

168 # iterate TestCaseSequences 

169 for items in self.testcase_sequences: 

170 status, message = items.get_status() 

171 if not status: 

172 return status, message 

173 

174 return True, 'OK' 

175 

176 

177class TestCaseSequence(db.Model): 

178 # 

179 # TestCse Sequence object 

180 # 

181 

182 __tablename__ = 'testcase_sequences' 

183 

184 # fields 

185 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

186 name = db.Column(db.String(64), nullable=False) 

187 description = db.Column(db.String(512), nullable=False) 

188 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

189 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

190 edited = db.Column(db.DateTime, nullable=True) 

191 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

192 classname_id = db.Column(db.Integer, db.ForeignKey('classnames.id'), nullable=False) 

193 

194 # relashionships 

195 creator = db.relationship('User', backref='created_testcase_sequences', lazy='select', foreign_keys=[creator_id]) 

196 editor = db.relationship('User', backref='edited_testcase_sequences', lazy='select', foreign_keys=[editor_id]) 

197 classname = db.relationship('ClassName', backref='testcase_sequences', lazy='select', foreign_keys=[classname_id]) 

198 testrun = db.relationship( 

199 'Testrun', 

200 secondary=testrun_casesequence, 

201 lazy='select', 

202 backref=db.backref('testcase_sequences', order_by='TestCaseSequence.created', lazy=True), 

203 ) 

204 

205 @property 

206 def uuid(self): 

207 return str(uuid.UUID(bytes=self.id)) 

208 

209 def __str__(self): 

210 return self.name 

211 

212 def __repr__(self): 

213 return f'<TestCaseSequence: {self.uuid}>' 

214 

215 def to_json(self, TestCaseSequenceNumber=1): 

216 # 

217 # returns item as JSON 

218 # 

219 

220 # get name of DataFile 

221 if len(self.datafiles) > 0: 

222 TestDataFileName = self.datafiles[0].uuid 

223 TestDataSheetName = self.datafiles[0].sheet 

224 else: 

225 TestDataFileName = TestDataSheetName = None 

226 return [ 

227 self.classname.name, 

228 { 

229 'SequenceClass': self.classname.name, 

230 'GC.DATABASE_FILENAME': TestDataFileName, 

231 'GC.DATABASE_SHEETNAME': TestDataSheetName, 

232 'GC.EXECUTION_PARALLEL': 1, 

233 'GC.DATABASE_LINES': '0-999999', 

234 'GC.STRUCTURE_TESTCASE': { 

235 i+1: self.testcases[i].to_json( 

236 TestCaseSequenceNumber, 

237 i+1, 

238 ) for i in range(len(self.testcases)) 

239 }, 

240 } 

241 ] 

242 

243 def get_status(self): 

244 # 

245 # check for item completeness 

246 # returns tuple: (status, message) 

247 # 

248 

249 # check for DataFiles 

250 if len(self.datafiles) == 0: 

251 return False, f'TestCaseSequence {self} does not contain DataFiles' 

252 

253 # check for TestCases 

254 if len(self.testcases) == 0: 

255 return False, f'TestCaseSequence {self} does not contain TestCases' 

256 

257 # iterate TestCases 

258 for items in self.testcases: 

259 status, message = items.get_status() 

260 if not status: 

261 return status, message 

262 

263 return True, 'OK' 

264 

265 

266class DataFile(db.Model): 

267 # 

268 # DataFile object 

269 # 

270 

271 __tablename__ = 'datafiles' 

272 

273 # fields 

274 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

275 filename = db.Column(db.String(64), nullable=False) 

276 sheet = db.Column(db.String(32), nullable=False, default='data') 

277 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

278 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

279 

280 # relationships 

281 creator = db.relationship('User', backref='created_datafiles', lazy='select', foreign_keys=[creator_id]) 

282 testcase_sequence = db.relationship( 

283 'TestCaseSequence', 

284 secondary=testcase_sequence_datafile, 

285 lazy='select', 

286 backref=db.backref('datafiles', lazy=True), 

287 ) 

288 

289 @property 

290 def uuid(self): 

291 return str(uuid.UUID(bytes=self.id)) 

292 

293 @property 

294 def url(self): 

295 return '/'.join(( 

296 'http:/', 

297 app.config.get('BAANGT_DATAFILE_HOST'), 

298 app.config.get('BAANGT_DATAFILE_GET'), 

299 self.uuid, 

300 )) 

301 

302 

303 def __str__(self): 

304 return self.filename 

305 

306 def __repr__(self): 

307 return f'<DataFile: {self.uuid}>' 

308 

309 

310class TestCase(db.Model): 

311 # 

312 # testCase object 

313 # 

314 

315 __tablename__ = 'testcases' 

316 

317 # fields 

318 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

319 name = db.Column(db.String(64), nullable=False) 

320 description = db.Column(db.String(512), nullable=False) 

321 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

322 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

323 edited = db.Column(db.DateTime, nullable=True) 

324 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

325 classname_id = db.Column(db.Integer, db.ForeignKey('classnames.id'), nullable=False) 

326 browser_type_id = db.Column(db.Integer, db.ForeignKey('browser_types.id'), nullable=False) 

327 testcase_type_id = db.Column(db.Integer, db.ForeignKey('testcase_types.id'), nullable=False) 

328 

329 # realshionshipd 

330 creator = db.relationship('User', backref='created_testcases', lazy='select', foreign_keys=[creator_id]) 

331 editor = db.relationship('User', backref='edited_testcases', lazy='select', foreign_keys=[editor_id]) 

332 classname = db.relationship('ClassName', backref='testcases', lazy='select', foreign_keys=[classname_id]) 

333 browser_type = db.relationship('BrowserType', backref='testcases', lazy='select', foreign_keys=[browser_type_id]) 

334 testcase_type = db.relationship('TestCaseType', backref='testcases', lazy='select', foreign_keys=[testcase_type_id]) 

335 testcase_sequence = db.relationship( 

336 'TestCaseSequence', 

337 secondary=testcase_sequence_case, 

338 lazy='select', 

339 backref=db.backref('testcases', order_by='TestCase.created', lazy=True), 

340 ) 

341 

342 @property 

343 def uuid(self): 

344 return str(uuid.UUID(bytes=self.id)) 

345 

346 def __str__(self): 

347 return self.name 

348 

349 def __repr__(self): 

350 return f'<TestCase: {self.uuid}>' 

351 

352 def to_json(self, TestCaseSequenceNumber=1, TestCaseNumber=1): 

353 # 

354 # returns item as JSON 

355 # 

356 

357 return [ 

358 self.classname.name, 

359 { 

360 'GC.KWARGS_TESTCASETYPE': self.testcase_type.name, 

361 'GC.KWARGS_BROWSER': self.browser_type.name, 

362 'GC.BROWSER_ATTRIBUTES': '', 

363 }, 

364 { 

365 'GC.STRUCTURE_TESTSTEP': { 

366 i+1: self.teststep_sequences[i].to_json( 

367 TestCaseSequenceNumber, 

368 TestCaseNumber, 

369 i+1, 

370 ) for i in range(len(self.teststep_sequences)) 

371 }, 

372 } 

373 ] 

374 

375 def get_status(self): 

376 # 

377 # check for item completeness 

378 # returns tuple: (status, message) 

379 # 

380 

381 # check for TestStepSequences 

382 if len(self.teststep_sequences) == 0: 

383 return False, f'TestCase {self} does not contain TestStepSequences' 

384 

385 # iterate TestStepSequence 

386 for items in self.teststep_sequences: 

387 status, message = items.get_status() 

388 if not status: 

389 return status, message 

390 

391 return True, 'OK' 

392 

393 

394class TestStepSequence(db.Model): 

395 # 

396 # TestStep Sequence object 

397 # 

398 

399 __tablename__ = 'teststep_sequences' 

400 

401 # fields 

402 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

403 name = db.Column(db.String(64), nullable=False) 

404 description = db.Column(db.String(512), nullable=False) 

405 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

406 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

407 edited = db.Column(db.DateTime, nullable=True) 

408 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

409 classname_id = db.Column(db.Integer, db.ForeignKey('classnames.id'), nullable=False) 

410 

411 # relashionship 

412 creator = db.relationship('User', backref='created_teststep_sequences', lazy='select', foreign_keys=[creator_id]) 

413 editor = db.relationship('User', backref='edited_teststep_sequences', lazy='select', foreign_keys=[editor_id]) 

414 classname = db.relationship('ClassName', backref='teststep_sequences', lazy='select', foreign_keys=[classname_id]) 

415 testcase = db.relationship( 

416 'TestCase', 

417 secondary=testcase_stepsequence, 

418 lazy='select', 

419 backref=db.backref('teststep_sequences', order_by='TestStepSequence.created', lazy=True), 

420 ) 

421 

422 @property 

423 def uuid(self): 

424 return str(uuid.UUID(bytes=self.id)) 

425 

426 def __str__(self): 

427 return self.name 

428 

429 def __repr__(self): 

430 return f'<TestStepSequence: {self.uuid}>' 

431 

432 def to_json(self, TestCaseSequenceNumber=1, TestCaseNumber=1, TestStepNumber=1): 

433 # 

434 # returns item as JSON 

435 # 

436 

437 return [ 

438 { 

439 'TestStepClass': self.classname.name, 

440 }, 

441 { 

442 'GC.STRUCTURE_TESTSTEPEXECUTION': { 

443 i+1: self.teststeps[i].to_json( 

444 TestCaseSequenceNumber, 

445 TestCaseNumber, 

446 TestStepNumber, 

447 i+1, 

448 ) for i in range(len(self.teststeps)) 

449 } 

450 }, 

451 ] 

452 

453 def get_status(self): 

454 # 

455 # check for item completeness 

456 # returns tuple: (status, message) 

457 # 

458 

459 # check for TestSteps 

460 if len(self.teststeps) == 0: 

461 return False, f'TestStepSequence {self} does not contain TestSteps' 

462 

463 return True, 'OK' 

464 

465 

466class TestStepExecution(db.Model): 

467 # 

468 # TestStep object 

469 # 

470 __tablename__ = 'teststep_executions' 

471 

472 # fields 

473 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

474 name = db.Column(db.String(64), nullable=False) 

475 description = db.Column(db.String(512), nullable=False) 

476 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

477 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

478 edited = db.Column(db.DateTime, nullable=True) 

479 locator = db.Column(db.String(512), nullable=True) 

480 optional = db.Column(db.Boolean, nullable=False, default=False) 

481 # sa dialect 

482 timeout = db.Column(DOUBLE_PRECISION(precision='5,2'), nullable=True) 

483 release = db.Column(db.String(64), nullable=True) 

484 value = db.Column(db.String(1024), nullable=True) 

485 value2 = db.Column(db.String(1024), nullable=True) 

486 comparison = db.Column(db.String(16), nullable=True) 

487 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

488 activity_type_id = db.Column(db.Integer, db.ForeignKey('activity_types.id'), nullable=False) 

489 locator_type_id = db.Column(db.Integer, db.ForeignKey('locator_types.id'), nullable=True) 

490 teststep_sequence_id = db.Column(BINARY(16), db.ForeignKey('teststep_sequences.id'), nullable=True) 

491 

492 # relashionships 

493 creator = db.relationship('User', backref='created_teststeps', lazy='select', foreign_keys=[creator_id]) 

494 editor = db.relationship('User', backref='edited_teststeps', lazy='select', foreign_keys=[editor_id]) 

495 activity_type = db.relationship('ActivityType', backref='teststeps', lazy='select', foreign_keys=[activity_type_id]) 

496 locator_type = db.relationship('LocatorType', backref='teststeps', lazy='select', foreign_keys=[locator_type_id]) 

497 teststep_sequence = db.relationship( 

498 'TestStepSequence', 

499 backref=db.backref('teststeps', order_by='TestStepExecution.created'), 

500 lazy='select', 

501 foreign_keys=[teststep_sequence_id], 

502 ) 

503 

504 @property 

505 def uuid(self): 

506 return str(uuid.UUID(bytes=self.id)) 

507 

508 def __str__(self): 

509 return self.name 

510 

511 def __repr__(self): 

512 return f'<TestStepExecution: {self.uuid}>' 

513 

514 def to_json(self, TestCaseSequenceNumber=1, TestCaseNumber=1, TestStepNumber=1, TestStepExecutionNumber=1): 

515 # 

516 # returns item as JSON 

517 # 

518 

519 # set LocatorType name 

520 #locator_type = '' 

521 #if self.locator_type: 

522 # locator_type = self.locator_type.name 

523 

524 return { 

525 'Activity': self.activity_type.name, 

526 'LocatorType': self.locator_type.name if self.locator_type else '', 

527 'Locator': self.locator or '', 

528 'Value': self.value or '', 

529 'Comparison': self.comparison or '', 

530 'Value2': self.value2 or '', 

531 'Timeout': self.timeout or '', 

532 'Optional': self.optional or '', 

533 'Release': self.release or '', 

534 } 

535 

536# 

537# supporting entities 

538# 

539class GlobalTestStepExecution(db.Model): 

540 __tablename__ = 'global_teststep_executions' 

541 id = db.Column(BINARY(16), primary_key=True, default=uuidAsBytes) 

542 name = db.Column(db.String(64), nullable=False) 

543 description = db.Column(db.String(512), nullable=False) 

544 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

545 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

546 edited = db.Column(db.DateTime, nullable=True) 

547 editor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) 

548 activity_type_id = db.Column(db.Integer, db.ForeignKey('activity_types.id'), nullable=False) 

549 locator_type_id = db.Column(db.Integer, db.ForeignKey('locator_types.id'), nullable=False) 

550 teststep_sequence_id = db.Column(BINARY(16), db.ForeignKey('teststep_sequences.id'), nullable=True) 

551 

552 # relationships 

553 creator = db.relationship('User', backref='created_global_teststeps', lazy='select', foreign_keys=[creator_id]) 

554 editor = db.relationship('User', backref='edited_global_teststeps', lazy='select', foreign_keys=[editor_id]) 

555 activity_type = db.relationship('ActivityType', backref='global_teststeps', lazy='select', foreign_keys=[activity_type_id]) 

556 locator_type = db.relationship('LocatorType', backref='global_teststeps', lazy='select', foreign_keys=[locator_type_id]) 

557 teststep_sequence = db.relationship('TestStepSequence', backref='global_teststeps', lazy='select', foreign_keys=[teststep_sequence_id]) 

558 

559 @property 

560 def uuid(self): 

561 return str(uuid.UUID(bytes=self.id)) 

562 

563 def __str__(self): 

564 return self.name 

565 

566 

567class ClassName(db.Model): 

568 __tablename__ = 'classnames' 

569 id = db.Column(db.Integer, primary_key=True) 

570 name = db.Column(db.String(64), nullable=False) 

571 description = db.Column(db.String(512), nullable=False) 

572 

573 def __str__(self): 

574 return self.name 

575 

576class BrowserType(db.Model): 

577 __tablename__ = 'browser_types' 

578 id = db.Column(db.Integer, primary_key=True) 

579 name = db.Column(db.String(64), nullable=False) 

580 description = db.Column(db.String(512), nullable=False) 

581 

582 def __str__(self): 

583 return self.name 

584 

585class TestCaseType(db.Model): 

586 __tablename__ = 'testcase_types' 

587 id = db.Column(db.Integer, primary_key=True) 

588 name = db.Column(db.String(64), nullable=False) 

589 description = db.Column(db.String(512), nullable=False) 

590 

591 def __str__(self): 

592 return self.name 

593 

594class ActivityType(db.Model): 

595 __tablename__ = 'activity_types' 

596 id = db.Column(db.Integer, primary_key=True) 

597 name = db.Column(db.String(64), nullable=False) 

598 description = db.Column(db.String(512), nullable=False) 

599 

600 def __str__(self): 

601 return self.name 

602 

603class LocatorType(db.Model): 

604 __tablename__ = 'locator_types' 

605 id = db.Column(db.Integer, primary_key=True) 

606 name = db.Column(db.String(64), nullable=False) 

607 description = db.Column(db.String(512), nullable=False) 

608 

609 def __str__(self): 

610 return self.name 

611 

612 

613# 

614# Testrun results 

615# 

616 

617class TestRunCall(db.Model): 

618 __tablename__ = 'testrun_calls' 

619 id = db.Column(BINARY(16), primary_key=True) 

620 created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) 

621 creator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) 

622 testrun_id = db.Column(BINARY(16), db.ForeignKey('testruns.id'), nullable=False) 

623 

624 # relationships 

625 creator = db.relationship('User', backref='testruns_called', lazy='select', foreign_keys=[creator_id]) 

626 testrun = db.relationship( 

627 'Testrun', 

628 backref=db.backref('calls', order_by='TestRunCall.created'), 

629 lazy='select', 

630 foreign_keys=[testrun_id], 

631 ) 

632 

633 # Testrun call faild 

634 is_failed = db.Column(db.Boolean, nullable=False, default=False) 

635 error_message = db.Column(db.String(512), nullable=True) 

636 

637 # summary 

638 is_finished = db.Column(db.Boolean, nullable=False, default=False) 

639 testrecords = db.Column(db.Integer, nullable=True) 

640 successful = db.Column(db.Integer, nullable=True) 

641 error = db.Column(db.Integer, nullable=True) 

642 paused = db.Column(db.Integer, nullable=True) 

643 duration = db.Column(db.Integer, nullable=True) 

644 stage = db.Column(db.String(32), nullable=True) 

645 

646 def __str__(self): 

647 return str(uuid.UUID(bytes=self.id)) 

648