1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 from aria.orchestrator.workflows.api import task_graph, task
21 class MockTask(task.BaseTask):
23 super(MockTask, self).__init__(ctx={})
28 return task_graph.TaskGraph(name='mock-graph')
31 class TestTaskGraphTasks(object):
33 def test_add_task(self, graph):
35 add_result = graph.add_tasks(task)
36 assert add_result == [task]
37 tasks = [t for t in graph.tasks]
38 assert len(tasks) == 1
39 assert tasks[0] == task
41 def test_add_empty_group(self, graph):
42 result = graph.add_tasks([])
45 def test_add_group(self, graph):
46 tasks = [MockTask(), MockTask(), MockTask()]
47 added_tasks = graph.add_tasks(*tasks)
48 assert added_tasks == tasks
50 def test_add_partially_existing_group(self, graph):
53 tasks = [MockTask(), task, MockTask()]
54 added_tasks = graph.add_tasks(*tasks)
55 assert added_tasks == [tasks[0], tasks[2]]
57 def test_add_recursively_group(self, graph):
58 recursive_group = [MockTask(), MockTask()]
59 tasks = [MockTask(), recursive_group, MockTask()]
60 added_tasks = graph.add_tasks(tasks)
61 assert added_tasks == [tasks[0], recursive_group[0], recursive_group[1], tasks[2]]
63 def test_add_existing_task(self, graph):
66 # adding a task already in graph - should have no effect, and return False
67 add_result = graph.add_tasks(task)
68 assert add_result == []
69 tasks = [t for t in graph.tasks]
70 assert len(tasks) == 1
71 assert tasks[0] == task
73 def test_remove_task(self, graph):
75 other_task = MockTask()
77 graph.add_tasks(other_task)
78 graph.remove_tasks(other_task)
79 tasks = [t for t in graph.tasks]
80 assert len(tasks) == 1
81 assert tasks[0] == task
83 def test_remove_tasks_with_dependency(self, graph):
85 dependent_task = MockTask()
87 graph.add_tasks(dependent_task)
88 graph.add_dependency(dependent_task, task)
89 remove_result = graph.remove_tasks(dependent_task)
90 assert remove_result == [dependent_task]
91 tasks = [t for t in graph.tasks]
92 assert len(tasks) == 1
93 assert tasks[0] == task
94 # asserting no dependencies are left for the dependent task
95 assert len(list(graph.get_dependencies(task))) == 0
97 def test_remove_empty_group(self, graph):
98 result = graph.remove_tasks([])
101 def test_remove_group(self, graph):
102 tasks = [MockTask(), MockTask(), MockTask()]
103 graph.add_tasks(*tasks)
104 removed_tasks = graph.remove_tasks(*tasks)
105 assert removed_tasks == tasks
107 def test_remove_partially_existing_group(self, graph):
109 graph.add_tasks(task)
110 tasks = [MockTask(), task, MockTask()]
111 removed_tasks = graph.remove_tasks(*tasks)
112 assert removed_tasks == [task]
114 def test_remove_recursively_group(self, graph):
115 recursive_group = [MockTask(), MockTask()]
116 tasks = [MockTask(), recursive_group, MockTask()]
117 graph.add_tasks(tasks)
118 removed_tasks = graph.remove_tasks(tasks)
119 assert removed_tasks == [tasks[0], recursive_group[0], recursive_group[1], tasks[2]]
121 def test_remove_nonexistent_task(self, graph):
123 task_not_in_graph = MockTask()
124 graph.add_tasks(task)
125 # removing a task not in graph - should have no effect, and return False
126 remove_result = graph.remove_tasks(task_not_in_graph)
127 assert remove_result == []
128 tasks = [t for t in graph.tasks]
129 assert len(tasks) == 1
130 assert tasks[0] == task
132 def test_has_task(self, graph):
134 graph.add_tasks(task)
135 assert graph.has_tasks(task) is True
137 def test_has_nonexistent_task(self, graph):
139 task_not_in_graph = MockTask()
140 graph.add_tasks(task)
141 assert graph.has_tasks(task_not_in_graph) is False
143 def test_has_empty_group(self, graph):
144 # the "empty task" is in the graph
145 assert graph.has_tasks([]) is True
147 def test_has_group(self, graph):
148 tasks = [MockTask(), MockTask(), MockTask()]
149 graph.add_tasks(*tasks)
150 assert graph.has_tasks(*tasks) is True
152 def test_has_partially_existing_group(self, graph):
154 graph.add_tasks(task)
155 tasks = [MockTask(), task, MockTask()]
156 assert graph.has_tasks(tasks) is False
158 def test_has_recursively_group(self, graph):
159 recursive_group = [MockTask(), MockTask()]
160 tasks = [MockTask(), recursive_group, MockTask()]
161 graph.add_tasks(tasks)
162 assert graph.has_tasks(tasks) is True
164 def test_get_task(self, graph):
166 graph.add_tasks(task)
167 assert graph.get_task(task.id) == task
169 def test_get_nonexistent_task(self, graph):
171 task_not_in_graph = MockTask()
172 graph.add_tasks(task)
173 with pytest.raises(task_graph.TaskNotInGraphError):
174 graph.get_task(task_not_in_graph.id)
177 class TestTaskGraphGraphTraversal(object):
179 def test_tasks_iteration(self, graph):
181 other_task = MockTask()
182 graph.add_tasks(task)
183 graph.add_tasks(other_task)
184 tasks = [t for t in graph.tasks]
185 assert set(tasks) == set([task, other_task])
187 def test_get_dependents(self, graph):
189 dependent_task_1 = MockTask()
190 dependent_task_2 = MockTask()
191 transitively_dependent_task = MockTask()
193 graph.add_tasks(task)
194 graph.add_tasks(dependent_task_1)
195 graph.add_tasks(dependent_task_2)
196 graph.add_tasks(transitively_dependent_task)
198 graph.add_dependency(dependent_task_1, task)
199 graph.add_dependency(dependent_task_2, task)
200 graph.add_dependency(transitively_dependent_task, dependent_task_2)
202 dependent_tasks = list(graph.get_dependents(task))
203 # transitively_dependent_task not expected to appear in the result
204 assert set(dependent_tasks) == set([dependent_task_1, dependent_task_2])
206 def test_get_task_empty_dependents(self, graph):
208 other_task = MockTask()
209 graph.add_tasks(task)
210 graph.add_tasks(other_task)
211 dependent_tasks = list(graph.get_dependents(task))
212 assert len(dependent_tasks) == 0
214 def test_get_nonexistent_task_dependents(self, graph):
216 task_not_in_graph = MockTask()
217 graph.add_tasks(task)
218 with pytest.raises(task_graph.TaskNotInGraphError):
219 list(graph.get_dependents(task_not_in_graph))
221 def test_get_dependencies(self, graph):
223 dependency_task_1 = MockTask()
224 dependency_task_2 = MockTask()
225 transitively_dependency_task = MockTask()
227 graph.add_tasks(task)
228 graph.add_tasks(dependency_task_1)
229 graph.add_tasks(dependency_task_2)
230 graph.add_tasks(transitively_dependency_task)
232 graph.add_dependency(task, dependency_task_1)
233 graph.add_dependency(task, dependency_task_2)
234 graph.add_dependency(dependency_task_2, transitively_dependency_task)
236 dependency_tasks = list(graph.get_dependencies(task))
237 # transitively_dependency_task not expected to appear in the result
238 assert set(dependency_tasks) == set([dependency_task_1, dependency_task_2])
240 def test_get_task_empty_dependencies(self, graph):
242 other_task = MockTask()
243 graph.add_tasks(task)
244 graph.add_tasks(other_task)
245 dependency_tasks = list(graph.get_dependencies(task))
246 assert len(dependency_tasks) == 0
248 def test_get_nonexistent_task_dependencies(self, graph):
250 task_not_in_graph = MockTask()
251 graph.add_tasks(task)
252 with pytest.raises(task_graph.TaskNotInGraphError):
253 list(graph.get_dependencies(task_not_in_graph))
256 class TestTaskGraphDependencies(object):
258 def test_add_dependency(self, graph):
260 dependency_task = MockTask()
261 unrelated_task = MockTask()
262 graph.add_tasks(task)
263 graph.add_tasks(dependency_task)
264 graph.add_tasks(unrelated_task)
265 graph.add_dependency(task, dependency_task)
266 add_result = graph.has_dependency(task, dependency_task)
267 assert add_result is True
268 dependency_tasks = list(graph.get_dependencies(task))
269 assert len(dependency_tasks) == 1
270 assert dependency_tasks[0] == dependency_task
272 def test_add_existing_dependency(self, graph):
274 dependency_task = MockTask()
275 graph.add_tasks(task)
276 graph.add_tasks(dependency_task)
277 graph.add_dependency(task, dependency_task)
278 add_result = graph.has_dependency(task, dependency_task)
279 # adding a dependency already in graph - should have no effect, and return False
280 assert add_result is True
281 graph.add_dependency(task, dependency_task)
282 add_result = graph.has_dependency(task, dependency_task)
283 assert add_result is True
284 dependency_tasks = list(graph.get_dependencies(task))
285 assert len(dependency_tasks) == 1
286 assert dependency_tasks[0] == dependency_task
288 def test_add_dependency_nonexistent_dependent(self, graph):
290 task_not_in_graph = MockTask()
291 graph.add_tasks(task)
292 with pytest.raises(task_graph.TaskNotInGraphError):
293 graph.add_dependency(task_not_in_graph, task)
295 def test_add_dependency_nonexistent_dependency(self, graph):
297 task_not_in_graph = MockTask()
298 graph.add_tasks(task)
299 with pytest.raises(task_graph.TaskNotInGraphError):
300 graph.add_dependency(task, task_not_in_graph)
302 def test_add_dependency_empty_dependent(self, graph):
304 graph.add_tasks(task)
305 # expecting add_dependency result to be False - no dependency has been created
306 assert set(graph.tasks) == set((task,))
308 def test_add_dependency_empty_dependency(self, graph):
310 graph.add_tasks(task)
311 # expecting add_dependency result to be False - no dependency has been created
312 assert set(graph.tasks) == set((task,))
314 def test_add_dependency_dependent_group(self, graph):
316 group_tasks = [MockTask() for _ in xrange(3)]
317 graph.add_tasks(task)
318 graph.add_tasks(*group_tasks)
319 graph.add_dependency(group_tasks, task)
320 assert graph.has_dependency(group_tasks[0], task) is True
321 assert graph.has_dependency(group_tasks[1], task) is True
322 assert graph.has_dependency(group_tasks[2], task) is True
324 def test_add_dependency_dependency_group(self, graph):
326 group_tasks = [MockTask() for _ in xrange(3)]
327 graph.add_tasks(task)
328 graph.add_tasks(*group_tasks)
329 graph.add_dependency(task, group_tasks)
330 assert graph.has_dependency(task, group_tasks[0]) is True
331 assert graph.has_dependency(task, group_tasks[1]) is True
332 assert graph.has_dependency(task, group_tasks[2]) is True
334 def test_add_dependency_between_groups(self, graph):
335 group_1_tasks = [MockTask() for _ in xrange(3)]
336 group_2_tasks = [MockTask() for _ in xrange(3)]
337 graph.add_tasks(*group_1_tasks)
338 graph.add_tasks(*group_2_tasks)
339 graph.add_dependency(group_1_tasks, group_2_tasks)
340 for group_2_task in group_2_tasks:
341 assert graph.has_dependency(group_1_tasks[0], group_2_task) is True
342 assert graph.has_dependency(group_1_tasks[1], group_2_task) is True
343 assert graph.has_dependency(group_1_tasks[2], group_2_task) is True
345 def test_add_dependency_dependency_group_with_some_existing_dependencies(self, graph):
347 group_tasks = [MockTask() for _ in xrange(3)]
348 graph.add_tasks(task)
349 graph.add_tasks(*group_tasks)
350 # adding a dependency on a specific task manually,
351 # before adding a dependency on the whole parallel
352 graph.add_dependency(task, group_tasks[1])
353 graph.add_dependency(task, group_tasks)
354 assert graph.has_dependency(task, group_tasks[0]) is True
355 assert graph.has_dependency(task, group_tasks[1]) is True
356 assert graph.has_dependency(task, group_tasks[2]) is True
358 def test_add_existing_dependency_between_groups(self, graph):
359 group_1_tasks = [MockTask() for _ in xrange(3)]
360 group_2_tasks = [MockTask() for _ in xrange(3)]
361 graph.add_tasks(*group_1_tasks)
362 graph.add_tasks(*group_2_tasks)
363 graph.add_dependency(group_1_tasks, group_2_tasks)
364 add_result = graph.has_dependency(group_1_tasks, group_2_tasks)
365 assert add_result is True
366 # adding a dependency already in graph - should have no effect, and return False
367 graph.add_dependency(group_1_tasks, group_2_tasks)
368 add_result = graph.has_dependency(group_1_tasks, group_2_tasks)
369 assert add_result is True
370 for group_2_task in group_2_tasks:
371 assert graph.has_dependency(group_1_tasks[0], group_2_task) is True
372 assert graph.has_dependency(group_1_tasks[1], group_2_task) is True
373 assert graph.has_dependency(group_1_tasks[2], group_2_task) is True
375 def test_has_dependency(self, graph):
377 dependency_task = MockTask()
378 graph.add_tasks(task)
379 graph.add_tasks(dependency_task)
380 graph.add_dependency(task, dependency_task)
381 assert graph.has_dependency(task, dependency_task) is True
383 def test_has_nonexistent_dependency(self, graph):
385 other_task = MockTask()
386 graph.add_tasks(task)
387 graph.add_tasks(other_task)
388 assert graph.has_dependency(task, other_task) is False
390 def test_has_dependency_nonexistent_dependent(self, graph):
392 task_not_in_graph = MockTask()
393 graph.add_tasks(task)
394 with pytest.raises(task_graph.TaskNotInGraphError):
395 graph.has_dependency(task_not_in_graph, task)
397 def test_has_dependency_nonexistent_dependency(self, graph):
399 task_not_in_graph = MockTask()
400 graph.add_tasks(task)
401 with pytest.raises(task_graph.TaskNotInGraphError):
402 graph.has_dependency(task, task_not_in_graph)
404 def test_has_dependency_empty_dependent(self, graph):
406 graph.add_tasks(task)
407 # expecting has_dependency result to be False - dependency in an empty form
408 assert graph.has_dependency([], task) is False
410 def test_has_dependency_empty_dependency(self, graph):
412 graph.add_tasks(task)
413 # expecting has_dependency result to be True - dependency in an empty form
414 assert graph.has_dependency(task, []) is False
416 def test_has_dependency_dependent_group(self, graph):
418 group_tasks = [MockTask() for _ in xrange(3)]
419 graph.add_tasks(task)
420 graph.add_tasks(*group_tasks)
421 assert graph.has_dependency(group_tasks, task) is False
422 graph.add_dependency(group_tasks, task)
423 assert graph.has_dependency(group_tasks, task) is True
425 def test_has_dependency_dependency_parallel(self, graph):
427 group_tasks = [MockTask() for _ in xrange(3)]
428 graph.add_tasks(task)
429 graph.add_tasks(*group_tasks)
430 assert graph.has_dependency(task, group_tasks) is False
431 graph.add_dependency(task, group_tasks)
432 assert graph.has_dependency(task, group_tasks) is True
434 def test_has_dependency_between_groups(self, graph):
435 group_1_tasks = [MockTask() for _ in xrange(3)]
436 group_2_tasks = [MockTask() for _ in xrange(3)]
437 graph.add_tasks(*group_1_tasks)
438 graph.add_tasks(*group_2_tasks)
439 assert graph.has_dependency(group_2_tasks, group_1_tasks) is False
440 graph.add_dependency(group_2_tasks, group_1_tasks)
441 assert graph.has_dependency(group_2_tasks, group_1_tasks) is True
443 def test_has_dependency_dependency_parallel_with_some_existing_dependencies(self, graph):
445 parallel_tasks = [MockTask() for _ in xrange(3)]
446 graph.add_tasks(task)
447 parallel = graph.add_tasks(*parallel_tasks)
448 graph.add_dependency(task, parallel_tasks[1])
449 # only a partial dependency exists - has_dependency is expected to return False
450 assert graph.has_dependency(task, parallel) is False
452 def test_has_nonexistent_dependency_between_groups(self, graph):
453 group_1_tasks = [MockTask() for _ in xrange(3)]
454 group_2_tasks = [MockTask() for _ in xrange(3)]
455 graph.add_tasks(*group_1_tasks)
456 graph.add_tasks(*group_2_tasks)
457 assert graph.has_dependency(group_1_tasks, group_2_tasks) is False
459 def test_remove_dependency(self, graph):
461 dependency_task = MockTask()
462 another_dependent_task = MockTask()
463 graph.add_tasks(task)
464 graph.add_tasks(dependency_task)
465 graph.add_tasks(another_dependent_task)
466 graph.add_dependency(task, dependency_task)
467 graph.add_dependency(another_dependent_task, dependency_task)
469 graph.remove_dependency(task, dependency_task)
470 remove_result = graph.has_dependency(task, dependency_task)
471 assert remove_result is False
472 assert graph.has_dependency(task, dependency_task) is False
473 assert graph.has_dependency(another_dependent_task, dependency_task) is True
475 def test_remove_nonexistent_dependency(self, graph):
477 dependency_task = MockTask()
478 graph.add_tasks(task)
479 graph.add_tasks(dependency_task)
480 # removing a dependency not in graph - should have no effect, and return False
481 graph.remove_dependency(task, dependency_task)
482 remove_result = graph.has_dependency(task, dependency_task)
483 assert remove_result is False
484 tasks = [t for t in graph.tasks]
485 assert set(tasks) == set([task, dependency_task])
487 def test_remove_dependency_nonexistent_dependent(self, graph):
489 task_not_in_graph = MockTask()
490 graph.add_tasks(task)
491 with pytest.raises(task_graph.TaskNotInGraphError):
492 graph.remove_dependency(task_not_in_graph, task)
494 def test_remove_dependency_nonexistent_dependency(self, graph):
495 # in this test the dependency *task* is not in the graph, not just the dependency itself
497 task_not_in_graph = MockTask()
498 graph.add_tasks(task)
499 with pytest.raises(task_graph.TaskNotInGraphError):
500 graph.remove_dependency(task, task_not_in_graph)
502 def test_remove_dependency_empty_dependent(self, graph):
504 graph.add_tasks(task)
505 # expecting remove_dependency result to be False - no dependency has been created
506 graph.remove_dependency([], task)
507 assert set(graph.tasks) == set((task,))
509 def test_remove_dependency_empty_dependency(self, graph):
511 graph.add_tasks(task)
512 # expecting remove_dependency result to be False - no dependency has been created
513 graph.remove_dependency(task, [])
514 assert set(graph.tasks) == set((task,))
516 def test_remove_dependency_dependent_group(self, graph):
518 group_tasks = [MockTask() for _ in xrange(3)]
519 graph.add_tasks(task)
520 graph.add_tasks(*group_tasks)
521 graph.add_dependency(group_tasks, task)
522 graph.remove_dependency(group_tasks, task)
523 remove_result = graph.has_dependency(group_tasks, task)
524 assert remove_result is False
525 assert graph.has_dependency(group_tasks[0], task) is False
526 assert graph.has_dependency(group_tasks[1], task) is False
527 assert graph.has_dependency(group_tasks[2], task) is False
529 def test_remove_dependency_dependency_group(self, graph):
531 group_tasks = [MockTask() for _ in xrange(3)]
532 graph.add_tasks(task)
533 graph.add_tasks(*group_tasks)
534 graph.add_dependency(task, group_tasks)
535 graph.remove_dependency(task, group_tasks)
536 remove_result = graph.has_dependency(task, group_tasks)
537 assert remove_result is False
538 assert graph.has_dependency(task, group_tasks[0]) is False
539 assert graph.has_dependency(task, group_tasks[1]) is False
540 assert graph.has_dependency(task, group_tasks[2]) is False
542 def test_remove_dependency_between_groups(self, graph):
543 group_1_tasks = [MockTask() for _ in xrange(3)]
544 group_2_tasks = [MockTask() for _ in xrange(3)]
545 graph.add_tasks(*group_1_tasks)
546 graph.add_tasks(*group_2_tasks)
547 graph.add_dependency(group_2_tasks, group_1_tasks)
548 graph.remove_dependency(group_2_tasks, group_1_tasks)
549 remove_result = graph.has_dependency(group_2_tasks, group_1_tasks)
550 assert remove_result is False
551 for group_2_task in group_2_tasks:
552 assert graph.has_dependency(group_2_task, group_1_tasks[0]) is False
553 assert graph.has_dependency(group_2_task, group_1_tasks[1]) is False
554 assert graph.has_dependency(group_2_task, group_1_tasks[2]) is False
556 def test_remove_dependency_dependency_group_with_some_existing_dependencies(self, graph):
558 group_tasks = [MockTask() for _ in xrange(3)]
559 graph.add_tasks(task)
560 graph.add_tasks(*group_tasks)
561 graph.add_dependency(task, group_tasks[1])
562 graph.remove_dependency(task, group_tasks)
563 remove_result = graph.has_dependency(task, group_tasks)
564 # only a partial dependency exists - remove_dependency is expected to return False
565 assert remove_result is False
566 # no dependencies are expected to have changed
567 assert graph.has_dependency(task, group_tasks[0]) is False
568 assert graph.has_dependency(task, group_tasks[1]) is True
569 assert graph.has_dependency(task, group_tasks[2]) is False
571 def test_remove_nonexistent_dependency_between_groups(self, graph):
572 group_1_tasks = [MockTask() for _ in xrange(3)]
573 group_2_tasks = [MockTask() for _ in xrange(3)]
574 graph.add_tasks(*group_1_tasks)
575 graph.add_tasks(*group_2_tasks)
576 # removing a dependency not in graph - should have no effect, and return False
577 graph.remove_dependency(group_2_tasks, group_1_tasks)
578 remove_result = graph.has_dependency(group_2_tasks, group_1_tasks)
579 assert remove_result is False
583 def test_group_with_nested_sequence(self, graph):
584 all_tasks = [MockTask() for _ in xrange(5)]
585 graph.add_tasks(all_tasks[0],
586 graph.sequence(all_tasks[1], all_tasks[2], all_tasks[3]),
588 assert set(graph.tasks) == set(all_tasks)
590 # tasks[2] and tasks[3] should each have a single dependency; the rest should have none
591 assert len(list(graph.get_dependencies(all_tasks[0]))) == 0
592 assert len(list(graph.get_dependencies(all_tasks[1]))) == 0
593 assert set(graph.get_dependencies(all_tasks[2])) == set([all_tasks[1]])
594 assert set(graph.get_dependencies(all_tasks[3])) == set([all_tasks[2]])
595 assert len(list(graph.get_dependencies(all_tasks[4]))) == 0
597 def test_group_with_nested_group(self, graph):
598 tasks = [MockTask() for _ in xrange(5)]
599 graph.add_tasks(tasks[0], (tasks[1], tasks[2], tasks[3]), tasks[4])
600 graph_tasks = [t for t in graph.tasks]
601 assert set(graph_tasks) == set(tasks)
602 # none of the tasks should have any dependencies
603 for i in xrange(len(tasks)):
604 assert len(list(graph.get_dependencies(tasks[i]))) == 0
606 def test_group_with_recursively_nested_group(self, graph):
607 recursively_nested_tasks = [MockTask(), MockTask(), MockTask()]
608 nested_tasks = [MockTask(), MockTask(), MockTask(), recursively_nested_tasks]
609 tasks = [MockTask(), MockTask(), MockTask(), nested_tasks]
610 graph.add_tasks(*tasks)
612 assert set(graph.tasks) == set(tasks[:3] + nested_tasks[:3] + recursively_nested_tasks)
613 for tasks_list in [tasks, nested_tasks, recursively_nested_tasks]:
614 for i in xrange(len(tasks_list[:3])):
615 assert len(list(graph.get_dependencies(tasks_list[i]))) == 0
617 def test_group_with_recursively_nested_group_and_interdependencies(self, graph):
618 recursively_nested_tasks = [MockTask(), MockTask(), MockTask()]
619 nested_tasks = [MockTask(), MockTask(), MockTask(), recursively_nested_tasks]
620 tasks = [MockTask(), MockTask(), MockTask(), nested_tasks]
621 graph.add_tasks(*tasks)
623 graph.add_dependency(tasks[2], nested_tasks[2])
624 graph.add_dependency(nested_tasks[1], recursively_nested_tasks[0])
625 graph.add_dependency(recursively_nested_tasks[1], tasks[0])
627 assert set(graph.tasks) == set(tasks[:3] + nested_tasks[:3] + recursively_nested_tasks)
628 assert set(graph.get_dependencies(tasks[0])) == set()
629 assert set(graph.get_dependencies(tasks[1])) == set()
630 assert set(graph.get_dependencies(tasks[2])) == set([nested_tasks[2]])
632 assert set(graph.get_dependencies(nested_tasks[0])) == set()
633 assert set(graph.get_dependencies(nested_tasks[1])) == set([recursively_nested_tasks[0]])
634 assert set(graph.get_dependencies(nested_tasks[2])) == set()
636 assert set(graph.get_dependencies(recursively_nested_tasks[0])) == set()
637 assert set(graph.get_dependencies(recursively_nested_tasks[1])) == set([tasks[0]])
638 assert set(graph.get_dependencies(recursively_nested_tasks[2])) == set()
641 class TestTaskGraphSequence(object):
643 def test_sequence(self, graph):
644 tasks = [MockTask(), MockTask(), MockTask()]
645 graph.sequence(*tasks)
646 graph_tasks = [t for t in graph.tasks]
647 assert set(graph_tasks) == set(tasks)
648 assert len(list(graph.get_dependencies(tasks[0]))) == 0
649 assert set(graph.get_dependencies(tasks[1])) == set([tasks[0]])
650 assert set(graph.get_dependencies(tasks[2])) == set([tasks[1]])
652 def test_sequence_with_some_tasks_and_dependencies_already_in_graph(self, graph):
653 # tests both that tasks which werent previously in graph get inserted, and
654 # that existing tasks don't get re-added to graph
655 tasks = [MockTask(), MockTask(), MockTask()]
656 # insert some tasks and dependencies to the graph
657 graph.add_tasks(tasks[1])
658 graph.add_tasks(tasks[2])
659 graph.add_dependency(tasks[2], tasks[1])
661 graph.sequence(*tasks)
662 graph_tasks = [t for t in graph.tasks]
663 assert set(graph_tasks) == set(tasks)
664 assert len(list(graph.get_dependencies(tasks[0]))) == 0
665 assert set(graph.get_dependencies(tasks[1])) == set([tasks[0]])
666 assert set(graph.get_dependencies(tasks[2])) == set([tasks[1]])
668 def test_sequence_with_nested_sequence(self, graph):
669 tasks = [MockTask() for _ in xrange(5)]
670 graph.sequence(tasks[0], graph.sequence(tasks[1], tasks[2], tasks[3]), tasks[4])
671 graph_tasks = [t for t in graph.tasks]
672 assert set(graph_tasks) == set(tasks)
673 # first task should have no dependencies
674 assert len(list(graph.get_dependencies(tasks[0]))) == 0
675 assert len(list(graph.get_dependencies(tasks[1]))) == 1
676 assert len(list(graph.get_dependencies(tasks[2]))) == 2
677 assert len(list(graph.get_dependencies(tasks[3]))) == 2
678 assert len(list(graph.get_dependencies(tasks[4]))) == 3
680 def test_sequence_with_nested_group(self, graph):
681 tasks = [MockTask() for _ in xrange(5)]
682 graph.sequence(tasks[0], (tasks[1], tasks[2], tasks[3]), tasks[4])
683 graph_tasks = [t for t in graph.tasks]
684 assert set(graph_tasks) == set(tasks)
685 # first task should have no dependencies
686 assert len(list(graph.get_dependencies(tasks[0]))) == 0
687 # rest of the tasks (except last) should have a single dependency - the first task
688 for i in xrange(1, 4):
689 assert set(graph.get_dependencies(tasks[i])) == set([tasks[0]])
690 # last task should have have a dependency on all tasks except for the first one
691 assert set(graph.get_dependencies(tasks[4])) == set([tasks[1], tasks[2], tasks[3]])
693 def test_sequence_with_recursively_nested_group(self, graph):
694 recursively_nested_group = [MockTask(), MockTask()]
695 nested_group = [MockTask(), recursively_nested_group, MockTask()]
696 sequence_tasks = [MockTask(), nested_group, MockTask()]
698 graph.sequence(*sequence_tasks)
699 graph_tasks = [t for t in graph.tasks]
700 assert set(graph_tasks) == set([sequence_tasks[0], nested_group[0],
701 recursively_nested_group[0], recursively_nested_group[1],
702 nested_group[2], sequence_tasks[2]])
704 assert list(graph.get_dependencies(nested_group[0])) == [sequence_tasks[0]]
705 assert list(graph.get_dependencies(recursively_nested_group[0])) == [sequence_tasks[0]]
706 assert list(graph.get_dependencies(recursively_nested_group[1])) == [sequence_tasks[0]]
707 assert list(graph.get_dependencies(nested_group[2])) == [sequence_tasks[0]]
709 assert list(graph.get_dependents(nested_group[0])) == [sequence_tasks[2]]
710 assert list(graph.get_dependents(recursively_nested_group[0])) == [sequence_tasks[2]]
711 assert list(graph.get_dependents(recursively_nested_group[1])) == [sequence_tasks[2]]
712 assert list(graph.get_dependents(nested_group[2])) == [sequence_tasks[2]]
714 def test_sequence_with_empty_group(self, graph):
715 tasks = [MockTask(), [], MockTask()]
716 graph.sequence(*tasks)
717 graph_tasks = set([t for t in graph.tasks])
718 assert graph_tasks == set([tasks[0], tasks[2]])
719 assert list(graph.get_dependents(tasks[0])) == [tasks[2]]
720 assert list(graph.get_dependencies(tasks[2])) == [tasks[0]]
722 def test_sequence_with_recursively_nested_sequence_and_interdependencies(self, graph):
723 recursively_nested_tasks = list(graph.sequence(MockTask(), MockTask(), MockTask()))
724 nested_tasks = list(graph.sequence(MockTask(),
727 recursively_nested_tasks))
728 tasks = [MockTask(), MockTask(), MockTask(), nested_tasks]
729 graph.sequence(*tasks)
731 assert set(graph.tasks) == set(tasks[:3] + nested_tasks[:3] + recursively_nested_tasks)
732 assert set(graph.get_dependencies(tasks[0])) == set()
733 for i in xrange(1, len(tasks[:-1])):
734 assert set(graph.get_dependencies(tasks[i])) == set([tasks[i - 1]])
736 assert set(graph.get_dependencies(nested_tasks[0])) == set([tasks[2]])
737 for i in xrange(1, len(nested_tasks[:-1])):
738 assert set(graph.get_dependencies(nested_tasks[i])) == \
739 set([tasks[2], nested_tasks[i-1]])
741 assert set(graph.get_dependencies(recursively_nested_tasks[0])) == \
742 set([tasks[2], nested_tasks[2]])
743 for i in xrange(1, len(recursively_nested_tasks[:-1])):
744 assert set(graph.get_dependencies(recursively_nested_tasks[i])) == \
745 set([tasks[2], nested_tasks[2], recursively_nested_tasks[i-1]])