Skip to content

Commit

Permalink
feat(hooks): improve test coverage across Message pacts
Browse files Browse the repository at this point in the history
- Added more coverage for message pacts code
- Found and fixed bug related to unmarshaling MapMatcher during
  Message Verification
  • Loading branch information
mefellows committed Mar 3, 2019
1 parent f5678c7 commit 3cd947f
Show file tree
Hide file tree
Showing 7 changed files with 702 additions and 45 deletions.
26 changes: 26 additions & 0 deletions dsl/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@ import (
"github.com/pact-foundation/pact-go/types"
)

// Client is the interface
type Client interface {
// StartServer starts a remote Pact Mock Server.
StartServer(args []string, port int) *types.MockServer

// ListServers lists all known Mock Servers
ListServers() []*types.MockServer

// StopServer stops a remote Pact Mock Server.
StopServer(server *types.MockServer) (*types.MockServer, error)

// RemoveAllServers stops all remote Pact Mock Servers.
RemoveAllServers(server *types.MockServer) *[]types.MockServer

// VerifyProvider runs the verification process against a running Provider.
VerifyProvider(request types.VerifyRequest) (types.ProviderVerifierResponse, error)

// UpdateMessagePact adds a pact message to a contract file
UpdateMessagePact(request types.PactMessageRequest) error

// ReifyMessage takes a structured object, potentially containing nested Matchers
// and returns an object with just the example (generated) content
// The object may be a simple JSON primitive e.g. string or number or a complex object
ReifyMessage(request *types.PactReificationRequest) (res *types.ReificationResponse, err error)
}

