deploy with confidence using pact go!

44
Deploy with Confidence! Deploy faster and safer using Pact PRESENTED BY Matt Fellows (@matthewfellows)

Upload: dius

Post on 16-Jan-2017

290 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Deploy with Confidence using Pact Go!

Deploy with Confidence!

Deploy faster and safer using Pact

PRESENTED BY Matt Fellows (@matthewfellows)

Page 2: Deploy with Confidence using Pact Go!

Everyone is doing microservices

Page 3: Deploy with Confidence using Pact Go!
Page 4: Deploy with Confidence using Pact Go!
Page 5: Deploy with Confidence using Pact Go!
Page 6: Deploy with Confidence using Pact Go!

How do you test this?

Page 7: Deploy with Confidence using Pact Go!

“Integration tests are a scam”

- JB Rainsberger

Page 8: Deploy with Confidence using Pact Go!

Scam, you say? Justify!

Integrated tests are:

● Slow● Fragile ● Hard to manage

When they fail, you can’t point to the problem!

Page 9: Deploy with Confidence using Pact Go!

Scam, you say? Justify!

“But my integration tests run in Docker, why can’t I use them?”

- People

Page 10: Deploy with Confidence using Pact Go!

Scam, you say? Justify!

“Because Maths”

- Me

Page 11: Deploy with Confidence using Pact Go!
Page 12: Deploy with Confidence using Pact Go!

Branches per box vs test cases required

2 code branches = 128 tests5 code branches = 78,125 tests10 code branches = 10M tests

Page 13: Deploy with Confidence using Pact Go!

Good tests have the exact opposite properties

Page 14: Deploy with Confidence using Pact Go!
Page 15: Deploy with Confidence using Pact Go!

Dictator Driven Contracts

Page 16: Deploy with Confidence using Pact Go!

1. Sit in ivory tower and postulate2. Document perfect API (Swagger, API blueprint etc.)3. Create said API4. Publish said document to consumers5. Repeat steps 1-4

How to: Dictator Driven Contracts

Page 17: Deploy with Confidence using Pact Go!
Page 18: Deploy with Confidence using Pact Go!
Page 19: Deploy with Confidence using Pact Go!
Page 20: Deploy with Confidence using Pact Go!

Dictator Consumer Driven Contracts

Page 21: Deploy with Confidence using Pact Go!
Page 22: Deploy with Confidence using Pact Go!

Benefits?

Page 23: Deploy with Confidence using Pact Go!

You’ll know when you break a consumer

Page 24: Deploy with Confidence using Pact Go!

You have a form of documentation

Page 25: Deploy with Confidence using Pact Go!

You can test things independently

Page 26: Deploy with Confidence using Pact Go!

Pactwww.pact.io

Page 27: Deploy with Confidence using Pact Go!

Evolved from combining these two principles

Page 28: Deploy with Confidence using Pact Go!

Step 1: Define Consumer expectations

Page 29: Deploy with Confidence using Pact Go!

Step 1: Define Consumer expectations

Step 2: Verify expectations on Provider

Page 30: Deploy with Confidence using Pact Go!

Start with a consumer test

Page 31: Deploy with Confidence using Pact Go!

Given “User A exists”When I Receive “a GET request for user A”

With “these headers and query”Respond with “200 OK”

And “User A’s details in the body”

Page 32: Deploy with Confidence using Pact Go!

Given “User A does not exist”When I Receive “a GET request for user A”

Respond with “404 Not Found”

Page 33: Deploy with Confidence using Pact Go!

Example

Page 34: Deploy with Confidence using Pact Go!

// Create a Pact test runner, connecting to local Daemon

// NOTE: I tend to use TestMain(m *testing.M) to set this up!

pact := dsl.Pact{

Port: 6666,

Consumer: "My Consumer",

Provider: "My Provider",

}

// Shuts down Mock Service when done

defer pact.Teardown()

Page 35: Deploy with Confidence using Pact Go!

// Setup our expected interactions on the Mock Service.

pact.

AddInteraction().

Given("User billy exists").

UponReceiving("A request to login with user 'billy'").

WithRequest(dsl.Request{

Method: "POST",

Path: "/users/login",

Body: loginRequest,

}).

