github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/command/local_command_test.go (about)

     1  package command
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"testing"
     9  
    10  	"github.com/evergreen-ci/evergreen"
    11  	. "github.com/smartystreets/goconvey/convey"
    12  )
    13  
    14  func TestLocalCommands(t *testing.T) {
    15  	if runtime.GOOS == "windows" {
    16  		t.Skip("shell command test doesn't make sense on windows")
    17  	}
    18  
    19  	Convey("When running local commands", t, func() {
    20  
    21  		Convey("the preparation step should replace expansions and forward"+
    22  			" slashes in the command string", func() {
    23  
    24  			command := &LocalCommand{
    25  				CmdString: "one ${two} \\three${four|five}",
    26  			}
    27  
    28  			expansions := NewExpansions(map[string]string{
    29  				"two": "TWO",
    30  				"six": "SIX",
    31  			})
    32  
    33  			// run the preparation stage, and make sure the replacements are
    34  			// correctly made
    35  			So(command.PrepToRun(expansions), ShouldBeNil)
    36  			So(command.CmdString, ShouldEqual, "one TWO \\threefive")
    37  
    38  		})
    39  
    40  		Convey("the preparation step should replace expansion in the working directory", func() {
    41  			command := &LocalCommand{
    42  				WorkingDirectory: "one ${two} ${other|three} four five ${six}",
    43  			}
    44  
    45  			expansions := NewExpansions(map[string]string{
    46  				"two": "TWO",
    47  				"six": "SIX",
    48  			})
    49  
    50  			So(command.PrepToRun(expansions), ShouldBeNil)
    51  			So(command.WorkingDirectory, ShouldEqual, "one TWO three four five SIX")
    52  		})
    53  
    54  		Convey("the perpetration step should return an error if invalid expansions", func() {
    55  			expansions := NewExpansions(map[string]string{"foo": "bar"})
    56  
    57  			for _, cmd := range []*LocalCommand{
    58  				{WorkingDirectory: "${foo|${bar}}"},
    59  				{CmdString: "${foo${bar}}"},
    60  			} {
    61  				So(cmd.PrepToRun(expansions), ShouldNotBeNil)
    62  			}
    63  
    64  		})
    65  
    66  		Convey("the preparation step should not replace strings without expansions", func() {
    67  			var cmd *LocalCommand
    68  
    69  			expansions := NewExpansions(map[string]string{"foo": "bar"})
    70  
    71  			for _, input := range []string{"", "nothing", "this is empty", "foo"} {
    72  				cmd = &LocalCommand{WorkingDirectory: input}
    73  				So(cmd.PrepToRun(expansions), ShouldBeNil)
    74  				So(cmd.WorkingDirectory, ShouldEqual, input)
    75  
    76  				cmd = &LocalCommand{CmdString: input}
    77  				So(cmd.PrepToRun(expansions), ShouldBeNil)
    78  				So(cmd.CmdString, ShouldEqual, input)
    79  			}
    80  		})
    81  
    82  		Convey("the specified environment should be used", func() {
    83  			stdout := &CacheLastWritten{}
    84  
    85  			command := &LocalCommand{
    86  				CmdString: "echo $local_command_test",
    87  				Stdout:    stdout,
    88  				Stderr:    ioutil.Discard,
    89  			}
    90  
    91  			// get the current env
    92  			command.Environment = os.Environ()
    93  
    94  			// run the command - the environment variable should be empty
    95  			So(command.Run(), ShouldBeNil)
    96  			So(string(stdout.LastWritten), ShouldEqual, "\n")
    97  
    98  			// add the environment variable to the env
    99  			command.Environment = append(command.Environment,
   100  				"local_command_test=hello")
   101  
   102  			// run the command again - the environment variable should be set
   103  			// correctly
   104  			So(command.Run(), ShouldBeNil)
   105  			So(string(stdout.LastWritten), ShouldEqual, "hello\n")
   106  
   107  		})
   108  
   109  		Convey("the specified working directory should be used", func() {
   110  
   111  			stdout := &CacheLastWritten{}
   112  
   113  			workingDir, err := filepath.Abs(evergreen.FindEvergreenHome())
   114  			So(err, ShouldBeNil)
   115  
   116  			command := &LocalCommand{
   117  				CmdString:        "pwd",
   118  				Stdout:           stdout,
   119  				Stderr:           ioutil.Discard,
   120  				WorkingDirectory: workingDir,
   121  			}
   122  			// run the command - the working directory should be as specified
   123  			So(command.Run(), ShouldBeNil)
   124  
   125  			reportedPwd := string(stdout.LastWritten)
   126  			reportedPwd = reportedPwd[:len(reportedPwd)-1]
   127  			reportedPwd, err = filepath.EvalSymlinks(reportedPwd)
   128  			So(err, ShouldBeNil)
   129  
   130  			So(reportedPwd, ShouldEqual, workingDir)
   131  
   132  		})
   133  
   134  		Convey("the specified shell should be used", func() {
   135  			for _, sh := range []string{"bash", "sh", "/bin/bash", "/bin/sh"} {
   136  				stdout := &CacheLastWritten{}
   137  				command := &LocalCommand{
   138  					Shell:     sh,
   139  					CmdString: "echo $0",
   140  					Stdout:    stdout,
   141  					Stderr:    ioutil.Discard,
   142  				}
   143  
   144  				So(command.Run(), ShouldBeNil)
   145  				So(string(stdout.LastWritten), ShouldEqual, sh+"\n")
   146  			}
   147  		})
   148  
   149  		Convey("if not specified, sh should be used", func() {
   150  			stdout := &CacheLastWritten{}
   151  			command := &LocalCommand{
   152  				CmdString: "echo $0",
   153  				Stdout:    stdout,
   154  				Stderr:    ioutil.Discard,
   155  			}
   156  
   157  			So(command.Run(), ShouldBeNil)
   158  			So(string(stdout.LastWritten), ShouldEqual, "sh\n")
   159  		})
   160  
   161  		Convey("when specified, local command can also use python", func() {
   162  			stdout := &CacheLastWritten{}
   163  			command := &LocalCommand{
   164  				Shell:     "python",
   165  				CmdString: "print('hello world')",
   166  				Stdout:    stdout,
   167  				Stderr:    ioutil.Discard,
   168  			}
   169  
   170  			So(command.Run(), ShouldBeNil)
   171  			So(string(stdout.LastWritten), ShouldEqual, "hello world\n")
   172  		})
   173  
   174  	})
   175  }
   176  
   177  func TestLocalCommandGroups(t *testing.T) {
   178  
   179  	Convey("With a group of local commands", t, func() {
   180  
   181  		Convey("the global preparation step should invoke all of the prep"+
   182  			" steps for the group", func() {
   183  
   184  			// the three commands for the group, whose preparation steps will
   185  			// yield different results for expanding the command string
   186  			firstCommand := &LocalCommand{
   187  				CmdString: "one\\ ${two} \\three",
   188  			}
   189  			secondCommand := &LocalCommand{
   190  				CmdString: "${four|five}",
   191  			}
   192  			thirdCommand := &LocalCommand{
   193  				CmdString: "six seven",
   194  			}
   195  
   196  			expansions := NewExpansions(map[string]string{
   197  				"two": "TWO",
   198  				"six": "SIX",
   199  			})
   200  
   201  			cmdGroup := &LocalCommandGroup{
   202  				Commands: []*LocalCommand{firstCommand, secondCommand,
   203  					thirdCommand},
   204  				Expansions: expansions,
   205  			}
   206  
   207  			// run the preparation step for the command group, make sure it is
   208  			// run for each command individually
   209  			So(cmdGroup.PrepToRun(), ShouldBeNil)
   210  			So(firstCommand.CmdString, ShouldEqual, "one\\ TWO \\three")
   211  			So(secondCommand.CmdString, ShouldEqual, "five")
   212  			So(thirdCommand.CmdString, ShouldEqual, "six seven")
   213  
   214  		})
   215  
   216  		Convey("The global preparation step should fail if any of the"+
   217  			" individual group members' prep steps fail", func() {
   218  
   219  			// the three commands for the group. only the second will error
   220  			firstCommand := &LocalCommand{
   221  				CmdString: "one\\ ${two} \\three",
   222  			}
   223  			secondCommand := &LocalCommand{
   224  				CmdString: "${four|five}${",
   225  			}
   226  			thirdCommand := &LocalCommand{
   227  				CmdString: "six seven",
   228  			}
   229  
   230  			expansions := NewExpansions(map[string]string{
   231  				"two": "TWO",
   232  				"six": "SIX",
   233  			})
   234  
   235  			cmdGroup := &LocalCommandGroup{
   236  				Commands: []*LocalCommand{firstCommand, secondCommand,
   237  					thirdCommand},
   238  				Expansions: expansions,
   239  			}
   240  
   241  			// the preparation step should fail
   242  			So(cmdGroup.PrepToRun(), ShouldNotBeNil)
   243  
   244  		})
   245  
   246  	})
   247  
   248  }
   249  
   250  func TestLocalScript(t *testing.T) {
   251  	if runtime.GOOS == "windows" {
   252  		t.Skip("shell command test doesn't make sense on windows")
   253  	}
   254  
   255  	Convey("When running local commands in script mode", t, func() {
   256  
   257  		Convey("A multi-line script should run all lines", func() {
   258  
   259  			stdout := &CacheLastWritten{}
   260  
   261  			workingDir, err := filepath.Abs(evergreen.FindEvergreenHome())
   262  			So(err, ShouldBeNil)
   263  
   264  			command := &LocalCommand{
   265  				CmdString:        "set -v\necho 'hi'\necho 'foo'\necho `pwd`",
   266  				ScriptMode:       true,
   267  				Stdout:           stdout,
   268  				Stderr:           ioutil.Discard,
   269  				WorkingDirectory: workingDir,
   270  			}
   271  
   272  			// run the command - the working directory should be as specified
   273  			So(command.Run(), ShouldBeNil)
   274  
   275  			reportedPwd := string(stdout.LastWritten)
   276  			reportedPwd = reportedPwd[:len(reportedPwd)-1]
   277  			reportedPwd, err = filepath.EvalSymlinks(reportedPwd)
   278  			So(err, ShouldBeNil)
   279  			So(reportedPwd, ShouldEqual, workingDir)
   280  		})
   281  
   282  	})
   283  }