202 lines
3.7 KiB
Go
202 lines
3.7 KiB
Go
|
// Copyright Earl Warren <contact@earl-warren.org>
|
||
|
// Copyright Loïc Dachary <loic@dachary.org>
|
||
|
// Copyright twenty-panda <twenty-panda@posteo.com>
|
||
|
// SPDX-License-Identifier: MIT
|
||
|
|
||
|
package hoverfly
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
type M interface {
|
||
|
Run() (code int)
|
||
|
}
|
||
|
|
||
|
type Hoverfly interface {
|
||
|
Run(m M)
|
||
|
|
||
|
GetOutput() io.Writer
|
||
|
SetOutput(io.Writer)
|
||
|
|
||
|
GetURL() string
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
modeCapture = "capture"
|
||
|
modeSimulate = "simulate"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
exit = os.Exit
|
||
|
getwd = os.Getwd
|
||
|
)
|
||
|
|
||
|
func Run(t testing.TB, name string) func() {
|
||
|
t.Helper()
|
||
|
|
||
|
if !hoverflySingleton.active {
|
||
|
return func() {}
|
||
|
}
|
||
|
|
||
|
httpProxyRestore := func() {}
|
||
|
if val, ok := os.LookupEnv("http_proxy"); ok {
|
||
|
httpProxyRestore = func() {
|
||
|
os.Setenv("http_proxy", val)
|
||
|
}
|
||
|
}
|
||
|
os.Setenv("http_proxy", hoverflySingleton.GetURL())
|
||
|
|
||
|
if *hoverflySingleton.mode == modeSimulate {
|
||
|
require.NoError(t, hoverflySingleton.loadSimulation(name))
|
||
|
require.NoError(t, hoverflySingleton.hoverctl("mode", "simulate", "--matching-strategy", "first"))
|
||
|
return func() { httpProxyRestore() }
|
||
|
}
|
||
|
|
||
|
if *hoverflySingleton.mode == modeCapture {
|
||
|
require.NoError(t, hoverflySingleton.hoverctl("mode", "capture", "--stateful"))
|
||
|
|
||
|
return func() {
|
||
|
httpProxyRestore()
|
||
|
require.NoError(t, hoverflySingleton.saveSimulation(name))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
panic(fmt.Errorf("unknown mode %s", *hoverflySingleton.mode))
|
||
|
}
|
||
|
|
||
|
func MainTest(m *testing.M) {
|
||
|
hoverflySingleton.Run(m)
|
||
|
}
|
||
|
|
||
|
type hoverfly struct {
|
||
|
home string
|
||
|
httpProxy *string
|
||
|
output io.Writer
|
||
|
mode *string
|
||
|
active bool
|
||
|
}
|
||
|
|
||
|
var hoverflySingleton = &hoverfly{}
|
||
|
|
||
|
func GetSingleton() Hoverfly {
|
||
|
return hoverflySingleton
|
||
|
}
|
||
|
|
||
|
func newHoverfly() Hoverfly {
|
||
|
return &hoverfly{}
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) hoverctl(args ...string) error {
|
||
|
hoverctl := "hoverctl"
|
||
|
cmd := exec.Command(hoverctl, args...)
|
||
|
cmd.Env = append(
|
||
|
cmd.Env,
|
||
|
"HOME="+o.home,
|
||
|
)
|
||
|
if output := o.GetOutput(); output != nil {
|
||
|
cmd.Stdout = output
|
||
|
cmd.Stderr = output
|
||
|
fmt.Fprintf(output, "%v: %s %v\n", cmd.Env, hoverctl, args)
|
||
|
}
|
||
|
if err := cmd.Run(); err != nil {
|
||
|
return fmt.Errorf(hoverctl+"start: %w\n", err)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) getSimulationDir() (string, error) {
|
||
|
pwd, err := getwd()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
p := path.Join(pwd, "hoverfly")
|
||
|
if err := os.MkdirAll(p, 0o755); err != nil {
|
||
|
return p, err
|
||
|
}
|
||
|
return p, nil
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) getSimulationPath(name string) (string, error) {
|
||
|
dir, err := o.getSimulationDir()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return path.Join(dir, name+".json"), nil
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) loadSimulation(name string) error {
|
||
|
simulation, err := o.getSimulationPath(name)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return o.hoverctl("import", simulation)
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) saveSimulation(name string) error {
|
||
|
simulation, err := o.getSimulationPath(name)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return o.hoverctl("export", simulation)
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) setup() error {
|
||
|
if val, ok := os.LookupEnv("HOVERFLY"); ok {
|
||
|
o.active = true
|
||
|
o.mode = &val
|
||
|
} else {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
home, err := os.MkdirTemp(os.TempDir(), "hoverfly")
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("TempDir: %w", err)
|
||
|
}
|
||
|
o.home = home
|
||
|
return o.hoverctl("start")
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) teardown() error {
|
||
|
if !o.active {
|
||
|
return nil
|
||
|
}
|
||
|
if err := o.hoverctl("logs"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := o.hoverctl("stop"); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if o.home != "" {
|
||
|
return os.RemoveAll(o.home)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) SetOutput(output io.Writer) {
|
||
|
o.output = output
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) GetOutput() io.Writer {
|
||
|
return o.output
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) GetURL() string {
|
||
|
return "http://localhost:8500"
|
||
|
}
|
||
|
|
||
|
func (o *hoverfly) Run(m M) {
|
||
|
_ = o.setup()
|
||
|
exitCode := m.Run()
|
||
|
_ = o.teardown()
|
||
|
exit(exitCode)
|
||
|
}
|