github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/dag/walk_test.go (about) 1 package dag 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "testing" 8 "time" 9 ) 10 11 func TestWalker_basic(t *testing.T) { 12 var g AcyclicGraph 13 g.Add(1) 14 g.Add(2) 15 g.Connect(BasicEdge(1, 2)) 16 17 // Run it a bunch of times since it is timing dependent 18 for i := 0; i < 50; i++ { 19 var order []interface{} 20 w := &Walker{Callback: walkCbRecord(&order)} 21 w.Update(&g) 22 23 // Wait 24 if err := w.Wait(); err != nil { 25 t.Fatalf("err: %s", err) 26 } 27 28 // Check 29 expected := []interface{}{1, 2} 30 if !reflect.DeepEqual(order, expected) { 31 t.Fatalf("bad: %#v", order) 32 } 33 } 34 } 35 36 func TestWalker_updateNilGraph(t *testing.T) { 37 var g AcyclicGraph 38 g.Add(1) 39 g.Add(2) 40 g.Connect(BasicEdge(1, 2)) 41 42 // Run it a bunch of times since it is timing dependent 43 for i := 0; i < 50; i++ { 44 var order []interface{} 45 w := &Walker{Callback: walkCbRecord(&order)} 46 w.Update(&g) 47 w.Update(nil) 48 49 // Wait 50 if err := w.Wait(); err != nil { 51 t.Fatalf("err: %s", err) 52 } 53 } 54 } 55 56 func TestWalker_error(t *testing.T) { 57 var g AcyclicGraph 58 g.Add(1) 59 g.Add(2) 60 g.Add(3) 61 g.Add(4) 62 g.Connect(BasicEdge(1, 2)) 63 g.Connect(BasicEdge(2, 3)) 64 g.Connect(BasicEdge(3, 4)) 65 66 // Record function 67 var order []interface{} 68 recordF := walkCbRecord(&order) 69 70 // Build a callback that delays until we close a channel 71 cb := func(v Vertex) error { 72 if v == 2 { 73 return fmt.Errorf("error!") 74 } 75 76 return recordF(v) 77 } 78 79 w := &Walker{Callback: cb} 80 w.Update(&g) 81 82 // Wait 83 if err := w.Wait(); err == nil { 84 t.Fatal("expect error") 85 } 86 87 // Check 88 expected := []interface{}{1} 89 if !reflect.DeepEqual(order, expected) { 90 t.Fatalf("bad: %#v", order) 91 } 92 } 93 94 func TestWalker_newVertex(t *testing.T) { 95 // Run it a bunch of times since it is timing dependent 96 for i := 0; i < 50; i++ { 97 var g AcyclicGraph 98 g.Add(1) 99 g.Add(2) 100 g.Connect(BasicEdge(1, 2)) 101 102 var order []interface{} 103 w := &Walker{Callback: walkCbRecord(&order)} 104 w.Update(&g) 105 106 // Wait a bit 107 time.Sleep(10 * time.Millisecond) 108 109 // Update the graph 110 g.Add(3) 111 w.Update(&g) 112 113 // Update the graph again but with the same vertex 114 g.Add(3) 115 w.Update(&g) 116 117 // Wait 118 if err := w.Wait(); err != nil { 119 t.Fatalf("err: %s", err) 120 } 121 122 // Check 123 expected := []interface{}{1, 2, 3} 124 if !reflect.DeepEqual(order, expected) { 125 t.Fatalf("bad: %#v", order) 126 } 127 } 128 } 129 130 func TestWalker_removeVertex(t *testing.T) { 131 // Run it a bunch of times since it is timing dependent 132 for i := 0; i < 50; i++ { 133 var g AcyclicGraph 134 g.Add(1) 135 g.Add(2) 136 g.Connect(BasicEdge(1, 2)) 137 138 // Record function 139 var order []interface{} 140 recordF := walkCbRecord(&order) 141 142 // Build a callback that delays until we close a channel 143 var w *Walker 144 cb := func(v Vertex) error { 145 if v == 1 { 146 g.Remove(2) 147 w.Update(&g) 148 } 149 150 return recordF(v) 151 } 152 153 // Add the initial vertices 154 w = &Walker{Callback: cb} 155 w.Update(&g) 156 157 // Wait 158 if err := w.Wait(); err != nil { 159 t.Fatalf("err: %s", err) 160 } 161 162 // Check 163 expected := []interface{}{1} 164 if !reflect.DeepEqual(order, expected) { 165 t.Fatalf("bad: %#v", order) 166 } 167 } 168 } 169 170 func TestWalker_newEdge(t *testing.T) { 171 // Run it a bunch of times since it is timing dependent 172 for i := 0; i < 50; i++ { 173 var g AcyclicGraph 174 g.Add(1) 175 g.Add(2) 176 g.Connect(BasicEdge(1, 2)) 177 178 // Record function 179 var order []interface{} 180 recordF := walkCbRecord(&order) 181 182 // Build a callback that delays until we close a channel 183 var w *Walker 184 cb := func(v Vertex) error { 185 if v == 1 { 186 g.Add(3) 187 g.Connect(BasicEdge(3, 2)) 188 w.Update(&g) 189 } 190 191 return recordF(v) 192 } 193 194 // Add the initial vertices 195 w = &Walker{Callback: cb} 196 w.Update(&g) 197 198 // Wait 199 if err := w.Wait(); err != nil { 200 t.Fatalf("err: %s", err) 201 } 202 203 // Check 204 expected := []interface{}{1, 3, 2} 205 if !reflect.DeepEqual(order, expected) { 206 t.Fatalf("bad: %#v", order) 207 } 208 } 209 } 210 211 func TestWalker_removeEdge(t *testing.T) { 212 // Run it a bunch of times since it is timing dependent 213 for i := 0; i < 50; i++ { 214 var g AcyclicGraph 215 g.Add(1) 216 g.Add(2) 217 g.Add(3) 218 g.Connect(BasicEdge(1, 2)) 219 g.Connect(BasicEdge(3, 2)) 220 221 // Record function 222 var order []interface{} 223 recordF := walkCbRecord(&order) 224 225 // The way this works is that our original graph forces 226 // the order of 1 => 3 => 2. During the execution of 1, we 227 // remove the edge forcing 3 before 2. Then, during the execution 228 // of 3, we wait on a channel that is only closed by 2, implicitly 229 // forcing 2 before 3 via the callback (and not the graph). If 230 // 2 cannot execute before 3 (edge removal is non-functional), then 231 // this test will timeout. 232 var w *Walker 233 gateCh := make(chan struct{}) 234 cb := func(v Vertex) error { 235 if v == 1 { 236 g.RemoveEdge(BasicEdge(3, 2)) 237 w.Update(&g) 238 } 239 240 if v == 2 { 241 close(gateCh) 242 } 243 244 if v == 3 { 245 select { 246 case <-gateCh: 247 case <-time.After(50 * time.Millisecond): 248 return fmt.Errorf("timeout 3 waiting for 2") 249 } 250 } 251 252 return recordF(v) 253 } 254 255 // Add the initial vertices 256 w = &Walker{Callback: cb} 257 w.Update(&g) 258 259 // Wait 260 if err := w.Wait(); err != nil { 261 t.Fatalf("err: %s", err) 262 } 263 264 // Check 265 expected := []interface{}{1, 2, 3} 266 if !reflect.DeepEqual(order, expected) { 267 t.Fatalf("bad: %#v", order) 268 } 269 } 270 } 271 272 // walkCbRecord is a test helper callback that just records the order called. 273 func walkCbRecord(order *[]interface{}) WalkFunc { 274 var l sync.Mutex 275 return func(v Vertex) error { 276 l.Lock() 277 defer l.Unlock() 278 *order = append(*order, v) 279 return nil 280 } 281 }