From 9599373824098f2f4764f783cf6d315f8419daf3 Mon Sep 17 00:00:00 2001 From: Matt Fellows Date: Sun, 4 Jul 2021 21:04:23 +1000 Subject: [PATCH] wip: support message metadata verification --- examples/provider_test.go | 6 ++--- message/message.go | 7 +++-- message/message_verifier.go | 52 ++++++++++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/examples/provider_test.go b/examples/provider_test.go index 9a99cd004..34760631a 100644 --- a/examples/provider_test.go +++ b/examples/provider_test.go @@ -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 } }, } diff --git a/message/message.go b/message/message.go index 11c9d85ea..b1c0e98d4 100644 --- a/message/message.go +++ b/message/message.go @@ -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 @@ -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{} diff --git a/message/message_verifier.go b/message/message_verifier.go index 7918d742b..e8bd0ee8b 100644 --- a/message/message_verifier.go +++ b/message/message_verifier.go @@ -1,6 +1,7 @@ package message import ( + "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -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) @@ -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? @@ -226,7 +264,7 @@ 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) @@ -234,7 +272,9 @@ var messageVerificationHandler = func(messageHandlers MessageHandlers, stateHand } // 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) @@ -242,7 +282,7 @@ var messageVerificationHandler = func(messageHandlers MessageHandlers, stateHand } w.WriteHeader(http.StatusOK) - w.Write(resBody) + w.Write(body) } }