WillRespondWith(dsl.Response{

Status: 200,

Headers: map[string]string{

"Content-Type": "application/json",

},

Body: `

{

"user": {

"name": "billy"

}

}

`,

})

Page 36: Deploy with Confidence using Pact Go!

// Run the test and verify the interactions.

err := pact.Verify(func() error {

client := Client{

Host: fmt.Sprintf("http://localhost:%d", pact.Server.Port),

}

client.loginHandler(rr, req)

// Expect User to be set on the Client

if client.user == nil {

return errors.New("Expected user not to be nil")

}

return nil

})

if err != nil {

t.Fatalf("Error on Verify: %v", err)

}

// Write pact to file `<pwd>/pacts/my_consumer-my_provider.json`

// NOTE: This also is a good candidate for use in TestMain(m *testing.M)

pact.WritePact()

Page 37: Deploy with Confidence using Pact Go!

Next publish your pacts

Page 38: Deploy with Confidence using Pact Go!

// Publish the Pacts...

p := dsl.Publisher{}

err := p.Publish(types.PublishRequest{

PactURLs: []string{"../pacts/myconsumer-myprovider.json"},

PactBroker: os.Getenv("PACT_BROKER_HOST"),

ConsumerVersion: "1.0.0",

Tags: []string{"latest", "production"},

BrokerUsername: os.Getenv("PACT_BROKER_USERNAME"),

BrokerPassword: os.Getenv("PACT_BROKER_PASSWORD"),

})

Page 39: Deploy with Confidence using Pact Go!

Then verify your provider

Page 40: Deploy with Confidence using Pact Go!

// Verify the Provider from tagged Pact files stored in a Pact Broker

response = pact.VerifyProvider(types.VerifyRequest{

ProviderBaseURL: fmt.Sprintf("http://localhost:%d", providerPort),

BrokerURL: brokerHost,

Tags: []string{"latest", "prod"},

ProviderStatesURL: fmt.Sprintf("http://localhost:%d/states", providerPort),

ProviderStatesSetupURL: fmt.Sprintf("http://localhost:%d/setup", providerPort),

BrokerUsername: os.Getenv("PACT_BROKER_USERNAME"),

BrokerPassword: os.Getenv("PACT_BROKER_PASSWORD"),

})

if response.ExitCode != 0 {

t.Fatalf("Got %d, Want exit code 0", response.ExitCode)

}

Page 41: Deploy with Confidence using Pact Go!

Verifying a pact between billy and bobby

Given User billy exists

A request to login with user 'billy'

with POST /users/login

returns a response which

Setting up provider state 'User billy exists' for consumer 'billy' using provider state server at

http://localhost:55128/setup

has status code 200

has a matching body

includes headers

"Content-Type" with value "application/json"

Given User billy does not exist

A request to login with user 'billy'

with POST /users/login

returns a response which

Setting up provider state 'User billy does not exist' for consumer 'billy' using provider state server at

http://localhost:55128/setup

has status code 404

includes headers

"Content-Type" with value "application/json"

...

Finished in 0.03042 seconds

7 examples, 0 failures

Page 42: Deploy with Confidence using Pact Go!

Verifying a pact between billy and bobby

Given User billy exists

A request to login with user 'billy'

with POST /users/login

returns a response which

Setting up provider state 'User billy exists' for consumer 'billy' using provider state server at

http://localhost:55420/setup

has status code 200

has a matching body (FAILED - 1)

includes headers

"Content-Type" with value "application/json"

Failures:

1) Verifying a pact between billy and bobby Given User billy exists A request to login with user 'billy' with POST

/users/login returns a response which has a matching body

Failure/Error: expect(response_body).to match_term expected_response_body, diff_options

Actual: {"user":{"user":"billy"}}

@@ -1,6 +1,5 @@

{

"user": {

- "name": "billy"

}

}

Page 43: Deploy with Confidence using Pact Go!

Find out more

● Gitbook: docs.pact.io● Github: pact-foundation/pact-go● Google users group:

https://groups.google.com/forum/#!forum/pact-support● Gitter: Join the chat at

https://gitter.im/realestate-com-au/pact● Twitter: @pact_up

Page 44: Deploy with Confidence using Pact Go!

Thank you

- @matthewfellows

Given “The presentation is over”Upon Receiving “A request for an answer”With “A valid question”Respond With “A valid answer”