def test__masterDeactivated(self): yield self.master.db.insertTestData([ fakedb.Master(id=22, active=0), fakedb.Scheduler(id=13, name='some:scheduler'), fakedb.SchedulerMaster(schedulerid=13, masterid=22), fakedb.Scheduler(id=14, name='other:scheduler'), fakedb.SchedulerMaster(schedulerid=14, masterid=22), ]) yield self.rtype._masterDeactivated(22) self.master.db.schedulers.assertSchedulerMaster(13, None) self.master.db.schedulers.assertSchedulerMaster(14, None)
def setUp(self): self.setUpEndpoint() self.db.insertTestData([ fakedb.Master(id=22, active=0), fakedb.Master(id=33, active=1), fakedb.Scheduler(id=13, name='some:scheduler'), fakedb.SchedulerMaster(schedulerid=13, masterid=None), fakedb.Scheduler(id=14, name='other:scheduler'), fakedb.SchedulerMaster(schedulerid=14, masterid=22), fakedb.Scheduler(id=15, name='another:scheduler'), fakedb.SchedulerMaster(schedulerid=15, masterid=33), ])
def test_pruneChanges(self): yield self.insertTestData([ fakedb.Scheduler(id=29), fakedb.SourceStamp(id=234, branch='aa'), fakedb.SourceStamp(id=235, branch='bb'), fakedb.Change(changeid=11), fakedb.Change(changeid=12, sourcestampid=234), fakedb.SchedulerChange(schedulerid=29, changeid=12), ] + self.change13_rows + [ fakedb.SchedulerChange(schedulerid=29, changeid=13), ] + self.change14_rows + [ fakedb.SchedulerChange(schedulerid=29, changeid=14), fakedb.Change(changeid=15, sourcestampid=235), ] ) # pruning with a horizon of 2 should delete changes 11, 12 and 13 yield self.db.changes.pruneChanges(2) def thd(conn): results = {} for tbl_name in ('scheduler_changes', 'change_files', 'change_properties', 'changes'): tbl = self.db.model.metadata.tables[tbl_name] res = conn.execute(sa.select([tbl.c.changeid])) results[tbl_name] = sorted( [row[0] for row in res.fetchall()]) self.assertEqual(results, { 'scheduler_changes': [14], 'change_files': [14], 'change_properties': [], 'changes': [14, 15], }) yield self.db.pool.do(thd)
def test_schedulerEnable(self): SOMETIME = 1348971992 yield self.master.db.insertTestData([ fakedb.Master(id=22, active=0, last_active=SOMETIME), fakedb.Scheduler(id=13, name='some:scheduler'), fakedb.SchedulerMaster(schedulerid=13, masterid=22), ]) yield self.rtype.schedulerEnable(13, False) self.master.mq.assertProductions( [(('schedulers', '13', 'updated'), {'enabled': False, 'master': {'active': False, 'last_active': epoch2datetime(SOMETIME), 'masterid': 22, 'name': 'some:master'}, 'name': 'some:scheduler', 'schedulerid': 13})]) yield self.rtype.schedulerEnable(13, True) self.master.mq.assertProductions( [(('schedulers', '13', 'updated'), {'enabled': True, 'master': {'active': False, 'last_active': epoch2datetime(SOMETIME), 'masterid': 22, 'name': 'some:master'}, 'name': 'some:scheduler', 'schedulerid': 13})])
def test_setMasterState_false_deletes_links(self): yield self.insertTestData([ fakedb.Master(id=7, name='some:master', active=1, last_active=OTHERTIME), fakedb.Scheduler(id=21), fakedb.SchedulerMaster(schedulerid=21, masterid=7), ]) deactivated = yield self.db.masters.setMasterState(masterid=7, active=False) self.assertTrue(deactivated) # check that the scheduler_masters row was deleted def thd(conn): tbl = self.db.model.scheduler_masters self.assertEqual(conn.execute(tbl.select()).fetchall(), []) yield self.db.pool.do(thd)
def attachScheduler(self, scheduler, objectid, schedulerid, overrideBuildsetMethods=False, createBuilderDB=False): """Set up a scheduler with a fake master and db; sets self.sched, and sets the master's basedir to the absolute path of 'basedir' in the test directory. If C{overrideBuildsetMethods} is true, then all of the addBuildsetForXxx methods are overridden to simply append the method name and arguments to self.addBuildsetCalls. These overridden methods return buildsets starting with 500 and buildrequest IDs starting with 100. For C{addBuildsetForSourceStamp}, this also overrides DB API methods C{addSourceStamp} and C{addSourceStampSet}, and uses that information to generate C{addBuildsetForSourceStamp} results. @returns: scheduler """ scheduler.objectid = objectid # set up a fake master db = self.db = self.master.db self.mq = self.master.mq scheduler.setServiceParent(self.master) rows = [ fakedb.Object(id=objectid, name=scheduler.name, class_name='SomeScheduler'), fakedb.Scheduler(id=schedulerid, name=scheduler.name), ] if createBuilderDB is True: rows.extend([ fakedb.Builder(name=bname) for bname in scheduler.builderNames ]) db.insertTestData(rows) if overrideBuildsetMethods: for method in ('addBuildsetForSourceStampsWithDefaults', 'addBuildsetForChanges', 'addBuildsetForSourceStamps'): actual = getattr(scheduler, method) fake = getattr(self, 'fake_{}'.format(method)) self.assertArgSpecMatches(actual, fake) setattr(scheduler, method, fake) self.addBuildsetCalls = [] self._bsidGenerator = iter(range(500, 999)) self._bridGenerator = iter(range(100, 999)) # temporarily override the sourcestamp and sourcestampset methods self.addedSourceStamps = [] self.addedSourceStampSets = [] def fake_addSourceStamp(**kwargs): self.assertEqual(kwargs['sourcestampsetid'], 400 + len(self.addedSourceStampSets) - 1) self.addedSourceStamps.append(kwargs) return defer.succeed(300 + len(self.addedSourceStamps) - 1) self.db.sourcestamps.addSourceStamp = fake_addSourceStamp def fake_addSourceStampSet(): self.addedSourceStampSets.append([]) return defer.succeed(400 + len(self.addedSourceStampSets) - 1) self.db.sourcestamps.addSourceStampSet = fake_addSourceStampSet # patch methods to detect a failure to upcall the activate and # deactivate methods .. unless we're testing BaseScheduler def patch(meth): oldMethod = getattr(scheduler, meth) @defer.inlineCallbacks def newMethod(): self._parentMethodCalled = False rv = yield oldMethod() self.assertTrue(self._parentMethodCalled, "'{}' did not call its parent".format(meth)) return rv setattr(scheduler, meth, newMethod) oldParent = getattr(base.BaseScheduler, meth) def newParent(self_): self._parentMethodCalled = True return oldParent(self_) self.patch(base.BaseScheduler, meth, newParent) if scheduler.__class__.activate != base.BaseScheduler.activate: patch('activate') if scheduler.__class__.deactivate != base.BaseScheduler.deactivate: patch('deactivate') self.sched = scheduler return scheduler
class Tests(interfaces.InterfaceTests): # test data ss92 = fakedb.SourceStamp(id=92) change3 = fakedb.Change(changeid=3) change4 = fakedb.Change(changeid=4) change5 = fakedb.Change(changeid=5) change6 = fakedb.Change(changeid=6, branch='sql') scheduler24 = fakedb.Scheduler(id=24, name='schname') master13 = fakedb.Master(id=13, name='m1', active=1) scheduler24master = fakedb.SchedulerMaster(schedulerid=24, masterid=13) scheduler25 = fakedb.Scheduler(id=25, name='schname2') master14 = fakedb.Master(id=14, name='m2', active=0) scheduler25master = fakedb.SchedulerMaster(schedulerid=25, masterid=14) # tests def test_signature_enable(self): @self.assertArgSpecMatches(self.db.schedulers.enable) def enable(self, schedulerid, v): pass @defer.inlineCallbacks def test_enable(self): yield self.insertTestData([self.scheduler24, self.master13, self.scheduler24master]) sch = yield self.db.schedulers.getScheduler(24) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=24, name='schname', enabled=True, masterid=13)) yield self.db.schedulers.enable(24, False) sch = yield self.db.schedulers.getScheduler(24) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=24, name='schname', enabled=False, masterid=13)) yield self.db.schedulers.enable(24, True) sch = yield self.db.schedulers.getScheduler(24) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=24, name='schname', enabled=True, masterid=13)) def test_signature_classifyChanges(self): @self.assertArgSpecMatches(self.db.schedulers.classifyChanges) def classifyChanges(self, schedulerid, classifications): pass @defer.inlineCallbacks def test_classifyChanges(self): yield self.insertTestData([self.ss92, self.change3, self.change4, self.scheduler24]) yield self.db.schedulers.classifyChanges(24, {3: False, 4: True}) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {3: False, 4: True}) @defer.inlineCallbacks def test_classifyChanges_again(self): # test reclassifying changes, which may happen during some timing # conditions. It's important that this test uses multiple changes, # only one of which already exists yield self.insertTestData([ self.ss92, self.change3, self.change4, self.change5, self.change6, self.scheduler24, fakedb.SchedulerChange(schedulerid=24, changeid=5, important=0), ]) yield self.db.schedulers.classifyChanges( 24, {3: True, 4: False, 5: True, 6: False}) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {3: True, 4: False, 5: True, 6: False}) def test_signature_flushChangeClassifications(self): @self.assertArgSpecMatches( self.db.schedulers.flushChangeClassifications) def flushChangeClassifications(self, schedulerid, less_than=None): pass @defer.inlineCallbacks def test_flushChangeClassifications(self): yield self.insertTestData([self.ss92, self.change3, self.change4, self.change5, self.scheduler24]) yield self.addClassifications(24, (3, 1), (4, 0), (5, 1)) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {3: True, 4: False, 5: True}) yield self.db.schedulers.flushChangeClassifications(24) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {}) @defer.inlineCallbacks def test_flushChangeClassifications_less_than(self): yield self.insertTestData([self.ss92, self.change3, self.change4, self.change5, self.scheduler24]) yield self.addClassifications(24, (3, 1), (4, 0), (5, 1)) yield self.db.schedulers.flushChangeClassifications(24, less_than=5) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {5: True}) def test_signature_getChangeClassifications(self): @self.assertArgSpecMatches(self.db.schedulers.getChangeClassifications) def getChangeClassifications(self, schedulerid, branch=-1, repository=-1, project=-1, codebase=-1): pass @defer.inlineCallbacks def test_getChangeClassifications(self): yield self.insertTestData([self.ss92, self.change3, self.change4, self.change5, self.change6, self.scheduler24]) yield self.addClassifications(24, (3, 1), (4, 0), (5, 1), (6, 1)) res = yield self.db.schedulers.getChangeClassifications(24) self.assertEqual(res, {3: True, 4: False, 5: True, 6: True}) @defer.inlineCallbacks def test_getChangeClassifications_branch(self): yield self.insertTestData([self.ss92, self.change3, self.change4, self.change5, self.change6, self.scheduler24]) yield self.addClassifications(24, (3, 1), (4, 0), (5, 1), (6, 1)) res = yield self.db.schedulers.getChangeClassifications(24, branch='sql') self.assertEqual(res, {6: True}) def test_signature_findSchedulerId(self): @self.assertArgSpecMatches(self.db.schedulers.findSchedulerId) def findSchedulerId(self, name): pass @defer.inlineCallbacks def test_findSchedulerId_new(self): id = yield self.db.schedulers.findSchedulerId('schname') sch = yield self.db.schedulers.getScheduler(id) self.assertEqual(sch['name'], 'schname') @defer.inlineCallbacks def test_findSchedulerId_existing(self): id = yield self.db.schedulers.findSchedulerId('schname') id2 = yield self.db.schedulers.findSchedulerId('schname') self.assertEqual(id, id2) def test_signature_setSchedulerMaster(self): @self.assertArgSpecMatches(self.db.schedulers.setSchedulerMaster) def setSchedulerMaster(self, schedulerid, masterid): pass @defer.inlineCallbacks def test_setSchedulerMaster_fresh(self): yield self.insertTestData([self.scheduler24, self.master13]) yield self.db.schedulers.setSchedulerMaster(24, 13) sch = yield self.db.schedulers.getScheduler(24) self.assertEqual(sch['masterid'], 13) @defer.inlineCallbacks def test_setSchedulerMaster_inactive_but_linked(self): d = self.insertTestData([ self.master13, self.scheduler25, self.master14, self.scheduler25master, ]) d.addCallback(lambda _: self.db.schedulers.setSchedulerMaster(25, 13)) yield self.assertFailure(d, schedulers.SchedulerAlreadyClaimedError) @defer.inlineCallbacks def test_setSchedulerMaster_inactive_but_linked_to_this_master(self): yield self.insertTestData([ self.scheduler25, self.master14, self.scheduler25master, ]) yield self.db.schedulers.setSchedulerMaster(25, 14) @defer.inlineCallbacks def test_setSchedulerMaster_active(self): d = self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, ]) d.addCallback(lambda _: self.db.schedulers.setSchedulerMaster(24, 14)) yield self.assertFailure(d, schedulers.SchedulerAlreadyClaimedError) @defer.inlineCallbacks def test_setSchedulerMaster_None(self): yield self.insertTestData([ self.scheduler25, self.master14, self.scheduler25master, ]) yield self.db.schedulers.setSchedulerMaster(25, None) sch = yield self.db.schedulers.getScheduler(25) self.assertEqual(sch['masterid'], None) @defer.inlineCallbacks def test_setSchedulerMaster_None_unowned(self): yield self.insertTestData([self.scheduler25]) yield self.db.schedulers.setSchedulerMaster(25, None) sch = yield self.db.schedulers.getScheduler(25) self.assertEqual(sch['masterid'], None) def test_signature_getScheduler(self): @self.assertArgSpecMatches(self.db.schedulers.getScheduler) def getScheduler(self, schedulerid): pass @defer.inlineCallbacks def test_getScheduler(self): yield self.insertTestData([self.scheduler24]) sch = yield self.db.schedulers.getScheduler(24) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=24, name='schname', enabled=True, masterid=None)) @defer.inlineCallbacks def test_getScheduler_missing(self): sch = yield self.db.schedulers.getScheduler(24) self.assertEqual(sch, None) @defer.inlineCallbacks def test_getScheduler_active(self): yield self.insertTestData([self.scheduler24, self.master13, self.scheduler24master]) sch = yield self.db.schedulers.getScheduler(24) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=24, name='schname', enabled=True, masterid=13)) @defer.inlineCallbacks def test_getScheduler_inactive_but_linked(self): yield self.insertTestData([self.scheduler25, self.master14, self.scheduler25master]) sch = yield self.db.schedulers.getScheduler(25) validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sch, dict( id=25, name='schname2', enabled=True, masterid=14)) # row exists, but marked inactive def test_signature_getSchedulers(self): @self.assertArgSpecMatches(self.db.schedulers.getSchedulers) def getSchedulers(self, active=None, masterid=None): pass @defer.inlineCallbacks def test_getSchedulers(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25, ]) def schKey(sch): return sch['id'] schlist = yield self.db.schedulers.getSchedulers() for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist, key=schKey), sorted([ dict(id=24, name='schname', enabled=True, masterid=13), dict(id=25, name='schname2', enabled=True, masterid=None), ], key=schKey)) @defer.inlineCallbacks def test_getSchedulers_masterid(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25, ]) schlist = yield self.db.schedulers.getSchedulers(masterid=13) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), sorted([ dict(id=24, name='schname', enabled=True, masterid=13), ])) @defer.inlineCallbacks def test_getSchedulers_active(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25 ]) schlist = yield self.db.schedulers.getSchedulers(active=True) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), sorted([ dict(id=24, name='schname', enabled=True, masterid=13), ])) @defer.inlineCallbacks def test_getSchedulers_active_masterid(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25 ]) schlist = yield self.db.schedulers.getSchedulers( active=True, masterid=13) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), sorted([ dict(id=24, name='schname', enabled=True, masterid=13), ])) schlist = yield self.db.schedulers.getSchedulers( active=True, masterid=14) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), []) @defer.inlineCallbacks def test_getSchedulers_inactive(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25 ]) schlist = yield self.db.schedulers.getSchedulers(active=False) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), sorted([ dict(id=25, name='schname2', enabled=True, masterid=None), ])) @defer.inlineCallbacks def test_getSchedulers_inactive_masterid(self): yield self.insertTestData([ self.scheduler24, self.master13, self.scheduler24master, self.scheduler25 ]) schlist = yield self.db.schedulers.getSchedulers( active=False, masterid=13) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), []) schlist = yield self.db.schedulers.getSchedulers( active=False, masterid=14) for sch in schlist: validation.verifyDbDict(self, 'schedulerdict', sch) self.assertEqual(sorted(schlist), []) # always returns [] by spec!
def insert_initial_data(self): self.master.db.insertTestData([ fakedb.Master(id=1), fakedb.Worker(id=1, name='example-worker'), fakedb.Scheduler(id=1, name='custom', enabled=1), fakedb.Scheduler(id=2, name='all', enabled=2), fakedb.Scheduler(id=3, name='force', enabled=3), fakedb.SchedulerMaster(schedulerid=1, masterid=1), fakedb.SchedulerMaster(schedulerid=2, masterid=1), fakedb.SchedulerMaster(schedulerid=3, masterid=1), fakedb.Builder(id=1, name='runtests1'), fakedb.Builder(id=2, name='runtests2'), fakedb.Builder(id=3, name='runtests3'), fakedb.BuilderMaster(id=1, builderid=1, masterid=1), fakedb.BuilderMaster(id=2, builderid=2, masterid=1), fakedb.BuilderMaster(id=3, builderid=3, masterid=1), fakedb.Tag(id=1, name='tag1'), fakedb.Tag(id=2, name='tag12'), fakedb.Tag(id=3, name='tag23'), fakedb.BuildersTags(id=1, builderid=1, tagid=1), fakedb.BuildersTags(id=2, builderid=1, tagid=2), fakedb.BuildersTags(id=3, builderid=2, tagid=2), fakedb.BuildersTags(id=4, builderid=2, tagid=3), fakedb.BuildersTags(id=5, builderid=3, tagid=3), fakedb.Buildset(id=1, results=SUCCESS, reason="Force reason 1", submitted_at=100000, complete_at=100110, complete=1), fakedb.Buildset(id=2, results=SUCCESS, reason="Force reason 2", submitted_at=100200, complete_at=100330, complete=1), fakedb.Buildset(id=3, results=SUCCESS, reason="Force reason 3", submitted_at=100400, complete_at=100550, complete=1), fakedb.BuildsetProperty(buildsetid=1, property_name='scheduler', property_value='["custom", "Scheduler"]'), fakedb.BuildsetProperty(buildsetid=2, property_name='scheduler', property_value='["all", "Scheduler"]'), fakedb.BuildsetProperty(buildsetid=3, property_name='scheduler', property_value='["force", "Scheduler"]'), fakedb.BuildsetProperty( buildsetid=3, property_name='owner', property_value='["*****@*****.**", "Force Build Form"]'), fakedb.SourceStamp(id=1, branch='master', revision='1234abcd'), fakedb.Change(changeid=1, branch='master', revision='1234abcd', sourcestampid=1), fakedb.ChangeProperty( changeid=1, property_name="owner", property_value='["*****@*****.**", "change"]'), fakedb.ChangeProperty(changeid=1, property_name="other_prop", property_value='["value", "change"]'), fakedb.BuildsetSourceStamp(id=1, buildsetid=1, sourcestampid=1), fakedb.BuildsetSourceStamp(id=2, buildsetid=2, sourcestampid=1), fakedb.BuildsetSourceStamp(id=3, buildsetid=3, sourcestampid=1), fakedb.BuildRequest(id=1, buildsetid=1, builderid=1, results=SUCCESS, submitted_at=100001, complete_at=100109, complete=1), fakedb.BuildRequest(id=2, buildsetid=2, builderid=1, results=SUCCESS, submitted_at=100201, complete_at=100329, complete=1), fakedb.BuildRequest(id=3, buildsetid=3, builderid=2, results=SUCCESS, submitted_at=100401, complete_at=100549, complete=1), fakedb.Build(id=1, number=1, buildrequestid=1, builderid=1, workerid=1, masterid=1001, started_at=100002, complete_at=100108, state_string='build successful', results=SUCCESS), fakedb.Build(id=2, number=2, buildrequestid=2, builderid=1, workerid=1, masterid=1001, started_at=100202, complete_at=100328, state_string='build successful', results=SUCCESS), fakedb.Build(id=3, number=1, buildrequestid=3, builderid=2, workerid=1, masterid=1001, started_at=100402, complete_at=100548, state_string='build successful', results=SUCCESS), fakedb.BuildProperty(buildid=3, name='reason', value='"force build"', source="Force Build Form"), fakedb.BuildProperty(buildid=3, name='owner', value='"*****@*****.**"', source="Force Build Form"), fakedb.BuildProperty(buildid=3, name='scheduler', value='"force"', source="Scheduler"), fakedb.BuildProperty(buildid=3, name='buildername', value='"runtests3"', source="Builder"), fakedb.BuildProperty(buildid=3, name='workername', value='"example-worker"', source="Worker"), fakedb.Step(id=1, number=1, name='step1', buildid=1, started_at=100010, complete_at=100019, state_string='step1 done'), fakedb.Step(id=2, number=2, name='step2', buildid=1, started_at=100020, complete_at=100029, state_string='step2 done'), fakedb.Step(id=3, number=3, name='step3', buildid=1, started_at=100030, complete_at=100039, state_string='step3 done'), fakedb.Step(id=11, number=1, name='step1', buildid=2, started_at=100210, complete_at=100219, state_string='step1 done'), fakedb.Step(id=12, number=2, name='step2', buildid=2, started_at=100220, complete_at=100229, state_string='step2 done'), fakedb.Step(id=13, number=3, name='step3', buildid=2, started_at=100230, complete_at=100239, state_string='step3 done'), fakedb.Step(id=21, number=1, name='step1', buildid=3, started_at=100410, complete_at=100419, state_string='step1 done'), fakedb.Step(id=22, number=2, name='step2', buildid=3, started_at=100420, complete_at=100429, state_string='step2 done'), fakedb.Step(id=23, number=3, name='step3', buildid=3, started_at=100430, complete_at=100439, state_string='step3 done'), fakedb.Log(id=1, name='stdio', slug='stdio', stepid=1, complete=1, num_lines=10), fakedb.Log(id=2, name='stdio', slug='stdio', stepid=2, complete=1, num_lines=20), fakedb.Log(id=3, name='stdio', slug='stdio', stepid=3, complete=1, num_lines=30), fakedb.Log(id=11, name='stdio', slug='stdio', stepid=11, complete=1, num_lines=30), fakedb.Log(id=12, name='stdio', slug='stdio', stepid=12, complete=1, num_lines=40), fakedb.Log(id=13, name='stdio', slug='stdio', stepid=13, complete=1, num_lines=50), fakedb.Log(id=21, name='stdio', slug='stdio', stepid=21, complete=1, num_lines=50), fakedb.Log(id=22, name='stdio', slug='stdio', stepid=22, complete=1, num_lines=60), fakedb.Log(id=23, name='stdio', slug='stdio', stepid=23, complete=1, num_lines=70), fakedb.LogChunk(logid=1, first_line=0, last_line=2, content='o line1\no line2\n'), fakedb.LogChunk(logid=1, first_line=2, last_line=3, content='o line3\n'), fakedb.LogChunk(logid=2, first_line=0, last_line=4, content='o line1\no line2\no line3\no line4\n'), ])