Merge pull request #164 from adamryman/wrap-all-execpt
WrapAll(middlewares, exclude ...string)
This commit is contained in:
Коммит
09b206d71c
|
@ -5,13 +5,15 @@ END_COLOR_LINE=$(UNDER)$(NO_COLOR)
|
|||
|
||||
TRANSPORT_TEST_MSG=\n$(OK_COLOR)Starting transport end to end test:$(END_COLOR_LINE)
|
||||
|
||||
MIDDLEWARES_TEST_MSG=\n$(OK_COLOR)Starting middlewares end to end test:$(END_COLOR_LINE)
|
||||
|
||||
CLI_TEST_MSG=\n$(OK_COLOR)Start server and cliclient generate, build, and run test:$(END_COLOR_LINE)
|
||||
|
||||
export PATH := $(CURDIR):$(PATH)
|
||||
|
||||
all: test
|
||||
|
||||
test: clean test-transport test-cli
|
||||
test: clean test-transport test-middlewares test-cli
|
||||
|
||||
truss:
|
||||
go build -o truss github.com/TuneLab/go-truss/cmd/truss
|
||||
|
@ -25,6 +27,12 @@ test-transport: protoc-gen-truss-protocast truss
|
|||
$(MAKE) -C transport
|
||||
rm -f ./truss ./protoc-gen-truss-protocast
|
||||
|
||||
test-middlewares: protoc-gen-truss-protocast truss
|
||||
@which truss
|
||||
@printf '$(MIDDLEWARES_TEST_MSG)'
|
||||
$(MAKE) -C middlewares
|
||||
rm -f ./truss ./protoc-gen-truss-protocast
|
||||
|
||||
test-cli: protoc-gen-truss-protocast truss
|
||||
@which truss
|
||||
@printf '$(CLI_TEST_MSG)'
|
||||
|
@ -35,4 +43,5 @@ clean:
|
|||
rm -f ./truss ./protoc-gen-truss-protocast
|
||||
go test ./cli -clean
|
||||
$(MAKE) -C transport clean
|
||||
$(MAKE) -C middlewares clean
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ the test. Then each `transport/{TRANSPORT}_test.go` imports the generated code,
|
|||
runs requests against the server, checking for errors and that the input values
|
||||
add to the expected output value(s).
|
||||
|
||||
# ./middlewares
|
||||
|
||||
`middlewares` is very similar to transport, having prewritten handlers and
|
||||
middlewares, it generates a truss service and copies these into that service.
|
||||
Then it runs tests against the endpoints (avoiding the transport logic) to see
|
||||
if middlewares were correctly applied and/or excluded from the endpoints.
|
||||
|
||||
# ./cli
|
||||
|
||||
The truss CLI integration runner does the following tasks:
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
NO_COLOR=\e[0m
|
||||
OK_COLOR=\e[38;5;118m
|
||||
UNDER=\n________________________________________________________________________________\n
|
||||
END_COLOR_LINE=$(UNDER)$(NO_COLOR)
|
||||
|
||||
TRUSS_MSG=\n$(OK_COLOR)Running Truss...$(END_COLOR_LINE)
|
||||
|
||||
TEST_RUNNING_MSG=\n$(OK_COLOR)Running middlewares tests:$(END_COLOR_LINE)
|
||||
|
||||
all: test
|
||||
|
||||
test:
|
||||
@echo -e '$(TRUSS_MSG)'
|
||||
truss middlewares-test.proto
|
||||
cp -r middlewares middlewarestest-service
|
||||
cp -r handlers middlewarestest-service
|
||||
@echo -e '$(TEST_RUNNING_MSG)'
|
||||
go test -v
|
||||
$(MAKE) clean
|
||||
|
||||
clean:
|
||||
rm -rf middlewarestest-service
|
|
@ -0,0 +1,46 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service"
|
||||
)
|
||||
|
||||
// NewService returns a naïve, stateless implementation of Service.
|
||||
func NewService() pb.MiddlewaresTestServer {
|
||||
return middlewarestestService{}
|
||||
}
|
||||
|
||||
type middlewarestestService struct{}
|
||||
|
||||
// AlwaysWrapped implements Service.
|
||||
func (s middlewarestestService) AlwaysWrapped(ctx context.Context, in *pb.Empty) (*pb.WrapAllTest, error) {
|
||||
var resp pb.WrapAllTest
|
||||
|
||||
always := ctx.Value("Always")
|
||||
if a, ok := always.(bool); ok {
|
||||
resp.Always = a
|
||||
}
|
||||
notSometimes := ctx.Value("NotSometimes")
|
||||
if ns, ok := notSometimes.(bool); ok {
|
||||
resp.NotSometimes = ns
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// SometimesWrapped implements Service.
|
||||
func (s middlewarestestService) SometimesWrapped(ctx context.Context, in *pb.Empty) (*pb.WrapAllTest, error) {
|
||||
var resp pb.WrapAllTest
|
||||
|
||||
always := ctx.Value("Always")
|
||||
if a, ok := always.(bool); ok {
|
||||
resp.Always = a
|
||||
}
|
||||
notSometimes := ctx.Value("NotSometimes")
|
||||
if ns, ok := notSometimes.(bool); ok {
|
||||
resp.NotSometimes = ns
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package middlewares;
|
||||
|
||||
import "github.com/TuneLab/go-truss/deftree/googlethirdparty/annotations.proto";
|
||||
|
||||
service MiddlewaresTest {
|
||||
// Test endpoints.WrapAll(middleware, exclude ...)
|
||||
// AlwaysWrapped will never be excluded in endpoints.WrapAll
|
||||
rpc AlwaysWrapped (Empty) returns (WrapAllTest) {
|
||||
option (google.api.http) = {
|
||||
get: "/alwayswrapped"
|
||||
};
|
||||
}
|
||||
// SometimesWrapped will be excluded from the middleware that set the
|
||||
// NotSometimes value
|
||||
rpc SometimesWrapped (Empty) returns (WrapAllTest) {
|
||||
option (google.api.http) = {
|
||||
get: "/sometimeswrapped"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
// WrapAllTest will be populated by middlewares which were wrapped
|
||||
// around endpoints using WrapAll
|
||||
message WrapAllTest {
|
||||
// Always will be set to true
|
||||
bool Always = 1;
|
||||
// NotSometimes will be set to true for endpoint AlwaysWrapped and set to
|
||||
// false for SometimesWrapped
|
||||
bool NotSometimes = 2;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
svc "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service/generated"
|
||||
)
|
||||
|
||||
// WrapEndpoints accepts the service's entire collection of endpoints, so that a
|
||||
// set of middlewares can be wrapped around every middleware (e.g., access
|
||||
// logging and instrumentation), and others wrapped selectively around some
|
||||
// endpoints and not others (e.g., endpoints requiring authenticated access).
|
||||
// Note that the final middleware applied will be the outermost middleware
|
||||
// (i.e. applied first)
|
||||
func WrapEndpoints(in svc.Endpoints) svc.Endpoints {
|
||||
|
||||
// Pass in the middlewares you want applied to every endpoint.
|
||||
// optionally pass in endpoints by name that you want to be excluded
|
||||
// e.g.
|
||||
// in.WrapAll(authMiddleware, "Status", "Ping")
|
||||
in.WrapAll(addBoolToContext("NotSometimes"), "SometimesWrapped")
|
||||
in.WrapAll(addBoolToContext("Always"))
|
||||
|
||||
return in
|
||||
}
|
||||
|
||||
func addBoolToContext(key string) endpoint.Middleware {
|
||||
return func(next endpoint.Endpoint) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
ctx = context.WithValue(ctx, key, true)
|
||||
return next(ctx, request)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service"
|
||||
)
|
||||
|
||||
func WrapService(in pb.MiddlewaresTestServer) pb.MiddlewaresTestServer {
|
||||
return in
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service"
|
||||
)
|
||||
|
||||
func TestAlwaysWrapped(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
resp, err := middlewareEndpoints.AlwaysWrapped(ctx, &pb.Empty{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !resp.Always {
|
||||
t.Error("Always middleware did not wrap AlwaysWrap endpoint")
|
||||
}
|
||||
|
||||
if !resp.NotSometimes {
|
||||
t.Error("NotSometimes middleware did not wrap AlwaysWrap endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSometimesWrapped(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
resp, err := middlewareEndpoints.SometimesWrapped(ctx, &pb.Empty{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !resp.Always {
|
||||
t.Error("Always middleware did not wrap SometimesWrapped endpoint")
|
||||
}
|
||||
|
||||
if resp.NotSometimes {
|
||||
t.Error("NotSometimes middleware did wrap SomtimesWrapped endpoint")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
pb "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service"
|
||||
svc "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service/generated"
|
||||
handler "github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service/handlers/server"
|
||||
"github.com/TuneLab/go-truss/cmd/_integration-tests/middlewares/middlewarestest-service/middlewares"
|
||||
)
|
||||
|
||||
var middlewareEndpoints svc.Endpoints
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
var service pb.MiddlewaresTestServer
|
||||
{
|
||||
service = handler.NewService()
|
||||
}
|
||||
|
||||
// Endpoint domain.
|
||||
alwaysWrapped := svc.MakeAlwaysWrappedEndpoint(service)
|
||||
sometimesWrapped := svc.MakeSometimesWrappedEndpoint(service)
|
||||
|
||||
middlewareEndpoints = svc.Endpoints{
|
||||
AlwaysWrappedEndpoint: alwaysWrapped,
|
||||
SometimesWrappedEndpoint: sometimesWrapped,
|
||||
}
|
||||
|
||||
middlewareEndpoints = middlewares.WrapEndpoints(middlewareEndpoints)
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
|
@ -58,6 +58,8 @@ func TestNewEndpointMiddleware(t *testing.T) {
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
_ "github.com/go-kit/kit/endpoint"
|
||||
|
||||
svc "github.com/TuneLab/go-truss/gengokit/general-service/generated"
|
||||
)
|
||||
|
||||
|
@ -65,12 +67,16 @@ func TestNewEndpointMiddleware(t *testing.T) {
|
|||
// set of middlewares can be wrapped around every middleware (e.g., access
|
||||
// logging and instrumentation), and others wrapped selectively around some
|
||||
// endpoints and not others (e.g., endpoints requiring authenticated access).
|
||||
// Note that the final middleware applied will be the outermost middleware
|
||||
// (i.e. applied first)
|
||||
func WrapEndpoints(in svc.Endpoints) svc.Endpoints {
|
||||
|
||||
// Pass in the middlewares you want applied to every endpoint.
|
||||
in.WrapAll(/* ...endpoint.Middleware */)
|
||||
// optionally pass in endpoints by name that you want to be excluded
|
||||
// e.g.
|
||||
// in.WrapAll(authMiddleware, "Status", "Ping")
|
||||
|
||||
// How to apply a middleware selectively.
|
||||
// How to apply a middleware to a single endpoint.
|
||||
// in.ExampleEndpoint = authMiddleware(in.ExampleEndpoint)
|
||||
|
||||
return in
|
||||
|
|
|
@ -4,6 +4,8 @@ const EndpointsBase = `
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
_ "github.com/go-kit/kit/endpoint"
|
||||
|
||||
svc "{{.ImportPath -}} /generated"
|
||||
)
|
||||
|
||||
|
@ -11,12 +13,16 @@ import (
|
|||
// set of middlewares can be wrapped around every middleware (e.g., access
|
||||
// logging and instrumentation), and others wrapped selectively around some
|
||||
// endpoints and not others (e.g., endpoints requiring authenticated access).
|
||||
// Note that the final middleware applied will be the outermost middleware
|
||||
// (i.e. applied first)
|
||||
func WrapEndpoints(in svc.Endpoints) svc.Endpoints {
|
||||
|
||||
// Pass in the middlewares you want applied to every endpoint.
|
||||
in.WrapAll(/* ...endpoint.Middleware */)
|
||||
// optionally pass in endpoints by name that you want to be excluded
|
||||
// e.g.
|
||||
// in.WrapAll(authMiddleware, "Status", "Ping")
|
||||
|
||||
// How to apply a middleware selectively.
|
||||
// How to apply a middleware to a single endpoint.
|
||||
// in.ExampleEndpoint = authMiddleware(in.ExampleEndpoint)
|
||||
|
||||
return in
|
||||
|
|
|
@ -6,6 +6,7 @@ package svc
|
|||
// formats. It also includes endpoint middlewares.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
|
@ -25,8 +26,7 @@ import (
|
|||
//
|
||||
// In a client, it's useful to collect individually constructed endpoints into a
|
||||
// single type that implements the Service interface. For example, you might
|
||||
// construct individual endpoints using transport/http.NewClient, combine them
|
||||
// into an Endpoints, and return it to the caller as a Service.
|
||||
// construct individual endpoints using transport/http.NewClient, combine them into an Endpoints, and return it to the caller as a Service.
|
||||
type Endpoints struct {
|
||||
{{range $i := .Service.Methods}}
|
||||
{{$i.Name}}Endpoint endpoint.Endpoint
|
||||
|
@ -63,14 +63,27 @@ type Endpoints struct {
|
|||
// WrapAll wraps each Endpoint field of struct Endpoints with a
|
||||
// go-kit/kit/endpoint.Middleware.
|
||||
// Use this for applying a set of middlewares to every endpoint in the service.
|
||||
// The middlewares will be applied in the order passed, with the first
|
||||
// middleware being the outermost middleware.
|
||||
func (e *Endpoints) WrapAll(middlewares ...endpoint.Middleware) {
|
||||
if len(middlewares) == 0 {
|
||||
return
|
||||
}
|
||||
m := endpoint.Chain(middlewares[0], middlewares[1:]...)
|
||||
{{range $i := .Service.Methods}}
|
||||
e.{{$i.Name}}Endpoint = m(e.{{$i.Name}}Endpoint)
|
||||
// Optionally, endpoints can be passed in by name to be excluded from being wrapped.
|
||||
// WrapAll(middleware, "Status", "Ping")
|
||||
func (e *Endpoints) WrapAll(middleware endpoint.Middleware, excluded ...string) {
|
||||
included := map[string]struct{}{
|
||||
{{- range $i := .Service.Methods}}
|
||||
"{{$i.Name}}": struct{}{},
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
for _, ex := range excluded {
|
||||
if _, ok := included[ex]; !ok {
|
||||
panic(fmt.Sprintf("Excluded endpoint '%s' does not exist; see middlewares/endpoints.go", ex))
|
||||
}
|
||||
delete(included, ex)
|
||||
}
|
||||
|
||||
for inc, _ := range included {
|
||||
{{- range $i := .Service.Methods}}
|
||||
if inc == "{{$i.Name}}" {
|
||||
e.{{$i.Name}}Endpoint = middleware(e.{{$i.Name}}Endpoint)
|
||||
}
|
||||
{{- end}}
|
||||
}
|
||||
}
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Загрузка…
Ссылка в новой задаче