Files
avo/tests/thirdparty/packages_test.go

176 lines
3.8 KiB
Go
Raw Normal View History

package thirdparty
import (
"flag"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"
"github.com/mmcloughlin/avo/internal/test"
)
// Custom flags.
var (
pkgsfilename = flag.String("pkgs", "", "packages configuration")
preserve = flag.Bool("preserve", false, "preserve working directories")
latest = flag.Bool("latest", false, "use latest versions of each package")
)
// TestPackages runs integration tests on all packages specified by packages
// file given on the command line.
func TestPackages(t *testing.T) {
// Load packages.
if *pkgsfilename == "" {
t.Skip("no packages specified")
}
pkgs, err := LoadPackagesFile(*pkgsfilename)
if err != nil {
t.Fatal(err)
}
for _, pkg := range pkgs {
pkg := pkg // scopelint
t.Run(pkg.Name(), func(t *testing.T) {
dir, clean := test.TempDir(t)
if !*preserve {
defer clean()
} else {
t.Logf("working directory: %s", dir)
}
pt := PackageTest{
T: t,
Package: pkg,
WorkDir: dir,
Latest: *latest,
}
pt.Run()
})
}
}
// PackageTest executes an integration test based on a given third-party package.
type PackageTest struct {
*testing.T
Package
WorkDir string // working directory for the test
Latest bool // use latest version of the package
repopath string // path the repo is cloned to
cwd string // working directory to execute commands in
}
// Run the test.
func (t *PackageTest) Run() {
t.checkout()
t.modinit()
t.replaceavo()
t.diff()
t.generate()
t.diff()
t.test()
}
// checkout the code at the specified version.
func (t *PackageTest) checkout() {
// Clone repo.
dst := filepath.Join(t.WorkDir, t.Name())
t.git("clone", "--quiet", t.CloneURL(), dst)
t.repopath = dst
t.cd(t.repopath)
// Checkout specific version.
if t.Latest {
t.Log("using latest version")
return
}
t.git("-C", t.repopath, "checkout", "--quiet", t.Version)
}
// modinit initializes the repo as a go module if it isn't one already.
func (t *PackageTest) modinit() {
// Check if module path already exists.
gomod := filepath.Join(t.repopath, "go.mod")
if _, err := os.Stat(gomod); err == nil {
t.Logf("already a module")
return
}
// Initialize the module.
t.gotool("mod", "init", t.ImportPath)
}
// replaceavo points all avo dependencies to the local version.
func (t *PackageTest) replaceavo() {
// Determine the path to avo.
_, self, _, ok := runtime.Caller(1)
if !ok {
t.Fatal("failed to determine path to avo")
}
avodir := filepath.Join(filepath.Dir(self), "..", "..")
// Edit all go.mod files in the repo.
err := filepath.Walk(t.repopath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
dir, base := filepath.Split(path)
if base != "go.mod" {
return nil
}
t.cd(dir)
t.gotool("mod", "tidy")
t.gotool("get", "github.com/mmcloughlin/avo")
t.gotool("mod", "edit", "-replace=github.com/mmcloughlin/avo="+avodir)
t.gotool("mod", "download")
return nil
})
if err != nil {
t.Fatal(err)
}
t.cd(t.repopath)
}
// generate runs generate commands.
func (t *PackageTest) generate() {
if len(t.Generate) == 0 {
t.Fatal("no commands specified")
}
for _, args := range t.Generate {
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = filepath.Join(t.repopath, t.Dir)
test.ExecCommand(t.T, cmd)
}
}
// diff runs git diff on the repository.
func (t *PackageTest) diff() {
t.git("-C", t.repopath, "diff")
}
// test runs go test.
func (t *PackageTest) test() {
t.gotool("test", t.TestPath())
}
// git runs a git command.
func (t *PackageTest) git(arg ...string) {
test.Exec(t.T, "git", arg...)
}
// gotool runs a go command.
func (t *PackageTest) gotool(arg ...string) {
cmd := exec.Command(test.GoTool(), arg...)
cmd.Dir = t.cwd
test.ExecCommand(t.T, cmd)
}
// cd sets the working directory.
func (t *PackageTest) cd(dir string) {
t.cwd = dir
}