def test_init(self): ss = SubtaskState() self.assertIsInstance(ss, SubtaskState) ss.results.append(1) ss2 = SubtaskState() ss2.results.append(2) self.assertEqual(ss.results, [1]) self.assertEqual(ss2.results, [2])
def __add_subtask_to_tasks_states(self, node_name, node_id, price, ctd, address): if ctd.task_id not in self.tasks_states: raise RuntimeError("Should never be here!") logger.debug('add_subtask_to_tasks_states(%r, %r, %r, %r, %r)', node_name, node_id, price, ctd, address) ss = SubtaskState() ss.computer.node_id = node_id ss.computer.node_name = node_name ss.computer.performance = ctd.performance ss.computer.ip_address = address ss.computer.price = price ss.time_started = time.time() ss.deadline = ctd.deadline # TODO: read node ip address ss.subtask_definition = ctd.short_description ss.subtask_id = ctd.subtask_id ss.extra_data = ctd.extra_data ss.subtask_status = TaskStatus.starting ss.value = 0 self.tasks_states[ctd.task_id].subtask_states[ctd.subtask_id] = ss
def test_subtask_customizer(self): subtask_state = SubtaskState() subtask_details_dialog = SubtaskDetailsDialog( self.gui.main_window.window) customizer = SubtaskDetailsDialogCustomizer(subtask_details_dialog, self.logic, subtask_state) self.assertIsInstance(customizer, SubtaskDetailsDialogCustomizer) self.assertEqual("0.000000 ETH", "{}".format(customizer.gui.ui.priceLabel.text())) subtask_state.value = 157.03 * 10**16 customizer.update_view(subtask_state) self.assertEqual("1.570300 ETH", "{}".format(customizer.gui.ui.priceLabel.text()))
def _get_task_border(as_path=False): offsets = generate_expected_offsets(30, 800, 600) subtask = SubtaskState() definition = RenderingTaskDefinition() definition.options = BlenderRendererOptions() definition.options.use_frames = False definition.resolution = [800, 600] for k in range(1, 31): subtask.extra_data = {'start_task': k, 'end_task': k} border = BlenderTaskTypeInfo.get_task_border(subtask, definition, 30, as_path=as_path) assert min(border) == (0, offsets[k]) assert max(border) == (797, offsets[k + 1] - 1) definition.options.use_frames = True definition.options.frames = list(range(2)) offsets = generate_expected_offsets(15, 800, 600) for k in range(1, 31): subtask.extra_data = {'start_task': k, 'end_task': k} border = BlenderTaskTypeInfo.get_task_border(subtask, definition, 30, as_path=as_path) i = (k - 1) % 15 + 1 assert min(border) == (0, offsets[i]) assert max(border) == (798, offsets[i + 1] - 1) subtask.extra_data = {'start_task': 2, 'end_task': 2} definition.options.use_frames = True definition.options.frames = list(range(30)) if as_path: assert BlenderTaskTypeInfo.get_task_border( subtask, definition, 30, as_path=as_path) == \ [(0, 600), (800, 600), (800, 0), (0, 0)] else: assert BlenderTaskTypeInfo.get_task_border(subtask, definition, 30, as_path=as_path) == [] definition.options.use_frames = False definition.resolution = (0, 0) assert BlenderTaskTypeInfo.get_task_border(subtask, definition, 30, as_path=as_path) == []
def get_subtasks(self, frame): if self.task_definition.options.use_frames: subtask_ids = self.frames_subtasks.get(to_unicode(frame), []) subtask_ids = filter(None, subtask_ids) else: subtask_ids = self.subtasks_given.keys() subtasks = dict() # Convert to SubtaskState in order to match parent's return type for subtask_id in subtask_ids: state = SubtaskState() state.extra_data = self.subtasks_given[subtask_id] subtasks[subtask_id] = state return subtasks
def __add_subtask_to_tasks_states(self, node_name, node_id, ctd, address): logger.debug('add_subtask_to_tasks_states(%r, %r, %r, %r)', node_name, node_id, ctd, address) ss = SubtaskState() ss.time_started = time.time() ss.node_id = node_id ss.node_name = node_name ss.deadline = ctd['deadline'] ss.subtask_definition = ctd['short_description'] ss.subtask_id = ctd['subtask_id'] ss.extra_data = ctd['extra_data'] ss.subtask_status = SubtaskStatus.starting (self.tasks_states[ctd['task_id']].subtask_states[ctd['subtask_id']] ) = ss
def test_task_result_incoming(self, mock_addr): mock_addr.return_value = self.addr_return subtask_id = "xxyyzz" node_id = 'node' task_mock = self._get_task_mock() task_mock.counting_nodes = {} with patch("golem.task.taskbase.Task.result_incoming" ) as result_incoming_mock: self.tm.task_result_incoming(subtask_id) assert not result_incoming_mock.called task_mock.subtasks_given = dict() task_mock.subtasks_given[subtask_id] = TaskClient(node_id) subtask_state = SubtaskState() subtask_state.status = SubtaskStatus.downloading subtask_state.subtask_id = subtask_id subtask_state.computer = Mock() subtask_state.computer.node_id = node_id task_state = TaskState() task_state.computer = Mock() task_state.subtask_states[subtask_id] = subtask_state sync_wait(self.tm.add_new_task(task_mock)) self.tm.subtask2task_mapping[subtask_id] = "xyz" self.tm.tasks_states["xyz"] = task_state with patch("golem.task.taskbase.Task.result_incoming" ) as result_incoming_mock: self.tm.task_result_incoming(subtask_id) assert result_incoming_mock.called self.tm.tasks = [] with patch("golem.task.taskbase.Task.result_incoming" ) as result_incoming_mock: self.tm.task_result_incoming(subtask_id) assert not result_incoming_mock.called
def __build_subtasks(n): subtasks = dict() subtask_id = None for i in xrange(0, n): subtask = SubtaskState() subtask.subtask_id = str(uuid.uuid4()) subtask.computer = ComputerState() subtask.computer.node_name = 'node_{}'.format(i) subtask.computer.node_id = 'deadbeef0{}'.format(i) subtask.results = [] subtask.stderr = 'error_{}'.format(i) subtask.stdout = 'output_{}'.format(i) subtask.extra_data = {'start_task': i, 'end_task': i} subtask_id = subtask.subtask_id subtasks[subtask.subtask_id] = subtask return subtasks, subtask_id
def test_to_dictionary(): ss = SubtaskState() ss.subtask_definition = "My long task definition" ss.subtask_id = "ABCDEF" ss.subtask_progress = 0.92 ss.time_started = get_timestamp_utc() ss.deadline = timeout_to_deadline(ss.time_started + 5) ss.extra_data = {"param1": 1323, "param2": "myparam"} ss.subtask_rem_time = deadline_to_timeout( ss.deadline) - ss.time_started ss.subtask_status = SubtaskStatus.starting ss.value = 138 ss.stdout = "path/to/file" ss.stderr = "path/to/file2" ss.results = ["path/to/file3", "path/to/file4"] ss.computation_time = 130 ss.node_id = "NODE1" ss_dict = ss.to_dictionary() assert ss_dict['description'] == "My long task definition" assert ss_dict['subtask_id'] == "ABCDEF" assert ss_dict['progress'] == 0.92 assert ss_dict['time_started'] == get_timestamp_utc() assert ss_dict.get('deadline') is None assert ss_dict.get('extra_data') is None assert ss_dict['time_remaining'] == 5 assert ss_dict['status'] == SubtaskStatus.starting.value assert ss_dict.get('value') is None assert ss_dict['stdout'] == "path/to/file" assert ss_dict['stderr'] == "path/to/file2" assert ss_dict['results'] == ["path/to/file3", "path/to/file4"] assert ss_dict.get('computation_time') is None assert ss_dict['node_id'] == "NODE1"
def test_sorting(self): task_dialog = TaskDetailsDialog(self.gui.main_window.window) task_state = TaskDesc() customizer = TaskDetailsDialogCustomizer(task_dialog, self.logic, task_state) self.assertEqual(customizer.sorting, -1) self.assertIsNone(customizer.sorting_order) task_state.task_state.progress = 0.33 task_state.task_state.remaining_time = 34 task_state.task_state.elapsed_time = 12 ss1 = SubtaskState() ss1.computer.node_name = "ABC" ss1.subtask_id = "def" ss1.subtask_status = SubtaskStatus.finished task_state.task_state.subtask_states['def'] = ss1 ss2 = SubtaskState() ss2.computer.node_name = "DEF" ss2.subtask_id = "abc" ss2.subtask_status = SubtaskStatus.finished task_state.task_state.subtask_states['abc'] = ss2 customizer.update_view(task_state.task_state) self.assertEqual(customizer.sorting, -1) self.assertIsNone(customizer.sorting_order) self.assertEqual(len(customizer.subtask_table_elements), 2) ids = [str(customizer.gui.ui.nodesTableWidget.item(i, 1).text()) for i in range(2)] self.assertIn('def', ids) self.assertIn('abc', ids) customizer._TaskDetailsDialogCustomizer__header_clicked(1) self.assertEqual(customizer.sorting, 1) self.assertEqual(customizer.sorting_order, SortingOrder.ascending) self.assertEqual(len(customizer.subtask_table_elements), 2) self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 0).text()), "DEF") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 0).text()), "ABC") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 1).text()), "abc") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 1).text()), "def") customizer._TaskDetailsDialogCustomizer__header_clicked(1) self.assertEqual(customizer.sorting, 1) self.assertEqual(customizer.sorting_order, SortingOrder.descending) self.assertEqual(len(customizer.subtask_table_elements), 2) self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 0).text()), "ABC") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 0).text()), "DEF") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 1).text()), "def") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 1).text()), "abc") ss3 = SubtaskState() ss3.computer.node_name = "FGH" ss3.subtask_id = "fgh" ss3.subtask_status = SubtaskStatus.finished task_state.task_state.subtask_states['fgh'] = ss3 customizer.update_view(task_state.task_state) self.assertEqual(customizer.sorting, 1) self.assertEqual(customizer.sorting_order, SortingOrder.descending) self.assertEqual(len(customizer.subtask_table_elements), 3) self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 0).text()), "FGH") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 0).text()), "ABC") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 0).text()), "DEF") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 1).text()), "fgh") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 1).text()), "def") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 1).text()), "abc") customizer._TaskDetailsDialogCustomizer__header_clicked(0) self.assertEqual(customizer.sorting, 0) self.assertEqual(customizer.sorting_order, SortingOrder.ascending) self.assertEqual(len(customizer.subtask_table_elements), 3) self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 0).text()), "ABC") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 0).text()), "DEF") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 0).text()), "FGH") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 1).text()), "def") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 1).text()), "abc") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 1).text()), "fgh") customizer._TaskDetailsDialogCustomizer__header_clicked(0) self.assertEqual(customizer.sorting, 0) self.assertEqual(customizer.sorting_order, SortingOrder.descending) self.assertEqual(len(customizer.subtask_table_elements), 3) self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 0).text()), "FGH") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 0).text()), "DEF") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 0).text()), "ABC") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(0, 1).text()), "fgh") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(1, 1).text()), "abc") self.assertEqual(str(customizer.gui.ui.nodesTableWidget.item(2, 1).text()), "def")
def __init_basic_customizer(self): task_dialog = TaskDetailsDialog(self.gui.main_window.window) task_state = TaskDesc() ss1 = SubtaskState() ss1.subtask_id = "abc" ss1.computer.node_name ="ABC" ss1.computer.ip_address = "10.10.10.10" ss1.computer.performance = "1000" ss1.subtask_definition = "DEF 1" ss1.subtask_status = SubtaskStatus.downloading ss2 = SubtaskState() ss2.subtask_id = "def" ss2.computer.node_name = "DEF" ss2.computer.ip_address = "10.10.10.20" ss2.computer.performance = "2000" ss2.subtask_definition = "DEF 2" ss2.subtask_status = SubtaskStatus.starting ss3 = SubtaskState() ss3.subtask_id = "xyz" ss3.computer.node_name = "XYZ" ss3.computer.ip_address = "10.10.10.30" ss3.computer.performance = "3000" ss3.subtask_definition = "DEF 3" ss3.subtask_status = SubtaskStatus.finished task_state.task_state.subtask_states["abc"] = ss1 task_state.task_state.subtask_states["def"] = ss2 task_state.task_state.subtask_states["xyz"] = ss3 task_state.task_state.progress = 0.33 task_state.task_state.remaining_time = 34 task_state.task_state.elapsed_time = 12 customizer = TaskDetailsDialogCustomizer(task_dialog, self.logic, task_state) return customizer
def test_subtask_priority(self): s_rst = SubtaskState() s_rst.subtask_status = SubtaskStatus.restarted s_fil = SubtaskState() s_fil.subtask_status = SubtaskStatus.failure s_rsd = SubtaskState() s_rsd.subtask_status = SubtaskStatus.resent s_fin = SubtaskState() s_fin.subtask_status = SubtaskStatus.finished s_sta = SubtaskState() s_sta.subtask_status = SubtaskStatus.starting s_wai = SubtaskState() s_wai.subtask_status = SubtaskStatus.downloading assert subtasks_priority(s_rst) > subtasks_priority(s_fin) assert subtasks_priority(s_fil) > subtasks_priority(s_fin) assert subtasks_priority(s_rsd) > subtasks_priority(s_fin) assert subtasks_priority(s_fin) > subtasks_priority(s_sta) assert subtasks_priority(s_fin) > subtasks_priority(s_wai)
def test_single_task(self): # Just a single task, created with one subtask and finished # afterwards rtsm = RequestorTaskStatsManager() tstate = TaskState() tstate.status = TaskStatus.notStarted tstate.time_started = 0.0 dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id=None, op=TaskOp.CREATED) # task created self.assertEqual(rtsm.get_current_stats(), CurrentStats(1, 0, 0, 0, 0, 0, 0, 0, 0)) self.assertEqual(rtsm.get_finished_stats(), EMPTY_FINISHED_STATS) tstate.status = TaskStatus.waiting dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id=None, op=TaskOp.STARTED) dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id=None, op=TaskOp.WORK_OFFER_RECEIVED) # work offer received, but nothing more changed self.assertEqual(rtsm.get_current_stats(), CurrentStats(1, 0, 0, 0, 0, 0, 0, 0, 1)) self.assertEqual(rtsm.get_finished_stats(), EMPTY_FINISHED_STATS) tstate.subtask_states["st1.1"] = SubtaskState() tstate.subtask_states["st1.1"].subtask_status = SubtaskStatus.starting dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id="st1.1", op=SubtaskOp.ASSIGNED) # assigned subtask reflected in stats self.assertEqual(rtsm.get_current_stats(), CurrentStats(1, 0, 1, 0, 0, 0, 0, 0, 1)) self.assertEqual(rtsm.get_finished_stats(), EMPTY_FINISHED_STATS) tstate.subtask_states["st1.1"].subtask_status = ( SubtaskStatus.downloading) dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id="st1.1", op=SubtaskOp.RESULT_DOWNLOADING) tstate.subtask_states["st1.1"].subtask_status = SubtaskStatus.finished dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id="st1.1", op=SubtaskOp.FINISHED) # subtask finished and verified ok self.assertEqual(rtsm.get_current_stats(), CurrentStats(1, 0, 1, 1, 1, 0, 0, 0, 1)) self.assertEqual(rtsm.get_finished_stats(), EMPTY_FINISHED_STATS) tstate.status = TaskStatus.finished dispatcher.send(signal='golem.taskmanager', event='task_status_updated', task_id="task1", task_state=tstate, subtask_id=None, op=TaskOp.FINISHED) # task done self.assertEqual(rtsm.get_current_stats(), CurrentStats(1, 1, 1, 1, 1, 0, 0, 0, 1)) # duration of the task is unknown hence the complex compare self.assertEqual(rtsm.get_finished_stats()[0][0], 1) self.assertGreaterEqual(rtsm.get_finished_stats()[0][1], 0.0) self.assertEqual(rtsm.get_finished_stats()[1], FinishedTasksSummary(0, 0.0)) self.assertEqual(rtsm.get_finished_stats()[2], FinishedTasksSummary(0, 0.0))
def test_multiple_tasks(self): rs = RequestorTaskStats() # create a task ts1 = self.create_task_and_taskstate(rs, "task1") # add two subtasks self.add_subtask(rs, "task1", ts1, "st1.1") self.add_subtask(rs, "task1", ts1, "st1.2") # and another task ts2 = self.create_task_and_taskstate(rs, "task2") self.add_subtask(rs, "task2", ts2, "st2.1") # check the stats now: # both tasks are not finished self.assertFalse(rs.is_task_finished("task1"), "task1 is still active") self.assertFalse(rs.is_task_finished("task2"), "task2 is still active") # current stats show 2 tasks, no finished tasks, 3 subtasks in progress self.assertEqual( rs.get_current_stats(), CurrentStats(2, 0, 3, 0, 0, 0, 0, 0, 2), "Two tasks should be in progress, with 3 subtasks " "requested") # finish one of the subtasks of the first task self.finish_subtask(rs, "task1", ts1, "st1.1") self.assertFalse(rs.is_task_finished("task1"), "task1 is still active") self.assertFalse(rs.is_task_finished("task2"), "task2 is still active") # current stats show 2 tasks, no finished tasks, 2 subtasks in progress self.assertEqual( rs.get_current_stats(), CurrentStats(2, 0, 3, 1, 1, 0, 0, 0, 2), "Two tasks should be in progress, with 3 subtasks; " "one subtask should be collected and verified") # finish task2 self.finish_subtask(rs, "task2", ts2, "st2.1") self.assertFalse(rs.is_task_finished("task1"), "task1 is still active") self.assertFalse(rs.is_task_finished("task2"), "task2 is still active") self.assertEqual( rs.get_current_stats(), CurrentStats(2, 0, 3, 2, 2, 0, 0, 0, 2), "Two tasks should be in progress, with 3 subtasks; " "two of the subtasks should be collected and verified") self.finish_task(rs, "task2", ts2) self.assertFalse(rs.is_task_finished("task1"), "task1 is still active") self.assertTrue(rs.is_task_finished("task2"), "task2 is finished") self.assertEqual( rs.get_current_stats(), CurrentStats(2, 1, 3, 2, 2, 0, 0, 0, 2), "One task should be in progress, with 1 subtask " "running and 2 finished") # add a restored task with 2 subtasks ts3 = TaskState() ts3.status = TaskStatus.notStarted ts3.time_started = 0.0 ts3.subtask_states["st3.1"] = SubtaskState() ts3.subtask_states["st3.1"].subtask_status = SubtaskStatus.starting ts3.subtask_states["st3.2"] = SubtaskState() ts3.subtask_states["st3.2"].subtask_status = SubtaskStatus.starting rs.on_message("task3", ts3, op=TaskOp.RESTORED) self.assertFalse(rs.is_task_finished("task1"), "task1 is still active") self.assertTrue(rs.is_task_finished("task2"), "task2 is finished") self.assertFalse(rs.is_task_finished("task3"), "task3 is still active") self.assertEqual( rs.get_current_stats(), CurrentStats(3, 1, 5, 2, 2, 0, 0, 0, 2), "2 tasks should be in progress, with 5 subtasks " "(2 of them are finished)") # close the remaining tasks self.finish_subtask(rs, "task1", ts1, "st1.2") self.finish_task(rs, "task1", ts1) self.finish_subtask(rs, "task3", ts3, "st3.2") self.finish_subtask(rs, "task3", ts3, "st3.1") self.finish_task(rs, "task3", ts3) self.assertEqual( rs.get_current_stats(), CurrentStats(3, 3, 5, 5, 5, 0, 0, 0, 2), "No tasks should be in progress, with all 5 subtasks " "collected and verified")
def add_subtask(rs, task, tstate, subtask): tstate.subtask_states[subtask] = SubtaskState() sst = tstate.subtask_states[subtask] sst.subtask_status = SubtaskStatus.starting rs.on_message(task, tstate, subtask, SubtaskOp.ASSIGNED)
def test_stats_collection(self): rs = RequestorTaskStats() # create a task tstate = TaskState() tstate.status = TaskStatus.notStarted tstate.time_started = 0.0 rs.on_message("task1", tstate, None, TaskOp.CREATED) # is it finished? self.assertFalse(rs.is_task_finished("task1"), "task1 should be in progress") # are the stats as expected? task1_ts = rs.get_task_stats("task1") self.compare_task_stats(task1_ts, EMPTY_TASK_STATS) # what about the current stats? cs = rs.get_current_stats() self.assertEqual( cs, CurrentStats(1, 0, 0, 0, 0, 0, 0, 0, 0), "There should be one task only with no information " "about any subtasks") # start the task tstate.status = TaskStatus.waiting rs.on_message("task1", tstate, op=TaskOp.STARTED) # still one task, no finished ones and no subtasks at all self.assertEqual( cs, CurrentStats(1, 0, 0, 0, 0, 0, 0, 0, 0), "There should be one task only with no information " "about any subtasks") # receive work offer rs.on_message("task1", tstate, op=TaskOp.WORK_OFFER_RECEIVED) # which does not mean that a subtask is in progress cs = rs.get_current_stats() self.assertEqual(cs, CurrentStats(1, 0, 0, 0, 0, 0, 0, 0, 1), "Got work offer now") # add a subtask tstate.subtask_states["st1"] = SubtaskState() sst = tstate.subtask_states["st1"] # type: SubtaskState sst.subtask_status = SubtaskStatus.starting rs.on_message("task1", tstate, "st1", SubtaskOp.ASSIGNED) # a subtask in progress cs = rs.get_current_stats() self.assertEqual( cs, CurrentStats(1, 0, 1, 0, 0, 0, 0, 0, 1), "One subtask was requested so far, otherwise there " "should be no changes to stats") # download results of that subtask sst.subtask_status = SubtaskStatus.downloading rs.on_message("task1", tstate, "st1", SubtaskOp.RESULT_DOWNLOADING) # still subtask in progress cs = rs.get_current_stats() self.assertEqual( cs, CurrentStats(1, 0, 1, 0, 0, 0, 0, 0, 1), "One subtask is still in progress, and even though " "its results are being downloaded it's not shown " "in the stats") # and finish the subtask now sst.subtask_status = SubtaskStatus.finished rs.on_message("task1", tstate, "st1", SubtaskOp.FINISHED) # no subtask in progress but task is still not finished cs = rs.get_current_stats() self.assertEqual( cs, CurrentStats(1, 0, 1, 1, 1, 0, 0, 0, 1), "Sole subtask was finished which means its results " "were collected and verified") # send an unexpected subtask rs.on_message("task1", tstate, op=OtherOp.UNEXPECTED) cs = rs.get_current_stats() self.assertEqual(cs, CurrentStats(1, 0, 1, 1, 1, 0, 0, 0, 1), "Unexpected subtask have no influence on stats") # finish the task now tstate.status = TaskStatus.finished rs.on_message("task1", tstate, op=TaskOp.FINISHED) # no subtasks in progress, task finished cs = rs.get_current_stats() self.assertEqual(cs, CurrentStats(1, 1, 1, 1, 1, 0, 0, 0, 1), "The only task is now finished") self.assertTrue(rs.is_task_finished("task1"), "A task should be finished now")