github.com/polydawn/docket@v0.5.4-0.20140630233848-90b70fb433da/dex/graph_integration_test.go (about)

     1  package dex
     2  
     3  // Very nearly all testing for dex is integration testing, sadly; this is inevitable since we're relying on exec to use git.
     4  
     5  import (
     6  	"path/filepath"
     7  	"bytes"
     8  	"os"
     9  	"archive/tar"
    10  	"testing"
    11  	"time"
    12  	"strings"
    13  	"github.com/coocood/assrt"
    14  )
    15  
    16  func TestLoadGraphAbsentIsNil(t *testing.T) {
    17  	do(func() {
    18  		assert := assrt.NewAssert(t)
    19  
    20  		assert.Nil(LoadGraph("."))
    21  
    22  		assert.Nil(LoadGraph("notadir"))
    23  	})
    24  }
    25  
    26  func assertLegitGraph(assert *assrt.Assert, g *Graph) {
    27  	assert.NotNil(g)
    28  
    29  	gstat, _ := os.Stat(filepath.Join(g.dir))
    30  	assert.True(gstat.IsDir())
    31  
    32  	assert.True(g.HasBranch("hroot/init"))
    33  
    34  	assert.Equal(
    35  		"",
    36  		g.cmd("ls-tree")("HEAD").Output(),
    37  	)
    38  }
    39  
    40  func TestNewGraphInit(t *testing.T) {
    41  	do(func() {
    42  		assertLegitGraph(
    43  			assrt.NewAssert(t),
    44  			NewGraph("."),
    45  		)
    46  	})
    47  }
    48  
    49  func TestLoadGraphEmpty(t *testing.T) {
    50  	do(func() {
    51  		assert := assrt.NewAssert(t)
    52  
    53  		NewGraph(".")
    54  
    55  		assertLegitGraph(assert, LoadGraph("."))
    56  	})
    57  }
    58  
    59  func TestNewGraphInitNewDir(t *testing.T) {
    60  	do(func() {
    61  		assertLegitGraph(
    62  			assrt.NewAssert(t),
    63  			NewGraph("deep"),
    64  		)
    65  	})
    66  }
    67  
    68  func TestNewGraphInitRejectedOnDeeper(t *testing.T) {
    69  	do(func() {
    70  		defer func() {
    71  			err := recover()
    72  			if err == nil { t.Fail(); }
    73  		}()
    74  		NewGraph("deep/deeper")
    75  	})
    76  }
    77  
    78  func fsSetA() *tar.Reader {
    79  	var buf bytes.Buffer
    80  	fs := tar.NewWriter(&buf)
    81  
    82  	// file 'a' is just ascii text with normal permissions
    83  	fs.WriteHeader(&tar.Header{
    84  		Name:     "a",
    85  		Mode:     0644,
    86  		Size:     2,
    87  		Typeflag: tar.TypeReg,
    88  		ModTime:  time.Unix(1000100, 5000),
    89  	})
    90  	fs.Write([]byte{ 'a', 'b' })
    91  
    92  	// file 'b' is binary with unusual permissions
    93  	fs.WriteHeader(&tar.Header{
    94  		Name:     "b",
    95  		Mode:     0640,
    96  		Size:     3,
    97  		Typeflag: tar.TypeReg,
    98  	})
    99  	fs.Write([]byte{ 0x1, 0x2, 0x3 })
   100  
   101  	fs.Close()
   102  	return tar.NewReader(&buf)
   103  }
   104  
   105  func fsSetB() *tar.Reader {
   106  	var buf bytes.Buffer
   107  	fs := tar.NewWriter(&buf)
   108  
   109  	// file 'a' is unchanged from SetA
   110  	fs.WriteHeader(&tar.Header{
   111  		Name:     "a",
   112  		Mode:     0644,
   113  		Size:     2,
   114  		Typeflag: tar.TypeReg,
   115  		ModTime:  time.Unix(1000100, 5000),
   116  	})
   117  	fs.Write([]byte{ 'a', 'b' })
   118  
   119  	// file 'b' is removed
   120  
   121  	// file 'e' is executable
   122  	fs.WriteHeader(&tar.Header{
   123  		Name:     "e",
   124  		Mode:     0755,
   125  		Size:     3,
   126  		Typeflag: tar.TypeReg,
   127  	})
   128  	fs.Write([]byte{ 'e', 'x', 'e' })
   129  
   130  	// file 'd/d/z' is deeper
   131  	fs.WriteHeader(&tar.Header{
   132  		Name:     "d/d/z",
   133  		Mode:     0644,
   134  		Size:     2,
   135  		Typeflag: tar.TypeReg,
   136  	})
   137  	fs.Write([]byte{ 'z', '\n' })
   138  
   139  	fs.Close()
   140  	return tar.NewReader(&buf)
   141  }
   142  
   143  func fsSetA2() *tar.Reader {
   144  	var buf bytes.Buffer
   145  	fs := tar.NewWriter(&buf)
   146  
   147  	// file 'a' diffs from SetA
   148  	fs.WriteHeader(&tar.Header{
   149  		Name:     "a",
   150  		Mode:     0644,
   151  		Size:     3,
   152  		Typeflag: tar.TypeReg,
   153  		ModTime:  time.Unix(1200100, 5000),
   154  	})
   155  	fs.Write([]byte{ 'a', '\n', 'b' })
   156  
   157  	// file 'b' is unchanged from SetA
   158  	fs.WriteHeader(&tar.Header{
   159  		Name:     "b",
   160  		Mode:     0640,
   161  		Size:     3,
   162  		Typeflag: tar.TypeReg,
   163  	})
   164  	fs.Write([]byte{ 0x1, 0x2, 0x3 })
   165  
   166  	fs.Close()
   167  	return tar.NewReader(&buf)
   168  }
   169  
   170  func fsSetC() *tar.Reader {
   171  	var buf bytes.Buffer
   172  	fs := tar.NewWriter(&buf)
   173  
   174  	// file 'a' diffs from SetA (and from SetA2, differently)
   175  	fs.WriteHeader(&tar.Header{
   176  		Name:     "a",
   177  		Mode:     0644,
   178  		Size:     3,
   179  		Typeflag: tar.TypeReg,
   180  		ModTime:  time.Unix(5100100, 5000),
   181  	})
   182  	fs.Write([]byte{ 'a', '\n', 'c' })
   183  
   184  	// file 'b' is still gone
   185  
   186  	// file 'e' is deleted from SetB
   187  
   188  	// file 'd/d/z' is renamed to 'd/z'
   189  	fs.WriteHeader(&tar.Header{
   190  		Name:     "d/z",
   191  		Mode:     0644,
   192  		Size:     2,
   193  		Typeflag: tar.TypeReg,
   194  	})
   195  	fs.Write([]byte{ 'z', '\n' })
   196  
   197  	// and and 'd/d' is *still around* as a (empty!) dir
   198  	fs.WriteHeader(&tar.Header{
   199  		Name:     "d/d",
   200  		Mode:     0755,
   201  		Typeflag: tar.TypeDir,
   202  	})
   203  	fs.Write([]byte{ 'z', '\n' })	//FIXME: heh
   204  
   205  	fs.Close()
   206  	return tar.NewReader(&buf)
   207  }
   208  
   209  func TestPublishNewOrphanLineage(t *testing.T) {
   210  	do(func() {
   211  		assert := assrt.NewAssert(t)
   212  
   213  		g := NewGraph(".")
   214  		lineage := "line"
   215  		ancestor := ""
   216  
   217  		g.Publish(
   218  			lineage,
   219  			ancestor,
   220  			&GraphStoreRequest_Tar{
   221  				Tarstream: fsSetA(),
   222  			},
   223  		)
   224  
   225  		assert.Equal(
   226  			3,
   227  			strings.Count(
   228  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage).Output(),
   229  				"\n",
   230  			),
   231  		)
   232  
   233  		assert.Equal(
   234  			`{"Name":"a","Type":"F","Mode":644,"ModTime":"1970-01-12T13:48:20Z"}` + "\n" +
   235  			`{"Name":"b","Type":"F","Mode":640}` + "\n",
   236  			g.cmd("show", git_branch_ref_prefix+hroot_image_ref_prefix+lineage+":"+".guitar").Output(),
   237  		)
   238  	})
   239  }
   240  
   241  func TestPublishLinearExtensionToLineage(t *testing.T) {
   242  	do(func() {
   243  		assert := assrt.NewAssert(t)
   244  
   245  		g := NewGraph(".")
   246  		lineage := "line"
   247  		ancestor := "line"
   248  
   249  		g.Publish(
   250  			lineage,
   251  			"",
   252  			&GraphStoreRequest_Tar{
   253  				Tarstream: fsSetA(),
   254  			},
   255  		)
   256  
   257  		g.Publish(
   258  			lineage,
   259  			ancestor,
   260  			&GraphStoreRequest_Tar{
   261  				Tarstream: fsSetB(),
   262  			},
   263  		)
   264  
   265  		assert.Equal(
   266  			4,
   267  			strings.Count(
   268  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage).Output(),
   269  				"\n",
   270  			),
   271  		)
   272  
   273  		assert.Equal(
   274  			1,	// shows a tree
   275  			strings.Count(
   276  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/d").Output(),
   277  				"\n",
   278  			),
   279  		)
   280  
   281  		assert.Equal(
   282  			1,	// shows the file
   283  			strings.Count(
   284  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/d/z").Output(),
   285  				"\n",
   286  			),
   287  		)
   288  
   289  		assert.Equal(
   290  			`{"Name":"a","Type":"F","Mode":644,"ModTime":"1970-01-12T13:48:20Z"}` + "\n" +
   291  			`{"Name":"d/d/z","Type":"F","Mode":644}` + "\n" +
   292  			`{"Name":"e","Type":"F","Mode":755}` + "\n",
   293  			g.cmd("show", git_branch_ref_prefix+hroot_image_ref_prefix+lineage+":"+".guitar").Output(),
   294  		)
   295  	})
   296  }
   297  
   298  func TestPublishNewDerivedLineage(t *testing.T) {
   299  	do(func() {
   300  		assert := assrt.NewAssert(t)
   301  
   302  		g := NewGraph(".")
   303  		lineage := "ferk"
   304  		ancestor := "line"
   305  
   306  		g.Publish(
   307  			ancestor,
   308  			"",
   309  			&GraphStoreRequest_Tar{
   310  				Tarstream: fsSetA(),
   311  			},
   312  		)
   313  
   314  		g.Publish(
   315  			lineage,
   316  			ancestor,
   317  			&GraphStoreRequest_Tar{
   318  				Tarstream: fsSetB(),
   319  			},
   320  		)
   321  
   322  		println(g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage).Output())
   323  		assert.Equal(
   324  			4,
   325  			strings.Count(
   326  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage).Output(),
   327  				"\n",
   328  			),
   329  		)
   330  
   331  		assert.Equal(
   332  			1,	// shows a tree
   333  			strings.Count(
   334  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/d").Output(),
   335  				"\n",
   336  			),
   337  		)
   338  
   339  		assert.Equal(
   340  			1,	// shows the file
   341  			strings.Count(
   342  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/d/z").Output(),
   343  				"\n",
   344  			),
   345  		)
   346  
   347  		assert.Equal(
   348  			`{"Name":"a","Type":"F","Mode":644,"ModTime":"1970-01-12T13:48:20Z"}` + "\n" +
   349  			`{"Name":"d/d/z","Type":"F","Mode":644}` + "\n" +
   350  			`{"Name":"e","Type":"F","Mode":755}` + "\n",
   351  			g.cmd("show", git_branch_ref_prefix+hroot_image_ref_prefix+lineage+":"+".guitar").Output(),
   352  		)
   353  	})
   354  }
   355  
   356  func TestPublishDerivativeExtensionToLineage(t *testing.T) {
   357  	do(func() {
   358  		assert := assrt.NewAssert(t)
   359  
   360  		g := NewGraph(".")
   361  		lineage := "ferk"
   362  		ancestor := "line"
   363  
   364  		// original ancestor import
   365  		g.Publish(
   366  			ancestor,
   367  			"",
   368  			&GraphStoreRequest_Tar{
   369  				Tarstream: fsSetA(),
   370  			},
   371  		)
   372  
   373  		// derive 1
   374  		g.Publish(
   375  			lineage,
   376  			ancestor,
   377  			&GraphStoreRequest_Tar{
   378  				Tarstream: fsSetB(),
   379  			},
   380  		)
   381  
   382  		// advance the ancestor
   383  		g.Publish(
   384  			ancestor,
   385  			ancestor,
   386  			&GraphStoreRequest_Tar{
   387  				Tarstream: fsSetA2(),
   388  			},
   389  		)
   390  
   391  		// advance the derived from the updated ancestor
   392  		g.Publish(
   393  			lineage,
   394  			ancestor,
   395  			&GraphStoreRequest_Tar{
   396  				Tarstream: fsSetC(),
   397  			},
   398  		)
   399  
   400  		assert.Equal(
   401  			3,
   402  			strings.Count(
   403  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage).Output(),
   404  				"\n",
   405  			),
   406  		)
   407  
   408  		assert.Equal(
   409  			1,	// has the file.  git itself still doesn't see dirs; just guitar does that.
   410  			strings.Count(
   411  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/").Output(),
   412  				"\n",
   413  			),
   414  		)
   415  
   416  		assert.Equal(
   417  			0,	// nothing here.  git itself still doesn't see dirs; just guitar does that.
   418  			strings.Count(
   419  				g.cmd("ls-tree", git_branch_ref_prefix+hroot_image_ref_prefix+lineage, "d/d/").Output(),
   420  				"\n",
   421  			),
   422  		)
   423  
   424  		assert.Equal(
   425  			`{"Name":"a","Type":"F","Mode":644,"ModTime":"1970-03-01T00:41:40Z"}` + "\n" +
   426  			`{"Name":"d/d","Type":"D","Mode":755}` + "\n" +
   427  			`{"Name":"d/z","Type":"F","Mode":644}` + "\n",
   428  			g.cmd("show", git_branch_ref_prefix+hroot_image_ref_prefix+lineage+":"+".guitar").Output(),
   429  		)
   430  	})
   431  }