Skip to content

Commit

Permalink
feat: add an Avro example
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Jun 1, 2023
1 parent 2d4bf72 commit 4d2cdeb
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 3 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -46,6 +46,7 @@ download_plugins:
~/.pact/bin/pact-plugin-cli -y install https://github.com/pactflow/pact-protobuf-plugin/releases/tag/v-0.3.0
~/.pact/bin/pact-plugin-cli -y install https://github.com/pact-foundation/pact-plugins/releases/tag/csv-plugin-0.0.1
~/.pact/bin/pact-plugin-cli -y install https://github.com/mefellows/pact-matt-plugin/releases/tag/v0.0.7
~/.pact/bin/pact-plugin-cli -y install https://github.com/austek/pact-avro-plugin/releases/tag/v0.0.3

cli:
@if [ ! -d pact/bin ]; then\
Expand Down
103 changes: 103 additions & 0 deletions examples/avro/avro_consumer_test.go
@@ -0,0 +1,103 @@
//go:build consumer
// +build consumer

package avro

import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"testing"

"github.com/pact-foundation/pact-go/v2/consumer"

"path/filepath"

"github.com/stretchr/testify/assert"
)

var dir, _ = os.Getwd()

func TestAvroHTTP(t *testing.T) {
mockProvider, err := consumer.NewV4Pact(consumer.MockHTTPProviderConfig{
Consumer: "AvroConsumer",
Provider: "AvroProvider",
PactDir: filepath.ToSlash(fmt.Sprintf("%s/../pacts", dir)),
})
assert.NoError(t, err)

dir, _ := os.Getwd()
path := fmt.Sprintf("%s/user.avsc", dir)

avroResponse := `{
"pact:avro": "` + path + `",
"pact:record-name": "User",
"pact:content-type": "avro/binary",
"id": "matching(number, 1)",
"username": "notEmpty('matt')"
}`

// Set up our expected interactions.
err = mockProvider.
AddInteraction().
UponReceiving("A request to do get some Avro stuff").
UsingPlugin(consumer.PluginConfig{
Plugin: "avro",
Version: "0.0.2",
}).
WithRequest("GET", "/avro").
WillRespondWith(200, func(res *consumer.V4InteractionWithPluginResponseBuilder) {
res.PluginContents("avro/binary", avroResponse)
}).
ExecuteTest(t, func(msc consumer.MockServerConfig) error {
resp, err := callServiceHTTP(msc)

assert.Equal(t, int64(1), resp.ID)
assert.Equal(t, "matt", resp.Username) // ??????!

return err
})
assert.NoError(t, err)
}

func callServiceHTTP(msc consumer.MockServerConfig) (*User, error) {
client := &http.Client{}
req := &http.Request{
Method: "GET",
URL: &url.URL{
Host: fmt.Sprintf("%s:%d", msc.Host, msc.Port),
Scheme: "http",
Path: "/avro",
},
Header: make(http.Header),
}

req.Header.Set("Content-Type", "avro/binary;record=User")

res, err := client.Do(req)

if err != nil {
return nil, err
}

bytes, err := ioutil.ReadAll(res.Body)

if err != nil {
return nil, err
}

codec := getCodec()
native, _, err := codec.NativeFromBinary(bytes)
if err != nil {
return nil, err
}

user := &User{
ID: native.(map[string]interface{})["id"].(int64),
Username: native.(map[string]interface{})["username"].(string),
}

return user, err
}
71 changes: 71 additions & 0 deletions examples/avro/avro_provider_test.go
@@ -0,0 +1,71 @@
//go:build provider
// +build provider

package avro

import (
"fmt"
"log"
"net/http"

"os"
"path/filepath"
"testing"

"github.com/pact-foundation/pact-go/v2/provider"
"github.com/pact-foundation/pact-go/v2/utils"
"github.com/stretchr/testify/assert"
)

var dir, _ = os.Getwd()
var pactDir = fmt.Sprintf("%s/../pacts", dir)

func TestAvroHTTPProvider(t *testing.T) {
httpPort, _ := utils.GetFreePort()

// Start provider API in the background
go startHTTPProvider(httpPort)

verifier := provider.NewVerifier()

// Verify the Provider with local Pact Files
err := verifier.VerifyProvider(t, provider.VerifyRequest{
ProviderBaseURL: fmt.Sprintf("http://127.0.0.1:%d", httpPort),
Provider: "AvroProvider",
PactFiles: []string{
filepath.ToSlash(fmt.Sprintf("%s/AvroConsumer-AvroProvider.json", pactDir)),
},
})

assert.NoError(t, err)
}

func startHTTPProvider(port int) {
mux := http.NewServeMux()

mux.HandleFunc("/avro", func(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Content-Type", "avro/binary;record=User")

user := &User{
ID: 1,
Username: "matt",
// Username: "sally", // matching rules not supported?
}

codec := getCodec()
binary, err := codec.BinaryFromNative(nil, map[string]interface{}{
"id": user.ID,
"username": user.Username,
})
if err != nil {
log.Println("ERROR: ", err)
w.WriteHeader(500)
} else {
fmt.Fprintf(w, string(binary))
w.WriteHeader(200)
}
})

log.Printf("started HTTP server on port: %d\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), mux))
}
21 changes: 21 additions & 0 deletions examples/avro/codec.go
@@ -0,0 +1,21 @@
package avro

import (
"io/ioutil"

"github.com/linkedin/goavro/v2"
)

func getCodec() *goavro.Codec {
schema, err := ioutil.ReadFile("user.avsc")
if err != nil {
panic(err)
}

codec, err := goavro.NewCodec(string(schema))
if err != nil {
panic(err)
}

return codec
}
9 changes: 9 additions & 0 deletions examples/avro/user.avsc
@@ -0,0 +1,9 @@
{
"type": "record",
"name": "User",
"namespace": "io.pact",
"fields" : [
{"name": "id", "type": "long"},
{"name": "username", "type": "string"}
]
}
6 changes: 6 additions & 0 deletions examples/avro/user.go
@@ -0,0 +1,6 @@
package avro

type User struct {
ID int64 `json:"id"`
Username string `json:"username"`
}
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -14,10 +14,11 @@ require (
github.com/hashicorp/go-version v1.5.0
github.com/hashicorp/logutils v1.0.0
github.com/klauspost/compress v1.15.4 // indirect
github.com/linkedin/goavro/v2 v2.12.0
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.5
github.com/ulikunitz/xz v0.5.10 // indirect
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
Expand All @@ -27,5 +28,4 @@ require (
google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 7 additions & 1 deletion go.sum
Expand Up @@ -161,6 +161,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
Expand Down Expand Up @@ -279,6 +280,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/linkedin/goavro/v2 v2.12.0 h1:rIQQSj8jdAUlKQh6DttK8wCRv4t4QO09g1C4aBWXslg=
github.com/linkedin/goavro/v2 v2.12.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
Expand Down Expand Up @@ -345,13 +348,16 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
Expand Down

0 comments on commit 4d2cdeb

Please sign in to comment.