Merge pull request #12121 from hashicorp/jbardin/dag-tests

Fix some intermittent dag test failures
This commit is contained in:
James Bardin 2017-02-21 11:14:07 -05:00 committed by GitHub
commit be5230c673
1 changed files with 144 additions and 138 deletions

View File

@ -92,180 +92,186 @@ func TestWalker_error(t *testing.T) {
} }
func TestWalker_newVertex(t *testing.T) { func TestWalker_newVertex(t *testing.T) {
// Run it a bunch of times since it is timing dependent var g AcyclicGraph
for i := 0; i < 50; i++ { g.Add(1)
var g AcyclicGraph g.Add(2)
g.Add(1) g.Connect(BasicEdge(1, 2))
g.Add(2)
g.Connect(BasicEdge(1, 2))
var order []interface{} // Record function
w := &Walker{Callback: walkCbRecord(&order)} var order []interface{}
w.Update(&g) recordF := walkCbRecord(&order)
done2 := make(chan int)
// Wait a bit // Build a callback that notifies us when 2 has been walked
time.Sleep(10 * time.Millisecond) var w *Walker
cb := func(v Vertex) error {
// Update the graph if v == 2 {
g.Add(3) defer close(done2)
w.Update(&g)
// Update the graph again but with the same vertex
g.Add(3)
w.Update(&g)
// Wait
if err := w.Wait(); err != nil {
t.Fatalf("err: %s", err)
} }
return recordF(v)
}
// Check // Add the initial vertices
expected := []interface{}{1, 2, 3} w = &Walker{Callback: cb}
if !reflect.DeepEqual(order, expected) { w.Update(&g)
t.Fatalf("bad: %#v", order)
} // if 2 has been visited, the walk is complete so far
<-done2
// Update the graph
g.Add(3)
w.Update(&g)
// Update the graph again but with the same vertex
g.Add(3)
w.Update(&g)
// Wait
if err := w.Wait(); err != nil {
t.Fatalf("err: %s", err)
}
// Check
expected := []interface{}{1, 2, 3}
if !reflect.DeepEqual(order, expected) {
t.Fatalf("bad: %#v", order)
} }
} }
func TestWalker_removeVertex(t *testing.T) { func TestWalker_removeVertex(t *testing.T) {
// Run it a bunch of times since it is timing dependent var g AcyclicGraph
for i := 0; i < 50; i++ { g.Add(1)
var g AcyclicGraph g.Add(2)
g.Add(1) g.Connect(BasicEdge(1, 2))
g.Add(2)
g.Connect(BasicEdge(1, 2))
// Record function // Record function
var order []interface{} var order []interface{}
recordF := walkCbRecord(&order) recordF := walkCbRecord(&order)
// Build a callback that delays until we close a channel var w *Walker
var w *Walker cb := func(v Vertex) error {
cb := func(v Vertex) error { if v == 1 {
if v == 1 { g.Remove(2)
g.Remove(2) w.Update(&g)
w.Update(&g)
}
return recordF(v)
} }
// Add the initial vertices return recordF(v)
w = &Walker{Callback: cb} }
w.Update(&g)
// Wait // Add the initial vertices
if err := w.Wait(); err != nil { w = &Walker{Callback: cb}
t.Fatalf("err: %s", err) w.Update(&g)
}
// Check // Wait
expected := []interface{}{1} if err := w.Wait(); err != nil {
if !reflect.DeepEqual(order, expected) { t.Fatalf("err: %s", err)
t.Fatalf("bad: %#v", order) }
}
// Check
expected := []interface{}{1}
if !reflect.DeepEqual(order, expected) {
t.Fatalf("bad: %#v", order)
} }
} }
func TestWalker_newEdge(t *testing.T) { func TestWalker_newEdge(t *testing.T) {
// Run it a bunch of times since it is timing dependent var g AcyclicGraph
for i := 0; i < 50; i++ { g.Add(1)
var g AcyclicGraph g.Add(2)
g.Add(1) g.Connect(BasicEdge(1, 2))
g.Add(2)
g.Connect(BasicEdge(1, 2))
// Record function // Record function
var order []interface{} var order []interface{}
recordF := walkCbRecord(&order) recordF := walkCbRecord(&order)
// Build a callback that delays until we close a channel var w *Walker
var w *Walker cb := func(v Vertex) error {
cb := func(v Vertex) error { // record where we are first, otherwise the Updated vertex may get
if v == 1 { // walked before the first visit.
g.Add(3) err := recordF(v)
g.Connect(BasicEdge(3, 2))
w.Update(&g)
}
return recordF(v) if v == 1 {
g.Add(3)
g.Connect(BasicEdge(3, 2))
w.Update(&g)
} }
return err
}
// Add the initial vertices // Add the initial vertices
w = &Walker{Callback: cb} w = &Walker{Callback: cb}
w.Update(&g) w.Update(&g)
// Wait // Wait
if err := w.Wait(); err != nil { if err := w.Wait(); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
// Check // Check
expected := []interface{}{1, 3, 2} expected := []interface{}{1, 3, 2}
if !reflect.DeepEqual(order, expected) { if !reflect.DeepEqual(order, expected) {
t.Fatalf("bad: %#v", order) t.Fatalf("bad: %#v", order)
}
} }
} }
func TestWalker_removeEdge(t *testing.T) { func TestWalker_removeEdge(t *testing.T) {
// Run it a bunch of times since it is timing dependent var g AcyclicGraph
for i := 0; i < 50; i++ { g.Add(1)
var g AcyclicGraph g.Add(2)
g.Add(1) g.Add(3)
g.Add(2) g.Connect(BasicEdge(1, 2))
g.Add(3) g.Connect(BasicEdge(1, 3))
g.Connect(BasicEdge(1, 2)) g.Connect(BasicEdge(3, 2))
g.Connect(BasicEdge(3, 2))
// Record function // Record function
var order []interface{} var order []interface{}
recordF := walkCbRecord(&order) recordF := walkCbRecord(&order)
// The way this works is that our original graph forces // The way this works is that our original graph forces
// the order of 1 => 3 => 2. During the execution of 1, we // the order of 1 => 3 => 2. During the execution of 1, we
// remove the edge forcing 3 before 2. Then, during the execution // remove the edge forcing 3 before 2. Then, during the execution
// of 3, we wait on a channel that is only closed by 2, implicitly // of 3, we wait on a channel that is only closed by 2, implicitly
// forcing 2 before 3 via the callback (and not the graph). If // forcing 2 before 3 via the callback (and not the graph). If
// 2 cannot execute before 3 (edge removal is non-functional), then // 2 cannot execute before 3 (edge removal is non-functional), then
// this test will timeout. // this test will timeout.
var w *Walker var w *Walker
gateCh := make(chan struct{}) gateCh := make(chan struct{})
cb := func(v Vertex) error { cb := func(v Vertex) error {
if v == 1 { switch v {
g.RemoveEdge(BasicEdge(3, 2)) case 1:
w.Update(&g) g.RemoveEdge(BasicEdge(3, 2))
w.Update(&g)
case 2:
// this visit isn't completed until we've recorded it
// Once the visit is official, we can then close the gate to
// let 3 continue.
defer close(gateCh)
case 3:
select {
case <-gateCh:
case <-time.After(50 * time.Millisecond):
return fmt.Errorf("timeout 3 waiting for 2")
} }
if v == 2 {
close(gateCh)
}
if v == 3 {
select {
case <-gateCh:
case <-time.After(50 * time.Millisecond):
return fmt.Errorf("timeout 3 waiting for 2")
}
}
return recordF(v)
} }
// Add the initial vertices return recordF(v)
w = &Walker{Callback: cb} }
w.Update(&g)
// Wait // Add the initial vertices
if err := w.Wait(); err != nil { w = &Walker{Callback: cb}
t.Fatalf("err: %s", err) w.Update(&g)
}
// Check // Wait
expected := []interface{}{1, 2, 3} if err := w.Wait(); err != nil {
if !reflect.DeepEqual(order, expected) { t.Fatalf("err: %s", err)
t.Fatalf("bad: %#v", order) }
}
// Check
expected := []interface{}{1, 2, 3}
if !reflect.DeepEqual(order, expected) {
t.Fatalf("bad: %#v", order)
} }
} }