def test_cycle_simple(self): self.pg.update_state('A', Waiting(['B'])) self.pg.update_state('B', Waiting(['A'])) # NB: Order matters: the second insertion is the one tracked as a cycle. self.assertEquals({'B'}, set(self.pg.dependencies_of('A'))) self.assertEquals(set(), set(self.pg.dependencies_of('B'))) self.assertEquals(set(), set(self.pg.cyclic_dependencies_of('A'))) self.assertEquals({'A'}, set(self.pg.cyclic_dependencies_of('B')))
def test_cycle_indirect(self): self.pg.update_state('A', Waiting(['B'])) self.pg.update_state('B', Waiting(['C'])) self.pg.update_state('C', Waiting(['A'])) self.assertEquals({'B'}, set(self.pg.dependencies_of('A'))) self.assertEquals({'C'}, set(self.pg.dependencies_of('B'))) self.assertEquals(set(), set(self.pg.dependencies_of('C'))) self.assertEquals(set(), set(self.pg.cyclic_dependencies_of('A'))) self.assertEquals(set(), set(self.pg.cyclic_dependencies_of('B'))) self.assertEquals({'A'}, set(self.pg.cyclic_dependencies_of('C')))
def test_cycle_long(self): # Creating a long chain is allowed. nodes = list(range(0, 100)) self._mk_chain(self.pg, nodes, states=(Waiting, )) walked_nodes = [node for node, _ in self.pg.walk([nodes[0]])] self.assertEquals(nodes, walked_nodes) # Closing the chain is not. begin, end = nodes[0], nodes[-1] self.pg.update_state(end, Waiting([begin])) self.assertEquals(set(), set(self.pg.dependencies_of(end))) self.assertEquals({begin}, set(self.pg.cyclic_dependencies_of(end)))
def test_state_roundtrips(self): states = [ Return('a'), Throw(PickleableException()), Waiting([TaskNode(None, None, None)]), Runnable(_runnable, ('an arg', )), Noop('nada {}', ('op', )) ] with closing(self.storage) as storage: for state in states: key = storage.put_state(state) actual = storage.get_state(key) self.assertEquals(state, actual) self.assertEquals(key, storage.put_state(actual))
def step(self, step_context): waiting_nodes = [] # Get the binary. binary_state = step_context.select_for(Select(self.snapshotted_process.binary_type), subject=self.subject, variants=self.variants) if type(binary_state) is Throw: return binary_state elif type(binary_state) is Waiting: waiting_nodes.extend(binary_state.dependencies) elif type(binary_state) is Noop: return Noop("Couldn't find binary: {}".format(binary_state)) elif type(binary_state) is not Return: State.raise_unrecognized(binary_state) # Create the request from the request callback after resolving its input clauses. input_values = [] for input_selector in self.snapshotted_process.input_selectors: sn_state = step_context.select_for(input_selector, self.subject, self.variants) if type(sn_state) is Waiting: waiting_nodes.extend(sn_state.dependencies) elif type(sn_state) is Return: input_values.append(sn_state.value) elif type(sn_state) is Noop: if input_selector.optional: input_values.append(None) else: return Noop('Was missing value for (at least) input {}'.format(input_selector)) elif type(sn_state) is Throw: return sn_state else: State.raise_unrecognized(sn_state) if waiting_nodes: return Waiting(waiting_nodes) # Now that we've returned on waiting, we can assume that relevant inputs have values. try: process_request = self.snapshotted_process.input_conversion(*input_values) except Exception as e: return Throw(e) # Request snapshots for the snapshot_subjects from the process request. snapshot_subjects_value = [] if process_request.snapshot_subjects: snapshot_subjects_state = step_context.select_for(SelectDependencies(Snapshot, SnapshottedProcessRequest, 'snapshot_subjects', field_types=(Files,)), process_request, self.variants) if type(snapshot_subjects_state) is not Return: return snapshot_subjects_state snapshot_subjects_value = snapshot_subjects_state.value # Ready to run. execution = _Process(step_context.snapshot_archive_root, process_request, binary_state.value, snapshot_subjects_value, self.snapshotted_process.output_conversion) return Runnable(_execute, (execution,))
def test_dependency_edges(self): self.pg.update_state('A', Waiting(['B', 'C'])) self.assertEquals({'B', 'C'}, set(self.pg.dependencies_of('A'))) self.assertEquals({'A'}, set(self.pg.dependents_of('B'))) self.assertEquals({'A'}, set(self.pg.dependents_of('C')))
def test_disallow_completing_with_incomplete_deps(self): self.pg.update_state('A', Waiting(['B'])) self.pg.update_state('B', Waiting(['C'])) with self.assertRaises(IncompleteDependencyException): self.pg.update_state('A', Return('done!'))
def test_disallow_completed_state_change(self): self.pg.update_state('A', Return('done!')) with self.assertRaises(CompletedNodeException): self.pg.update_state('A', Waiting(['B']))