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  }