github.com/jacobsoderblom/buffalo@v0.11.0/buffalo/cmd/test.go (about)

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"github.com/gobuffalo/buffalo/meta"
    14  	"github.com/gobuffalo/envy"
    15  	"github.com/pkg/errors"
    16  	"github.com/sirupsen/logrus"
    17  
    18  	"github.com/gobuffalo/pop"
    19  	"github.com/spf13/cobra"
    20  )
    21  
    22  const vendorPattern = "/vendor/"
    23  
    24  var vendorRegex = regexp.MustCompile(vendorPattern)
    25  
    26  func init() {
    27  	decorate("test", testCmd)
    28  	RootCmd.AddCommand(testCmd)
    29  }
    30  
    31  var testCmd = &cobra.Command{
    32  	Use:                "test",
    33  	Short:              "Runs the tests for your Buffalo app",
    34  	DisableFlagParsing: true,
    35  	RunE: func(c *cobra.Command, args []string) error {
    36  		os.Setenv("GO_ENV", "test")
    37  		if _, err := os.Stat("database.yml"); err == nil {
    38  			// there's a database
    39  			test, err := pop.Connect("test")
    40  			if err != nil {
    41  				return errors.WithStack(err)
    42  			}
    43  
    44  			// drop the test db:
    45  			test.Dialect.DropDB()
    46  
    47  			// create the test db:
    48  			err = test.Dialect.CreateDB()
    49  			if err != nil {
    50  				return errors.WithStack(err)
    51  			}
    52  
    53  			if schema := findSchema(); schema != nil {
    54  				err = test.Dialect.LoadSchema(schema)
    55  				if err != nil {
    56  					return errors.WithStack(err)
    57  				}
    58  			}
    59  		}
    60  		return testRunner(args)
    61  	},
    62  }
    63  
    64  func findSchema() io.Reader {
    65  	if f, err := os.Open(filepath.Join("migrations", "schema.sql")); err == nil {
    66  		return f
    67  	}
    68  	if dev, err := pop.Connect("development"); err == nil {
    69  		schema := &bytes.Buffer{}
    70  		if err = dev.Dialect.DumpSchema(schema); err == nil {
    71  			return schema
    72  		}
    73  	}
    74  
    75  	if test, err := pop.Connect("test"); err == nil {
    76  		if err := test.MigrateUp("./migrations"); err == nil {
    77  			if f, err := os.Open(filepath.Join("migrations", "schema.sql")); err == nil {
    78  				return f
    79  			}
    80  		}
    81  	}
    82  	return nil
    83  }
    84  
    85  func testRunner(args []string) error {
    86  	var mFlag bool
    87  	cargs := []string{}
    88  	pargs := []string{}
    89  	var larg string
    90  	for i, a := range args {
    91  		switch a {
    92  		case "-run":
    93  			cargs = append(cargs, "-run", args[i+1])
    94  		case "-m":
    95  			mFlag = true
    96  			cargs = append(cargs, "-testify.m", args[i+1])
    97  		case "-v":
    98  			cargs = append(cargs, "-v")
    99  		default:
   100  			if larg != "-run" && larg != "-m" {
   101  				pargs = append(pargs, a)
   102  			}
   103  		}
   104  		larg = a
   105  	}
   106  
   107  	cmd := newTestCmd(cargs)
   108  	if mFlag {
   109  		return mFlagRunner(cargs, pargs)
   110  	}
   111  
   112  	pkgs, err := testPackages(pargs)
   113  	if err != nil {
   114  		return errors.WithStack(err)
   115  	}
   116  	cmd.Args = append(cmd.Args, pkgs...)
   117  	logrus.Info(strings.Join(cmd.Args, " "))
   118  	return cmd.Run()
   119  }
   120  
   121  func mFlagRunner(args []string, pargs []string) error {
   122  	app := meta.New(".")
   123  	pwd, _ := os.Getwd()
   124  	defer os.Chdir(pwd)
   125  
   126  	pkgs, err := testPackages(pargs)
   127  	if err != nil {
   128  		return errors.WithStack(err)
   129  	}
   130  	var errs bool
   131  	for _, p := range pkgs {
   132  		os.Chdir(pwd)
   133  		if p == app.PackagePkg {
   134  			continue
   135  		}
   136  		cmd := newTestCmd(args)
   137  		p = strings.TrimPrefix(p, app.PackagePkg+string(filepath.Separator))
   138  		logrus.Info(strings.Join(cmd.Args, " "))
   139  		os.Chdir(p)
   140  		if err := cmd.Run(); err != nil {
   141  			errs = true
   142  		}
   143  	}
   144  	if errs {
   145  		return errors.New("errors running tests")
   146  	}
   147  	return nil
   148  }
   149  
   150  func testPackages(givenArgs []string) ([]string, error) {
   151  	// If there are args, then assume these are the packages to test.
   152  	//
   153  	// Instead of always returning all packages from 'go list ./...', just
   154  	// return the given packages in this case
   155  	if len(givenArgs) > 0 {
   156  		return givenArgs, nil
   157  	}
   158  	args := []string{}
   159  	out, err := exec.Command(envy.Get("GO_BIN", "go"), "list", "./...").Output()
   160  	if err != nil {
   161  		return args, err
   162  	}
   163  	pkgs := bytes.Split(bytes.TrimSpace(out), []byte("\n"))
   164  	for _, p := range pkgs {
   165  		if !vendorRegex.Match(p) {
   166  			args = append(args, string(p))
   167  		}
   168  	}
   169  	return args, nil
   170  }
   171  
   172  func newTestCmd(args []string) *exec.Cmd {
   173  	cargs := []string{"test", "-p", "1"}
   174  	if b, err := ioutil.ReadFile("database.yml"); err == nil {
   175  		if bytes.Contains(b, []byte("sqlite")) {
   176  			cargs = append(cargs, "-tags", "sqlite")
   177  		}
   178  	}
   179  	cargs = append(cargs, args...)
   180  	cmd := exec.Command(envy.Get("GO_BIN", "go"), cargs...)
   181  	cmd.Stdin = os.Stdin
   182  	cmd.Stdout = os.Stdout
   183  	cmd.Stderr = os.Stderr
   184  	return cmd
   185  }