Plugins integration tests

Signed-off-by: default avatarEmile Vauge <emile@vauge.com>
parent 44827880
......@@ -40,6 +40,9 @@ all: generate-webui build ## validate all checks, build linux binary, run all te
binary: generate-webui build ## build the linux binary
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary
binary-musl: generate-webui build ## build the linux binary
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary-musl
crossbinary: generate-webui build ## cross build the non-linux binaries
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate crossbinary
......@@ -68,7 +71,7 @@ test-unit: build ## run the unit tests
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit
test-integration: build ## run the integration tests
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary test-integration
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary binary-musl test-integration
validate: build ## validate gofmt, golint and go vet
$(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-glide validate-gofmt validate-govet validate-golint validate-misspell validate-vendor
......
......@@ -14,7 +14,6 @@ type FileSuite struct{ BaseSuite }
func (s *FileSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "file")
s.composeProject.Start(c)
}
......
defaultEntryPoints = ["http"]
logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8000"
[web]
address = ":8081"
[[plugins]]
path = "{{.PluginPath}}"
[file]
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:test.localhost"
......@@ -22,22 +22,23 @@ func Test(t *testing.T) {
}
func init() {
check.Suite(&SimpleSuite{})
check.Suite(&AccessLogSuite{})
check.Suite(&HTTPSSuite{})
check.Suite(&FileSuite{})
check.Suite(&HealthCheckSuite{})
check.Suite(&DockerSuite{})
check.Suite(&ConsulSuite{})
check.Suite(&ConsulCatalogSuite{})
check.Suite(&EtcdSuite{})
check.Suite(&MarathonSuite{})
check.Suite(&ConstraintSuite{})
check.Suite(&MesosSuite{})
check.Suite(&EurekaSuite{})
check.Suite(&AcmeSuite{})
check.Suite(&DynamoDBSuite{})
check.Suite(&ErrorPagesSuite{})
//check.Suite(&SimpleSuite{})
//check.Suite(&AccessLogSuite{})
//check.Suite(&HTTPSSuite{})
//check.Suite(&FileSuite{})
//check.Suite(&HealthCheckSuite{})
//check.Suite(&DockerSuite{})
//check.Suite(&ConsulSuite{})
//check.Suite(&ConsulCatalogSuite{})
//check.Suite(&EtcdSuite{})
//check.Suite(&MarathonSuite{})
//check.Suite(&ConstraintSuite{})
//check.Suite(&MesosSuite{})
//check.Suite(&EurekaSuite{})
//check.Suite(&AcmeSuite{})
//check.Suite(&DynamoDBSuite{})
//check.Suite(&ErrorPagesSuite{})
check.Suite(&PluginSuite{})
}
var traefikBinary = "../dist/traefik"
......
package integration
import (
"net/http"
"time"
"bytes"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
"io/ioutil"
"os"
"os/exec"
)
// Plugin test suites
type PluginSuite struct{ BaseSuite }
func (s *PluginSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "plugin")
s.composeProject.Start(c)
}
func (s *PluginSuite) TestMiddleware(c *check.C) {
// check that the plugin has been compiled
plugin := "resources/plugin/middleware/middleware.so"
err := try.FileExists(plugin, 30*time.Second)
c.Assert(err, checker.IsNil)
// check that traefik binary has been compiled
traefikBinary := "../dist/traefik-musl"
err = try.FileExists(traefikBinary, 60*time.Second)
c.Assert(err, checker.IsNil)
// load the plugin
whoamiHost := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/plugin/simple.toml", struct {
PluginPath string
Server1 string
}{plugin, whoamiHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, withConfigFile(file))
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
req.Host = "test.localhost"
resp, err := try.ResponseUntilStatusCode(req, 30*time.Second, http.StatusOK)
c.Assert(err, checker.IsNil)
body, err := ioutil.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
c.Assert(string(body), checker.Contains, "plugin.middleware.reponse.body")
}
func (s *PluginSuite) TestNoLoad(c *check.C) {
// check that the plugin has been compiled
plugin := "resources/plugin/no-load/no-load.so"
err := try.FileExists(plugin, 30*time.Second)
c.Assert(err, checker.IsNil)
// check that traefik binary has been compiled
traefikBinary := "../dist/traefik-musl"
err = try.FileExists(traefikBinary, 60*time.Second)
c.Assert(err, checker.IsNil)
// load the plugin
whoamiHost := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/plugin/simple.toml", struct {
PluginPath string
Server1 string
}{plugin, whoamiHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, withConfigFile(file))
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
c.Assert(out.String(), checker.Contains, "Error loading plugin: error in plugin Lookup: plugin: symbol Load not found in plugin")
}
func (s *PluginSuite) TestBadLoad(c *check.C) {
// check that the plugin has been compiled
plugin := "resources/plugin/bad-load/bad-load.so"
err := try.FileExists(plugin, 30*time.Second)
c.Assert(err, checker.IsNil)
// check that traefik binary has been compiled
traefikBinary := "../dist/traefik-musl"
err = try.FileExists(traefikBinary, 60*time.Second)
c.Assert(err, checker.IsNil)
// load the plugin
whoamiHost := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/plugin/simple.toml", struct {
PluginPath string
Server1 string
}{plugin, whoamiHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, withConfigFile(file))
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
c.Assert(out.String(), checker.Contains, "bad-load.so} does not implement Load() interface{} function")
}
func (s *PluginSuite) TestNoInterface(c *check.C) {
// check that the plugin has been compiled
plugin := "resources/plugin/no-interface/no-interface.so"
err := try.FileExists(plugin, 30*time.Second)
c.Assert(err, checker.IsNil)
// check that traefik binary has been compiled
traefikBinary := "../dist/traefik-musl"
err = try.FileExists(traefikBinary, 60*time.Second)
c.Assert(err, checker.IsNil)
// load the plugin
whoamiHost := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/plugin/simple.toml", struct {
PluginPath string
Server1 string
}{plugin, whoamiHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, withConfigFile(file))
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
c.Assert(out.String(), checker.Contains, "no-interface.so} does not implement any plugin interface")
}
#binary:
# image: golang:1.8
# command: go build -o dist/traefik-plugin ./cmd/traefik
# working_dir: /go/src/github.com/containous/traefik
# volumes:
# - ../../../:/go/src/github.com/containous/traefik
middleware:
image: golang:1.8
command: go build -buildmode=plugin -o /plugin-test/middleware/middleware.so /plugin-test/middleware/middleware.go
volumes:
- ../plugin:/plugin-test
- ../../../:/go/src/github.com/containous/traefik
no-interface:
image: golang:1.8
command: go build -buildmode=plugin -o /plugin-test/no-interface/no-interface.so /plugin-test/no-interface/no-interface.go
volumes:
- ../plugin:/plugin-test
- ../../../:/go/src/github.com/containous/traefik
no-load:
image: golang:1.8
command: go build -buildmode=plugin -o /plugin-test/no-load/no-load.so /plugin-test/no-load/no-load.go
volumes:
- ../plugin:/plugin-test
- ../../../:/go/src/github.com/containous/traefik
bad-load:
image: golang:1.8
command: go build -buildmode=plugin -o /plugin-test/bad-load/bad-load.so /plugin-test/bad-load/bad-load.go
volumes:
- ../plugin:/plugin-test
- ../../../:/go/src/github.com/containous/traefik
whoami:
image: emilevauge/whoami
labels:
traefik.frontend.rule: Host:test.localhost
clean:
image: golang:1.8
command: /plugin-test/clean_plugins.sh /plugin-test/middleware/middleware.so /plugin-test/no-load/no-load.so /plugin-test/no-load/no-panic.so /plugin-test/no-interface/no-interface.so /plugin-test/bad-load/bad-load.so
volumes:
- ../plugin:/plugin-test
- ../../../:/go/src/github.com/containous/traefik
package main
import (
"github.com/containous/traefik/plugin"
"net/http"
)
var _ plugin.Middleware = (*BadLoad)(nil)
// BadLoad is a plugin that should not load
type BadLoad struct {
}
// Load loads the plugin instance
func Load() string {
return "bad load!"
}
// ServeHTTP implements the Middleware interface
func (s *BadLoad) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
}
#!/usr/bin/env sh
trap 'echo "Caught SIGTERM"' TERM
sleep 10000 &
# Waiting for SIGTERM
wait $!
# Remove plugins
for plugin in "$@"
do
echo "Removing plugin ${plugin}"
rm $plugin
done
\ No newline at end of file
package main
import (
"bytes"
"github.com/containous/traefik/plugin"
"io"
"io/ioutil"
"net/http"
)
var _ plugin.Middleware = (*Middleware)(nil)
// Middleware is a working Middleware plugin
type Middleware struct {
}
// Load loads the plugin instance
func Load() interface{} {
return &Middleware{}
}
// ServeHTTP implements the Middleware interface
func (s *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
r.Header.Add("Traefik-Plugin-Middleware", "plugin.middleware.request.header")
w.Header().Add("Traefik-Plugin-Middleware", "plugin.middleware.response.header")
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "can't read body", http.StatusBadRequest)
return
}
body = append(body, []byte("\nplugin.middleware.reponse.body")...)
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
// Create a response wrapper:
mrw := &myResponseWriter{
ResponseWriter: w,
buf: &bytes.Buffer{},
}
next(w, r)
if _, err := io.Copy(w, mrw.buf); err != nil {
return
}
}
type myResponseWriter struct {
http.ResponseWriter
buf *bytes.Buffer
}
func (mrw *myResponseWriter) Write(p []byte) (int, error) {
return mrw.buf.Write(p)
}
package main
// NoInterface is a plugin that does not implement any interface
type NoInterface struct {
}
// Load loads the plugin instance
func Load() interface{} {
return &NoInterface{}
}
package main
import (
"github.com/containous/traefik/plugin"
"net/http"
)
var _ plugin.Middleware = (*NoLoad)(nil)
// NoLoad is a plugin that does not have any Load function
type NoLoad struct {
}
// ServeHTTP implements the Middleware interface
func (s *NoLoad) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
}
......@@ -25,6 +25,16 @@ func Sleep(d time.Duration) {
time.Sleep(d)
}
// FileExists tries if the file exists until timeout
func FileExists(file string, timeout time.Duration) error {
return Do(timeout, func() error {
if _, err := os.Stat(file); os.IsNotExist(err) {
return err
}
return nil
})
}
// Response is like Request, but returns the response for further
// processing at the call site.
// Conditions are not allowed since it would complicate signaling if the
......
......@@ -26,7 +26,7 @@ if [ -z "$DATE" ]; then
fi
# Build binaries
CGO_ENABLED=1 GOGC=off go build $FLAGS -ldflags "-s -w \
CGO_ENABLED=0 GOGC=off go build $FLAGS -ldflags "-s -w \
-X github.com/containous/traefik/version.Version=$VERSION \
-X github.com/containous/traefik/version.Codename=$CODENAME \
-X github.com/containous/traefik/version.BuildDate=$DATE" \
......
#!/usr/bin/env bash
set -e
if ! test -e autogen/gen.go; then
echo >&2 'error: generate must be run before binary'
false
fi
rm -f dist/traefik-musl
FLAGS=""
if [ -n "$VERBOSE" ]; then
FLAGS="${FLAGS} -v"
fi
if [ -z "$VERSION" ]; then
VERSION=$(git rev-parse HEAD)
fi
if [ -z "$CODENAME" ]; then
CODENAME=cheddar
fi
if [ -z "$DATE" ]; then
DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p')
fi
# Build binaries
CGO_ENABLED=1 GOGC=off go build $FLAGS -ldflags "-s -w \
-X github.com/containous/traefik/version.Version=$VERSION \
-X github.com/containous/traefik/version.Codename=$CODENAME \
-X github.com/containous/traefik/version.BuildDate=$DATE" \
-a -o dist/traefik-musl ./cmd/traefik
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment