def test_partial_decryption_w_task_monitor(self): """ Test that partial decryption can be monitored using a TaskMonitor object. """ # Get a new task monitor and a counter task_monitor = TaskMonitor() partialDecryptionCounter = Counter() # Register a task monitor callback to increment the counter once # for each 5% progress of partial decryption def partial_decryption_callback(tm): partialDecryptionCounter.increment() task_monitor.add_on_progress_percent_callback( partial_decryption_callback, percent_span = 5.0) # Generate a partial decryption passing the task_monitor object tprk = self.tSetUp.generate_private_key(0, self.trustees[0].private_key) text_to_encrypt_dir = os.path.join(os.path.dirname(__file__), "TestThresholdPrivateKey.resources") text_to_encrypt = os.path.join(text_to_encrypt_dir, "text_to_encrypt") text_encrypted = self.tpkey.encrypt_text(text_to_encrypt) tprk.generate_partial_decryption(text_encrypted, task_monitor) # Check that the counter has been incremented 100/5 = 20 times self.assertEqual(partialDecryptionCounter.value, 20)
def test_partial_decryption_w_task_monitor(self): """ Test that partial decryption can be monitored using a TaskMonitor object. """ # Get a new task monitor and a counter task_monitor = TaskMonitor() partialDecryptionCounter = Counter() # Register a task monitor callback to increment the counter once # for each 5% progress of partial decryption def partial_decryption_callback(tm): partialDecryptionCounter.increment() task_monitor.add_on_progress_percent_callback( partial_decryption_callback, percent_span=5.0) # Generate a partial decryption passing the task_monitor object tprk = self.tSetUp.generate_private_key(0, self.trustees[0].private_key) text_to_encrypt_dir = os.path.join( os.path.dirname(__file__), "TestThresholdPrivateKey.resources") text_to_encrypt = os.path.join(text_to_encrypt_dir, "text_to_encrypt") text_encrypted = self.tpkey.encrypt_text(text_to_encrypt) tprk.generate_partial_decryption(text_encrypted, task_monitor) # Check that the counter has been incremented 100/5 = 20 times self.assertEqual(partialDecryptionCounter.value, 20)
def test_cryptosystem_new_with_task_monitor(self): """ Test that EGCryptoSystem.new(...) correctly reports progress using task monitor. """ # Get new counter and logger objects counter = Counter() logger = Logger() # Create a task monitor task_monitor = TaskMonitor() # Register callbacks for: # 1) logging subtask creation, def task_start_cb(tm): tm_p = tm.parent msg = "New task started: \"%s\" " \ "(Subtask #%d of %d for task \"%s\")\n" % \ (tm.task_name, tm_p.current_subtask_num, \ tm_p.num_subtasks, tm_p.task_name) logger.log(msg) task_monitor.add_on_task_start_callback(task_start_cb) # 2) logging subtask completion, def task_end_cb(tm): msg = "Task completed: \"%s\"\n" % tm.task_name logger.log(msg) task_monitor.add_on_task_end_callback(task_end_cb) # 3) counting the number of ticks of progress task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks=1) # Note: # EGCryptoSystem.new(...) does not provide progress percent monitoring # We call EGCryptoSystem.new(...) with our task monitor object # We use the *insecure* size of 256bits for performance reasons EGCryptoSystem.new(nbits=256, task_monitor=task_monitor) # Check that the logged match the expected output of our callbacks: expected_log = \ """New task started: \"Generate safe prime\" (Subtask #1 of 1 for task \"Root\") Task completed: \"Generate safe prime\" New task started: \"Obtain a generator for the cyclic group\" (Subtask #2 of 2 for task \"Root\") Task completed: \"Obtain a generator for the cyclic group\" """ self.assertEqual(str(logger), expected_log) # Also, each of the two subtask produces a progress tick before testing # each safe prime or generator candidate (respectively). So counter # must have registered at least two ticks (likely more) self.assertTrue(counter.value >= 2)
def test_cryptosystem_new_with_task_monitor(self): """ Test that EGCryptoSystem.new(...) correctly reports progress using task monitor. """ # Get new counter and logger objects counter = Counter() logger = Logger() # Create a task monitor task_monitor = TaskMonitor() # Register callbacks for: # 1) logging subtask creation, def task_start_cb(tm): tm_p = tm.parent msg = "New task started: \"%s\" " \ "(Subtask #%d of %d for task \"%s\")\n" % \ (tm.task_name, tm_p.current_subtask_num, \ tm_p.num_subtasks, tm_p.task_name) logger.log(msg) task_monitor.add_on_task_start_callback(task_start_cb) # 2) logging subtask completion, def task_end_cb(tm): msg = "Task completed: \"%s\"\n" % tm.task_name logger.log(msg) task_monitor.add_on_task_end_callback(task_end_cb) # 3) counting the number of ticks of progress task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks = 1) # Note: # EGCryptoSystem.new(...) does not provide progress percent monitoring # We call EGCryptoSystem.new(...) with our task monitor object # We use the *insecure* size of 256bits for performance reasons EGCryptoSystem.new(nbits=256, task_monitor=task_monitor) # Check that the logged match the expected output of our callbacks: expected_log = \ """New task started: \"Generate safe prime\" (Subtask #1 of 1 for task \"Root\") Task completed: \"Generate safe prime\" New task started: \"Obtain a generator for the cyclic group\" (Subtask #2 of 2 for task \"Root\") Task completed: \"Obtain a generator for the cyclic group\" """ self.assertEqual(str(logger),expected_log) # Also, each of the two subtask produces a progress tick before testing # each safe prime or generator candidate (respectively). So counter # must have registered at least two ticks (likely more) self.assertTrue(counter.value >= 2)
def test_encryption_decryption_w_task_monitor(self): """ Test that encryption and decryption can be monitored using a TaskMonitor object. """ # Get a new task monitor and two counters, one for encryption and one # for decryption task_monitor = TaskMonitor() encryptionCounter = Counter() decryptionCounter = Counter() # Register a task monitor callback to increment encryptionCounter once # for each 5% progress of encryption def encryption_callback(tm): encryptionCounter.increment() task_monitor.add_on_progress_percent_callback(encryption_callback, percent_span = 5.0) # Encrypt the test message, passing the task monitor ciphertext = self.public_key.encrypt_text(self.message, task_monitor=task_monitor) # Unregister the encryption callback from the monitor and register # a callback to increment decryptionCounter once for each 5% progress # of decryption. task_monitor.remove_callback(encryption_callback) def decryption_callback(tm): decryptionCounter.increment() task_monitor.add_on_progress_percent_callback(decryption_callback, percent_span = 5.0) # Decrypt the message, passing the task monitor: self.private_key.decrypt_to_text(ciphertext, task_monitor=task_monitor) # Check that both counters have been incremented 100/5 = 20 times self.assertEqual(encryptionCounter.value, 20) self.assertEqual(decryptionCounter.value, 20)
def run_tool(nbits, filename, name, description): """ Runs the plonevote.gen_cryptosys tool and generates a new cryptosystem. """ # Define callbacks for the TaskMonitor for progress monitoring def cb_task_start(task): print task.task_name + ":" def cb_task_progress(task): sys.stdout.write(".") sys.stdout.flush() def cb_task_end(task): print "" # Create new TaskMonitor and register the callbacks taskmon = TaskMonitor() taskmon.add_on_task_start_callback(cb_task_start) taskmon.add_on_tick_callback(cb_task_progress) taskmon.add_on_task_end_callback(cb_task_end) # Generate a new cryptosystem of the requested size try: cryptosys = EGCryptoSystem.new(nbits, task_monitor=taskmon) except KeyLengthTooLowError: print "ERROR: The given bit size does not meet PloneVoteCryptoLib "\ "minimum security requirements (too short)." except KeyLengthNonBytableError: print "ERROR: The given bit size must be a multiple of 8." # Save the cryptosystem to file print "\nSaving cryptosystem to %s..." % filename, cryptosys.to_file(name, description, filename) print "SAVED.\n"
def run_tool(nbits, filename, name, description): """ Runs the plonevote.gen_cryptosys tool and generates a new cryptosystem. """ # Define callbacks for the TaskMonitor for progress monitoring def cb_task_start(task): print task.task_name + ":" def cb_task_progress(task): sys.stdout.write(".") sys.stdout.flush() def cb_task_end(task): print "" # Create new TaskMonitor and register the callbacks taskmon = TaskMonitor() taskmon.add_on_task_start_callback(cb_task_start) taskmon.add_on_tick_callback(cb_task_progress) taskmon.add_on_task_end_callback(cb_task_end) # Generate a new cryptosystem of the requested size try: cryptosys = EGCryptoSystem.new(nbits, task_monitor = taskmon) except KeyLengthTooLowError: print "ERROR: The given bit size does not meet PloneVoteCryptoLib "\ "minimum security requirements (too short)." except KeyLengthNonBytableError: print "ERROR: The given bit size must be a multiple of 8." # Save the cryptosystem to file print "\nSaving cryptosystem to %s..." % filename, cryptosys.to_file(name, description, filename) print "SAVED.\n"
# Define callbacks for the TaskMonitor for monitoring the decryption process if(len(in_file) <= 50): short_in_filename = in_file else: short_in_filename = os.path.split(in_file)[-1] if(len(short_in_filename) > 50): # Do ellipsis shortening short_in_filename = short_in_filename[0,20] + "..." + \ short_in_filename[-20,-1] def cb_task_percent_progress(task): print " %.2f%% of %s decrypted..." % \ (task.get_percent_completed(), short_in_filename) # Create new TaskMonitor and register the callbacks taskmon = TaskMonitor() taskmon.add_on_progress_percent_callback(cb_task_percent_progress, \ percent_span = 5) # Decrypt to bitstream print "Decrypting..." try: bitstream = private_key.decrypt_to_bitstream(ciphertext, task_monitor = taskmon) except IncompatibleCiphertextError, e: print "Incompatible private key and ciphertext error: %s" % s.msg # Save the resulting plaintext to the output file print "Writing decrypted data..." try: out_f = open(out_file, 'wb') except Exception, e:
# Define callbacks for the TaskMonitor for monitoring the encryption process if (len(in_file) <= 50): short_in_filename = in_file else: short_in_filename = os.path.split(in_file)[-1] if (len(short_in_filename) > 50): # Do ellipsis shortening short_in_filename = short_in_filename[0,20] + "..." + \ short_in_filename[-20,-1] def cb_task_percent_progress(task): print " %.2f%% of %s encrypted..." % \ (task.get_percent_completed(), short_in_filename) # Create new TaskMonitor and register the callbacks taskmon = TaskMonitor() taskmon.add_on_progress_percent_callback(cb_task_percent_progress, \ percent_span = 5) # Encrypt bitstream print "Encrypting..." ciphertext = public_key.encrypt_bitstream(bitstream, task_monitor=taskmon) # Save the ciphertext to the output file try: ciphertext.to_file(out_file) except Exception, e: print "Problem while saving the output file %s: %s" % (in_file, e.msg) def main():
def setUp(self): """ Unit test setup method. """ self.task_monitor = TaskMonitor()
class TestTaskMonitor(unittest.TestCase): """ Test the class: plonevotecryptolib.utilities.TaskMonitor.TaskMonitor """ def setUp(self): """ Unit test setup method. """ self.task_monitor = TaskMonitor() def test_report_ticks(self): """ Test that TaskMonitor can be used to report the number of steps (ticks) performed by a "TaskMonitor-enabled" function. """ # We register a callback that increments a counter by one and is # called every 10 ticks counter = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks = 10) # Now, we call the tme_fibonacci function with our task monitor, asking # for the 100th Fibonacci number tme_fibonacci(100, self.task_monitor) # The counter should have been updated once for every 10 numbers in the # sequence from 0 to our desired number, inclusive. So counter should # be 100/10 = 10. self.assertEqual(counter.value, 10) def test_report_percent(self): """ Test that TaskMonitor can be used to report the completion percentage of a "TaskMonitor-enabled" function that allows percentage monitoring. """ # We register a callback that increments a counter by one and is # called every 5% progress counter = Counter() self.task_monitor.add_on_progress_percent_callback( \ lambda tm: counter.increment(), percent_span = 5.0) # Now, we call the tme_fibonacci function with our task monitor, asking # for the 100th Fibonacci number tme_fibonacci(100, self.task_monitor) # The counter should have been updated once for every 5% advance in the # called function. This gives us 20 updates. self.assertEqual(counter.value, 20) def test_task_without_percent_reporting(self): """ Test how add_on_tick_callback(...) *and* add_on_progress_percent_callback(...) work when the task does not provide progress percent reporting (ie. a variable length task). """ # We register a callback that increments a counter by one and is # called every 10 ticks counter1 = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter1.increment(), num_ticks = 10) # We register a callback that increments a counter by one and is # called every 5% progress counter2 = Counter() self.task_monitor.add_on_progress_percent_callback( \ lambda tm: counter2.increment(), percent_span = 5.0) # Now, we call the tme_search_in_list function with our task monitor, # asking for the position of element 100 in range(0,300) tme_search_in_list(range(0,300), 100, self.task_monitor) # counter1 should have been update 10 times, one for each 10 ticks of # a total of 100 ticks (100 is the 100th element of range(0,300)) self.assertEqual(counter1.value, 10) # counter2 should have never been updated, since tme_search_in_list # does not provide progress percent monitoring self.assertEqual(counter2.value, 0) def test_subtask_reporting(self): """ Test complex reporting on a task with subtasks. This includes: * Test task start/end callbacks. * Test getting the name and number of each subtask. * Test reporting percent progress of the whole task and each subtask. """ # Construct a logger object logger = Logger() # Set up callbacks to log messages on: # subtask creation, def task_start_cb(tm): tm_p = tm.parent msg = "New task started: \"%s\" " \ "(Subtask #%d of %d for task \"%s\")\n" % \ (tm.task_name, tm_p.current_subtask_num, \ tm_p.num_subtasks, tm_p.task_name) logger.log(msg) self.task_monitor.add_on_task_start_callback(task_start_cb) # subtask completion, def task_end_cb(tm): msg = "Task completed: \"%s\"\n" % tm.task_name logger.log(msg) self.task_monitor.add_on_task_end_callback(task_end_cb) # and progress percent (20%) def task_percent_cb(tm): msg = "\"%s\"... %d%% completed.\n" % \ (tm.task_name, tm.get_percent_completed()) logger.log(msg) self.task_monitor.add_on_progress_percent_callback(task_percent_cb) # We also count the total number of ticks counter = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks = 1) # Call tme_fibonacci_subtasks using the task monitor tme_fibonacci_subtasks(self.task_monitor) # and compare the logged output with the expected one expected_output = \ """New task started: \"Multiple Fibonacci Tasks\" (Subtask #1 of 1 for task \"Root\") New task started: \"Fibonacci(300)\" (Subtask #1 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 300th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(300)\") \"Calculating the 300th Fibonacci number\"... 5% completed. \"Calculating the 300th Fibonacci number\"... 10% completed. \"Calculating the 300th Fibonacci number\"... 15% completed. \"Calculating the 300th Fibonacci number\"... 20% completed. \"Calculating the 300th Fibonacci number\"... 25% completed. \"Calculating the 300th Fibonacci number\"... 30% completed. \"Calculating the 300th Fibonacci number\"... 35% completed. \"Calculating the 300th Fibonacci number\"... 40% completed. \"Calculating the 300th Fibonacci number\"... 45% completed. \"Calculating the 300th Fibonacci number\"... 50% completed. \"Calculating the 300th Fibonacci number\"... 55% completed. \"Calculating the 300th Fibonacci number\"... 60% completed. \"Calculating the 300th Fibonacci number\"... 65% completed. \"Calculating the 300th Fibonacci number\"... 70% completed. \"Calculating the 300th Fibonacci number\"... 75% completed. \"Calculating the 300th Fibonacci number\"... 80% completed. \"Calculating the 300th Fibonacci number\"... 85% completed. \"Calculating the 300th Fibonacci number\"... 90% completed. \"Calculating the 300th Fibonacci number\"... 95% completed. \"Calculating the 300th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 300th Fibonacci number\" Task completed: \"Fibonacci(300)\" New task started: \"Fibonacci(500)\" (Subtask #2 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 500th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(500)\") \"Calculating the 500th Fibonacci number\"... 5% completed. \"Calculating the 500th Fibonacci number\"... 10% completed. \"Calculating the 500th Fibonacci number\"... 15% completed. \"Calculating the 500th Fibonacci number\"... 20% completed. \"Calculating the 500th Fibonacci number\"... 25% completed. \"Calculating the 500th Fibonacci number\"... 30% completed. \"Calculating the 500th Fibonacci number\"... 35% completed. \"Calculating the 500th Fibonacci number\"... 40% completed. \"Calculating the 500th Fibonacci number\"... 45% completed. \"Calculating the 500th Fibonacci number\"... 50% completed. \"Calculating the 500th Fibonacci number\"... 55% completed. \"Calculating the 500th Fibonacci number\"... 60% completed. \"Calculating the 500th Fibonacci number\"... 65% completed. \"Calculating the 500th Fibonacci number\"... 70% completed. \"Calculating the 500th Fibonacci number\"... 75% completed. \"Calculating the 500th Fibonacci number\"... 80% completed. \"Calculating the 500th Fibonacci number\"... 85% completed. \"Calculating the 500th Fibonacci number\"... 90% completed. \"Calculating the 500th Fibonacci number\"... 95% completed. \"Calculating the 500th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 500th Fibonacci number\" Task completed: \"Fibonacci(500)\" New task started: \"Fibonacci(200)\" (Subtask #3 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 200th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(200)\") \"Calculating the 200th Fibonacci number\"... 5% completed. \"Calculating the 200th Fibonacci number\"... 10% completed. \"Calculating the 200th Fibonacci number\"... 15% completed. \"Calculating the 200th Fibonacci number\"... 20% completed. \"Calculating the 200th Fibonacci number\"... 25% completed. \"Calculating the 200th Fibonacci number\"... 30% completed. \"Calculating the 200th Fibonacci number\"... 35% completed. \"Calculating the 200th Fibonacci number\"... 40% completed. \"Calculating the 200th Fibonacci number\"... 45% completed. \"Calculating the 200th Fibonacci number\"... 50% completed. \"Calculating the 200th Fibonacci number\"... 55% completed. \"Calculating the 200th Fibonacci number\"... 60% completed. \"Calculating the 200th Fibonacci number\"... 65% completed. \"Calculating the 200th Fibonacci number\"... 70% completed. \"Calculating the 200th Fibonacci number\"... 75% completed. \"Calculating the 200th Fibonacci number\"... 80% completed. \"Calculating the 200th Fibonacci number\"... 85% completed. \"Calculating the 200th Fibonacci number\"... 90% completed. \"Calculating the 200th Fibonacci number\"... 95% completed. \"Calculating the 200th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 200th Fibonacci number\" Task completed: \"Fibonacci(200)\" Task completed: \"Multiple Fibonacci Tasks\" """ self.assertEqual(str(logger), expected_output) # Including ticks for the 0th number in each succession.. self.assertEqual(counter.value, 1003) def test_remove_callback(self): """ Test the remove_callback method of TaskMonitor. """ # We will run a new Task Monitor to monitor the tme_fibonacci_subtasks # function. # First, we define a callback to count all ticks for our task counter = Counter() def tick_counter_cb(tm): counter.increment() self.task_monitor.add_on_tick_callback(tick_counter_cb, num_ticks = 1) # Then, we define a callback to be called whenever a subtask starts # This callback will remove our previous "tick counter" callback as # soon as the task named "Fibonacci(500)" starts. def task_start_cb(tm): if(tm.task_name == "Fibonacci(500)"): tm.remove_callback(tick_counter_cb) self.task_monitor.add_on_task_start_callback(task_start_cb) # Note that since remove_callback removes the callback solely for the # task for which it was called and its subtasks, our tick counter # callback will still be called for the "Fibonacci(200)" subtask of # tme_fibonacci_subtasks. # Lets run tme_fibonacci_subtasks: tme_fibonacci_subtasks(self.task_monitor) # Check that the counter has registered 301 ticks for Fibonacci(300) # (and subtasks) and 201 for Fibonacci(200) (and subtasks), but no # ticks for Fibonacci(500): self.assertEqual(counter.value, 502)
def run_tool(key_file, in_file, out_file): """ Runs the plonevote.encrypt tool and encrypts in_file into out_file. """ # Load the public key print("Loading public key...") try: public_key = PublicKey.from_file(key_file) except InvalidPloneVoteCryptoFileError as e: print("Invalid public key file (%s): %s" % (key_file, e.msg)) sys.exit(2) # Open the input file print("Reading input file...") try: in_f = open(in_file, 'rb') except Exception as e: print("Problem while opening input file %s: %s" % (in_file, e)) # Read the whole file into a bitstream bitstream = BitStream() try: read_quantum = 1024 # KB at a time bytes = in_f.read(read_quantum) while (bytes): for byte in bytes: bitstream.put_byte(ord(byte)) bytes = in_f.read(read_quantum) except Exception as e: print("Problem while reading from input file %s: %s" % (in_file, e)) in_f.close() # Define callbacks for the TaskMonitor for monitoring the encryption process if (len(in_file) <= 50): short_in_filename = in_file else: short_in_filename = os.path.split(in_file)[-1] if (len(short_in_filename) > 50): # Do ellipsis shortening short_in_filename = short_in_filename[0,20] + "..." + \ short_in_filename[-20,-1] def cb_task_percent_progress(task): print(" %.2f%% of %s encrypted..." % \ (task.get_percent_completed(), short_in_filename)) # Create new TaskMonitor and register the callbacks taskmon = TaskMonitor() taskmon.add_on_progress_percent_callback(cb_task_percent_progress, \ percent_span = 5) # Encrypt bitstream print("Encrypting...") ciphertext = public_key.encrypt_bitstream(bitstream, task_monitor=taskmon) # Save the ciphertext to the output file try: ciphertext.to_file(out_file) except Exception as e: print("Problem while saving the output file %s: %s" % (in_file, e.msg))
def setUp(self): """ Unit test setup method. """ self.task_monitor = TaskMonitor()
class TestTaskMonitor(unittest.TestCase): """ Test the class: plonevotecryptolib.utilities.TaskMonitor.TaskMonitor """ def setUp(self): """ Unit test setup method. """ self.task_monitor = TaskMonitor() def test_report_ticks(self): """ Test that TaskMonitor can be used to report the number of steps (ticks) performed by a "TaskMonitor-enabled" function. """ # We register a callback that increments a counter by one and is # called every 10 ticks counter = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks=10) # Now, we call the tme_fibonacci function with our task monitor, asking # for the 100th Fibonacci number tme_fibonacci(100, self.task_monitor) # The counter should have been updated once for every 10 numbers in the # sequence from 0 to our desired number, inclusive. So counter should # be 100/10 = 10. self.assertEqual(counter.value, 10) def test_report_percent(self): """ Test that TaskMonitor can be used to report the completion percentage of a "TaskMonitor-enabled" function that allows percentage monitoring. """ # We register a callback that increments a counter by one and is # called every 5% progress counter = Counter() self.task_monitor.add_on_progress_percent_callback( \ lambda tm: counter.increment(), percent_span = 5.0) # Now, we call the tme_fibonacci function with our task monitor, asking # for the 100th Fibonacci number tme_fibonacci(100, self.task_monitor) # The counter should have been updated once for every 5% advance in the # called function. This gives us 20 updates. self.assertEqual(counter.value, 20) def test_task_without_percent_reporting(self): """ Test how add_on_tick_callback(...) *and* add_on_progress_percent_callback(...) work when the task does not provide progress percent reporting (ie. a variable length task). """ # We register a callback that increments a counter by one and is # called every 10 ticks counter1 = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter1.increment(), num_ticks=10) # We register a callback that increments a counter by one and is # called every 5% progress counter2 = Counter() self.task_monitor.add_on_progress_percent_callback( \ lambda tm: counter2.increment(), percent_span = 5.0) # Now, we call the tme_search_in_list function with our task monitor, # asking for the position of element 100 in range(0,300) tme_search_in_list(list(range(0, 300)), 100, self.task_monitor) # counter1 should have been update 10 times, one for each 10 ticks of # a total of 100 ticks (100 is the 100th element of range(0,300)) self.assertEqual(counter1.value, 10) # counter2 should have never been updated, since tme_search_in_list # does not provide progress percent monitoring self.assertEqual(counter2.value, 0) def test_subtask_reporting(self): """ Test complex reporting on a task with subtasks. This includes: * Test task start/end callbacks. * Test getting the name and number of each subtask. * Test reporting percent progress of the whole task and each subtask. """ # Construct a logger object logger = Logger() # Set up callbacks to log messages on: # subtask creation, def task_start_cb(tm): tm_p = tm.parent msg = "New task started: \"%s\" " \ "(Subtask #%d of %d for task \"%s\")\n" % \ (tm.task_name, tm_p.current_subtask_num, \ tm_p.num_subtasks, tm_p.task_name) logger.log(msg) self.task_monitor.add_on_task_start_callback(task_start_cb) # subtask completion, def task_end_cb(tm): msg = "Task completed: \"%s\"\n" % tm.task_name logger.log(msg) self.task_monitor.add_on_task_end_callback(task_end_cb) # and progress percent (20%) def task_percent_cb(tm): msg = "\"%s\"... %d%% completed.\n" % \ (tm.task_name, tm.get_percent_completed()) logger.log(msg) self.task_monitor.add_on_progress_percent_callback(task_percent_cb) # We also count the total number of ticks counter = Counter() self.task_monitor.add_on_tick_callback(lambda tm: counter.increment(), num_ticks=1) # Call tme_fibonacci_subtasks using the task monitor tme_fibonacci_subtasks(self.task_monitor) # and compare the logged output with the expected one expected_output = \ """New task started: \"Multiple Fibonacci Tasks\" (Subtask #1 of 1 for task \"Root\") New task started: \"Fibonacci(300)\" (Subtask #1 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 300th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(300)\") \"Calculating the 300th Fibonacci number\"... 5% completed. \"Calculating the 300th Fibonacci number\"... 10% completed. \"Calculating the 300th Fibonacci number\"... 15% completed. \"Calculating the 300th Fibonacci number\"... 20% completed. \"Calculating the 300th Fibonacci number\"... 25% completed. \"Calculating the 300th Fibonacci number\"... 30% completed. \"Calculating the 300th Fibonacci number\"... 35% completed. \"Calculating the 300th Fibonacci number\"... 40% completed. \"Calculating the 300th Fibonacci number\"... 45% completed. \"Calculating the 300th Fibonacci number\"... 50% completed. \"Calculating the 300th Fibonacci number\"... 55% completed. \"Calculating the 300th Fibonacci number\"... 60% completed. \"Calculating the 300th Fibonacci number\"... 65% completed. \"Calculating the 300th Fibonacci number\"... 70% completed. \"Calculating the 300th Fibonacci number\"... 75% completed. \"Calculating the 300th Fibonacci number\"... 80% completed. \"Calculating the 300th Fibonacci number\"... 85% completed. \"Calculating the 300th Fibonacci number\"... 90% completed. \"Calculating the 300th Fibonacci number\"... 95% completed. \"Calculating the 300th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 300th Fibonacci number\" Task completed: \"Fibonacci(300)\" New task started: \"Fibonacci(500)\" (Subtask #2 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 500th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(500)\") \"Calculating the 500th Fibonacci number\"... 5% completed. \"Calculating the 500th Fibonacci number\"... 10% completed. \"Calculating the 500th Fibonacci number\"... 15% completed. \"Calculating the 500th Fibonacci number\"... 20% completed. \"Calculating the 500th Fibonacci number\"... 25% completed. \"Calculating the 500th Fibonacci number\"... 30% completed. \"Calculating the 500th Fibonacci number\"... 35% completed. \"Calculating the 500th Fibonacci number\"... 40% completed. \"Calculating the 500th Fibonacci number\"... 45% completed. \"Calculating the 500th Fibonacci number\"... 50% completed. \"Calculating the 500th Fibonacci number\"... 55% completed. \"Calculating the 500th Fibonacci number\"... 60% completed. \"Calculating the 500th Fibonacci number\"... 65% completed. \"Calculating the 500th Fibonacci number\"... 70% completed. \"Calculating the 500th Fibonacci number\"... 75% completed. \"Calculating the 500th Fibonacci number\"... 80% completed. \"Calculating the 500th Fibonacci number\"... 85% completed. \"Calculating the 500th Fibonacci number\"... 90% completed. \"Calculating the 500th Fibonacci number\"... 95% completed. \"Calculating the 500th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 500th Fibonacci number\" Task completed: \"Fibonacci(500)\" New task started: \"Fibonacci(200)\" (Subtask #3 of 3 for task \"Multiple Fibonacci Tasks\") New task started: \"Calculating the 200th Fibonacci number\" (Subtask #1 of 1 for task \"Fibonacci(200)\") \"Calculating the 200th Fibonacci number\"... 5% completed. \"Calculating the 200th Fibonacci number\"... 10% completed. \"Calculating the 200th Fibonacci number\"... 15% completed. \"Calculating the 200th Fibonacci number\"... 20% completed. \"Calculating the 200th Fibonacci number\"... 25% completed. \"Calculating the 200th Fibonacci number\"... 30% completed. \"Calculating the 200th Fibonacci number\"... 35% completed. \"Calculating the 200th Fibonacci number\"... 40% completed. \"Calculating the 200th Fibonacci number\"... 45% completed. \"Calculating the 200th Fibonacci number\"... 50% completed. \"Calculating the 200th Fibonacci number\"... 55% completed. \"Calculating the 200th Fibonacci number\"... 60% completed. \"Calculating the 200th Fibonacci number\"... 65% completed. \"Calculating the 200th Fibonacci number\"... 70% completed. \"Calculating the 200th Fibonacci number\"... 75% completed. \"Calculating the 200th Fibonacci number\"... 80% completed. \"Calculating the 200th Fibonacci number\"... 85% completed. \"Calculating the 200th Fibonacci number\"... 90% completed. \"Calculating the 200th Fibonacci number\"... 95% completed. \"Calculating the 200th Fibonacci number\"... 100% completed. Task completed: \"Calculating the 200th Fibonacci number\" Task completed: \"Fibonacci(200)\" Task completed: \"Multiple Fibonacci Tasks\" """ self.assertEqual(str(logger), expected_output) # Including ticks for the 0th number in each succession.. self.assertEqual(counter.value, 1003) def test_remove_callback(self): """ Test the remove_callback method of TaskMonitor. """ # We will run a new Task Monitor to monitor the tme_fibonacci_subtasks # function. # First, we define a callback to count all ticks for our task counter = Counter() def tick_counter_cb(tm): counter.increment() self.task_monitor.add_on_tick_callback(tick_counter_cb, num_ticks=1) # Then, we define a callback to be called whenever a subtask starts # This callback will remove our previous "tick counter" callback as # soon as the task named "Fibonacci(500)" starts. def task_start_cb(tm): if (tm.task_name == "Fibonacci(500)"): tm.remove_callback(tick_counter_cb) self.task_monitor.add_on_task_start_callback(task_start_cb) # Note that since remove_callback removes the callback solely for the # task for which it was called and its subtasks, our tick counter # callback will still be called for the "Fibonacci(200)" subtask of # tme_fibonacci_subtasks. # Lets run tme_fibonacci_subtasks: tme_fibonacci_subtasks(self.task_monitor) # Check that the counter has registered 301 ticks for Fibonacci(300) # (and subtasks) and 201 for Fibonacci(200) (and subtasks), but no # ticks for Fibonacci(500): self.assertEqual(counter.value, 502)