github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/apps/distgo/cmd/run/run_test.go (about)

     1  // Copyright 2016 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package run_test
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"path"
    22  	"regexp"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/nmiyake/pkg/dirs"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"github.com/palantir/godel/apps/distgo/cmd/run"
    31  	"github.com/palantir/godel/apps/distgo/params"
    32  	"github.com/palantir/godel/apps/distgo/pkg/git"
    33  )
    34  
    35  const (
    36  	runTestMain = `package main
    37  
    38  import (
    39  	"fmt"
    40  	"io/ioutil"
    41  	"os"
    42  	"path"
    43  )
    44  
    45  func main() {
    46  	fmt.Println("testMainOutput")
    47  	ioutil.WriteFile(path.Join("{{OUTPUT_PATH}}", "runTestMainOutput.txt"), []byte(fmt.Sprintf("%v", os.Args[1:])), 0644)
    48  }
    49  `
    50  	runTestMainBar = `package main
    51  
    52  import (
    53  	"fmt"
    54  	"io/ioutil"
    55  	"os"
    56  	"path"
    57  )
    58  
    59  func main() {
    60  	bar("testMainOutput")
    61  	ioutil.WriteFile(path.Join("{{OUTPUT_PATH}}", "runTestMainOutput.txt"), []byte(fmt.Sprintf("%v", os.Args[1:])), 0644)
    62  }
    63  `
    64  )
    65  
    66  func TestRun(t *testing.T) {
    67  	tmp, cleanup, err := dirs.TempDir("", "")
    68  	defer cleanup()
    69  	require.NoError(t, err)
    70  
    71  	for i, currCase := range []struct {
    72  		spec         func(projectDir string) params.ProductBuildSpec
    73  		runArgs      []string
    74  		preRunAction func(projectDir string)
    75  		validate     func(runErr error, caseNum int, projectDir string)
    76  	}{
    77  		{
    78  			// "run" runs main file
    79  			spec: func(projectDir string) params.ProductBuildSpec {
    80  				return params.NewProductBuildSpec(
    81  					projectDir,
    82  					"foo",
    83  					git.ProjectInfo{},
    84  					params.Product{
    85  						Build: params.Build{
    86  							MainPkg: "./.",
    87  						},
    88  					},
    89  					params.Project{},
    90  				)
    91  			},
    92  			preRunAction: func(projectDir string) {
    93  				err := ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte(strings.Replace(runTestMain, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
    94  				require.NoError(t, err)
    95  			},
    96  			validate: func(runErr error, caseNum int, projectDir string) {
    97  				assert.NoError(t, runErr, "Case %d", caseNum)
    98  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
    99  				require.NoError(t, err, "Case %d", caseNum)
   100  				assert.Equal(t, "[]", string(bytes))
   101  			},
   102  		},
   103  		{
   104  			// "run" uses arguments provided in configuration (but does not evaluate them)
   105  			spec: func(projectDir string) params.ProductBuildSpec {
   106  				return params.NewProductBuildSpec(
   107  					projectDir,
   108  					"foo",
   109  					git.ProjectInfo{},
   110  					params.Product{
   111  						Build: params.Build{
   112  							MainPkg: "./.",
   113  						},
   114  						Run: params.Run{
   115  							Args: []string{
   116  								"foo",
   117  								"bar",
   118  								"$GOPATH",
   119  							},
   120  						},
   121  					},
   122  					params.Project{},
   123  				)
   124  			},
   125  			preRunAction: func(projectDir string) {
   126  				err := ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte(strings.Replace(runTestMain, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
   127  				require.NoError(t, err)
   128  			},
   129  			validate: func(runErr error, caseNum int, projectDir string) {
   130  				assert.NoError(t, runErr, "Case %d", caseNum)
   131  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
   132  				require.NoError(t, err, "Case %d", caseNum)
   133  				assert.Equal(t, "[foo bar $GOPATH]", string(bytes))
   134  			},
   135  		},
   136  		{
   137  			// "run" uses arguments provided in slice
   138  			spec: func(projectDir string) params.ProductBuildSpec {
   139  				return params.NewProductBuildSpec(
   140  					projectDir,
   141  					"foo",
   142  					git.ProjectInfo{},
   143  					params.Product{
   144  						Build: params.Build{
   145  							MainPkg: "./.",
   146  						},
   147  					},
   148  					params.Project{},
   149  				)
   150  			},
   151  			runArgs: []string{"foo", "bar", "$GOPATH"},
   152  			preRunAction: func(projectDir string) {
   153  				err := ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte(strings.Replace(runTestMain, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
   154  				require.NoError(t, err)
   155  			},
   156  			validate: func(runErr error, caseNum int, projectDir string) {
   157  				assert.NoError(t, runErr, "Case %d", caseNum)
   158  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
   159  				require.NoError(t, err, "Case %d", caseNum)
   160  				assert.Equal(t, "[foo bar $GOPATH]", string(bytes))
   161  			},
   162  		},
   163  		{
   164  			// "run" combines arguments in configuration with provided arguments
   165  			spec: func(projectDir string) params.ProductBuildSpec {
   166  				return params.NewProductBuildSpec(
   167  					projectDir,
   168  					"foo",
   169  					git.ProjectInfo{},
   170  					params.Product{
   171  						Build: params.Build{
   172  							MainPkg: "./.",
   173  						},
   174  						Run: params.Run{
   175  							Args: []string{
   176  								"cfgArg_foo",
   177  								"cfgArg_bar",
   178  								"$cfgArg",
   179  							},
   180  						},
   181  					},
   182  					params.Project{},
   183  				)
   184  			},
   185  			runArgs: []string{"runArg_foo", "runArg_bar", "$runArg"},
   186  			preRunAction: func(projectDir string) {
   187  				err := ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte(strings.Replace(runTestMain, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
   188  				require.NoError(t, err)
   189  			},
   190  			validate: func(runErr error, caseNum int, projectDir string) {
   191  				assert.NoError(t, runErr, "Case %d", caseNum)
   192  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
   193  				require.NoError(t, err, "Case %d", caseNum)
   194  				assert.Equal(t, "[cfgArg_foo cfgArg_bar $cfgArg runArg_foo runArg_bar $runArg]", string(bytes))
   195  			},
   196  		},
   197  		{
   198  			// "run" works with multiple main package files as long as there is a single main function
   199  			spec: func(projectDir string) params.ProductBuildSpec {
   200  				return params.NewProductBuildSpec(
   201  					projectDir,
   202  					"foo",
   203  					git.ProjectInfo{},
   204  					params.Product{
   205  						Build: params.Build{
   206  							MainPkg: "./foo",
   207  						},
   208  					},
   209  					params.Project{},
   210  				)
   211  			},
   212  			preRunAction: func(projectDir string) {
   213  				err := os.MkdirAll(path.Join(projectDir, "foo"), 0755)
   214  				require.NoError(t, err)
   215  
   216  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "main_file.go"), []byte(strings.Replace(runTestMainBar, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
   217  				require.NoError(t, err)
   218  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "other_main_file.go"), []byte(`package main
   219  import "fmt"
   220  func bar(a ...interface{}) (n int, err error) {
   221  	return fmt.Println(a...)
   222  }
   223  `), 0644)
   224  				require.NoError(t, err)
   225  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "main_test.go"), []byte(`package main_test
   226  func Bar() string {
   227  	return "bar"
   228  }
   229  `), 0644)
   230  				require.NoError(t, err)
   231  			},
   232  			validate: func(runErr error, caseNum int, projectDir string) {
   233  				assert.NoError(t, runErr, "Case %d", caseNum)
   234  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
   235  				require.NoError(t, err, "Case %d", caseNum)
   236  				assert.Equal(t, "[]", string(bytes))
   237  			},
   238  		},
   239  		{
   240  			// "run" works with multiple main package files with tests
   241  			spec: func(projectDir string) params.ProductBuildSpec {
   242  				return params.NewProductBuildSpec(
   243  					projectDir,
   244  					"foo",
   245  					git.ProjectInfo{},
   246  					params.Product{
   247  						Build: params.Build{
   248  							MainPkg: "./foo",
   249  						},
   250  					},
   251  					params.Project{},
   252  				)
   253  			},
   254  			preRunAction: func(projectDir string) {
   255  				err := os.MkdirAll(path.Join(projectDir, "foo"), 0755)
   256  				require.NoError(t, err)
   257  
   258  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "main_file.go"), []byte(strings.Replace(runTestMain, "{{OUTPUT_PATH}}", projectDir, -1)), 0644)
   259  				require.NoError(t, err)
   260  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "main_test.go"), []byte(`package main
   261  import "testing"
   262  func TestBar(t *testing.T) {
   263  }
   264  `), 0644)
   265  				require.NoError(t, err)
   266  			},
   267  			validate: func(runErr error, caseNum int, projectDir string) {
   268  				assert.NoError(t, runErr, "Case %d", caseNum)
   269  				bytes, err := ioutil.ReadFile(path.Join(projectDir, "runTestMainOutput.txt"))
   270  				require.NoError(t, err, "Case %d", caseNum)
   271  				assert.Equal(t, "[]", string(bytes))
   272  			},
   273  		},
   274  		{
   275  			// "run" fails if a main package does not exist
   276  			spec: func(projectDir string) params.ProductBuildSpec {
   277  				return params.NewProductBuildSpec(
   278  					projectDir,
   279  					"foo",
   280  					git.ProjectInfo{},
   281  					params.Product{
   282  						Build: params.Build{
   283  							MainPkg: "./foo",
   284  						},
   285  					},
   286  					params.Project{},
   287  				)
   288  			},
   289  			preRunAction: func(projectDir string) {
   290  				err := os.MkdirAll(path.Join(projectDir, "foo"), 0755)
   291  				require.NoError(t, err)
   292  
   293  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "not_main_pkg.go"), []byte(`package foo
   294  func main() {
   295  }
   296  `), 0644)
   297  				require.NoError(t, err)
   298  			},
   299  			validate: func(runErr error, caseNum int, projectDir string) {
   300  				assert.Error(t, runErr, fmt.Sprintf("Case %d", caseNum))
   301  				assert.Regexp(t, regexp.MustCompile(`^failed to find main file: no go file with main package and main function exists in directory .+/foo$`), runErr.Error(), "Case %d", caseNum)
   302  			},
   303  		},
   304  		{
   305  			// "run" fails if main function does not exist in a main pkg
   306  			spec: func(projectDir string) params.ProductBuildSpec {
   307  				return params.NewProductBuildSpec(
   308  					projectDir,
   309  					"foo",
   310  					git.ProjectInfo{},
   311  					params.Product{
   312  						Build: params.Build{
   313  							MainPkg: "./foo",
   314  						},
   315  					},
   316  					params.Project{},
   317  				)
   318  			},
   319  			preRunAction: func(projectDir string) {
   320  				err := os.MkdirAll(path.Join(projectDir, "foo"), 0755)
   321  				require.NoError(t, err)
   322  
   323  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "no_main_func.go"), []byte(`package main
   324  func Foo() string {
   325  	return "foo"
   326  }
   327  `), 0644)
   328  				require.NoError(t, err)
   329  
   330  				err = ioutil.WriteFile(path.Join(projectDir, "foo", "main_func_not_main_pkg.go"), []byte(`package main_test
   331  func main() {
   332  }
   333  `), 0644)
   334  				require.NoError(t, err)
   335  			},
   336  			validate: func(runErr error, caseNum int, projectDir string) {
   337  				assert.Error(t, runErr, fmt.Sprintf("Case %d", caseNum))
   338  				assert.Regexp(t, regexp.MustCompile(`^failed to find main file: no go file with main package and main function exists in directory .+/foo$`), runErr.Error(), "Case %d", caseNum)
   339  			},
   340  		},
   341  	} {
   342  		currTmpDir, err := ioutil.TempDir(tmp, "")
   343  		require.NoError(t, err, "Case %d", i)
   344  
   345  		if currCase.preRunAction != nil {
   346  			currCase.preRunAction(currTmpDir)
   347  		}
   348  
   349  		err = run.DoRun(currCase.spec(currTmpDir), currCase.runArgs, ioutil.Discard, ioutil.Discard)
   350  		if currCase.validate != nil {
   351  			currCase.validate(err, i, currTmpDir)
   352  		}
   353  	}
   354  }