github.com/beauknowssoftware/makehcl@v0.0.0-20200322000747-1b9bb1e1c008/internal/plan/plan_test.go (about)

     1  package plan_test
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/beauknowssoftware/makehcl/internal/plan"
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const (
    16  	local = false
    17  )
    18  
    19  type filename = string
    20  type fileContents = []byte
    21  
    22  func createFile(t *testing.T, f filename, data fileContents) {
    23  	dir := filepath.Dir(f)
    24  	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
    25  		err = errors.Wrapf(err, "failed to create directory %v", dir)
    26  		t.Fatal(err)
    27  	}
    28  
    29  	if err := ioutil.WriteFile(f, data, os.ModePerm); err != nil {
    30  		err = errors.Wrapf(err, "failed to write file %v", f)
    31  		t.Fatal(err)
    32  	}
    33  }
    34  
    35  func copyFile(t *testing.T, src, dest string) {
    36  	out, err := os.Create(dest)
    37  	if err != nil {
    38  		err = errors.Wrapf(err, "failed to create %v", dest)
    39  		t.Fatal(err)
    40  	}
    41  	defer out.Close()
    42  
    43  	in, err := os.Open(src)
    44  	if err != nil {
    45  		err = errors.Wrapf(err, "failed to open %v", src)
    46  		t.Fatal(err)
    47  	}
    48  	defer in.Close()
    49  
    50  	if _, err := io.Copy(out, in); err != nil {
    51  		err = errors.Wrapf(err, "failed to copy from %v to %v", src, dest)
    52  		t.Fatal(err)
    53  	}
    54  }
    55  
    56  func safeDo(t *testing.T, o plan.DoOptions) plan.Plan {
    57  	p, err := plan.Do(o)
    58  	if err != nil {
    59  		err = errors.Wrap(err, "failed to plan")
    60  		t.Fatal(err)
    61  	}
    62  
    63  	return p
    64  }
    65  
    66  func copyDir(t *testing.T, src, dest string) {
    67  	entries, err := ioutil.ReadDir(src)
    68  	if err != nil {
    69  		err = errors.Wrapf(err, "failed to list %v", src)
    70  		t.Fatal(err)
    71  	}
    72  
    73  	for _, entry := range entries {
    74  		srcFile := filepath.Join(src, entry.Name())
    75  		destFile := filepath.Join(dest, entry.Name())
    76  		copyFile(t, srcFile, destFile)
    77  	}
    78  }
    79  
    80  func copyToTemp(t *testing.T, src string) string {
    81  	tempDir, err := ioutil.TempDir("", "makehcl")
    82  	if err != nil {
    83  		err = errors.Wrap(err, "failed to create temporary directory")
    84  		t.Fatal(err)
    85  	}
    86  
    87  	copyDir(t, src, tempDir)
    88  
    89  	return tempDir
    90  }
    91  
    92  func pushd(t *testing.T, dir string) func() {
    93  	originalDir, err := os.Getwd()
    94  	if err != nil {
    95  		err = errors.Wrap(err, "failed to get working directory")
    96  		t.Fatal(err)
    97  	}
    98  
    99  	if !local {
   100  		dir = copyToTemp(t, dir)
   101  	}
   102  
   103  	if err := os.Chdir(dir); err != nil {
   104  		err = errors.Wrapf(err, "failed to pushd to %v", dir)
   105  		t.Fatal(err)
   106  	}
   107  
   108  	return func() {
   109  		if err := os.Chdir(originalDir); err != nil {
   110  			err = errors.Wrapf(err, "failed to popd directories to %v", originalDir)
   111  			t.Fatal(err)
   112  		}
   113  
   114  		if !local {
   115  			if err := os.RemoveAll(dir); err != nil {
   116  				err = errors.Wrapf(err, "failed to remove %v", dir)
   117  				t.Fatal(err)
   118  			}
   119  		}
   120  	}
   121  }
   122  
   123  func TestRun(t *testing.T) {
   124  	tests := map[string]struct {
   125  		folder   string
   126  		existing []map[filename]fileContents
   127  		expected plan.Plan
   128  		options  plan.DoOptions
   129  	}{
   130  		"simple": {
   131  			folder: "testdata/simple",
   132  			expected: plan.Plan{
   133  				plan.Item{
   134  					Target: "test.txt",
   135  					Reasons: []plan.Reason{
   136  						{
   137  							Target:     "test.txt",
   138  							ReasonType: plan.DoesNotExist,
   139  						},
   140  					},
   141  				},
   142  			},
   143  		},
   144  		"dependencies": {
   145  			folder: "testdata/dependencies",
   146  			expected: plan.Plan{
   147  				plan.Item{
   148  					Target: "test2.txt",
   149  					Reasons: []plan.Reason{
   150  						{
   151  							Target:     "test2.txt",
   152  							ReasonType: plan.DoesNotExist,
   153  						},
   154  					},
   155  				},
   156  				plan.Item{
   157  					Target: "test.txt",
   158  					Reasons: []plan.Reason{
   159  						{
   160  							Target:     "test.txt",
   161  							ReasonType: plan.DoesNotExist,
   162  						},
   163  					},
   164  				},
   165  				plan.Item{
   166  					Target: "test3.txt",
   167  					Reasons: []plan.Reason{
   168  						{
   169  							Target:     "test3.txt",
   170  							ReasonType: plan.DoesNotExist,
   171  						},
   172  					},
   173  				},
   174  			},
   175  		},
   176  		"existing files": {
   177  			folder: "testdata/dependencies",
   178  			existing: []map[filename]fileContents{
   179  				{"test2.txt": {}},
   180  			},
   181  			expected: plan.Plan{
   182  				plan.Item{
   183  					Target: "test.txt",
   184  					Reasons: []plan.Reason{
   185  						{
   186  							Target:     "test.txt",
   187  							ReasonType: plan.DoesNotExist,
   188  						},
   189  					},
   190  				},
   191  				plan.Item{
   192  					Target: "test3.txt",
   193  					Reasons: []plan.Reason{
   194  						{
   195  							Target:     "test3.txt",
   196  							ReasonType: plan.DoesNotExist,
   197  						},
   198  					},
   199  				},
   200  			},
   201  		},
   202  		"ignore last modified": {
   203  			folder: "testdata/ignore_last_modified",
   204  			options: plan.DoOptions{
   205  				Options: plan.Options{
   206  					IgnoreLastModified: true,
   207  				},
   208  			},
   209  			existing: []map[filename]fileContents{
   210  				{"test2.txt": {}},
   211  				{"test.txt": {}},
   212  				{"test3.txt": {}},
   213  			},
   214  			expected: plan.Plan{
   215  				plan.Item{Target: "test2.txt"},
   216  				plan.Item{Target: "test.txt"},
   217  				plan.Item{Target: "test3.txt"},
   218  			},
   219  		},
   220  		"out of date": {
   221  			folder: "testdata/out_of_date",
   222  			existing: []map[filename]fileContents{
   223  				{"test2.txt": {}},
   224  				{"test.txt": {}},
   225  				{"test3.txt": {}},
   226  				{"test2.txt": {}},
   227  			},
   228  			expected: plan.Plan{
   229  				plan.Item{
   230  					Target: "test.txt",
   231  					Reasons: []plan.Reason{
   232  						{
   233  							Target:     "test2.txt",
   234  							ReasonType: plan.OlderThanDependency,
   235  						},
   236  					},
   237  				},
   238  				plan.Item{
   239  					Target: "test3.txt",
   240  					Reasons: []plan.Reason{
   241  						{
   242  							Target:     "test.txt",
   243  							ReasonType: plan.DependencyPlanned,
   244  						},
   245  					},
   246  				},
   247  			},
   248  		},
   249  		"multiple reasons": {
   250  			folder: "testdata/multiple_reasons",
   251  			existing: []map[filename]fileContents{
   252  				{"test3.txt": {}},
   253  				{"test2.txt": {}},
   254  				{"test.txt": {}},
   255  				{"test3.txt": {}},
   256  				{"test2.txt": {}},
   257  			},
   258  			expected: plan.Plan{
   259  				plan.Item{
   260  					Target: "test.txt",
   261  					Reasons: []plan.Reason{
   262  						{
   263  							Target:     "test2.txt",
   264  							ReasonType: plan.OlderThanDependency,
   265  						},
   266  						{
   267  							Target:     "test3.txt",
   268  							ReasonType: plan.OlderThanDependency,
   269  						},
   270  					},
   271  				},
   272  			},
   273  		},
   274  	}
   275  
   276  	for name, test := range tests {
   277  		t.Run(name, func(t *testing.T) {
   278  			popd := pushd(t, test.folder)
   279  			defer popd()
   280  
   281  			for _, batch := range test.existing {
   282  				for f, d := range batch {
   283  					createFile(t, f, d)
   284  				}
   285  			}
   286  
   287  			actual := safeDo(t, test.options)
   288  
   289  			if diff := cmp.Diff(test.expected, actual); diff != "" {
   290  				t.Fatalf("plan mismatch (-want,+got):\n%s", diff)
   291  			}
   292  		})
   293  	}
   294  }