github.com/vanadium-archive/go.jiri@v0.0.0-20160715023856-abfb8b131290/cmd/jiri/snapshot_test.go (about)

     1  // Copyright 2015 The Vanadium Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  
    14  	"v.io/jiri"
    15  	"v.io/jiri/gitutil"
    16  	"v.io/jiri/jiritest"
    17  	"v.io/jiri/project"
    18  	"v.io/jiri/tool"
    19  )
    20  
    21  func createLabelDir(t *testing.T, jirix *jiri.X, snapshotDir, name string, snapshots []string) {
    22  	if snapshotDir == "" {
    23  		snapshotDir = filepath.Join(jirix.Root, defaultSnapshotDir)
    24  	}
    25  	s := jirix.NewSeq()
    26  	labelDir, perm := filepath.Join(snapshotDir, "labels", name), os.FileMode(0700)
    27  	if err := s.MkdirAll(labelDir, perm).Done(); err != nil {
    28  		t.Fatalf("MkdirAll(%v, %v) failed: %v", labelDir, perm, err)
    29  	}
    30  	for i, snapshot := range snapshots {
    31  		path := filepath.Join(labelDir, snapshot)
    32  		_, err := os.Create(path)
    33  		if err != nil {
    34  			t.Fatalf("%v", err)
    35  		}
    36  		if i == 0 {
    37  			symlinkPath := filepath.Join(snapshotDir, name)
    38  			if err := s.Symlink(path, symlinkPath).Done(); err != nil {
    39  				t.Fatalf("Symlink(%v, %v) failed: %v", path, symlinkPath, err)
    40  			}
    41  		}
    42  	}
    43  }
    44  
    45  func generateOutput(labels []label) string {
    46  	output := ""
    47  	for _, label := range labels {
    48  		output += fmt.Sprintf("snapshots of label %q:\n", label.name)
    49  		for _, snapshot := range label.snapshots {
    50  			output += fmt.Sprintf("  %v\n", snapshot)
    51  		}
    52  	}
    53  	return output
    54  }
    55  
    56  type config struct {
    57  	remote bool
    58  	dir    string
    59  }
    60  
    61  type label struct {
    62  	name      string
    63  	snapshots []string
    64  }
    65  
    66  func TestList(t *testing.T) {
    67  	resetFlags()
    68  	fake, cleanup := jiritest.NewFakeJiriRoot(t)
    69  	defer cleanup()
    70  
    71  	snapshotDir1 := "" // Should use default dir.
    72  	snapshotDir2 := filepath.Join(fake.X.Root, "some/other/dir")
    73  
    74  	// Create a test suite.
    75  	tests := []config{
    76  		config{
    77  			dir: snapshotDir1,
    78  		},
    79  		config{
    80  			dir: snapshotDir2,
    81  		},
    82  	}
    83  	labels := []label{
    84  		label{
    85  			name:      "beta",
    86  			snapshots: []string{"beta-1", "beta-2", "beta-3"},
    87  		},
    88  		label{
    89  			name:      "stable",
    90  			snapshots: []string{"stable-1", "stable-2", "stable-3"},
    91  		},
    92  	}
    93  
    94  	for _, test := range tests {
    95  		snapshotDirFlag = test.dir
    96  		// Create the snapshots directory and populate it with the
    97  		// data specified by the test suite.
    98  		for _, label := range labels {
    99  			createLabelDir(t, fake.X, test.dir, label.name, label.snapshots)
   100  		}
   101  
   102  		// Check that running "jiri snapshot list" with no arguments
   103  		// returns the expected output.
   104  		var stdout bytes.Buffer
   105  		fake.X.Context = tool.NewContext(tool.ContextOpts{Stdout: &stdout})
   106  		if err := runSnapshotList(fake.X, nil); err != nil {
   107  			t.Fatalf("%v", err)
   108  		}
   109  		got, want := stdout.String(), generateOutput(labels)
   110  		if got != want {
   111  			t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v\n", got, want)
   112  		}
   113  
   114  		// Check that running "jiri snapshot list" with one argument
   115  		// returns the expected output.
   116  		stdout.Reset()
   117  		if err := runSnapshotList(fake.X, []string{"stable"}); err != nil {
   118  			t.Fatalf("%v", err)
   119  		}
   120  		got, want = stdout.String(), generateOutput(labels[1:])
   121  		if got != want {
   122  			t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v\n", got, want)
   123  		}
   124  
   125  		// Check that running "jiri snapshot list" with
   126  		// multiple arguments returns the expected output.
   127  		stdout.Reset()
   128  		if err := runSnapshotList(fake.X, []string{"beta", "stable"}); err != nil {
   129  			t.Fatalf("%v", err)
   130  		}
   131  		got, want = stdout.String(), generateOutput(labels)
   132  		if got != want {
   133  			t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v\n", got, want)
   134  		}
   135  	}
   136  }
   137  
   138  func checkReadme(t *testing.T, jirix *jiri.X, project, message string) {
   139  	s := jirix.NewSeq()
   140  	if _, err := s.Stat(project); err != nil {
   141  		t.Fatalf("%v", err)
   142  	}
   143  	readmeFile := filepath.Join(project, "README")
   144  	data, err := s.ReadFile(readmeFile)
   145  	if err != nil {
   146  		t.Fatalf("%v", err)
   147  	}
   148  	if got, want := data, []byte(message); bytes.Compare(got, want) != 0 {
   149  		t.Fatalf("unexpected content %v:\ngot\n%s\nwant\n%s\n", project, got, want)
   150  	}
   151  }
   152  
   153  func localProjectName(i int) string {
   154  	return "test-local-project-" + fmt.Sprintf("%d", i+1)
   155  }
   156  
   157  func remoteProjectName(i int) string {
   158  	return "test-remote-project-" + fmt.Sprintf("%d", i+1)
   159  }
   160  
   161  func writeReadme(t *testing.T, jirix *jiri.X, projectDir, message string) {
   162  	s := jirix.NewSeq()
   163  	path, perm := filepath.Join(projectDir, "README"), os.FileMode(0644)
   164  	if err := s.WriteFile(path, []byte(message), perm).Done(); err != nil {
   165  		t.Fatalf("%v", err)
   166  	}
   167  	cwd, err := os.Getwd()
   168  	if err != nil {
   169  		t.Fatalf("%v", err)
   170  	}
   171  	defer jirix.NewSeq().Chdir(cwd)
   172  	if err := s.Chdir(projectDir).Done(); err != nil {
   173  		t.Fatalf("%v", err)
   174  	}
   175  	if err := gitutil.New(jirix.NewSeq()).CommitFile(path, "creating README"); err != nil {
   176  		t.Fatalf("%v", err)
   177  	}
   178  }
   179  
   180  func resetFlags() {
   181  	snapshotDirFlag = ""
   182  	pushRemoteFlag = false
   183  }
   184  
   185  func TestGetSnapshotDir(t *testing.T) {
   186  	resetFlags()
   187  	defer resetFlags()
   188  	fake, cleanup := jiritest.NewFakeJiriRoot(t)
   189  	defer cleanup()
   190  
   191  	// With all flags at default values, snapshot dir should be default.
   192  	resetFlags()
   193  	got, err := getSnapshotDir(fake.X)
   194  	if err != nil {
   195  		t.Fatalf("getSnapshotDir() failed: %v\n", err)
   196  	}
   197  	if want := filepath.Join(fake.X.Root, defaultSnapshotDir); got != want {
   198  		t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
   199  	}
   200  
   201  	// With dir flag set to absolute path, snapshot dir should be value of dir
   202  	// flag.
   203  	resetFlags()
   204  	tempDir, err := fake.X.NewSeq().TempDir("", "")
   205  	if err != nil {
   206  		t.Fatalf("TempDir() failed: %v", err)
   207  	}
   208  	defer fake.X.NewSeq().RemoveAll(tempDir).Done()
   209  	snapshotDirFlag = tempDir
   210  	got, err = getSnapshotDir(fake.X)
   211  	if err != nil {
   212  		t.Fatalf("getSnapshotDir() failed: %v\n", err)
   213  	}
   214  	if want := snapshotDirFlag; got != want {
   215  		t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
   216  	}
   217  
   218  	// With dir flag set to relative path, snapshot dir should absolute path
   219  	// rooted at current working dir.
   220  	resetFlags()
   221  	snapshotDirFlag = "some/relative/path"
   222  	cwd, err := os.Getwd()
   223  	if err != nil {
   224  		t.Fatalf("os.Getwd() failed: %v", err)
   225  	}
   226  	defer fake.X.NewSeq().RemoveAll(filepath.Join(cwd, "some"))
   227  	got, err = getSnapshotDir(fake.X)
   228  	if err != nil {
   229  		t.Fatalf("getSnapshotDir() failed: %v\n", err)
   230  	}
   231  	if want := filepath.Join(cwd, snapshotDirFlag); got != want {
   232  		t.Errorf("unexpected snapshot dir: got %v want %v", got, want)
   233  	}
   234  }
   235  
   236  // TestCreate tests creating and checking out a snapshot.
   237  func TestCreate(t *testing.T) {
   238  	resetFlags()
   239  	defer resetFlags()
   240  	fake, cleanup := jiritest.NewFakeJiriRoot(t)
   241  	defer cleanup()
   242  	s := fake.X.NewSeq()
   243  
   244  	// Setup the initial remote and local projects.
   245  	numProjects, remoteProjects := 2, []string{}
   246  	for i := 0; i < numProjects; i++ {
   247  		if err := fake.CreateRemoteProject(remoteProjectName(i)); err != nil {
   248  			t.Fatalf("%v", err)
   249  		}
   250  		if err := fake.AddProject(project.Project{
   251  			Name:   remoteProjectName(i),
   252  			Path:   localProjectName(i),
   253  			Remote: fake.Projects[remoteProjectName(i)],
   254  		}); err != nil {
   255  			t.Fatalf("%v", err)
   256  		}
   257  	}
   258  
   259  	// Create initial commits in the remote projects and use UpdateUniverse()
   260  	// to mirror them locally.
   261  	for i := 0; i < numProjects; i++ {
   262  		writeReadme(t, fake.X, fake.Projects[remoteProjectName(i)], "revision 1")
   263  	}
   264  	if err := project.UpdateUniverse(fake.X, true); err != nil {
   265  		t.Fatalf("%v", err)
   266  	}
   267  
   268  	// Create a snapshot.
   269  	var stdout bytes.Buffer
   270  	fake.X.Context = tool.NewContext(tool.ContextOpts{Stdout: &stdout})
   271  	if err := runSnapshotCreate(fake.X, []string{"test-local"}); err != nil {
   272  		t.Fatalf("%v", err)
   273  	}
   274  
   275  	// Remove the local project repositories.
   276  	for i, _ := range remoteProjects {
   277  		localProject := filepath.Join(fake.X.Root, localProjectName(i))
   278  		if err := s.RemoveAll(localProject).Done(); err != nil {
   279  			t.Fatalf("%v", err)
   280  		}
   281  	}
   282  
   283  	// Check that invoking the UpdateUniverse() with the snapshot restores the
   284  	// local repositories.
   285  	snapshotDir := filepath.Join(fake.X.Root, defaultSnapshotDir)
   286  	snapshotFile := filepath.Join(snapshotDir, "test-local")
   287  	localX := fake.X.Clone(tool.ContextOpts{
   288  		Manifest: &snapshotFile,
   289  	})
   290  	if err := project.UpdateUniverse(localX, true); err != nil {
   291  		t.Fatalf("%v", err)
   292  	}
   293  	for i, _ := range remoteProjects {
   294  		localProject := filepath.Join(fake.X.Root, localProjectName(i))
   295  		checkReadme(t, fake.X, localProject, "revision 1")
   296  	}
   297  }
   298  
   299  // TestCreatePushRemote checks that creating a snapshot with the -push-remote
   300  // flag causes the snapshot to be committed and pushed upstream.
   301  func TestCreatePushRemote(t *testing.T) {
   302  	resetFlags()
   303  	defer resetFlags()
   304  
   305  	fake, cleanup := jiritest.NewFakeJiriRoot(t)
   306  	defer cleanup()
   307  
   308  	fake.EnableRemoteManifestPush()
   309  	defer fake.DisableRemoteManifestPush()
   310  
   311  	manifestDir := filepath.Join(fake.X.Root, "manifest")
   312  	snapshotDir := filepath.Join(manifestDir, "snapshot")
   313  	label := "test"
   314  
   315  	git := gitutil.New(fake.X.NewSeq(), gitutil.RootDirOpt(manifestDir))
   316  	commitCount, err := git.CountCommits("master", "")
   317  	if err != nil {
   318  		t.Fatalf("git.CountCommits(\"master\", \"\") failed: %v", err)
   319  	}
   320  
   321  	// Create snapshot with -push-remote flag set to true.
   322  	snapshotDirFlag = snapshotDir
   323  	pushRemoteFlag = true
   324  	if err := runSnapshotCreate(fake.X, []string{label}); err != nil {
   325  		t.Fatalf("%v", err)
   326  	}
   327  
   328  	// Check that repo has one new commit.
   329  	newCommitCount, err := git.CountCommits("master", "")
   330  	if err != nil {
   331  		t.Fatalf("git.CountCommits(\"master\", \"\") failed: %v", err)
   332  	}
   333  	if got, want := newCommitCount, commitCount+1; got != want {
   334  		t.Errorf("unexpected commit count: got %v want %v", got, want)
   335  	}
   336  
   337  	// Check that new label is commited.
   338  	labelFile := filepath.Join(snapshotDir, "labels", label)
   339  	if !git.IsFileCommitted(labelFile) {
   340  		t.Errorf("expected file %v to be committed but it was not", labelFile)
   341  	}
   342  }