Skip to content

Commit

Permalink
refactor(examples): make examples more consistent for readability
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Mar 17, 2019
1 parent 0346784 commit f7dda3b
Show file tree
Hide file tree
Showing 16 changed files with 100 additions and 114 deletions.
75 changes: 31 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Read [Getting started with Pact] for more information for beginners.
## Versions

<details><summary>Specification Compatibility</summary>

| Version | Stable | [Spec] Compatibility | Install |
| ------- | ---------- | -------------------- | ------------------ |
| 1.0.x | Yes | 2, 3\* | See [installation] |
Expand Down Expand Up @@ -149,70 +150,60 @@ We'll run through a simple example to get an understanding the concepts:
The simple example looks like this:

```go
package main

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

"github.com/pact-foundation/pact-go/dsl"
)

// Example Pact: How to run me!
// 1. cd <pact-go>/examples
// 2. go test -v -run TestConsumer
func TestConsumer(t *testing.T) {
type struct {
Name string `json:"name" pact:"example=billy"`
LastName string `json:"lastName" pact:"example=sampson"`
}

// Create Pact client
// Create Pact connecting to local Daemon
pact := &dsl.Pact{
Consumer: "MyConsumer",
Provider: "MyProvider",
Host: "localhost",
}
defer pact.Teardown()

// Pass in test case
var test = func() error {
// Pass in test case. This is the component that makes the external HTTP call
var test = func() (err error) {
u := fmt.Sprintf("http://localhost:%d/foobar", pact.Server.Port)
req, err := http.NewRequest("GET", u, strings.NewReader(`{"s":"foo"}`))
req, _ := http.NewRequest("GET", u, strings.NewReader(`{"name":"billy"}`))

// NOTE: by default, request bodies are expected to be sent with a Content-Type
// of application/json. If you don't explicitly set the content-type, you
// will get a mismatch during Verification.
req.Header.Set("Content-Type", "application/json")
if err != nil {
return err
}
if _, err = http.DefaultClient.Do(req); err != nil {
return err
}

return err
req.Header.Set("Authorization", "Bearer 1234")

_, err = http.DefaultClient.Do(req); err != nil {
return
}

// Set up our expected interactions.
pact.
AddInteraction().
Given("User 1 exists").
UponReceiving("A request to get user 1").
Given("User foo exists").
UponReceiving("A request to get foo").
WithRequest(dsl.Request{
Method: "GET",
Path: dsl.String("/users/1"),
Headers: dsl.MapMatcher{"Content-Type": "application/json"},
Path: dsl.String("/foobar"),
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json"), "Authorization": dsl.String("Bearer 1234")},
Body: map[string]string{
"name": "billy",
},
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": "application/json"},
Body: dsl.Match(&Foo{})
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")},
Body: dsl.Match(&User{}),
})

// Verify
// Run the test, verify it did what we expected and capture the contract
if err := pact.Verify(test); err != nil {
log.Fatalf("Error on Verify: %v", err)
}
}

```
### Provider API Testing
Expand Down Expand Up @@ -259,7 +250,7 @@ Here is the Provider test process broker down:
// Start provider API in the background
go startServer()

// Verify the Provider with local Pact Files
// Verify the Provider using the locally saved Pact Files
pact.VerifyProvider(t, types.VerifyRequest{
ProviderBaseURL: "http://localhost:8000",
PactURLs: []string{filepath.ToSlash(fmt.Sprintf("%s/myconsumer-myprovider.json", pactDir))},
Expand All @@ -282,9 +273,6 @@ Note that `PactURLs` may be a list of local pact files or remote based
urls (e.g. from a
[Pact Broker](http://docs.pact.io/documentation/sharings_pacts.html)).
See the `Skip()'ed` [integration tests](https://github.com/pact-foundation/pact-go/blob/master/dsl/pact_test.go)
for a more complete E2E example.
#### Provider Verification
When validating a Provider, you have 3 options to provide the Pact files:
Expand All @@ -311,7 +299,7 @@ When validating a Provider, you have 3 options to provide the Pact files:
})
```
1. Use `BrokerURL` and `Tags` to automatically find all of the latest consumers:
1. Use `BrokerURL` and `Tags` to automatically find all of the latest consumers given one or more tags:
```go
pact.VerifyProvider(t, types.VerifyRequest{
Expand Down Expand Up @@ -366,18 +354,18 @@ Read more about [Provider States](https://docs.pact.io/getting_started/provider_
#### Before and After Hooks
Sometimes, it's useful to be able to do things before or after a test has run, such as reset a database, log a metric etc. A `BeforeHook` runs before any other part of the Pact test lifecycle, and a `AfterHook` runs as the last step before returning the verification result back to the test.
Sometimes, it's useful to be able to do things before or after a test has run, such as reset a database, log a metric etc. A `BeforeEach` runs before any other part of the Pact test lifecycle, and a `AfterEach` runs as the last step before returning the verification result back to the test.
You can add them to your Verification as follows:
```go
pact.VerifyProvider(t, types.VerifyRequest{
...
BeforeHook: func() error {
BeforeEach: func() error {
fmt.Println("before hook, do something")
return nil
},
AfterHook: func() error {
AfterEach: func() error {
fmt.Println("after hook, do something")
return nil
},
Expand Down Expand Up @@ -437,7 +425,7 @@ _Important Note_: You should only use this feature for things that can not be pe
For each _interaction_ in a pact file, the order of execution is as follows:
`BeforeHook` -> `StateHandler` -> `RequestFilter (pre)`, `Execute Provider Test` -> `RequestFilter (post)` -> `AfterHook`
`BeforeEach` -> `StateHandler` -> `RequestFilter (pre)`, `Execute Provider Test` -> `RequestFilter (post)` -> `AfterEach`
If any of the middleware or hooks fail, the tests will also fail.
Expand Down Expand Up @@ -756,7 +744,6 @@ for more matching examples.

- [API Consumer](https://github.com/pact-foundation/pact-go/tree/master/examples/)
- [Golang ServeMux](https://github.com/pact-foundation/pact-go/tree/master/examples/mux)
- [Go Kit](https://github.com/pact-foundation/pact-go/tree/master/examples/go-kit)
- [Gin](https://github.com/pact-foundation/pact-go/tree/master/examples/gin)

### Asynchronous APIs
Expand Down
4 changes: 2 additions & 2 deletions client/service.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Package client implements the raw interface to the Pact CLI tools: The Pact Mock Service and Provider Verification
"binaries."
Package client is an internal package, implementing the raw interface to the
Pact CLI tools: The Pact Mock Service and Provider Verification "binaries."
See https://github.com/pact-foundation/pact-provider-verifier and
https://github.com/bethesque/pact-mock_service for more on the Ruby "binaries".
Expand Down
2 changes: 1 addition & 1 deletion command/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var versionCmd = &cobra.Command{
Short: "Print the version number of Pact Go",
Long: `All software has versions. This is Pact Go's`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Pact Go CLI v1.0.0-beta.3, using CLI tools version", cliToolsVersion)
fmt.Println("Pact Go CLI v1.0.0-beta.4, using CLI tools version", cliToolsVersion)
},
}

Expand Down
22 changes: 11 additions & 11 deletions dsl/pact.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func (p *Pact) WritePact() error {
// VerifyProviderRaw reads the provided pact files and runs verification against
// a running Provider API, providing raw response from the Verification process.
//
// Order of events: beforeHook, stateHandlers, requestFilter(pre <execute provider> post), afterHook
// Order of events: BeforeEach, stateHandlers, requestFilter(pre <execute provider> post), AfterEach
func (p *Pact) VerifyProviderRaw(request types.VerifyRequest) (types.ProviderVerifierResponse, error) {
p.Setup(false)
var res types.ProviderVerifierResponse
Expand All @@ -310,12 +310,12 @@ func (p *Pact) VerifyProviderRaw(request types.VerifyRequest) (types.ProviderVer

m := []proxy.Middleware{}

if request.BeforeHook != nil {
m = append(m, beforeHookMiddleware(request.BeforeHook))
if request.BeforeEach != nil {
m = append(m, BeforeEachMiddleware(request.BeforeEach))
}

if request.AfterHook != nil {
m = append(m, afterHookMiddleware(request.AfterHook))
if request.AfterEach != nil {
m = append(m, AfterEachMiddleware(request.AfterEach))
}

if len(request.StateHandlers) > 0 {
Expand Down Expand Up @@ -406,15 +406,15 @@ var checkCliCompatibility = func() {
}
}

// beforeHookMiddleware is invoked before any other, only on the __setup
// BeforeEachMiddleware is invoked before any other, only on the __setup
// request (to avoid duplication)
func beforeHookMiddleware(beforeHook types.Hook) proxy.Middleware {
func BeforeEachMiddleware(BeforeEach types.Hook) proxy.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/__setup" {

log.Println("[DEBUG] executing before hook")
err := beforeHook()
err := BeforeEach()

if err != nil {
log.Println("[ERROR] error executing before hook:", err)
Expand All @@ -426,17 +426,17 @@ func beforeHookMiddleware(beforeHook types.Hook) proxy.Middleware {
}
}

// afterHookMiddleware is invoked after any other, and is the last
// AfterEachMiddleware is invoked after any other, and is the last
// function to be called prior to returning to the test suite. It is
// therefore not invoked on __setup
func afterHookMiddleware(afterHook types.Hook) proxy.Middleware {
func AfterEachMiddleware(AfterEach types.Hook) proxy.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)

if r.URL.Path != "/__setup" {
log.Println("[DEBUG] executing after hook")
err := afterHook()
err := AfterEach()

if err != nil {
log.Println("[ERROR] error executing after hook:", err)
Expand Down
20 changes: 10 additions & 10 deletions dsl/pact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,11 +264,11 @@ func TestPact_VerifyProviderRaw(t *testing.T) {
ProviderBaseURL: "http://www.foo.com",
PactURLs: []string{"foo.json", "bar.json"},
RequestFilter: dummyMiddleware,
BeforeHook: func() error {
BeforeEach: func() error {
fmt.Println("aeuaoseu")
return nil
},
AfterHook: func() error {
AfterEach: func() error {
fmt.Println("aeuaoseu")
return nil
},
Expand Down Expand Up @@ -383,7 +383,7 @@ func TestPact_AddInteraction(t *testing.T) {
}
}

func TestPact_BeforeHook(t *testing.T) {
func TestPact_BeforeEach(t *testing.T) {
var called bool

req, err := http.NewRequest("GET", "/__setup", nil)
Expand All @@ -394,7 +394,7 @@ func TestPact_BeforeHook(t *testing.T) {

rr := httptest.NewRecorder()

mw := beforeHookMiddleware(func() error {
mw := BeforeEachMiddleware(func() error {
called = true
return nil
})
Expand All @@ -410,7 +410,7 @@ func TestPact_BeforeHook(t *testing.T) {
t.Error("expected http handler to be invoked")
}
}
func TestPact_BeforeHookNotSetupPath(t *testing.T) {
func TestPact_BeforeEachNotSetupPath(t *testing.T) {
var called bool

req, err := http.NewRequest("GET", "/blah", nil)
Expand All @@ -421,7 +421,7 @@ func TestPact_BeforeHookNotSetupPath(t *testing.T) {

rr := httptest.NewRecorder()

mw := beforeHookMiddleware(func() error {
mw := BeforeEachMiddleware(func() error {
called = true
return nil
})
Expand All @@ -437,7 +437,7 @@ func TestPact_BeforeHookNotSetupPath(t *testing.T) {
t.Error("expected http handler to be invoked")
}
}
func TestPact_AfterHook(t *testing.T) {
func TestPact_AfterEach(t *testing.T) {
var called bool

req, err := http.NewRequest("GET", "/blah", nil)
Expand All @@ -448,7 +448,7 @@ func TestPact_AfterHook(t *testing.T) {

rr := httptest.NewRecorder()

mw := afterHookMiddleware(func() error {
mw := AfterEachMiddleware(func() error {
called = true
return nil
})
Expand All @@ -464,7 +464,7 @@ func TestPact_AfterHook(t *testing.T) {
t.Error("expected http handler to be invoked")
}
}
func TestPact_AfterHookSetupPath(t *testing.T) {
func TestPact_AfterEachSetupPath(t *testing.T) {
var called bool

req, err := http.NewRequest("GET", "/__setup", nil)
Expand All @@ -475,7 +475,7 @@ func TestPact_AfterHookSetupPath(t *testing.T) {

rr := httptest.NewRecorder()

mw := afterHookMiddleware(func() error {
mw := AfterEachMiddleware(func() error {
called = true
return nil
})
Expand Down
12 changes: 7 additions & 5 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ how Pact could be used in each.
Each Provider API currently exposes a single `Login` endpoint at `POST /login/1`,
which the [Consumer](consumer/goconsumer) uses to authenticate a User.

We test 3 scenarios, highlighting the use of [Provider States](/pact-foundation/pact-go#provider#provider-states):
We test 5 scenarios, highlighting the use of [Provider States](/pact-foundation/pact-go#provider#provider-states), [Hooks](/pact-foundation/pact-go#before-and-after-hooks) and [RequestFilters](/pact-foundation/pact-go#request-filters):

1. When the user "jmarie" exists, and we perform a login, we expect an HTTP `200`
1. When the user "jmarie" does not exists, and we perform a login, we expect an HTTP `404`
1. When the user "jmarie" is unauthorized, and we perform a login, we expect an HTTP `403`
1. When the user is authenticated, and we request to get the user 'jmarie', we expect an HTTP `200`
1. When the user is unauthenticated, and we request to get the user 'jmarie', we expect an HTTP `401`

# Getting started

Expand All @@ -23,7 +25,7 @@ go get ./...

## Providers

1. [Go-Kit](go-kit)
1. [Mux](mux)
2. [Gin](gin)

## Consumer
Expand All @@ -46,12 +48,12 @@ This will generate a Pact file in `./pacts/jmarie-loginprovider.json`.

### Running the Consumer

Before you can run the consumer make sure the provider is
[running](#running-the-provider).
Before you can run the consumer make sure one of the providers is
running first. You can then run:

```
go run cmd/web/main.go
```

Hit http://localhost:8081/ in your browser. You can use the username/password
combination of "billy" / "issilly" to authenticate.
combination of "jmarie" / "issilly" to authenticate.
2 changes: 1 addition & 1 deletion examples/consumer/goconsumer/user_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ func TestPactConsumerGetUser_Unauthenticated(t *testing.T) {
pact.
AddInteraction().
Given("User jmarie is unauthenticated").
UponReceiving("A request to login with user 'jmarie'").
UponReceiving("A request to get with user 'jmarie'").
WithRequest(request{
Method: "GET",
Path: s("/users/10"),
Expand Down
Loading

0 comments on commit f7dda3b

Please sign in to comment.