mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-11-01 04:24:19 +00:00
*: Add integration tests for examples
This commit is contained in:
parent
e7c0290063
commit
415069be30
140
0-examples/integration_test.go
Normal file
140
0-examples/integration_test.go
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
package examples_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/diamondburned/arikawa/v3/internal/testenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExamples(t *testing.T) {
|
||||||
|
// Assert that the tests only run when the environment variables are set.
|
||||||
|
testenv.Must(t)
|
||||||
|
|
||||||
|
// Assert that the Go compiler is available.
|
||||||
|
_, err := exec.LookPath("go")
|
||||||
|
if err != nil {
|
||||||
|
t.Skip("skipping test; go compiler not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
examplePackages, err := os.ReadDir(".")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run all examples for 10 seconds each.
|
||||||
|
//
|
||||||
|
// TODO(diamondburned): find a way to detect that the bot is online. Maybe
|
||||||
|
// force all examples to print the current username?
|
||||||
|
const exampleRunDuration = 10 * time.Second
|
||||||
|
|
||||||
|
buildDir, err := os.MkdirTemp("", "arikawa-examples")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := os.RemoveAll(buildDir); err != nil {
|
||||||
|
t.Log("cannot remove artifacts dir:", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, pkg := range examplePackages {
|
||||||
|
if !pkg.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert package main.
|
||||||
|
if _, err := os.Stat(pkg.Name() + "/main.go"); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg := pkg
|
||||||
|
t.Run(pkg.Name(), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
binPath := buildDir + "/" + pkg.Name()
|
||||||
|
|
||||||
|
gobuild := exec.Command("go", "build", "-o", binPath, "./"+pkg.Name())
|
||||||
|
gobuild.Stderr = &lineLogger{dst: func(line string) { t.Log("go build:", line) }}
|
||||||
|
if err := gobuild.Run(); err != nil {
|
||||||
|
t.Fatal("cannot go build:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
timer := time.NewTimer(exampleRunDuration)
|
||||||
|
t.Cleanup(func() { timer.Stop() })
|
||||||
|
|
||||||
|
bin := exec.Command(binPath)
|
||||||
|
bin.Stderr = &lineLogger{dst: func(line string) { t.Log(pkg.Name()+":", line) }}
|
||||||
|
if err := bin.Start(); err != nil {
|
||||||
|
t.Fatal("cannot start binary:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdDone := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(cmdDone)
|
||||||
|
|
||||||
|
err := bin.Wait()
|
||||||
|
if err == nil {
|
||||||
|
return // all good
|
||||||
|
}
|
||||||
|
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if !errors.As(err, &exitErr) || !exitErr.Exited() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Error("binary exited with status", exitErr.ExitCode())
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-cmdDone:
|
||||||
|
return
|
||||||
|
case <-timer.C:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Works well. Just exit.
|
||||||
|
if err := bin.Process.Signal(os.Interrupt); err != nil {
|
||||||
|
t.Log("cannot interrupt binary:", err)
|
||||||
|
bin.Process.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
exitTimer := time.NewTimer(5 * time.Second)
|
||||||
|
t.Cleanup(func() { exitTimer.Stop() })
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-cmdDone:
|
||||||
|
return
|
||||||
|
case <-exitTimer.C:
|
||||||
|
t.Error("example did not exit after 5 seconds")
|
||||||
|
bin.Process.Kill()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lineLogger struct {
|
||||||
|
dst func(string)
|
||||||
|
buf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *lineLogger) Write(p []byte) (n int, err error) {
|
||||||
|
n, _ = l.buf.Write(p)
|
||||||
|
for {
|
||||||
|
line, err := l.buf.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
line = line[:len(line)-1] // remove newline
|
||||||
|
l.dst(line)
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
Loading…
Reference in a new issue