def test_variflow(self): p = admit.Project(self.outputDir) p.setlogginglevel(50) p.addtask(admit.File_AT(alias='root', file='root', touch=True)) p.addtask(admit.Flow11_AT(alias='flow1'), ['root']) p.addtask(admit.Flow1N_AT(alias='flow1N', n=2, touch=True, exist=True), ['root']) p.addtask(admit.Flow11_AT(alias='sub1Nf'), ['flow1N']) p.addtask(admit.Flow11_AT(alias='sub1Nv'), [('flow1N', 1)]) p.addtask(admit.FlowMN_AT(alias='flowMN', n=2, touch=True, exist=True), ['flow1', 'root', ('flow1N', 1)]) p.addtask(admit.Flow11_AT(alias='subMNf'), ['flowMN']) p.addtask(admit.FlowN1_AT(alias='subMNv', touch=True), [('flowMN', 0), ('flowMN', 2)]) p.addtask(admit.FlowN1_AT(alias='flowN1', touch=True), ['flow1N', ('flowMN', 1)]) p.addtask(admit.Flow11_AT(alias='subN1'), ['flowN1']) p.show() for n in [2, 3, 1, 2]: if (p.fm.find(lambda at: at._alias == 'flow1N')): p['flow1N'].setkey('n', n) if (p.fm.find(lambda at: at._alias == 'flowMN')): p['flowMN'].setkey('n', n + 1) p.run() p.show() self.assertLessEqual(len(p), 20, "Incorrect task count")
def test_multiflow2(self): admit.Project = Project() # Template multiflow is Flow11+FlowN1+Flow11 with two File inputs. mflow = Project(self.outputDir + "/mflow") tid1 = mflow.addtask(admit.File_AT()) tid2 = mflow.addtask(admit.File_AT()) tid3 = mflow.addtask(admit.Flow11_AT(), [(tid2, 0)]) tid4 = mflow.addtask(admit.FlowN1_AT(touch=True), [(tid2, 0), (tid3, 0)]) tid5 = mflow.addtask(admit.Flow11_AT(), [(tid4, 0)]) mflow[tid3].setkey("file", "Flow11a.dat") mflow[tid3].setAlias(({'alias1': 0}, 0), "alias11") mflow[tid4].setkey("file", "FlowN1a.dat") mflow[tid4].setAlias(({'alias2': 0}, 0), "alias22") mflow[tid5].setkey("file", "Flow11b.dat") mflow[tid5].setAlias(({'alias3': 0}, 0), "alias33") mflow[tid5].enabled(False) pm = mflow.pm for d in [self.outputDir + "/p1", self.outputDir + "/p2"]: p = Project(d) for f in ["File1.dat", "File2.dat"]: p.addtask(admit.File_AT(touch=True, file=f, alias=f[:-4])) p.run() p.write() pid0 = pm.addProject(d) assert pid0 != -1 # Clone template flow onto current project. pid = pm.getProjectId(d) assert pid == pid0 at1 = pm.findTaskAlias(pid, "File1") at2 = pm.findTaskAlias(pid, "File2") assert len(at1) == 1 assert len(at2) == 1 id1 = at1[0].id(True) id2 = at2[0].id(True) mflow.fm.show() pm[pid].show() pm[pid].fm.clone(id1, (mflow.fm, tid2), {tid1: id2}) pm[pid].show() pm[pid].run() pm[pid].write() # Dot output test. pm[pid][id1].markChanged() pm[pid].fm.diagram("%s/flow.dot" % d) try: os.system("dot -Tpng %s/flow.dot -o %s/flow.png" % (d, d)) except: pass del admit.Project
def test_addtask(self): # add first task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.p.addtask(task) # add another task task = admit.Flow11_AT(alias="at" + self.p.baseDir[-2]) # at1 or at2 task.setkey("file", "Flow11.dat") tid2 = self.p.addtask(task, [(tid1, 0)]) # to get the AT with task_id = 0 at = self.p.__getitem__(0) if (self.verbose): print at # check class type - should be the first task (File_AT) type = isinstance(at, admit.File_AT) self.assertTrue(type) # to get the AT with task_id = 1 at = self.p.__getitem__(1) if (self.verbose): print at # check class type - should be the second task (Flow11_AT) type = isinstance(at, admit.Flow11_AT) self.assertTrue(type)
def test_FM_showsetkey(self): """ test FM showsetkey() and script() """ fm = admit.Flow() # add one task task1 = admit.File_AT(touch=True) task1.setkey("file", "File.dat") tid1 = fm.add(task1) # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") tid2 = fm.add(task2, [(tid1, 0)]) # test showsetkey() keyfile = '/tmp/test_FM_showsetkey.%s' % os.getpid() fm.showsetkey(keyfile) self.assertTrue(os.path.isfile(keyfile)) # test script scriptfile = '/tmp/test_FM_script.%s' % os.getpid() file = open(scriptfile, mode='w') fm.script(file) file.close() self.assertTrue(os.path.isfile(scriptfile)) # cleanup if os.path.exists(keyfile): os.remove(keyfile) if os.path.exists(scriptfile): os.remove(scriptfile)
def test_findtask(self): # add first task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.p.addtask(task) # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.p.addtask(task, [(tid1, 0)]) tasks = self.p.findtask(lambda at: at.id() < 100) if (self.verbose): print "Found tasks:", tasks # check class type of the first task (File_AT) type = isinstance(tasks[0], admit.File_AT) if (self.verbose): print "AT id:", tasks[0].id() self.assertTrue(type) # check class type of second task (Flow11_AT) type = isinstance(tasks[1], admit.Flow11_AT) if (self.verbose): print "AT id:", tasks[1].id() self.assertTrue(type)
def test_markstalefrom(self): # add one task task1 = admit.File_AT(touch=True) task1.setkey("file", "File.dat") task1._stale = False tid1 = self.p.addtask(task1) if (self.verbose): print "Task1 state:", task1._stale # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") task2._stale = False tid2 = self.p.addtask(task2, [(tid1, 0)]) if (self.verbose): print "Task2 state:", task2._stale # mark - only the second task state will be changed self.p._markstalefrom(tid1) if (self.verbose): print "===== Task Ids =====", tid1, tid2 if (self.verbose): print "Task1 state after marking:", task1._stale print "Task2 state after marking:", task2._stale self.assertEqual(task1._stale, False) self.assertEqual(task2._stale, True)
def test_multiflow1(self): """ Test multiflow with two Project inputs """ # Parent projects. p1 = Project(self.outputDir + "/p1") p2 = Project(self.outputDir + "/p2") for p in [p1, p2]: # add task 1 task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = p.addtask(task) # add task 2 task = admit.Flow11_AT(alias="at" + p.baseDir[-2]) # at1 or at2 task.setkey("file", "Flow11.dat") tid2 = p.addtask(task, [(tid1, 0)]) # run flow p.run() # Multiflow project. mflow = Project(self.outputDir + "/mflow") # Add parent projects to the multiflow. # Note they must be completely up-to-date for this to succeed. pid1 = mflow.pm.addProject(self.outputDir + "/p1") pid2 = mflow.pm.addProject(self.outputDir + "/p2") # Find some ATs to link into the multiflow. # Here searching is done by alias name. stuples = [] for pid in [pid1, pid2]: alias = "at" + mflow.pm[pid].baseDir[-2] ats = mflow.pm.findTaskAlias(pid, alias) self.assertEqual(len(ats), 1, "Found wrong number of matches") self.assertEqual(ats[0]._alias, alias, "Alias mismatch") self.assertNotEqual(ats[0].getProject(), 0, "Null project ID") # Add task to the multiflow (must be a root task---no stuples). tid = mflow.addtask(ats[0]) self.assertNotEqual(tid, -1, "mflow.addtask(" + alias + ") failed") stuples.append((tid, 0)) # Combine output from the two newly linked tasks. tid = mflow.addtask(admit.FlowN1_AT(file="FlowN1.dat", touch=True), stuples) self.assertNotEqual(tid, -1, "mflow.addtask(FlowN1) failed") mflow.show() # Run the multiflow. mflow.run() # Make at2 out of date, then re-run the multiflow to update everything. at2 = mflow.findtask(lambda at: at._alias == "at2") self.assertEqual(len(at2), 1, "Found wrong number of matches for at2") self.assertEqual(at2[0]._alias, "at2", "Alias mismatch for at2") at2[0].setkey("file", "Flow11-at2.dat") mflow.show() mflow.run()
def test_Project_userdata(self): """ test Project.userdata() and get() """ val = ['test1', 1, 'admit'] task = admit.Flow11_AT() task._userdata = {} task._userdata['admit_unit_test'] = val self.project.addtask(task) self.project.userdata() self.assertEqual(val, self.project.get('admit_unit_test'))
def test_Project_findtask(self): """ test Project.findtask() """ # add first task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.project.addtask(task) # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.project.addtask(task, [(tid1, 0)]) tasks = self.project.findtask(lambda at: at.id() < 100) # check class types of tasks self.assertIsInstance(tasks[0], admit.File_AT) self.assertIsInstance(tasks[1], admit.Flow11_AT)
def test_flow2(self): # Construct a flow: File_AT -> Flow11_AT -> Flow1N_AT # add first task task1 = admit.File_AT(touch=True) tid1 = self.fm.add(task1) bdp = admit.File_BDP() task1.addoutput(bdp) # add second task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") tid2 = self.fm.add(task2, [(tid1, 0)]) # add third task task3 = admit.Flow1N_AT() task3.setkey("file", "Flow1N.dat") tid3 = self.fm.add(task3, [(tid2, 0)]) task4 = admit.FlowMN_AT() # test inFlow() found = self.fm.inFlow(task1) self.assertTrue(found) # should be true # test downstream of tid2 (including tid2) dstream = self.fm.downstream(tid2) self.assertEquals(dstream, set([tid2, tid3])) # test stale() for ds in dstream: isStale = self.fm._tasks[ds].isstale() # check before mark if isStale: self.fm._tasks[ds].markUpToDate() isStale = self.fm._tasks[ds].isstale() # check after mark self.assertFalse(isStale) # should not be stale self.fm.stale(tid2) # call stale() # after calling stale() for ds in dstream: isStale = self.fm._tasks[ds].isstale() self.assertTrue( isStale) # all ATs in downstream should be stale now # clone from tid2 (Flow11_AT) in the flow cloned = self.fm.clone(tid2) if (self.verbose): self.fm.show()
def test_Project_markstalefrom(self): """ test _markstalefrom() """ # add one task task1 = admit.File_AT(touch=True) task1.setkey("file", "File.dat") task1._stale = False tid1 = self.project.addtask(task1) # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") task2._stale = False tid2 = self.project.addtask(task2, [(tid1, 0)]) # mark - only the second task state will be changed self.project._markstalefrom(tid1) self.assertEqual(task1._stale, False) self.assertEqual(task2._stale, True)
def test_Project_script(self): """ test Project.script() """ # add one task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.project.addtask(task) # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.project.addtask(task, [(tid1, 0)]) name = '/tmp/test_script.%s' % os.getpid() self.project.script(name) # cleanup if os.path.exists(name): os.remove(name)
def test_userdata(self): key = 'admit_unit_test' val = ['test1', 1, 'admit'] task = admit.Flow11_AT() task._userdata = {} task._userdata[key] = val self.p.addtask(task) self.p.userdata() ret = self.p.get('admit_unit_test') if (self.verbose): print "User Data:", ret self.assertEqual(ret, val)
def test_FM_getsetdelitem(self): """ test FM __getitem__, __setitem__, __delitem__ """ # test add(), connectInputs(), verify(), and show() #__getitem__(), __delitem__(), __setitem__() fm = admit.Flow() # add first task task1 = admit.File_AT(touch=True) tid1 = fm.add(task1) bdp = admit.File_BDP() task1.addoutput(bdp) # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") tid2 = fm.add(task2, [(tid1, 0)]) # test connectInputs fm.connectInputs() # check the number of tasks self.assertEqual(len(fm), 2) # first task (File_AT) # fm[tid1] # call __getitem__ self.assertIsInstance(fm[tid1], admit.File_AT) # second task (Flow11_AT) # fm[tid2] # call __getitem__ self.assertIsInstance(fm[tid2], admit.Flow11_AT) # test __setitem__ newtask = admit.FlowMN_AT() newtask.setkey("file", "FlowMN.txt") fm[tid2] = newtask # call __setitem__ # check to see if task2 got overwritten self.assertIsInstance(fm[tid2], admit.FlowMN_AT) # now restore Flow11_AT fm[tid2] = task2 # call __setitem__ self.assertIsInstance(fm[tid2], admit.Flow11_AT) # test __delitem__ (delete Flow11) at = fm[tid2] del fm[tid2] # call __delitem__ self.assertEqual(len(fm), 1) # Add task back. fm[tid2] = at # call __setitem__ # test verify() self.assertTrue(fm.verify())
def test_Project_showsetkey(self): """ test Project.showsetkey() """ # add one task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.project.addtask(task) # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.project.addtask(task, [(tid1, 0)]) keyfile = '/tmp/test_showsetkeys.%s' % os.getpid() self.project.showsetkey(keyfile) self.assertTrue(os.path.isfile(keyfile)) # cleanup if os.path.exists(keyfile): os.remove(keyfile)
def test_Project_addtask(self): """ test Project.addtask(), __getitem__() """ # add first task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.project.addtask(task) # add another task task = admit.Flow11_AT(alias="at" + self.project.baseDir[-2]) # at1 or at2 task.setkey("file", "Flow11.dat") tid2 = self.project.addtask(task, [(tid1, 0)]) # to get the AT with task_id = 0 at = self.project.__getitem__(0) self.assertIsInstance(at, admit.File_AT) # to get the AT with task_id = 1 at = self.project.__getitem__(1) self.assertIsInstance(at, admit.Flow11_AT)
def test_FM_inFlow_downstream(self): """ test FM inFlow(), downstream(), stale(), clone() """ fm = admit.Flow() # Construct a flow: File_AT -> Flow11_AT -> Flow1N_AT # add first task task1 = admit.File_AT(touch=True) tid1 = fm.add(task1) bdp = admit.File_BDP() task1.addoutput(bdp) # add second task task2 = admit.Flow11_AT() tid2 = fm.add(task2, [(tid1, 0)]) task2.setkey("file", "Flow11.dat") # add third task task3 = admit.Flow1N_AT() tid3 = fm.add(task3, [(tid2, 0)]) task3.setkey("file", "Flow1N.dat") # test inFlow() self.assertTrue(fm.inFlow(task1)) # test downstream of tid2 (including tid2) dstream = fm.downstream(tid2) self.assertEquals(dstream, set([tid2, tid3])) # test stale() for ds in dstream: isStale = fm._tasks[ds].isstale() # check before mark if isStale: fm._tasks[ds].markUpToDate() isStale = fm._tasks[ds].isstale() # check after mark self.assertFalse(isStale) # should not be stale fm.stale(tid2) # all ATs in downstream should be stale now for ds in dstream: self.assertTrue(fm._tasks[ds].isstale()) # clone from tid2 (Flow11_AT) in the flow cloned_tid = fm.clone(tid2) self.assertEqual(cloned_tid, 3)
def test_FM_find_replace(self): """ test FM find() and replace() """ fm = admit.Flow() # add first task File_AT task = admit.File_AT(touch=True) tid1 = fm.add(task) # add another task Flow11_AT task = admit.Flow11_AT() tid2 = fm.add(task, [(tid1, 0)]) task.setkey("file", "Flow11.dat") # now try to find the tasks tasks = fm.find(lambda at: at.id() < 100) # check class types of the tasks self.assertIsInstance(tasks[0], admit.File_AT) self.assertIsInstance(tasks[1], admit.Flow11_AT) # test replace() task = admit.FlowMN_AT() fm.replace(tid2, task) # to find new tasks tasks = fm.find(lambda at: at.id() < 100) # check class types of the tasks self.assertIsInstance(tasks[0], admit.File_AT) self.assertIsInstance(tasks[1], admit.FlowMN_AT) # check the number of tasks self.assertEqual(len(fm), 2) # Test __contains__() self.assertFalse(100 in fm) self.assertTrue(tid1 in fm) # test __iter__ # we should have two tasks counter = 0 for t in fm: counter += 1 self.assertEqual(counter, 2)
def test_showsetkey(self): # add one task task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = self.p.addtask(task) # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.p.addtask(task, [(tid1, 0)]) name = '/tmp/test_showsetkeys.%s' % os.getpid() self.p.showsetkey(name) if (self.verbose): print "===== Keys =====" cmd = "cat %s" % name os.system(cmd) print "===== End =====" # cleanup if os.path.exists(name): os.remove(name)
def test_showsetkey(self): # add one task task1 = admit.File_AT(touch=True) task1.setkey("file", "File.dat") tid1 = self.fm.add(task1) # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") tid2 = self.fm.add(task2, [(tid1, 0)]) # test showsetkey() name1 = '/tmp/test_FM_showsetkey.%s' % os.getpid() self.fm.showsetkey(name1) if (self.verbose): print "===== Keys =====" cmd = "cat %s" % name1 os.system(cmd) print "===== End =====" # test script name2 = '/tmp/test_FM_script.%s' % os.getpid() file = open(name2, mode='w') self.fm.script(file) file.close() if (self.verbose): print "===== Script Created =====" cmd = "cat %s" % name2 os.system(cmd) print "===== End =====" # cleanup if os.path.exists(name1): os.remove(name1) if os.path.exists(name2): os.remove(name2)
def test_task2(self): # add first task task1 = admit.File_AT(touch=True) tid1 = self.fm.add(task1) bdp = admit.File_BDP() task1.addoutput(bdp) # add another task task2 = admit.Flow11_AT() task2.setkey("file", "Flow11.dat") tid2 = self.fm.add(task2, [(tid1, 0)]) # test connectInputs self.fm.connectInputs() num = len(self.fm) # should be 2 self.assertTrue(num == 2) if (self.verbose): print "The number of tasks in flow:", num print "The task IDs:", tid1, tid2 # first task (File_AT) t1 = self.fm[tid1] # call __getitem__ type = isinstance(t1, admit.File_AT) if (self.verbose): print "After call __getitem__", t1.id() self.assertTrue(type) # second task (Flow11_AT) t2 = self.fm[tid2] # call __getitem__ type = isinstance(t2, admit.Flow11_AT) if (self.verbose): print "After call __getitem__", t2.id() self.assertTrue(type) # test __setitem__ newtask = admit.FlowMN_AT() newtask.setkey("file", "FlowMN.txt") self.fm[tid2] = newtask # call __setitem__ if (self.verbose): self.fm.show() # check to see if task2 got overwritten t2 = self.fm[tid2] type = isinstance(t2, admit.FlowMN_AT) self.assertTrue(type) # now restore Flow11_AT self.fm[tid2] = task2 # call __setitem__ if (self.verbose): self.fm.show() # check it again t2 = self.fm[tid2] type = isinstance(t2, admit.Flow11_AT) self.assertTrue(type) # test __delitem__ (delete Flow11) at = self.fm[tid2] del self.fm[tid2] # call __delitem__ num = len(self.fm) # should be 1 now self.assertTrue(num == 1) # Add task back. self.fm[tid2] = at # call __setitem__ # test verify() check = self.fm.verify() self.assertTrue(check)
def test_clone(self): admit.Project = Project() p1 = Project(self.outputDir + "/clone-p1") task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid1 = p1.addtask(task) # task = admit.Flow11_AT(alias="at1") task.setkey("file", "Flow11-at1.dat") tid2 = p1.addtask(task, [(tid1, 0)]) p2 = Project(self.outputDir + "/clone-p2") task = admit.File_AT(touch=True) task.setkey("file", "File.dat") tid3 = p2.addtask(task) # # The following 2-to-1 flow simply inputs the same File BDP twice. # This is to exercise cloning a sub-root task with multiple inputs # (which is ok since the *sub-flow* stems from only one AT, FlowN1). task = admit.FlowN1_AT(alias="at2") task.setkey("file", "FlowN1-at2.dat") tid4 = p2.addtask(task, [(tid3, 0), (tid3, 0)]) # task = admit.Flow11_AT(alias="at3a") task.setkey("file", "Flow11-at3a.dat") tid5 = p2.addtask(task, [(tid4, 0)]) p1.fm.clone(tid2, (p2.fm, tid4)) # Task to be re-cloned; avoid filename clashes. p2[tid5].setkey("file", "Flow11-at3b.dat") p2[tid5].setAlias(({'at3b': 0}, 0), "at3bb") # We should *not* be able to clone a sub-flow containing ATs # receiving inputs beyond the sub-root without an explicit dependency # map. Here we append a FlowN1 to p2 to make it depend on the root # File AT, outside the sub-flow. task = admit.FlowN1_AT(alias="at4") task.setkey("file", "FlowN1-at4.dat") tid6 = p2.addtask(task, [(tid5, 0), (tid3, 0)]) try: p1.fm.clone(tid2, (p2.fm, tid4)) except: # Clean up aborted clone() (since we're ignoring the failure here). # This is highly volatile code users should never imitate! p1.fm.remove(p1.fm._tasklevs.keys()[-1]) else: raise Exception, "Non-autonomous clone() unexpectedly succeeded" # Non-autonomous sub-flows are ok if all dependencies are explicit. try: p1.fm.clone(tid2, (p2.fm, tid4), {tid3: tid1}) except: raise Exception, "Non-autonomous clone() unexpectedly failed" assert len(p1) == 5 # This should produce output in clone-p1/ only, not clone-p2/. p1.fm.show() p1.run() p1.write() del admit.Project
def test_task1(self): # add first task task = admit.File_AT(touch=True) tid1 = self.fm.add(task) if (self.verbose): print "FM unit test task1 ID:", tid1 # add another task task = admit.Flow11_AT() task.setkey("file", "Flow11.dat") tid2 = self.fm.add(task, [(tid1, 0)]) if (self.verbose): print "FM unit test task2 ID:", tid2 # now try to find the tasks tasks = self.fm.find(lambda at: at.id() < 100) if (self.verbose): print "Found tasks:", tasks # check class type of the first task (File_AT) type = isinstance(tasks[0], admit.File_AT) if (self.verbose): print "AT id:", tasks[0].id() self.assertTrue(type) # check class type of second task (Flow11_AT) type = isinstance(tasks[1], admit.Flow11_AT) if (self.verbose): print "AT id:", tasks[1].id() self.assertTrue(type) # test replace() task = admit.FlowMN_AT() self.fm.replace(tid2, task) # to find new tasks tasks = self.fm.find(lambda at: at.id() < 100) if (self.verbose): print "Found tasks after replace Flow11 with FlowMN:", tasks # first task (File_AT) type = isinstance(tasks[0], admit.File_AT) if (self.verbose): print "After replace AT id:", tasks[0].id() self.assertTrue(type) # second task (FlowMN_AT) type = isinstance(tasks[1], admit.FlowMN_AT) if (self.verbose): print "After replace AT id:", tasks[1].id() self.assertTrue(type) # the number of tasks num = len(self.fm) if (self.verbose): print "The number of tasks:", num self.assertEqual(2, num) # Test __contains__() contains = 100 in self.fm # should be false self.assertFalse(contains) contains = tid1 in self.fm # should be true self.assertTrue(contains) # test __iter__ # we should have two tasks counter = 0 for t in self.fm: counter += 1 if (self.verbose): print "Task id:", t self.assertEqual(counter, 2)