github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/cmd/nash/install_test.go (about)

     1  package main_test
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	main "github.com/madlambda/nash/cmd/nash"
    10  	"github.com/madlambda/nash/internal/testing/fixture"
    11  )
    12  
    13  // TODO: test when nashpath lib already exists and has libraries inside
    14  
    15  func TestInstallLib(t *testing.T) {
    16  	type testcase struct {
    17  		name        string
    18  		libfiles    []string
    19  		installpath string
    20  		// want will map the wanted files to the original files copied from the lib
    21  		// the wanted files paths are relative to inside the nashpath lib dir.
    22  		// the files need to be mapped to the original files because of content validation
    23  		// when multiple files are installed.
    24  		want map[string]string
    25  	}
    26  
    27  	cases := []testcase{
    28  		{
    29  			name: "SingleFile",
    30  			libfiles: []string{
    31  				"/testfile/file.sh",
    32  			},
    33  			installpath: "/testfile/file.sh",
    34  			want: map[string]string{
    35  				"file.sh": "/testfile/file.sh",
    36  			},
    37  		},
    38  		{
    39  			name: "SingleDir",
    40  			libfiles: []string{
    41  				"/testfile/file.sh",
    42  			},
    43  			installpath: "/testfile",
    44  			want: map[string]string{
    45  				"/testfile/file.sh": "/testfile/file.sh",
    46  			},
    47  		},
    48  		{
    49  			name: "SingleDirWithMultipleFiles",
    50  			libfiles: []string{
    51  				"/testfile/file.sh",
    52  				"/testfile/fileagain.sh",
    53  			},
    54  			installpath: "/testfile",
    55  			want: map[string]string{
    56  				"/testfile/file.sh":      "/testfile/file.sh",
    57  				"/testfile/fileagain.sh": "/testfile/fileagain.sh",
    58  			},
    59  		},
    60  		{
    61  			name: "MultipleDirsWithMultipleFiles",
    62  			libfiles: []string{
    63  				"/testfile/file.sh",
    64  				"/testfile/dir1/file.sh",
    65  				"/testfile/dir1/fileagain.sh",
    66  				"/testfile/dir2/file.sh",
    67  				"/testfile/dir2/fileagain.sh",
    68  				"/testfile/dir2/dir3/file.sh",
    69  			},
    70  			installpath: "/testfile",
    71  			want: map[string]string{
    72  				"/testfile/file.sh":           "/testfile/file.sh",
    73  				"/testfile/dir1/file.sh":      "/testfile/dir1/file.sh",
    74  				"/testfile/dir1/fileagain.sh": "/testfile/dir1/fileagain.sh",
    75  				"/testfile/dir2/file.sh":      "/testfile/dir2/file.sh",
    76  				"/testfile/dir2/fileagain.sh": "/testfile/dir2/fileagain.sh",
    77  				"/testfile/dir2/dir3/file.sh": "/testfile/dir2/dir3/file.sh",
    78  			},
    79  		},
    80  		{
    81  			name: "InstallOnlyFilesIndicatedByInstallDir",
    82  			libfiles: []string{
    83  				"/testfile/file.sh",
    84  				"/testfile/dir1/file.sh",
    85  				"/testfile/dir1/fileagain.sh",
    86  				"/testfile/dir2/file.sh",
    87  				"/testfile/dir2/fileagain.sh",
    88  				"/testfile/dir2/dir3/file.sh",
    89  			},
    90  			installpath: "/testfile/dir2",
    91  			want: map[string]string{
    92  				"/dir2/file.sh":      "/testfile/dir2/file.sh",
    93  				"/dir2/fileagain.sh": "/testfile/dir2/fileagain.sh",
    94  				"/dir2/dir3/file.sh": "/testfile/dir2/dir3/file.sh",
    95  			},
    96  		},
    97  	}
    98  
    99  	for _, c := range cases {
   100  		t.Run(c.name, func(t *testing.T) {
   101  			nashpath, rmnashpath := fixture.Tmpdir(t)
   102  			defer rmnashpath()
   103  
   104  			libfilesDir, rmlibfilesDir := fixture.Tmpdir(t)
   105  			defer rmlibfilesDir()
   106  
   107  			nashlibdir := main.NashLibDir(nashpath)
   108  			libfiles := []string{}
   109  
   110  			libfileFullPath := func(libfilepath string) string {
   111  				return filepath.Join(libfilesDir, libfilepath)
   112  			}
   113  
   114  			for _, f := range c.libfiles {
   115  				libfiles = append(libfiles, libfileFullPath(f))
   116  			}
   117  
   118  			createdLibFiles := fixture.CreateFiles(t, libfiles)
   119  			installpath := filepath.Join(libfilesDir, c.installpath)
   120  
   121  			err := main.InstallLib(nashpath, installpath)
   122  			if err != nil {
   123  				t.Fatal(err)
   124  			}
   125  
   126  			listNashPathFiles := func() []string {
   127  				files := []string{}
   128  				filepath.Walk(nashpath, func(path string, stats os.FileInfo, err error) error {
   129  					if stats.IsDir() {
   130  						return nil
   131  					}
   132  					files = append(files, path)
   133  					return nil
   134  				})
   135  				return files
   136  			}
   137  
   138  			gotFiles := listNashPathFiles()
   139  
   140  			fatal := func() {
   141  				t.Errorf("nashpath: [%s]", nashpath)
   142  				t.Errorf("nashpath contents:")
   143  
   144  				for _, path := range gotFiles {
   145  					t.Errorf("[%s]", path)
   146  				}
   147  				t.Fatal("")
   148  			}
   149  
   150  			if len(gotFiles) != len(c.want) {
   151  				t.Errorf("wanted[%d] files but got[%d]", len(c.want), len(gotFiles))
   152  				fatal()
   153  			}
   154  
   155  			for wantFilepath, libfilepath := range c.want {
   156  				completeLibFilepath := libfileFullPath(libfilepath)
   157  				wantContents, ok := createdLibFiles[completeLibFilepath]
   158  
   159  				if !ok {
   160  					t.Errorf("unable to find libfilepath[%s] contents on created lib files map[%+v]", completeLibFilepath, createdLibFiles)
   161  					t.Fatal("this probably means a wrongly specified test case with wanted files that are not present on the libfiles")
   162  				}
   163  
   164  				fullWantFilepath := filepath.Join(nashlibdir, wantFilepath)
   165  				wantFile, err := os.Open(fullWantFilepath)
   166  				if err != nil {
   167  					t.Errorf("error[%s] checking wanted file[%s]", err, wantFilepath)
   168  					fatal()
   169  				}
   170  				gotContentsRaw, err := ioutil.ReadAll(wantFile)
   171  				wantFile.Close()
   172  
   173  				if err != nil {
   174  					t.Errorf("error[%s] checking existence of wanted file[%s]", err, wantFilepath)
   175  					fatal()
   176  				}
   177  
   178  				gotContents := string(gotContentsRaw)
   179  				if gotContents != wantContents {
   180  					t.Errorf("for file [%s] wanted contents [%s] but got [%s]", wantFilepath, wantContents, gotContents)
   181  					fatal()
   182  				}
   183  			}
   184  		})
   185  	}
   186  }
   187  
   188  func TestSourcePathCantBeEqualToNashLibDir(t *testing.T) {
   189  	nashpath, rmnashpath := fixture.Tmpdir(t)
   190  	defer rmnashpath()
   191  
   192  	nashlibdir := main.NashLibDir(nashpath)
   193  
   194  	fixture.CreateFile(t, filepath.Join(nashlibdir, "whatever.sh"))
   195  
   196  	assertInstallLibFails(t, nashpath, nashlibdir)
   197  }
   198  
   199  func TestSourcePathCantBeInsideNashLibDir(t *testing.T) {
   200  	nashpath, rmnashpath := fixture.Tmpdir(t)
   201  	defer rmnashpath()
   202  
   203  	nashlibdir := main.NashLibDir(nashpath)
   204  	sourcelibdir := filepath.Join(nashlibdir, "somedir")
   205  	fixture.CreateFile(t, filepath.Join(sourcelibdir, "whatever.sh"))
   206  
   207  	assertInstallLibFails(t, nashpath, sourcelibdir)
   208  }
   209  
   210  func TestRelativeSourcePathCantBeInsideNashLibDir(t *testing.T) {
   211  	nashpath, rmnashpath := fixture.Tmpdir(t)
   212  	defer rmnashpath()
   213  
   214  	nashlibdir := main.NashLibDir(nashpath)
   215  	fixture.CreateFile(t, filepath.Join(nashlibdir, "somedir", "whatever.sh"))
   216  
   217  	oldwd := fixture.WorkingDir(t)
   218  	defer fixture.ChangeDir(t, oldwd)
   219  
   220  	fixture.ChangeDir(t, nashlibdir)
   221  
   222  	assertInstallLibFails(t, nashpath, "./somedir")
   223  }
   224  
   225  func TestFailsOnUnexistentSourcePath(t *testing.T) {
   226  	nashpath, rmnashpath := fixture.Tmpdir(t)
   227  	defer rmnashpath()
   228  
   229  	assertInstallLibFails(t, nashpath, "/nonexistent/nash/crap")
   230  }
   231  
   232  func TestFailsOnUnreadableSourcePath(t *testing.T) {
   233  	nashpath, rmnashpath := fixture.Tmpdir(t)
   234  	defer rmnashpath()
   235  
   236  	sourcedir, rmsourcedir := fixture.Tmpdir(t)
   237  	defer rmsourcedir()
   238  
   239  	fixture.Chmod(t, sourcedir, writeOnly)
   240  	assertInstallLibFails(t, nashpath, sourcedir)
   241  }
   242  
   243  func TestFailsOnUnreadableFileInsideSourcePath(t *testing.T) {
   244  	nashpath, rmnashpath := fixture.Tmpdir(t)
   245  	defer rmnashpath()
   246  
   247  	sourcedir, rmsourcedir := fixture.Tmpdir(t)
   248  	defer rmsourcedir()
   249  
   250  	readableFile := filepath.Join(sourcedir, "file1.sh")
   251  	unreadableFile := filepath.Join(sourcedir, "file2.sh")
   252  
   253  	fixture.CreateFiles(t, []string{readableFile, unreadableFile})
   254  	fixture.Chmod(t, unreadableFile, writeOnly)
   255  
   256  	assertInstallLibFails(t, nashpath, sourcedir)
   257  }
   258  
   259  func TestFailsOnUnwriteableNashPath(t *testing.T) {
   260  	nashpath, rmnashpath := fixture.Tmpdir(t)
   261  	defer rmnashpath()
   262  
   263  	sourcedir, rmsourcedir := fixture.Tmpdir(t)
   264  	defer rmsourcedir()
   265  
   266  	fixture.Chmod(t, nashpath, readOnly)
   267  	fixture.CreateFile(t, filepath.Join(sourcedir, "file.sh"))
   268  
   269  	assertInstallLibFails(t, nashpath, sourcedir)
   270  }
   271  
   272  func TestFailsOnUnwriteableFileInsideNashLibdir(t *testing.T) {
   273  	nashpath, rmnashpath := fixture.Tmpdir(t)
   274  	defer rmnashpath()
   275  
   276  	sourcedir, rmsourcedir := fixture.Tmpdir(t)
   277  	defer rmsourcedir()
   278  
   279  	filename := "test.sh"
   280  	sourcefile := filepath.Join(sourcedir, filename)
   281  	expectedInstalledFile := filepath.Join(
   282  		main.NashLibDir(nashpath),
   283  		filepath.Base(sourcedir),
   284  		filename,
   285  	)
   286  
   287  	fixture.CreateFiles(t, []string{sourcefile, expectedInstalledFile})
   288  	fixture.Chmod(t, expectedInstalledFile, readOnly)
   289  
   290  	assertInstallLibFails(t, nashpath, sourcedir)
   291  }
   292  
   293  func assertInstallLibFails(t *testing.T, nashpath string, sourcepath string) {
   294  	t.Helper()
   295  
   296  	err := main.InstallLib(nashpath, sourcepath)
   297  	if err == nil {
   298  		t.Fatal("expected error, got nil")
   299  	}
   300  }
   301  
   302  const writeOnly = 0333
   303  const readOnly = 0555