github.com/jdhenke/godel@v0.0.0-20161213181855-abeb3861bf0d/apps/gunit/integration_test/integration_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 integration_test
    16  
    17  import (
    18  	"io/ioutil"
    19  	"os"
    20  	"os/exec"
    21  	"path"
    22  	"regexp"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/nmiyake/pkg/dirs"
    27  	"github.com/nmiyake/pkg/gofiles"
    28  	"github.com/palantir/pkg/pkgpath"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"github.com/palantir/godel/pkg/products"
    33  )
    34  
    35  func TestRun(t *testing.T) {
    36  	cli, err := products.Bin("gunit")
    37  	require.NoError(t, err)
    38  
    39  	wd, err := os.Getwd()
    40  	require.NoError(t, err)
    41  
    42  	tmpDir, cleanup, err := dirs.TempDir(wd, "")
    43  	defer cleanup()
    44  	require.NoError(t, err)
    45  
    46  	originalWd, err := os.Getwd()
    47  	require.NoError(t, err)
    48  	defer func() {
    49  		if err := os.Chdir(originalWd); err != nil {
    50  			require.NoError(t, err)
    51  		}
    52  	}()
    53  
    54  	for i, currCase := range []struct {
    55  		name          string
    56  		filesToCreate []gofiles.GoFileSpec
    57  		config        string
    58  		args          []string
    59  		wantMatch     func(currCaseTmpDir string) string
    60  		wantError     string
    61  	}{
    62  		{
    63  			name: "passing tests",
    64  			filesToCreate: []gofiles.GoFileSpec{
    65  				{
    66  					RelPath: "foo.go",
    67  					Src: `package foo
    68  					import "fmt"
    69  					func Foo() {
    70  						fmt.Println("Foo")
    71  					}`,
    72  				},
    73  				{
    74  					RelPath: "foo_test.go",
    75  					Src: `package foo
    76  					import "testing"
    77  					func TestFoo(t *testing.T) {
    78  						Foo()
    79  					}`,
    80  				},
    81  				{
    82  					RelPath: "vendor/bar/bar.go",
    83  					Src: `package bar
    84  					import "fmt"
    85  					func Bar() {
    86  						fmt.Println("Bar")
    87  					}`,
    88  				},
    89  			},
    90  			config: unindent(`exclude:
    91  					  paths:
    92  					    - "vendor"
    93  					`),
    94  			wantMatch: func(currCaseTmpDir string) string {
    95  				return "ok  \t" + pkgName(t, currCaseTmpDir) + "\t[0-9.]+s"
    96  			},
    97  		},
    98  		{
    99  			name: "failing tests",
   100  			filesToCreate: []gofiles.GoFileSpec{
   101  				{
   102  					RelPath: "foo.go",
   103  					Src: `package foo
   104  					import "fmt"
   105  					func Foo() {
   106  						fmt.Println("Foo")
   107  					}`,
   108  				},
   109  				{
   110  					RelPath: "foo_test.go",
   111  					Src: `package foo
   112  					import "testing"
   113  					func TestFoo(t *testing.T) {
   114  						Foo()
   115  						t.Errorf("myFail")
   116  					}`,
   117  				},
   118  			},
   119  			wantMatch: func(currCaseTmpDir string) string {
   120  				return `(?s)Foo\n--- FAIL: TestFoo (.+)\n.+foo_test.go:[0-9]+: myFail.+FAIL\t` + pkgName(t, currCaseTmpDir) + "\t[0-9.]+s"
   121  			},
   122  			wantError: "(?s).+1 package had failing tests:.+",
   123  		},
   124  		{
   125  			name: "fails if there are no packages to test (no buildable Go files)",
   126  			wantMatch: func(currCaseTmpDir string) string {
   127  				return "^no packages to test\n$"
   128  			},
   129  			wantError: "^no packages to test\n$",
   130  		},
   131  		{
   132  			name: "test that does not compile fails",
   133  			filesToCreate: []gofiles.GoFileSpec{
   134  				{
   135  					RelPath: "foo.go",
   136  					Src: `package foo
   137  					import "fmt"
   138  					func Foo() {
   139  						fmt.Println("Foo")
   140  					}`,
   141  				},
   142  				{
   143  					RelPath: "foo_test.go",
   144  					Src: `package foo
   145  					import "testing"
   146  					import "github.com/palantir/godel/apps/gunit/blah/foo"
   147  					func TestFoo(t *testing.T) {
   148  						foo.Foo()
   149  						t.Errorf("myFail")
   150  					}`,
   151  				},
   152  			},
   153  			wantMatch: func(currCaseTmpDir string) string {
   154  				return `(?s)foo_test.go:[0-9]+:[0-9]+: cannot find package.+\nFAIL\t` + pkgName(t, currCaseTmpDir) + `\t\[setup failed\]`
   155  			},
   156  			wantError: "(?s).+1 package had failing tests:.+",
   157  		},
   158  		{
   159  			name: "running with a tag runs only tagged tests",
   160  			filesToCreate: []gofiles.GoFileSpec{
   161  				{
   162  					RelPath: "foo_test.go",
   163  					Src: `package foo
   164  					import "testing"
   165  					func TestFoo(t *testing.T) {
   166  						t.Errorf("fooFail")
   167  					}`,
   168  				},
   169  				{
   170  					RelPath: "integration/bar_test.go",
   171  					Src: `package bar
   172  					import "testing"
   173  					func TestBar(t *testing.T) {
   174  						t.Errorf("barFail")
   175  					}`,
   176  				},
   177  			},
   178  			config: unindent(`tags:
   179  					  integration:
   180  					    names:
   181  					      - "integration"
   182  					exclude:
   183  					  paths:
   184  					    - "vendor"
   185  					`),
   186  			args: []string{
   187  				"--tags", "integration",
   188  			},
   189  			wantMatch: func(currCaseTmpDir string) string {
   190  				return `(?s)--- FAIL: TestBar (.+)\n.+bar_test.go:[0-9]+: barFail.+FAIL\t` + pkgName(t, currCaseTmpDir) + "/integration\t[0-9.]+s"
   191  			},
   192  			wantError: "(?s).+1 package had failing tests:.+",
   193  		},
   194  		{
   195  			name: "fails if tags do not match any packages",
   196  			filesToCreate: []gofiles.GoFileSpec{
   197  				{
   198  					RelPath: "foo_test.go",
   199  					Src: `package foo
   200  					import "testing"
   201  					func TestFoo(t *testing.T) {
   202  						t.Errorf("fooFail")
   203  					}`,
   204  				},
   205  			},
   206  			config: unindent(`tags:
   207  					  integration:
   208  					    names:
   209  					      - "integration"
   210  					`),
   211  			args: []string{
   212  				"--tags", "integration",
   213  			},
   214  			wantMatch: func(currCaseTmpDir string) string {
   215  				return "^no packages to test\n$"
   216  			},
   217  			wantError: "^no packages to test\n$",
   218  		},
   219  		{
   220  			name: "union of tags is run when multiple tags are specified",
   221  			filesToCreate: []gofiles.GoFileSpec{
   222  				{
   223  					RelPath: "foo_test.go",
   224  					Src: `package foo
   225  					import "testing"
   226  					func TestFoo(t *testing.T) {
   227  						t.Errorf("fooFail")
   228  					}`,
   229  				},
   230  				{
   231  					RelPath: "bar/bar_test.go",
   232  					Src: `package bar
   233  					import "testing"
   234  					func TestBar(t *testing.T) {
   235  						t.Errorf("barFail")
   236  					}`,
   237  				},
   238  				{
   239  					RelPath: "baz/baz_test.go",
   240  					Src: `package baz
   241  					import "testing"
   242  					func TestBaz(t *testing.T) {
   243  						t.Errorf("bazFail")
   244  					}`,
   245  				},
   246  			},
   247  			config: unindent(`tags:
   248  					  bar:
   249  					    paths:
   250  					      - "bar"
   251  					  baz:
   252  					    paths:
   253  					      - "baz"
   254  					exclude:
   255  					  paths:
   256  					    - "vendor"
   257  					`),
   258  			args: []string{
   259  				"--tags", "bar,baz",
   260  			},
   261  			wantMatch: func(currCaseTmpDir string) string {
   262  				return `(?s)--- FAIL: TestBar (.+)\n.+bar_test.go:[0-9]+: barFail.+FAIL\t` + pkgName(t, currCaseTmpDir) + `/bar\t[0-9.]+s.+` +
   263  					`--- FAIL: TestBaz (.+)\n.+baz_test.go:[0-9]+: bazFail.+FAIL\t` + pkgName(t, currCaseTmpDir) + `/baz\t[0-9.]+s.+`
   264  			},
   265  			wantError: "(?s).+2 packages had failing tests:.+",
   266  		},
   267  		{
   268  			name: "only non-tagged tests are run if multiple tags are specified and tests are run without arguments",
   269  			filesToCreate: []gofiles.GoFileSpec{
   270  				{
   271  					RelPath: "foo_test.go",
   272  					Src: `package foo
   273  					import "testing"
   274  					func TestFoo(t *testing.T) {
   275  						t.Errorf("fooFail")
   276  					}`,
   277  				},
   278  				{
   279  					RelPath: "bar/bar_test.go",
   280  					Src: `package bar
   281  					import "testing"
   282  					func TestBar(t *testing.T) {
   283  						t.Errorf("barFail")
   284  					}`,
   285  				},
   286  				{
   287  					RelPath: "baz/baz_test.go",
   288  					Src: `package baz
   289  					import "testing"
   290  					func TestBaz(t *testing.T) {
   291  						t.Errorf("bazFail")
   292  					}`,
   293  				},
   294  			},
   295  			config: unindent(`tags:
   296  					  bar:
   297  					    paths:
   298  					      - "bar"
   299  					  baz:
   300  					    paths:
   301  					      - "baz"
   302  					exclude:
   303  					  paths:
   304  					    - "vendor"
   305  					`),
   306  			wantMatch: func(currCaseTmpDir string) string {
   307  				return `(?s)--- FAIL: TestFoo (.+)\n.+foo_test.go:[0-9]+: fooFail.+FAIL\t` + pkgName(t, currCaseTmpDir) + `\t[0-9.]+s.+`
   308  			},
   309  			wantError: "(?s).+1 package had failing tests:.+",
   310  		},
   311  		{
   312  			name: "fails if invalid tag is supplied",
   313  			filesToCreate: []gofiles.GoFileSpec{
   314  				{
   315  					RelPath: "foo_test.go",
   316  					Src: `package foo
   317  					import "testing"
   318  					func TestFoo(t *testing.T) {
   319  						t.Errorf("fooFail")
   320  					}`,
   321  				},
   322  			},
   323  			config: unindent(`exclude:
   324  					  paths:
   325  					    - "vendor"
   326  					`),
   327  			args: []string{
   328  				"--tags", "invalid,n!otvalid",
   329  			},
   330  			wantMatch: func(currCaseTmpDir string) string {
   331  				return `invalid tags: "invalid", "n!otvalid"`
   332  			},
   333  			wantError: `invalid tags: "invalid", "n!otvalid"`,
   334  		},
   335  	} {
   336  		currCaseTmpDir, err := ioutil.TempDir(tmpDir, "")
   337  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   338  
   339  		_, err = gofiles.Write(currCaseTmpDir, currCase.filesToCreate)
   340  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   341  
   342  		configFile := path.Join(currCaseTmpDir, "config.yml")
   343  		err = ioutil.WriteFile(configFile, []byte(currCase.config), 0644)
   344  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   345  
   346  		err = os.Chdir(currCaseTmpDir)
   347  		require.NoError(t, err)
   348  
   349  		args := []string{"--config", configFile}
   350  		args = append(args, currCase.args...)
   351  		args = append(args, "test")
   352  
   353  		cmd := exec.Command(cli, args...)
   354  		outputBytes, err := cmd.CombinedOutput()
   355  		output := string(outputBytes)
   356  
   357  		if err != nil {
   358  			if currCase.wantError == "" {
   359  				t.Fatalf("Case %d: %s\nunexpected error:\n%v\nOutput: %v", i, currCase.name, err, output)
   360  			} else if !regexp.MustCompile(currCase.wantError).MatchString(output) {
   361  				t.Fatalf("Case %d: %s\nexpected error output to contain %v, but was %v", i, currCase.name, currCase.wantError, output)
   362  			}
   363  		} else if currCase.wantError != "" {
   364  			t.Fatalf("Case %d: %s\nexpected error %v, but was none.\nOutput: %v", i, currCase.name, currCase.wantError, output)
   365  		}
   366  
   367  		expectedExpr := currCase.wantMatch(currCaseTmpDir)
   368  		if !regexp.MustCompile(expectedExpr).MatchString(output) {
   369  			t.Errorf("Case %d: %s\nOutput did not match expected expression.\nExpected:\n%v\nActual:\n%v", i, currCase.name, expectedExpr, output)
   370  		}
   371  	}
   372  }
   373  
   374  func TestClean(t *testing.T) {
   375  	cli, err := products.Bin("gunit")
   376  	require.NoError(t, err)
   377  
   378  	wd, err := os.Getwd()
   379  	require.NoError(t, err)
   380  
   381  	tmpDir, cleanup, err := dirs.TempDir(wd, "")
   382  	defer cleanup()
   383  	require.NoError(t, err)
   384  
   385  	files, err := gofiles.Write(tmpDir, []gofiles.GoFileSpec{
   386  		{
   387  			RelPath: "tmp_placeholder_test.go",
   388  			Src:     "package main",
   389  		},
   390  	})
   391  	require.NoError(t, err)
   392  
   393  	originalWd, err := os.Getwd()
   394  	require.NoError(t, err)
   395  	defer func() {
   396  		if err := os.Chdir(originalWd); err != nil {
   397  			require.NoError(t, err)
   398  		}
   399  	}()
   400  
   401  	err = os.Chdir(tmpDir)
   402  	require.NoError(t, err)
   403  
   404  	cmd := exec.Command(cli, "clean")
   405  	output, err := cmd.CombinedOutput()
   406  	require.NoError(t, err, "Command %v failed with output:\n%s", cmd.Args, string(output))
   407  
   408  	_, err = os.Stat(files["tmp_placeholder_test.go"].Path)
   409  	assert.True(t, os.IsNotExist(err))
   410  }
   411  
   412  func unindent(input string) string {
   413  	return strings.Replace(input, "\n\t\t\t\t\t", "\n", -1)
   414  }
   415  
   416  func pkgName(t *testing.T, path string) string {
   417  	pkgPath, err := pkgpath.NewAbsPkgPath(path).GoPathSrcRel()
   418  	require.NoError(t, err)
   419  	return pkgPath
   420  }