// PactClient is the main interface into starting/stopping
// the underlying Pact CLI subsystem
type PactClient struct {
Expand Down
22 changes: 13 additions & 9 deletions dsl/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

func TestClient_List(t *testing.T) {
client, _ := createClient(true)
client, _ := createMockClient(true)
servers := client.ListServers()

if len(servers) != 3 {
Expand All @@ -25,7 +25,7 @@ func TestClient_List(t *testing.T) {
}

func TestClient_StartServer(t *testing.T) {
client, svc := createClient(true)
client, svc := createMockClient(true)
defer stubPorts()()

port, _ := utils.GetFreePort()
Expand All @@ -36,15 +36,15 @@ func TestClient_StartServer(t *testing.T) {
}

func TestClient_StartServerFail(t *testing.T) {
client, _ := createClient(false)
client, _ := createMockClient(false)
server := client.StartServer([]string{}, 0)
if server.Port != 0 {
t.Fatalf("Expected server to be empty %v", server)
}
}

func TestClient_StopServer(t *testing.T) {
client, svc := createClient(true)
client, svc := createMockClient(true)

client.StopServer(&types.MockServer{})
if svc.ServiceStopCount != 1 {
Expand All @@ -53,7 +53,7 @@ func TestClient_StopServer(t *testing.T) {
}

func TestClient_StopServerFail(t *testing.T) {
client, _ := createClient(true)
client, _ := createMockClient(true)
res, err := client.StopServer(&types.MockServer{})
should := &types.MockServer{}
if !reflect.DeepEqual(res, should) {
Expand All @@ -65,7 +65,7 @@ func TestClient_StopServerFail(t *testing.T) {
}

func TestClient_VerifyProvider(t *testing.T) {
client, _ := createClient(true)
client, _ := createMockClient(true)

ms := setupMockServer(true, t)
defer ms.Close()
Expand All @@ -85,7 +85,7 @@ func TestClient_VerifyProvider(t *testing.T) {
}

func TestClient_VerifyProviderFailValidation(t *testing.T) {
client, _ := createClient(true)
client, _ := createMockClient(true)

req := types.VerifyRequest{}
_, err := client.VerifyProvider(req)
Expand All @@ -100,7 +100,7 @@ func TestClient_VerifyProviderFailValidation(t *testing.T) {
}

func TestClient_VerifyProviderFailExecution(t *testing.T) {
client, _ := createClient(false)
client, _ := createMockClient(false)

ms := setupMockServer(true, t)
defer ms.Close()
Expand Down Expand Up @@ -187,9 +187,13 @@ func waitForPortInTest(port int, t *testing.T) {
// but executes actual client code. This means we don't spin up the real
// mock service but execute our code in isolation.
//
// Use this when you want too exercise the client code, but not shell out to Ruby.
// Where possible, you should consider creating a mockClient{} object and
// stubbing out the required behaviour.
//
// Stubbing the exec.Cmd interface is hard, see fakeExec* functions for
// the magic.
func createClient(success bool) (*PactClient, *ServiceMock) {
func createMockClient(success bool) (*PactClient, *ServiceMock) {
execFunc := fakeExecSuccessCommand
if !success {
execFunc = fakeExecFailCommand
Expand Down
17 changes: 17 additions & 0 deletions dsl/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,23 @@ func (m StructMatcher) GetValue() interface{} {
// to also contain complex matchers
type MapMatcher map[string]Matcher

// UnmarshalJSON is a custom JSON parser for MapMatcher
// It treats the matchers as strings
func (m *MapMatcher) UnmarshalJSON(bytes []byte) (err error) {
sk := make(map[string]string)
err = json.Unmarshal(bytes, &sk)
if err != nil {
return
}

*m = make(map[string]Matcher)
for k, v := range sk {
(*m)[k] = String(v)
}

return
}

// Takes an object and converts it to a JSON representation
func objectToString(obj interface{}) string {
switch content := obj.(type) {
Expand Down
57 changes: 57 additions & 0 deletions dsl/mock_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dsl

import (
"errors"

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

// Mock Client for testing the DSL package
type mockClient struct {
}

// StartServer starts a remote Pact Mock Server.
func (p *mockClient) StartServer(args []string, port int) *types.MockServer {
return &types.MockServer{
Pid: 0,
Port: 0,
}
}

// ListServers lists all known Mock Servers
func (p *mockClient) ListServers() []*types.MockServer {
var servers []*types.MockServer

return servers
}

// StopServer stops a remote Pact Mock Server.
func (p *mockClient) StopServer(server *types.MockServer) (*types.MockServer, error) {
return nil, errors.New("failed stopping server")
}

// RemoveAllServers stops all remote Pact Mock Servers.
func (p *mockClient) RemoveAllServers(server *types.MockServer) *[]types.MockServer {
return nil
}

// VerifyProvider runs the verification process against a running Provider.
func (p *mockClient) VerifyProvider(request types.VerifyRequest) (types.ProviderVerifierResponse, error) {
return types.ProviderVerifierResponse{}, nil
}

// UpdateMessagePact adds a pact message to a contract file
func (p *mockClient) UpdateMessagePact(request types.PactMessageRequest) error {
return nil
}

// ReifyMessage takes a structured object, potentially containing nested Matchers
// and returns an object with just the example (generated) content
// The object may be a simple JSON primitive e.g. string or number or a complex object
func (p *mockClient) ReifyMessage(request *types.PactReificationRequest) (res *types.ReificationResponse, err error) {
return &types.ReificationResponse{
Response: map[string]string{
"foo": "bar",
},
}, nil
}
22 changes: 13 additions & 9 deletions dsl/pact.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type Pact struct {
Server *types.MockServer

// Pact RPC Client.
pactClient *PactClient
pactClient Client

// Consumer is the name of the Consumer/Client.
Consumer string
Expand Down Expand Up @@ -157,12 +157,9 @@ func (p *Pact) Setup(startMockServer bool) *Pact {
}

if p.pactClient == nil {
p.pactClient = NewClient()
p.pactClient.TimeoutDuration = p.ClientTimeout
}

if p.PactFileWriteMode == "" {
p.PactFileWriteMode = "overwrite"
c := NewClient()
c.TimeoutDuration = p.ClientTimeout
p.pactClient = c
}

if p.PactFileWriteMode == "" {
Expand Down Expand Up @@ -409,7 +406,7 @@ var checkCliCompatibility = func() {
func stateHandlerMiddleware(stateHandlers types.StateHandlers) proxy.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == "/__setup" {
if r.URL.Path == "/__setup" {
var s *types.ProviderState
decoder := json.NewDecoder(r.Body)
decoder.Decode(&s)
Expand All @@ -435,6 +432,8 @@ func stateHandlerMiddleware(stateHandlers types.StateHandlers) proxy.Middleware
}

log.Println("[DEBUG] skipping state handler for request", r.RequestURI)

// Pass through to application
next.ServeHTTP(w, r)
})
}
Expand All @@ -454,7 +453,12 @@ var messageVerificationHandler = func(messageHandlers MessageHandlers, stateHand
return
}

json.Unmarshal(body, &message)
err = json.Unmarshal(body, &message)

if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}

// Setup any provider state
for _, state := range message.States {
Expand Down
Loading

0 comments on commit 3cd947f

Please sign in to comment.