committed by
GitHub
parent
49adad921f
commit
205fc6a3d7
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
@@ -73,3 +73,20 @@ jobs:
|
|||||||
run: ./script/bootstrap
|
run: ./script/bootstrap
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: ./script/lint
|
run: ./script/lint
|
||||||
|
|
||||||
|
thirdparty:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.13.x]
|
||||||
|
platform: [ubuntu-latest]
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
- name: Run Third-Party Tests
|
||||||
|
working-directory: ./tests/thirdparty
|
||||||
|
run: go test -v -pkgs packages.json
|
||||||
|
|||||||
@@ -46,8 +46,31 @@ func TempDir(t *testing.T) (string, func()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gobin returns a best guess path to the "go" binary.
|
// ExecCommand executes the command, logging the command and output and failing
|
||||||
func gobin() string {
|
// the test on error.
|
||||||
|
func ExecCommand(t *testing.T, cmd *exec.Cmd) {
|
||||||
|
t.Helper()
|
||||||
|
t.Logf("exec: %s", cmd.Args)
|
||||||
|
if cmd.Dir != "" {
|
||||||
|
t.Logf("dir: %s", cmd.Dir)
|
||||||
|
}
|
||||||
|
b, err := cmd.CombinedOutput()
|
||||||
|
t.Logf("output:\n%s\n", string(b))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the named program with the given arguments, logging the command
|
||||||
|
// and output and failing the test on error.
|
||||||
|
func Exec(t *testing.T, name string, arg ...string) {
|
||||||
|
t.Helper()
|
||||||
|
cmd := exec.Command(name, arg...)
|
||||||
|
ExecCommand(t, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoTool returns a best guess path to the "go" binary.
|
||||||
|
func GoTool() string {
|
||||||
var exeSuffix string
|
var exeSuffix string
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
exeSuffix = ".exe"
|
exeSuffix = ".exe"
|
||||||
@@ -61,14 +84,7 @@ func gobin() string {
|
|||||||
|
|
||||||
// goexec runs a "go" command and checks the output.
|
// goexec runs a "go" command and checks the output.
|
||||||
func goexec(t *testing.T, arg ...string) {
|
func goexec(t *testing.T, arg ...string) {
|
||||||
t.Helper()
|
Exec(t, GoTool(), arg...)
|
||||||
cmd := exec.Command(gobin(), arg...)
|
|
||||||
t.Logf("exec: %s", cmd.Args)
|
|
||||||
b, err := cmd.CombinedOutput()
|
|
||||||
t.Logf("output:\n%s\n", string(b))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logger builds a logger that writes to the test object.
|
// Logger builds a logger that writes to the test object.
|
||||||
|
|||||||
48
tests/thirdparty/config.go
vendored
Normal file
48
tests/thirdparty/config.go
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Package thirdparty executes integration tests based on third-party packages that use avo.
|
||||||
|
package thirdparty
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Package defines an integration test based on a third-party package using avo.
|
||||||
|
type Package struct {
|
||||||
|
ImportPath string `json:"import_path"` // package import path
|
||||||
|
Version string `json:"version"` // git sha, tag or branch
|
||||||
|
Generate [][]string `json:"generate"` // generate commands to run
|
||||||
|
Dir string `json:"dir"` // working directory for generate commands
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the package name.
|
||||||
|
func (p Package) Name() string {
|
||||||
|
return filepath.Base(p.ImportPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneURL returns the git clone URL.
|
||||||
|
func (p Package) CloneURL() string {
|
||||||
|
return "https://" + p.ImportPath + ".git"
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPackages loads a list of package configurations from JSON format.
|
||||||
|
func LoadPackages(r io.Reader) ([]Package, error) {
|
||||||
|
var pkgs []Package
|
||||||
|
d := json.NewDecoder(r)
|
||||||
|
d.DisallowUnknownFields()
|
||||||
|
if err := d.Decode(&pkgs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pkgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPackagesFile loads a list of package configurations from a JSON file.
|
||||||
|
func LoadPackagesFile(filename string) ([]Package, error) {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
return LoadPackages(f)
|
||||||
|
}
|
||||||
51
tests/thirdparty/config_test.go
vendored
Normal file
51
tests/thirdparty/config_test.go
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package thirdparty
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPackageName(t *testing.T) {
|
||||||
|
p := Package{ImportPath: "github.com/username/repo"}
|
||||||
|
if p.Name() != "repo" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPackageCloneURL(t *testing.T) {
|
||||||
|
p := Package{ImportPath: "github.com/username/repo"}
|
||||||
|
if p.CloneURL() != "https://github.com/username/repo.git" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadPackages(t *testing.T) {
|
||||||
|
r := strings.NewReader(`[{"unknown_field": "value"}]`)
|
||||||
|
_, err := LoadPackages(r)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected non-nil error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadPackagesFile(t *testing.T) {
|
||||||
|
pkgs, err := LoadPackagesFile("packages.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
t.Log(pkg.ImportPath)
|
||||||
|
}
|
||||||
|
if len(pkgs) == 0 {
|
||||||
|
t.Fatal("no packages loaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadPackagesFileNotExist(t *testing.T) {
|
||||||
|
pkgs, err := LoadPackagesFile("does_not_exist")
|
||||||
|
if pkgs != nil {
|
||||||
|
t.Fatal("expected nil return")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected non-nil error")
|
||||||
|
}
|
||||||
|
}
|
||||||
134
tests/thirdparty/packages.json
vendored
Normal file
134
tests/thirdparty/packages.json
vendored
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"import_path": "github.com/zeebo/xxh3",
|
||||||
|
"version": "65f423c10688c362d2a2ce6987b665c72ee7bddd",
|
||||||
|
"dir": "avo",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
".",
|
||||||
|
"-avx",
|
||||||
|
"-out",
|
||||||
|
"../vector_avx_amd64.s"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
".",
|
||||||
|
"-sse",
|
||||||
|
"-out",
|
||||||
|
"../vector_sse_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/dgryski/go-sip13",
|
||||||
|
"version": "25c5027a8c7bfa6dab4b577e53e5c9068f6e2152",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"_avo/asm.go",
|
||||||
|
"-out",
|
||||||
|
"sip13_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/orisano/wyhash",
|
||||||
|
"version": "32a3f7f6ba4797e2d87dab2969cc9dd63d39cce9",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"avo/gen.go",
|
||||||
|
"-out",
|
||||||
|
"blocks_amd64.s",
|
||||||
|
"-stubs",
|
||||||
|
"blocks_amd64.go"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/dgryski/go-bloomindex",
|
||||||
|
"version": "0902316dce158c154b958ee5cfc706c62af29a42",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm.go",
|
||||||
|
"-out",
|
||||||
|
"query_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/dgryski/go-marvin32",
|
||||||
|
"version": "7d18f4c6ea7c24b29d1c7a670f8ae40b0812f2e3",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm.go",
|
||||||
|
"-out",
|
||||||
|
"marvin_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/dgryski/go-speck",
|
||||||
|
"version": "5b36d4c08d8840c352a153bf37281434ad550ec0",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm.go",
|
||||||
|
"-out",
|
||||||
|
"speck_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/dgryski/go-chaskey",
|
||||||
|
"version": "ba454392bc5ab6daae103e15147185f8f4a27dcc",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm.go",
|
||||||
|
"-out",
|
||||||
|
"core_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/mkevac/gopherconrussia2019",
|
||||||
|
"version": "235b8b0156a20b4e078b88462e669730f99caeb1",
|
||||||
|
"dir": "simplesimd",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm.go",
|
||||||
|
"-out",
|
||||||
|
"simd.s",
|
||||||
|
"-stubs",
|
||||||
|
"stub.go"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"import_path": "github.com/phoreproject/bls",
|
||||||
|
"version": "9d5f85bf4a9badf491a1b9b27fb3344b489bd2c4",
|
||||||
|
"generate": [
|
||||||
|
[
|
||||||
|
"go",
|
||||||
|
"run",
|
||||||
|
"asm/asm.go",
|
||||||
|
"-out",
|
||||||
|
"primitivefuncs_amd64.s"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
161
tests/thirdparty/packages_test.go
vendored
Normal file
161
tests/thirdparty/packages_test.go
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
if filepath.Base(path) != "go.mod" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t.gotool("mod", "edit", "-replace=github.com/mmcloughlin/avo="+avodir, path)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", "./...")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.repopath
|
||||||
|
test.ExecCommand(t.T, cmd)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user