Skip to content

Commit

Permalink
Merge pull request #1 from ameliaikeda/protobuf-support
Browse files Browse the repository at this point in the history
Add in protocol buffer support
  • Loading branch information
ameliaikeda authored Sep 10, 2021
2 parents 12d5799 + b3c6215 commit da9c9e1
Show file tree
Hide file tree
Showing 109 changed files with 13,998 additions and 108,748 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
language: go

go:
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
- 1.16.x
- 1.17.x

install:
- export PATH=${PATH}:${HOME}/gopath/bin
Expand All @@ -16,4 +14,4 @@ before_script:

script:
- go test -v ./...
- go test -v -test.race ./...
- go test -v -race ./...
180 changes: 0 additions & 180 deletions Gopkg.lock

This file was deleted.

19 changes: 0 additions & 19 deletions Gopkg.toml

This file was deleted.

80 changes: 80 additions & 0 deletions e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/http2"

"github.com/monzo/typhon/prototest"
)

type e2eFlavour interface {
Expand Down Expand Up @@ -133,6 +135,46 @@ func TestE2E(t *testing.T) {
})
}

func TestE2EProtobuf(t *testing.T) {
flavours(t, func(t *testing.T, flav e2eFlavour) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

svc := Service(func(req Request) Response {
// Simple requests like this shouldn't be chunked
assert.NotContains(t, req.TransferEncoding, "chunked")
assert.True(t, req.ContentLength > 0)
return req.Response(&prototest.Greeting{
Message: "👋!",
Priority: 2})
})
svc = svc.Filter(ErrorFilter)
s := flav.Serve(svc)
defer s.Stop(context.Background())

g := &prototest.Greeting{Message: "Hello world!", Priority: 1}
req := NewRequest(ctx, "GET", flav.URL(s), nil)
req.Header.Set("Accept", "application/json, application/protobuf")
req.EncodeAsProtobuf(g)
rsp := req.Send().Response()
require.NoError(t, rsp.Error)
assert.Equal(t, http.StatusOK, rsp.StatusCode)
assert.Equal(t, flav.Proto(), rsp.Proto)
assert.Equal(t, "application/protobuf", rsp.Header.Get("Content-Type"))
require.NotNil(t, rsp.Request)
assert.Equal(t, req, *rsp.Request)
body := &prototest.Greeting{}
require.NoError(t, rsp.Decode(body))

// proto.Message cannot be compared, so check fields directly.
assert.Equal(t, "👋!", body.Message)
assert.Equal(t, int32(2), body.Priority)
// The response is simple too; shouldn't be chunked
assert.NotContains(t, rsp.TransferEncoding, "chunked")
assert.EqualValues(t, 9, rsp.ContentLength)
})
}

func TestE2EStreaming(t *testing.T) {
someFlavours(t, []string{"http1.1", "http1.1-tls"}, func(t *testing.T, flav e2eFlavour) {
ctx, cancel := context.WithCancel(context.Background())
Expand Down Expand Up @@ -279,6 +321,44 @@ func TestE2EError(t *testing.T) {
})
}

func TestE2EErrorWithProtobuf(t *testing.T) {
flavours(t, func(t *testing.T, flav e2eFlavour) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

expectedErr := terrors.Unauthorized("ah_ah_ah", "You didn't say the magic word!", map[string]string{
"param": "value"})
svc := Service(func(req Request) Response {
rsp := Response{
Error: expectedErr}
rsp.Write([]byte("throwaway")) // should be removed
return rsp
})
svc = svc.Filter(ErrorFilter)
s := flav.Serve(svc)
defer s.Stop(context.Background())

g := &prototest.Greeting{Message: "Hello world!", Priority: 1}
req := NewRequest(ctx, "GET", flav.URL(s), g)
req.Header.Set("Accept", "application/json, application/protobuf")
rsp := req.Send().Response()

assert.Equal(t, http.StatusUnauthorized, rsp.StatusCode)
assert.Equal(t, "application/protobuf", rsp.Header.Get("Content-Type"))
assert.True(t, rsp.ContentLength > 0)

b, _ := rsp.BodyBytes(false)
assert.NotContains(t, string(b), "throwaway")

require.Error(t, rsp.Error)
terr := terrors.Wrap(rsp.Error, nil).(*terrors.Error)
terrExpect := terrors.Unauthorized("ah_ah_ah", "You didn't say the magic word!", nil)
assert.Equal(t, terrExpect.Message, terr.Message)
assert.Equal(t, terrExpect.Code, terr.Code)
assert.Equal(t, "value", terr.Params["param"])
})
}

func TestE2ECancellation(t *testing.T) {
flavours(t, func(t *testing.T, flav e2eFlavour) {
cancelled := make(chan struct{})
Expand Down
13 changes: 11 additions & 2 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"strings"

legacyproto "github.com/golang/protobuf/proto"
"github.com/monzo/slog"
"github.com/monzo/terrors"
terrorsproto "github.com/monzo/terrors/proto"
Expand Down Expand Up @@ -105,14 +106,22 @@ func ErrorFilter(req Request, svc Service) Response {
b, _ := rsp.BodyBytes(false)
switch rsp.Header.Get("Terror") {
case "1":
var err error
tp := &terrorsproto.Error{}
if err := json.Unmarshal(b, tp); err != nil {

switch rsp.Header.Get("Content-Type") {
case "application/octet-stream", "application/x-protobuf", "application/protobuf":
err = legacyproto.Unmarshal(b, tp)
default:
err = json.Unmarshal(b, tp)
}

if err != nil {
slog.Warn(rsp.Request, "Failed to unmarshal terror: %v", err)
rsp.Error = errors.New(string(b))
} else {
rsp.Error = terrors.Unmarshal(tp)
}

default:
rsp.Error = errors.New(string(b))
}
Expand Down
24 changes: 24 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module github.com/monzo/typhon

go 1.17

require (
github.com/deckarep/golang-set v1.7.1
github.com/fortytw2/leaktest v1.2.0
github.com/golang/protobuf v1.4.1
github.com/monzo/slog v0.0.0-20180411100359-4277a1759ecc
github.com/monzo/terrors v0.0.0-20201123122426-526801726c25
github.com/stretchr/testify v1.2.2
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
google.golang.org/protobuf v1.25.0
)

require (
github.com/cihub/seelog v0.0.0-20151216151435-d2c6e5aa9fbf // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/text v0.3.0 // indirect
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 // indirect
)
Loading

0 comments on commit da9c9e1

Please sign in to comment.