5
5
from django .test import TestCase
6
6
from django .core .exceptions import ValidationError
7
7
from django_postgresql_dag .models import NodeNotReachableException
8
+
8
9
# from .dag_output import expected_dag_output
9
10
from .models import NetworkNode , NetworkEdge
10
11
14
15
node_name_list = ["root" , "a1" , "a2" , "a3" , "b1" , "b2" , "b3" , "b4" , "c1" , "c2" ]
15
16
16
17
17
- class DagTestCase (TestCase ):
18
-
18
+ class DagTestCase (TestCase ):
19
19
def setUp (self ):
20
20
for node in node_name_list :
21
21
NetworkNode .objects .create (name = node )
22
-
22
+
23
23
def test_01_objects_were_created (self ):
24
24
for node in node_name_list :
25
25
self .assertEqual (NetworkNode .objects .get (name = f"{ node } " ).name , f"{ node } " )
@@ -61,19 +61,19 @@ def test_02_dag(self):
61
61
try :
62
62
b3 .add_parent (c1 )
63
63
except ValidationError as e :
64
- self .assertEqual (e .message , ' The object is an ancestor.' )
64
+ self .assertEqual (e .message , " The object is an ancestor." )
65
65
66
66
# Try to add a node that is already an ancestor (alternate method)
67
67
try :
68
68
c1 .add_child (b3 )
69
69
except ValidationError as e :
70
- self .assertEqual (e .message , ' The object is an ancestor.' )
70
+ self .assertEqual (e .message , " The object is an ancestor." )
71
71
72
72
# Try to add a node as it's own child
73
73
try :
74
74
b3 .add_child (b3 )
75
75
except ValidationError as e :
76
- self .assertEqual (e .message , ' The object is an ancestor.' )
76
+ self .assertEqual (e .message , " The object is an ancestor." )
77
77
78
78
# Verify that the tree methods work
79
79
tree_from_root = root .descendants_tree ()
@@ -116,31 +116,44 @@ def test_02_dag(self):
116
116
117
117
# Check other descendant methods
118
118
self .assertEqual (b4 .descendants_ids (), [c1 .id ])
119
- self .assertEqual (b4 .descendants_and_self_ids (), [b4 .id , c1 .id ])
120
- self .assertEqual (b4 .self_and_descendants_ids (), [c1 .id , b4 .id ])
121
- self .assertEqual (b4 .descendants_and_self ()[0 ], b4 )
122
- self .assertEqual (b4 .descendants_and_self ()[1 ], c1 )
123
- self .assertEqual (b4 .self_and_descendants ()[0 ], c1 )
124
- self .assertEqual (b4 .self_and_descendants ()[1 ], b4 )
125
-
119
+ self .assertEqual (b4 .descendants_and_self_ids (), [c1 .id , b4 .id ])
120
+ self .assertEqual (b4 .self_and_descendants_ids (), [b4 .id , c1 .id ])
121
+ self .assertEqual (b4 .descendants_and_self ()[0 ], c1 )
122
+ self .assertEqual (b4 .descendants_and_self ()[1 ], b4 )
123
+ self .assertEqual (b4 .self_and_descendants ()[0 ], b4 )
124
+ self .assertEqual (b4 .self_and_descendants ()[1 ], c1 )
125
+
126
+ # Check clan methods
127
+ self .assertEqual (a1 .clan_ids (), [root .id , a1 .id , b1 .id , b2 .id ])
128
+ self .assertEqual (a1 .clan ()[0 ], root )
129
+ self .assertEqual (a1 .clan ()[3 ], b2 )
126
130
127
131
# Check distance between nodes
128
132
self .assertEqual (root .distance (c1 ), 3 )
129
133
130
134
# Test additional fields for edge
131
- self .assertEqual (b3 .children .through .objects .filter (child = c1 )[0 ].name , ' b3 c1' )
135
+ self .assertEqual (b3 .children .through .objects .filter (child = c1 )[0 ].name , " b3 c1" )
132
136
133
- self .assertTrue ([p .name for p in root .shortest_path (c1 )] == ['root' , 'a3' , 'b3' , 'c1' ] or [p .name for p in c1 .shortest_path (root , directional = False )] == ['root' , 'a3' , 'b4' , 'c1' ])
137
+ self .assertTrue (
138
+ [p .name for p in root .shortest_path (c1 )] == ["root" , "a3" , "b3" , "c1" ]
139
+ or [p .name for p in c1 .shortest_path (root , directional = False )]
140
+ == ["root" , "a3" , "b4" , "c1" ]
141
+ )
134
142
135
143
try :
136
144
[p .name for p in c1 .shortest_path (root )]
137
145
except Exception as e :
138
146
self .assertRaises (NodeNotReachableException )
139
147
140
- self .assertTrue ([p .name for p in c1 .shortest_path (root , directional = False )] == ['root' , 'a3' , 'b3' , 'c1' ] or [p .name for p in c1 .shortest_path (root , directional = False )] == ['root' , 'a3' , 'b4' , 'c1' ])
148
+ self .assertTrue (
149
+ [p .name for p in c1 .shortest_path (root , directional = False )]
150
+ == ["root" , "a3" , "b3" , "c1" ]
151
+ or [p .name for p in c1 .shortest_path (root , directional = False )]
152
+ == ["root" , "a3" , "b4" , "c1" ]
153
+ )
141
154
142
- self .assertEqual ([p .name for p in root .get_leaves ()], ['b2' , 'c1' , 'c2' , 'b1' ])
143
- self .assertEqual ([p .name for p in c2 .get_roots ()], [' root' ])
155
+ self .assertEqual ([p .name for p in root .get_leaves ()], ["b2" , "c1" , "c2" , "b1" ])
156
+ self .assertEqual ([p .name for p in c2 .get_roots ()], [" root" ])
144
157
145
158
self .assertTrue (root .is_root ())
146
159
self .assertTrue (c1 .is_leaf ())
@@ -151,26 +164,26 @@ def test_02_dag(self):
151
164
152
165
# Remove a node and test island
153
166
self .assertTrue (c2 in b3 .descendants ())
154
- self .assertEqual ([p .name for p in c2 .ancestors ()], [' root' , 'a3' , 'b3' ])
167
+ self .assertEqual ([p .name for p in c2 .ancestors ()], [" root" , "a3" , "b3" ])
155
168
c2 .remove_parent (b3 )
156
169
self .assertFalse (c2 in b3 .descendants ())
157
170
self .assertEqual ([p .name for p in c2 .ancestors ()], [])
158
171
self .assertTrue (c2 .is_island ())
159
172
160
173
# Remove a node and test that it is still connected elsewhere
161
174
self .assertTrue (c1 in b3 .descendants ())
162
- self .assertEqual ([p .name for p in c1 .ancestors ()], [' root' , 'a3' , 'b3' , 'b4' ])
175
+ self .assertEqual ([p .name for p in c1 .ancestors ()], [" root" , "a3" , "b3" , "b4" ])
163
176
b3 .remove_child (c1 )
164
177
self .assertFalse (c1 in b3 .descendants ())
165
- self .assertEqual ([p .name for p in c1 .ancestors ()], [' root' , 'a3' , 'b4' ])
178
+ self .assertEqual ([p .name for p in c1 .ancestors ()], [" root" , "a3" , "b4" ])
166
179
self .assertFalse (c1 .is_island ())
167
180
168
181
"""
169
182
Simulate a basic irrigation canal network
170
183
"""
171
- log = logging .getLogger (' test_2_canal' )
184
+ log = logging .getLogger (" test_2_canal" )
172
185
173
- node_name_list2 = [x for x in range (0 ,201 )]
186
+ node_name_list2 = [x for x in range (0 , 201 )]
174
187
adjacency_list = [
175
188
["0" , "1" ],
176
189
["1" , "2" ],
@@ -374,7 +387,7 @@ def test_02_dag(self):
374
387
["199" , "200" ],
375
388
]
376
389
377
- for n in range (1 ,200 ):
390
+ for n in range (1 , 200 ):
378
391
if n % 5 != 0 :
379
392
node_name_list2 .append (f"SA{ n } " )
380
393
node_name_list2 .append (f"SB{ n } " )
@@ -395,27 +408,35 @@ def test_02_dag(self):
395
408
canal_root = NetworkNode .objects .get (name = "0" )
396
409
start_time = time .time ()
397
410
log .debug ("Descendants: %s" % str (len (canal_root .descendants ())))
398
- execution_time = ( time .time () - start_time )
411
+ execution_time = time .time () - start_time
399
412
log .debug ("Execution time in seconds: %s" % str (execution_time ))
400
413
401
414
# Compute descendants of a leaf node
402
415
canal_leaf = NetworkNode .objects .get (name = "200" )
403
416
start_time = time .time ()
404
417
log .debug ("Ancestors: %s" % str (len (canal_leaf .ancestors ())))
405
- execution_time = ( time .time () - start_time )
418
+ execution_time = time .time () - start_time
406
419
log .debug ("Execution time in seconds: %s" % str (execution_time ))
407
420
408
421
# Count number of paths from start to end of graph
409
422
start_time = time .time ()
410
- log .debug ("Paths through graph: : %s" % str (len (canal_root .path_ids_list (canal_leaf , max_depth = n + 1 , max_paths = 500000000 ))))
411
- execution_time = (time .time () - start_time )
423
+ log .debug (
424
+ "Paths through graph: : %s"
425
+ % str (
426
+ len (
427
+ canal_root .path_ids_list (
428
+ canal_leaf , max_depth = n + 1 , max_paths = 500000000
429
+ )
430
+ )
431
+ )
432
+ )
433
+ execution_time = time .time () - start_time
412
434
log .debug ("Execution time in seconds: %s" % str (execution_time ))
413
435
414
436
# Find distance from root to leaf
415
437
log .debug ("Distance: %s" % str (canal_root .distance (canal_leaf , max_depth = 100 )))
416
438
self .assertEqual (canal_root .distance (canal_leaf , max_depth = 100 ), 60 )
417
439
418
-
419
440
log .debug ("Node count: %s" % str (NetworkNode .objects .count ()))
420
441
log .debug ("Edge count: %s" % str (NetworkEdge .objects .count ()))
421
442
@@ -425,26 +446,27 @@ def test_03_deep_dag(self):
425
446
reasonable amount of time (linear in size of graph, not
426
447
exponential).
427
448
"""
449
+
428
450
def run_test ():
429
451
# Using the graph generation algorithm below, the number of potential
430
452
# paths from node 0 doubles for each increase in n.
431
453
# number_of_paths = 2^(n-1) WRONG!!!
432
454
# When n=22, there are on the order of 1 million paths through the graph
433
455
# from node 0, so results for intermediate nodes need to be cached
434
456
435
- log = logging .getLogger (' test_3' )
457
+ log = logging .getLogger (" test_3" )
436
458
437
459
n = 22 # Keep it an even number
438
460
439
- for i in range (2 * n ):
461
+ for i in range (2 * n ):
440
462
NetworkNode (pk = i , name = str (i )).save ()
441
463
442
464
# Create edges
443
- for i in range (0 , 2 * n - 2 , 2 ):
465
+ for i in range (0 , 2 * n - 2 , 2 ):
444
466
p1 = NetworkNode .objects .get (pk = i )
445
- p2 = NetworkNode .objects .get (pk = i + 1 )
446
- p3 = NetworkNode .objects .get (pk = i + 2 )
447
- p4 = NetworkNode .objects .get (pk = i + 3 )
467
+ p2 = NetworkNode .objects .get (pk = i + 1 )
468
+ p3 = NetworkNode .objects .get (pk = i + 2 )
469
+ p4 = NetworkNode .objects .get (pk = i + 3 )
448
470
449
471
p1 .add_child (p3 )
450
472
p1 .add_child (p4 )
@@ -455,23 +477,28 @@ def run_test():
455
477
root_node = NetworkNode .objects .get (pk = 0 )
456
478
start_time = time .time ()
457
479
log .debug ("Descendants: %s" % str (len (root_node .ancestors ())))
458
- execution_time = ( time .time () - start_time )
480
+ execution_time = time .time () - start_time
459
481
log .debug ("Execution time in seconds: %s" % str (execution_time ))
460
482
461
483
# Compute ancestors of a leaf node
462
- leaf_node = NetworkNode .objects .get (pk = 2 * n - 1 )
484
+ leaf_node = NetworkNode .objects .get (pk = 2 * n - 1 )
463
485
start_time = time .time ()
464
486
log .debug ("Ancestors: %s" % str (len (leaf_node .ancestors ())))
465
- execution_time = ( time .time () - start_time )
487
+ execution_time = time .time () - start_time
466
488
log .debug ("Execution time in seconds: %s" % str (execution_time ))
467
489
468
490
first = NetworkNode .objects .get (name = "0" )
469
- last = NetworkNode .objects .get (pk = 2 * n - 1 )
491
+ last = NetworkNode .objects .get (pk = 2 * n - 1 )
470
492
471
493
# Count number of paths from start to end of graph
472
494
start_time = time .time ()
473
- log .debug ("Paths through graph: %s" % str (len (first .path_ids_list (last , max_depth = n + 1 , max_paths = 500000000 ))))
474
- execution_time = (time .time () - start_time )
495
+ log .debug (
496
+ "Paths through graph: %s"
497
+ % str (
498
+ len (first .path_ids_list (last , max_depth = n + 1 , max_paths = 500000000 ))
499
+ )
500
+ )
501
+ execution_time = time .time () - start_time
475
502
log .debug ("Execution time in seconds: %s" % str (execution_time ))
476
503
477
504
self .assertEqual (first .distance (last , max_depth = n ), n - 1 )
@@ -480,10 +507,12 @@ def run_test():
480
507
log .debug ("Edge count: %s" % str (NetworkEdge .objects .count ()))
481
508
482
509
# Connect the first-created node to the last-created node
483
- NetworkNode .objects .get (pk = 0 ).add_child (NetworkNode .objects .get (pk = 2 * n - 1 ))
510
+ NetworkNode .objects .get (pk = 0 ).add_child (
511
+ NetworkNode .objects .get (pk = 2 * n - 1 )
512
+ )
484
513
485
514
middle = NetworkNode .objects .get (pk = n - 1 )
486
- self .assertEqual (first .distance (middle , max_depth = n ), n / 2 - 1 )
515
+ self .assertEqual (first .distance (middle , max_depth = n ), n / 2 - 1 )
487
516
488
517
# Run the test, raising an error if the code times out
489
518
p = multiprocessing .Process (target = run_test )
@@ -492,4 +521,4 @@ def run_test():
492
521
if p .is_alive ():
493
522
p .terminate ()
494
523
p .join ()
495
- raise RuntimeError (' Graph operations take too long!' )
524
+ raise RuntimeError (" Graph operations take too long!" )
0 commit comments