Skip to content

Commit

Permalink
feat(messages): implement initial producer and consumer interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Mar 25, 2018
1 parent fe43204 commit 4089f19
Show file tree
Hide file tree
Showing 19 changed files with 577 additions and 41 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ _*
pact-go
pacts
logs
log
tmp

# IDE
.vscode
26 changes: 26 additions & 0 deletions client/message_verification_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package client

import (
"log"
)

// MessageVerificationService is a wrapper for the Pact Provider Verifier Service.
type MessageVerificationService struct {
ServiceManager
}

// NewService creates a new MessageVerificationService with default settings.
// Named Arguments allowed:
// --consumer
// --provider
// --pact-dir
func (v *MessageVerificationService) NewService(args []string) Service {
v.Args = args
// Currently has an issue, see https://travis-ci.org/pact-foundation/pact-message-ruby/builds/357675751
// v.Args = []string{"update", `{ "description": "a test mesage", "content": { "name": "Mary" } }`, "--consumer", "from", "--provider", "golang", "--pact-dir", "/tmp"}

log.Printf("[DEBUG] starting message service with args: %v\n", v.Args)
v.Cmd = "pact-message"

return v
}
1 change: 1 addition & 0 deletions client/verification_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func (v *VerificationService) NewService(args []string) Service {

v.Args = args
v.Cmd = getVerifierCommandPath()

return v
}

Expand Down
15 changes: 0 additions & 15 deletions command/install_test.go

This file was deleted.

55 changes: 53 additions & 2 deletions dsl/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
type PactClient struct {
pactMockSvcManager client.Service
verificationSvcManager client.Service
messageSvcManager client.Service

// Track mock servers
Servers []MockService
Expand All @@ -37,17 +38,24 @@ type PactClient struct {
Address string
}

// NewClient creates a new Pact client manager
func NewClient(MockServiceManager client.Service, verificationServiceManager client.Service) *PactClient {
// newClient creates a new Pact client manager with the provided services
func newClient(MockServiceManager client.Service, verificationServiceManager client.Service, messageServiceManager client.Service) *PactClient {
MockServiceManager.Setup()
verificationServiceManager.Setup()
messageServiceManager.Setup()

return &PactClient{
pactMockSvcManager: MockServiceManager,
verificationSvcManager: verificationServiceManager,
messageSvcManager: messageServiceManager,
}
}

// NewClient creates a new Pact client manager with defaults
func NewClient() *PactClient {
return newClient(&client.MockService{}, &client.VerificationService{}, &client.MessageVerificationService{})
}

// StartServer starts a remote Pact Mock Server.
func (p *PactClient) StartServer(args []string, port int) *types.MockServer {
log.Println("[DEBUG] client: starting a server with args:", args, "port:", port)
Expand Down Expand Up @@ -166,6 +174,49 @@ func (p *PactClient) VerifyProvider(request types.VerifyRequest) (types.Provider
return response, fmt.Errorf("error verifying provider: %s\n\nSTDERR:\n%s\n\nSTDOUT:\n%s", err, stdErr, stdOut)
}

// UpdateMessagePact adds a pact message to a contract file
func (p *PactClient) UpdateMessagePact(request types.PactMessageRequest) error {
log.Println("[DEBUG] client: adding pact message...")

// Convert request into flags, and validate request
err := request.Validate()
if err != nil {
return err
}

svc := p.messageSvcManager.NewService(request.Args)
cmd := svc.Command()

stdOutPipe, err := cmd.StdoutPipe()
if err != nil {
return err
}
stdErrPipe, err := cmd.StderrPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}
stdOut, err := ioutil.ReadAll(stdOutPipe)
if err != nil {
return err
}
stdErr, err := ioutil.ReadAll(stdErrPipe)
if err != nil {
return err
}

err = cmd.Wait()

if err == nil {
return nil
}

return fmt.Errorf("error creating message: %s\n\nSTDERR:\n%s\n\nSTDOUT:\n%s", err, stdErr, stdOut)
}

// Get a port given a URL
func getPort(rawURL string) int {
parsedURL, err := url.Parse(rawURL)
Expand Down
2 changes: 1 addition & 1 deletion dsl/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func createClient(success bool) (*PactClient, *ServiceMock) {
}
}()

d := NewClient(svc, svc)
d := newClient(svc, svc, svc)
return d, svc
}

Expand Down
12 changes: 2 additions & 10 deletions dsl/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,7 @@ func (m Matcher) MarshalJSON() ([]byte, error) {

// UnmarshalJSON is a custom decoder for Header type
func (m *Matcher) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &m); err != nil {
return err
}

return nil
return json.Unmarshal(data, &m)
}

// MapMatcher allows a map[string]string-like object
Expand All @@ -199,11 +195,7 @@ func (h MapMatcher) MarshalJSON() ([]byte, error) {

// UnmarshalJSON is a custom decoder for Header type
func (h *MapMatcher) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &h); err != nil {
return err
}

return nil
return json.Unmarshal(data, &h)
}

// Takes an object and converts it to a JSON representation
Expand Down
50 changes: 50 additions & 0 deletions dsl/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dsl

// Message is a representation of a single, unidirectional message
// e.g. MQ, pub/sub, Websocket, Lambda
// Message is the main implementation of the Pact Message interface.
type Message struct {
// Message Body
Content interface{} `json:"content,omitempty"`

// Provider state to be written into the Pact file
State string `json:"providerState,omitempty"`

// Message metadata
Metadata MapMatcher `json:"metadata,omitempty"`

// Description to be written into the Pact file
Description string `json:"description"`

Args []string `json:"-"`
}

// Given specifies a provider state. Optional.
func (p *Message) Given(state string) *Message {
p.State = state
return p
}

// ExpectsToReceive specifies the content it is expecting to be
// given from the Provider. The function must be able to handle this
// message for the interaction to succeed.
func (p *Message) ExpectsToReceive(description string) *Message {
p.Description = description
return p
}

// WithMetadata specifies message-implementation specific metadata
// to go with the content
func (p *Message) WithMetadata(metadata MapMatcher) *Message {
p.Metadata = metadata
return p
}

// WithContent specifies the details of the HTTP request that will be used to
// confirm that the Provider provides an API listening on the given interface.
// Mandatory.
func (p *Message) WithContent(content interface{}) *Message {
p.Content = toObject(content)

return p
}
Loading

0 comments on commit 4089f19

Please sign in to comment.