Skip to content

Commit

Permalink
wip: support message metadata verification
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Jul 6, 2021
1 parent 7c6a10d commit 9599373
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 11 deletions.
6 changes: 3 additions & 3 deletions examples/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ func TestV3MessageProvider(t *testing.T) {

// Map test descriptions to message producer (handlers)
functionMappings := MessageHandlers{
"a user event": func([]ProviderStateV3) (interface{}, error) {
"a user event": func([]ProviderStateV3) (message.MessageBody, message.MessageMetadata, error) {
if user != nil {
return user, nil
return user, nil, nil
} else {
return ProviderStateV3Response{
"message": "not found",
}, nil
}, nil, nil
}
},
}
Expand Down
7 changes: 5 additions & 2 deletions message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import (
"github.com/pact-foundation/pact-go/v2/models"
)

type MessageBody interface{}
type MessageMetadata map[string]interface{}

// MessageHandler is a provider function that generates a
// message for a Consumer given a Message context (state, description etc.)
type MessageHandler func([]models.ProviderStateV3) (interface{}, error)
type MessageHandler func([]models.ProviderStateV3) (MessageBody, MessageMetadata, error)
type MessageProducer MessageHandler

// MessageHandlers is a list of handlers ordered by description
Expand All @@ -29,7 +32,7 @@ type Message struct {
messageHandle *mockserver.Message
messagePactV3 *MessagePactV3

// Type to Marshall content into when sending back to the consumer
// Type to Marshal content into when sending back to the consumer
// Defaults to interface{}
Type interface{}

Expand Down
52 changes: 46 additions & 6 deletions message/message_verifier.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package message

import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -133,13 +134,13 @@ var messageStateHandler = func(messageHandlers MessageHandlers, stateHandlers mo
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")

log.Printf("[TRACE] message state handler")
log.Printf("[TRACE] message state handler %+v", r)

// Extract message
var message messageStateHandlerRequest
body, err := ioutil.ReadAll(r.Body)
r.Body.Close()
log.Printf("[TRACE] message state handler received request: %+s, %s", body, r.URL.Path)
log.Printf("[TRACE] message state handler received request: %s, %s", string(body), r.URL.Path)

if err != nil {
w.WriteHeader(http.StatusBadRequest)
Expand Down Expand Up @@ -188,9 +189,46 @@ var messageStateHandler = func(messageHandlers MessageHandlers, stateHandlers mo

}

w.WriteHeader(http.StatusOK)
// w.WriteHeader(http.StatusOK)
}
}

type messageWithMetadata struct {
Contents []byte `json:"pactMessageContents"`
Metadata MessageMetadata `json:"pactMessageMetadata"`
}

func appendMetadataToResponse(res interface{}, metadata MessageMetadata) ([]byte, error) {
data, err := json.Marshal(res)
if err != nil {
return nil, err
}
withMetadata := &messageWithMetadata{
Contents: data,
Metadata: metadata,
}

return json.Marshal(withMetadata)
}

var PACT_MESSAGE_METADATA_HEADER = "PACT_MESSAGE_METADATA"

func appendMetadataToResponseHeaders(metadata MessageMetadata, w http.ResponseWriter) {
if len(metadata) > 0 {
log.Println("[DEBUG] adding message metadata header", metadata)
json, err := json.Marshal(metadata)
if err != nil {
log.Println("[WARN] invalid metadata", metadata, ". Unable to marshal to JSON:", err)
}
log.Println("[TRACE] encoded metadata to JSON:", string(json))

encoded := base64.StdEncoding.EncodeToString(json)
log.Println("[TRACE] encoded metadata to base64:", encoded)

w.Header().Add(PACT_MESSAGE_METADATA_HEADER, encoded)
}
}

var messageVerificationHandler = func(messageHandlers MessageHandlers, stateHandlers models.StateHandlers) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// TODO: should this be set by the provider itself? How does the metadata go back?
Expand Down Expand Up @@ -226,23 +264,25 @@ var messageVerificationHandler = func(messageHandlers MessageHandlers, stateHand
}

// Execute function handler
res, handlerErr := f(message.States)
res, metadata, handlerErr := f(message.States)

if handlerErr != nil {
w.WriteHeader(http.StatusServiceUnavailable)
return
}

// Write the body back
resBody, errM := json.Marshal(res)
appendMetadataToResponseHeaders(metadata, w)

body, errM := json.Marshal(res)
if errM != nil {
w.WriteHeader(http.StatusServiceUnavailable)
log.Println("[ERROR] error marshalling objcet:", errM)
return
}

w.WriteHeader(http.StatusOK)
w.Write(resBody)
w.Write(body)
}
}

Expand Down

0 comments on commit 9599373

Please sign in to comment.