github.com/ves/terraform@v0.8.0-beta2/dag/marshal_test.go (about)

     1  package dag
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  func TestGraphDot_empty(t *testing.T) {
    11  	var g Graph
    12  	g.Add(1)
    13  	g.Add(2)
    14  	g.Add(3)
    15  
    16  	actual := strings.TrimSpace(string(g.Dot(nil)))
    17  	expected := strings.TrimSpace(testGraphDotEmptyStr)
    18  	if actual != expected {
    19  		t.Fatalf("bad: %s", actual)
    20  	}
    21  }
    22  
    23  func TestGraphDot_basic(t *testing.T) {
    24  	var g Graph
    25  	g.Add(1)
    26  	g.Add(2)
    27  	g.Add(3)
    28  	g.Connect(BasicEdge(1, 3))
    29  
    30  	actual := strings.TrimSpace(string(g.Dot(nil)))
    31  	expected := strings.TrimSpace(testGraphDotBasicStr)
    32  	if actual != expected {
    33  		t.Fatalf("bad: %s", actual)
    34  	}
    35  }
    36  
    37  const testGraphDotBasicStr = `digraph {
    38  	compound = "true"
    39  	newrank = "true"
    40  	subgraph "root" {
    41  		"[root] 1" -> "[root] 3"
    42  	}
    43  }
    44  `
    45  
    46  const testGraphDotEmptyStr = `digraph {
    47  	compound = "true"
    48  	newrank = "true"
    49  	subgraph "root" {
    50  	}
    51  }`
    52  
    53  func TestGraphJSON_empty(t *testing.T) {
    54  	var g Graph
    55  	g.Add(1)
    56  	g.Add(2)
    57  	g.Add(3)
    58  
    59  	js, err := g.MarshalJSON()
    60  	if err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	actual := strings.TrimSpace(string(js))
    65  	expected := strings.TrimSpace(testGraphJSONEmptyStr)
    66  	if actual != expected {
    67  		t.Fatalf("bad: %s", actual)
    68  	}
    69  }
    70  
    71  func TestGraphJSON_basic(t *testing.T) {
    72  	var g Graph
    73  	g.Add(1)
    74  	g.Add(2)
    75  	g.Add(3)
    76  	g.Connect(BasicEdge(1, 3))
    77  
    78  	js, err := g.MarshalJSON()
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  	actual := strings.TrimSpace(string(js))
    83  	expected := strings.TrimSpace(testGraphJSONBasicStr)
    84  	if actual != expected {
    85  		t.Fatalf("bad: %s", actual)
    86  	}
    87  }
    88  
    89  // record some graph transformations, and make sure we get the same graph when
    90  // they're replayed
    91  func TestGraphJSON_basicRecord(t *testing.T) {
    92  	var g Graph
    93  	var buf bytes.Buffer
    94  	g.SetDebugWriter(&buf)
    95  
    96  	g.Add(1)
    97  	g.Add(2)
    98  	g.Add(3)
    99  	g.Connect(BasicEdge(1, 2))
   100  	g.Connect(BasicEdge(1, 3))
   101  	g.Connect(BasicEdge(2, 3))
   102  	(&AcyclicGraph{g}).TransitiveReduction()
   103  
   104  	recorded := buf.Bytes()
   105  	// the Walk doesn't happen in a determined order, so just count operations
   106  	// for now to make sure we wrote stuff out.
   107  	if len(bytes.Split(recorded, []byte{'\n'})) != 17 {
   108  		t.Fatalf("bad: %s", recorded)
   109  	}
   110  
   111  	original, err := g.MarshalJSON()
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  
   116  	// replay the logs, and marshal the graph back out again
   117  	m, err := decodeGraph(bytes.NewReader(buf.Bytes()))
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	replayed, err := json.MarshalIndent(m, "", "  ")
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	if !bytes.Equal(original, replayed) {
   128  		t.Fatalf("\noriginal: %s\nreplayed: %s", original, replayed)
   129  	}
   130  }
   131  
   132  // Verify that Vertex and Edge annotations appear in the debug output
   133  func TestGraphJSON_debugInfo(t *testing.T) {
   134  	var g Graph
   135  	var buf bytes.Buffer
   136  	g.SetDebugWriter(&buf)
   137  
   138  	g.Add(1)
   139  	g.Add(2)
   140  	g.Add(3)
   141  	g.Connect(BasicEdge(1, 2))
   142  
   143  	g.DebugVertexInfo(2, "2")
   144  	g.DebugVertexInfo(3, "3")
   145  	g.DebugEdgeInfo(BasicEdge(1, 2), "1|2")
   146  
   147  	dec := json.NewDecoder(bytes.NewReader(buf.Bytes()))
   148  
   149  	var found2, found3, foundEdge bool
   150  	for dec.More() {
   151  		var d streamDecode
   152  
   153  		err := dec.Decode(&d)
   154  		if err != nil {
   155  			t.Fatal(err)
   156  		}
   157  
   158  		switch d.Type {
   159  		case "VertexDebugInfo":
   160  			va := &vertexDebugInfo{}
   161  			err := json.Unmarshal(d.JSON, va)
   162  			if err != nil {
   163  				t.Fatal(err)
   164  			}
   165  
   166  			switch va.Info {
   167  			case "2":
   168  				if va.Vertex.Name != "2" {
   169  					t.Fatalf("wrong vertex annotated 2: %#v", va)
   170  				}
   171  				found2 = true
   172  			case "3":
   173  				if va.Vertex.Name != "3" {
   174  					t.Fatalf("wrong vertex annotated 3: %#v", va)
   175  				}
   176  				found3 = true
   177  			default:
   178  				t.Fatalf("unexpected annotation: %#v", va)
   179  			}
   180  		case "EdgeDebugInfo":
   181  			ea := &edgeDebugInfo{}
   182  			err := json.Unmarshal(d.JSON, ea)
   183  			if err != nil {
   184  				t.Fatal(err)
   185  			}
   186  
   187  			switch ea.Info {
   188  			case "1|2":
   189  				if ea.Edge.Name != "1|2" {
   190  					t.Fatalf("incorrect edge annotation: %#v\n", ea)
   191  				}
   192  				foundEdge = true
   193  			default:
   194  				t.Fatalf("unexpected edge Info: %#v", ea)
   195  			}
   196  		}
   197  	}
   198  
   199  	if !found2 {
   200  		t.Fatal("annotation 2 not found")
   201  	}
   202  	if !found3 {
   203  		t.Fatal("annotation 3 not found")
   204  	}
   205  	if !foundEdge {
   206  		t.Fatal("edge annotation not found")
   207  	}
   208  }
   209  
   210  // Verify that debug operations appear in the debug output
   211  func TestGraphJSON_debugOperations(t *testing.T) {
   212  	var g Graph
   213  	var buf bytes.Buffer
   214  	g.SetDebugWriter(&buf)
   215  
   216  	debugOp := g.DebugOperation("AddOne", "adding node 1")
   217  	g.Add(1)
   218  	debugOp.End("done adding node 1")
   219  
   220  	// use an immediate closure to test defers
   221  	func() {
   222  		defer g.DebugOperation("AddTwo", "adding nodes 2 and 3").End("done adding 2 and 3")
   223  		g.Add(2)
   224  		defer g.DebugOperation("NestedAddThree", "second defer").End("done adding node 3")
   225  		g.Add(3)
   226  	}()
   227  
   228  	g.Connect(BasicEdge(1, 2))
   229  
   230  	dec := json.NewDecoder(bytes.NewReader(buf.Bytes()))
   231  
   232  	var ops []string
   233  	for dec.More() {
   234  		var d streamDecode
   235  
   236  		err := dec.Decode(&d)
   237  		if err != nil {
   238  			t.Fatal(err)
   239  		}
   240  
   241  		if d.Type != "Operation" {
   242  			continue
   243  		}
   244  
   245  		o := &marshalOperation{}
   246  		err = json.Unmarshal(d.JSON, o)
   247  		if err != nil {
   248  			t.Fatal(err)
   249  		}
   250  
   251  		switch {
   252  		case o.Begin == "AddOne":
   253  			ops = append(ops, "BeginAddOne")
   254  		case o.End == "AddOne":
   255  			ops = append(ops, "EndAddOne")
   256  		case o.Begin == "AddTwo":
   257  			ops = append(ops, "BeginAddTwo")
   258  		case o.End == "AddTwo":
   259  			ops = append(ops, "EndAddTwo")
   260  		case o.Begin == "NestedAddThree":
   261  			ops = append(ops, "BeginAddThree")
   262  		case o.End == "NestedAddThree":
   263  			ops = append(ops, "EndAddThree")
   264  		}
   265  	}
   266  
   267  	expectedOps := []string{
   268  		"BeginAddOne",
   269  		"EndAddOne",
   270  		"BeginAddTwo",
   271  		"BeginAddThree",
   272  		"EndAddThree",
   273  		"EndAddTwo",
   274  	}
   275  
   276  	if strings.Join(ops, ",") != strings.Join(expectedOps, ",") {
   277  		t.Fatalf("incorrect order of operations: %v", ops)
   278  	}
   279  }
   280  
   281  const testGraphJSONEmptyStr = `{
   282    "Type": "Graph",
   283    "Name": "root",
   284    "Vertices": [
   285      {
   286        "ID": "1",
   287        "Name": "1"
   288      },
   289      {
   290        "ID": "2",
   291        "Name": "2"
   292      },
   293      {
   294        "ID": "3",
   295        "Name": "3"
   296      }
   297    ]
   298  }`
   299  
   300  const testGraphJSONBasicStr = `{
   301    "Type": "Graph",
   302    "Name": "root",
   303    "Vertices": [
   304      {
   305        "ID": "1",
   306        "Name": "1"
   307      },
   308      {
   309        "ID": "2",
   310        "Name": "2"
   311      },
   312      {
   313        "ID": "3",
   314        "Name": "3"
   315      }
   316    ],
   317    "Edges": [
   318      {
   319        "Name": "1|3",
   320        "Source": "1",
   321        "Target": "3"
   322      }
   323    ]
   324  }`