diff --git a/native/addon.cc b/native/addon.cc index f0ff8107..b2cf2c89 100644 --- a/native/addon.cc +++ b/native/addon.cc @@ -52,6 +52,9 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) { exports.Set(Napi::String::New(env, "pactffiMessageWithContents"), Napi::Function::New(env, PactffiMessageWithContents)); exports.Set(Napi::String::New(env, "pactffiMessageWithMetadata"), Napi::Function::New(env, PactffiMessageWithMetadata)); exports.Set(Napi::String::New(env, "pactffiMessageExpectsToReceive"), Napi::Function::New(env, PactffiMessageExpectsToReceive)); + exports.Set(Napi::String::New(env, "pactffiGetAsyncMessageRequestContents"), Napi::Function::New(env, PactffiGetAsyncMessageRequestContents)); + exports.Set(Napi::String::New(env, "pactffiGetSyncMessageRequestContents"), Napi::Function::New(env, PactffiGetSyncMessageRequestContents)); + exports.Set(Napi::String::New(env, "pactffiGetSyncMessageResponseContents"), Napi::Function::New(env, PactffiGetSyncMessageResponseContents)); // Provider exports.Set(Napi::String::New(env, "pactffiVerifierNewForApplication"), Napi::Function::New(env, PactffiVerifierNewForApplication)); diff --git a/native/consumer.cc b/native/consumer.cc index 98b6a5e8..2422be82 100644 --- a/native/consumer.cc +++ b/native/consumer.cc @@ -1895,208 +1895,236 @@ Napi::Value PactffiPluginInteractionContents(const Napi::CallbackInfo& info) { return Napi::Boolean::New(env, res); } -/* -// GetMessageContents retreives the binary contents of the request for a given message -// any matchers are stripped away if given -// if the contents is from a plugin, the byte[] representation of the parsed -// plugin data is returned, again, with any matchers etc. removed -func (m *Message) GetMessageRequestContents() ([]byte, error) { - log.Println("[DEBUG] GetMessageRequestContents") - if m.messageType == MESSAGE_TYPE_ASYNC { - iter := C.pactffi_pact_handle_get_message_iter(m.pact.handle) - log.Println("[DEBUG] pactffi_pact_handle_get_message_iter") - if iter == nil { - return nil, errors.New("unable to get a message iterator") - } - log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - OK") - - /////// - // TODO: some debugging in here to see what's exploding....... - /////// - - log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - len", len(m.server.messages)) - - for i := 0; i < len(m.server.messages); i++ { - log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - index", i) - message := C.pactffi_pact_message_iter_next(iter) - log.Println("[DEBUG] pactffi_pact_message_iter_next - message", message) - - if i == m.index { - log.Println("[DEBUG] pactffi_pact_message_iter_next - index match", message) - - if message == nil { - return nil, errors.New("retreived a null message pointer") - } - - len := C.pactffi_message_get_contents_length(message) - log.Println("[DEBUG] pactffi_message_get_contents_length - len", len) - if len == 0 { - return nil, errors.New("retreived an empty message") - } - data := C.pactffi_message_get_contents_bin(message) - log.Println("[DEBUG] pactffi_message_get_contents_bin - data", data) - if data == nil { - return nil, errors.New("retreived an empty pointer to the message contents") - } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) - - return bytes, nil - } - } - - } else { - iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle) - if iter == nil { - return nil, errors.New("unable to get a message iterator") - } - - for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) - - if i == m.index { - if message == nil { - return nil, errors.New("retreived a null message pointer") - } - - len := C.pactffi_sync_message_get_request_contents_length(message) - if len == 0 { - return nil, errors.New("retreived an empty message") - } - data := C.pactffi_sync_message_get_request_contents_bin(message) - if data == nil { - return nil, errors.New("retreived an empty pointer to the message contents") - } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) - - return bytes, nil - } - } - } - - return nil, errors.New("unable to find the message") -} +/** + * Get the message request contents for an asynchronous message + * + * Retrieves the binary contents of the request for a given message. + * Any matchers are stripped away if given. + * If the contents is from a plugin, the byte[] representation of the parsed + * plugin data is returned, again, with any matchers etc. removed. + * + * * `pact` - Handle to the Pact + * * `message_count` - Number of messages in the pact + * * `message_index` - Index of the message to retrieve (0-based) + * + * Returns a Buffer containing the message contents, or throws an error if the message cannot be found. + * + * C interface: + * + * struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact); + * struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); + * size_t pactffi_message_get_contents_length(Message *message); + * const unsigned char *pactffi_message_get_contents_bin(const Message *message); + */ +Napi::Value PactffiGetAsyncMessageRequestContents(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); -// GetMessageResponseContents retreives the binary contents of the response for a given message -// any matchers are stripped away if given -// if the contents is from a plugin, the byte[] representation of the parsed -// plugin data is returned, again, with any matchers etc. removed -func (m *Message) GetMessageResponseContents() ([][]byte, error) { - - responses := make([][]byte, len(m.server.messages)) - if m.messageType == MESSAGE_TYPE_ASYNC { - return nil, errors.New("invalid request: asynchronous messages do not have response") - } - iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle) - if iter == nil { - return nil, errors.New("unable to get a message iterator") - } - - for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) - - if message == nil { - return nil, errors.New("retreived a null message pointer") - } - - // Get Response body - len := C.pactffi_sync_message_get_response_contents_length(message, C.ulong(i)) - if len == 0 { - return nil, errors.New("retreived an empty message") - } - data := C.pactffi_sync_message_get_response_contents_bin(message, C.ulong(i)) - if data == nil { - return nil, errors.New("retreived an empty pointer to the message contents") - } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) - - responses[i] = bytes - } - - return responses, nil + if (info.Length() < 3) { + throw Napi::Error::New(env, "PactffiGetAsyncMessageRequestContents received < 3 arguments"); + } + + if (!info[0].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetAsyncMessageRequestContents(arg 0) expected a PactHandle (uint16_t)"); + } + + if (!info[1].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetAsyncMessageRequestContents(arg 1) expected a number (message_count)"); + } + + if (!info[2].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetAsyncMessageRequestContents(arg 2) expected a number (message_index)"); + } + + PactHandle pact = info[0].As().Int32Value(); + uint32_t message_count = info[1].As().Uint32Value(); + uint32_t message_index = info[2].As().Uint32Value(); + + struct PactMessageIterator *iter = pactffi_pact_handle_get_message_iter(pact); + if (iter == nullptr) { + throw Napi::Error::New(env, "Unable to get a message iterator"); + } + + for (uint32_t i = 0; i < message_count; i++) { + struct Message *message = pactffi_pact_message_iter_next(iter); + + if (i == message_index) { + if (message == nullptr) { + throw Napi::Error::New(env, "Retrieved a null message pointer"); + } + + size_t len = pactffi_message_get_contents_length(message); + if (len == 0) { + throw Napi::Error::New(env, "Retrieved an empty message"); + } + + const unsigned char *data = pactffi_message_get_contents_bin(message); + if (data == nullptr) { + throw Napi::Error::New(env, "Retrieved an empty pointer to the message contents"); + } + + return Napi::Buffer::Copy(env, data, len); + } + } + + throw Napi::Error::New(env, "Unable to find the message"); } -// StartTransport starts up a mock server on the given address:port for the given transport -// https://docs.rs/pact_ffi/latest/pact_ffi/mock_server/fn.pactffi_create_mock_server_for_transport.html -func (m *MessageServer) StartTransport(transport string, address string, port int, config map[string][]interface{}) (int, error) { - if len(m.messages) == 0 { - return 0, ErrNoInteractions - } - - log.Println("[DEBUG] mock server starting on address:", address, port) - cAddress := C.CString(address) - defer free(cAddress) - - cTransport := C.CString(transport) - defer free(cTransport) - - configJson := stringFromInterface(config) - cConfig := C.CString(configJson) - defer free(cConfig) - - p := C.pactffi_create_mock_server_for_transport(m.messagePact.handle, cAddress, C.int(port), cTransport, cConfig) - - // | Error | Description - // |-------|------------- - // | -1 | An invalid handle was received. Handles should be created with pactffi_new_pact - // | -2 | transport_config is not valid JSON - // | -3 | The mock server could not be started - // | -4 | The method panicked - // | -5 | The address is not valid - msPort := int(p) - switch msPort { - case -1: - return 0, ErrInvalidMockServerConfig - case -2: - return 0, ErrInvalidMockServerConfig - case -3: - return 0, ErrMockServerUnableToStart - case -4: - return 0, ErrMockServerPanic - case -5: - return 0, ErrInvalidAddress - default: - if msPort > 0 { - log.Println("[DEBUG] mock server running on port:", msPort) - return msPort, nil - } - return msPort, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", msPort) - } +/** + * Get the message request contents for a synchronous message + * + * Retrieves the binary contents of the request for a given synchronous message. + * Any matchers are stripped away if given. + * If the contents is from a plugin, the byte[] representation of the parsed + * plugin data is returned, again, with any matchers etc. removed. + * + * * `pact` - Handle to the Pact + * * `message_count` - Number of messages in the pact + * * `message_index` - Index of the message to retrieve (0-based) + * + * Returns a Buffer containing the message contents, or throws an error if the message cannot be found. + * + * C interface: + * + * struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact); + * struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); + * size_t pactffi_sync_message_get_request_contents_length(SynchronousMessage *message); + * const unsigned char *pactffi_sync_message_get_request_contents_bin(SynchronousMessage *message); + */ +Napi::Value PactffiGetSyncMessageRequestContents(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + if (info.Length() < 3) { + throw Napi::Error::New(env, "PactffiGetSyncMessageRequestContents received < 3 arguments"); + } + + if (!info[0].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageRequestContents(arg 0) expected a PactHandle (uint16_t)"); + } + + if (!info[1].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageRequestContents(arg 1) expected a number (message_count)"); + } + + if (!info[2].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageRequestContents(arg 2) expected a number (message_index)"); + } + + PactHandle pact = info[0].As().Int32Value(); + uint32_t message_count = info[1].As().Uint32Value(); + uint32_t message_index = info[2].As().Uint32Value(); + + struct PactSyncMessageIterator *iter = pactffi_pact_handle_get_sync_message_iter(pact); + if (iter == nullptr) { + throw Napi::Error::New(env, "Unable to get a sync message iterator"); + } + + for (uint32_t i = 0; i < message_count; i++) { + struct SynchronousMessage *message = pactffi_pact_sync_message_iter_next(iter); + + if (i == message_index) { + if (message == nullptr) { + throw Napi::Error::New(env, "Retrieved a null message pointer"); + } + + size_t len = pactffi_sync_message_get_request_contents_length(message); + if (len == 0) { + throw Napi::Error::New(env, "Retrieved an empty message"); + } + + const unsigned char *data = pactffi_sync_message_get_request_contents_bin(message); + if (data == nullptr) { + throw Napi::Error::New(env, "Retrieved an empty pointer to the message contents"); + } + + return Napi::Buffer::Copy(env, data, len); + } + } + + throw Napi::Error::New(env, "Unable to find the message"); } -// Get the length of the request contents of a `SynchronousMessage`. -size_t pactffi_sync_message_get_request_contents_length(SynchronousMessage *message); -struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact); -struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); +/** + * Get the message response contents for synchronous messages + * + * Retrieves the binary contents of all responses for a given synchronous message. + * Any matchers are stripped away if given. + * If the contents is from a plugin, the byte[] representation of the parsed + * plugin data is returned, again, with any matchers etc. removed. + * + * * `pact` - Handle to the Pact + * * `message_count` - Number of messages in the pact + * * `message_index` - Index of the message to retrieve (0-based) + * + * Returns an array of Buffers containing all the message response contents, or throws an error if the message cannot be found. + * + * C interface: + * + * struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact); + * struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); + * size_t pactffi_sync_message_get_number_responses(const SynchronousMessage *message); + * size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, size_t index); + * const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, size_t index); + */ +Napi::Value PactffiGetSyncMessageResponseContents(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + if (info.Length() < 3) { + throw Napi::Error::New(env, "PactffiGetSyncMessageResponseContents received < 3 arguments"); + } + + if (!info[0].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageResponseContents(arg 0) expected a PactHandle (uint16_t)"); + } + + if (!info[1].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageResponseContents(arg 1) expected a number (message_count)"); + } + + if (!info[2].IsNumber()) { + throw Napi::Error::New(env, "PactffiGetSyncMessageResponseContents(arg 2) expected a number (message_index)"); + } -// Async -// Get the length of the contents of a `Message`. -size_t pactffi_message_get_contents_length(Message *message); + PactHandle pact = info[0].As().Int32Value(); + uint32_t message_count = info[1].As().Uint32Value(); + uint32_t message_index = info[2].As().Uint32Value(); -// Get the contents of a `Message` as a pointer to an array of bytes. -const unsigned char *pactffi_message_get_contents_bin(const Message *message); -struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact); -struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); + struct PactSyncMessageIterator *iter = pactffi_pact_handle_get_sync_message_iter(pact); + if (iter == nullptr) { + throw Napi::Error::New(env, "Unable to get a sync message iterator"); + } -// Need the index of the body to get -const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, size_t index); -size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, size_t index); + for (uint32_t i = 0; i < message_count; i++) { + struct SynchronousMessage *message = pactffi_pact_sync_message_iter_next(iter); + + if (i == message_index) { + if (message == nullptr) { + throw Napi::Error::New(env, "Retrieved a null message pointer"); + } -// Sync -// Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes. -// The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`. -const unsigned char *pactffi_sync_message_get_request_contents_bin(SynchronousMessage *message); -// Set Sync message request body - non binary -void pactffi_sync_message_set_request_contents(InteractionHandle *message, const char *contents, const char *content_type); + size_t num_responses = pactffi_sync_message_get_number_responses(message); + if (num_responses == 0) { + throw Napi::Error::New(env, "Retrieved a message with no responses"); + } -// Set Sync message request body - binary -void pactffi_sync_message_set_request_contents_bin(InteractionHandle *message, const unsigned char *contents, size_t len, const char *content_type); + Napi::Array responses = Napi::Array::New(env, num_responses); -// Set sync message response contents - non binary -void pactffi_sync_message_set_response_contents(InteractionHandle *message, size_t index, const char *contents, const char *content_type); + for (size_t response_index = 0; response_index < num_responses; response_index++) { + size_t len = pactffi_sync_message_get_response_contents_length(message, response_index); + if (len == 0) { + throw Napi::Error::New(env, "Retrieved an empty response"); + } -// Set sync message response contents - binary -void pactffi_sync_message_set_response_contents_bin(InteractionHandle *message, size_t index, const unsigned char *contents, size_t len, const char *content_type); -*/ \ No newline at end of file + const unsigned char *data = pactffi_sync_message_get_response_contents_bin(message, response_index); + if (data == nullptr) { + throw Napi::Error::New(env, "Retrieved an empty pointer to the response contents"); + } + + responses[response_index] = Napi::Buffer::Copy(env, data, len); + } + + return responses; + } + } + + throw Napi::Error::New(env, "Unable to find the message"); +} diff --git a/native/consumer.h b/native/consumer.h index 1f7f2441..b0b7e00e 100644 --- a/native/consumer.h +++ b/native/consumer.h @@ -41,6 +41,9 @@ Napi::Value PactffiMessageWithBinaryContents(const Napi::CallbackInfo& info); Napi::Value PactffiMessageWithMetadata(const Napi::CallbackInfo& info); Napi::Value PactffiMessageExpectsToReceive(const Napi::CallbackInfo& info); Napi::Value PactffiWriteMessagePactFile(const Napi::CallbackInfo& info); +Napi::Value PactffiGetAsyncMessageRequestContents(const Napi::CallbackInfo& info); +Napi::Value PactffiGetSyncMessageRequestContents(const Napi::CallbackInfo& info); +Napi::Value PactffiGetSyncMessageResponseContents(const Napi::CallbackInfo& info); // Plugins Napi::Value PactffiUsingPlugin(const Napi::CallbackInfo& info); @@ -125,4 +128,4 @@ Napi::Value PactffiSyncMessageGetResponseContents(const Napi::CallbackInfo& info Napi::Value PactffiSyncMessageGetResponseContentsBin(const Napi::CallbackInfo& info); Napi::Value PactffiSyncMessageGetResponseContentsLength(const Napi::CallbackInfo& info); Napi::Value PactffiSyncMessageSetDescription(const Napi::CallbackInfo& info); -Napi::Value PactffiCreateMockServerForTransport(const Napi::CallbackInfo& info); +Napi::Value PactffiCreateMockServerForTransport(const Napi::CallbackInfo& info); \ No newline at end of file diff --git a/src/consumer/index.ts b/src/consumer/index.ts index ed7b3d46..fad244e1 100644 --- a/src/consumer/index.ts +++ b/src/consumer/index.ts @@ -24,7 +24,15 @@ import { import { getFfiLib } from '../ffi'; import { mockServerMismatches, writePact } from './internals'; -const asyncMessage = (ffi: Ffi, interactionPtr: number) => ({ +const asyncMessage = ( + ffi: Ffi, + interactionPtr: number, + pactPtr: number, + messageCount: number, + index: number +) => ({ + // todo count the number of messages (and ref them?) + // Required to get contents withPluginRequestInteractionContents: ( contentType: string, contents: string @@ -56,6 +64,8 @@ const asyncMessage = (ffi: Ffi, interactionPtr: number) => ({ reifyMessage: () => ffi.pactffiMessageReify(interactionPtr), withMetadata: (name: string, value: string) => ffi.pactffiMessageWithMetadata(interactionPtr, name, value), + getRequestContents: () => + ffi.pactffiGetAsyncMessageRequestContents(pactPtr, messageCount, index), }); export const makeConsumerPact = ( @@ -69,6 +79,9 @@ export const makeConsumerPact = ( setLogLevel(logLevel); } const ffi = getFfiLib(logLevel, logFile); + // We need to track the number of messages so that we can + // correctly reference them when extracting contents + let messageCount = 0; const pactPtr = ffi.pactffiNewPact(consumer, provider); if (!ffi.pactffiWithSpecification(pactPtr, version)) { @@ -137,12 +150,15 @@ export const makeConsumerPact = ( ffi.pactffiWithPactMetadata(pactPtr, namespace, name, value), newAsynchronousMessage: (description: string): AsynchronousMessage => { const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description); + const index = messageCount; + messageCount += 1; - return asyncMessage(ffi, interactionPtr); + return asyncMessage(ffi, interactionPtr, pactPtr, messageCount, index); }, newSynchronousMessage: (description: string): SynchronousMessage => { - // TODO: will this automatically set the correct spec version? const interactionPtr = ffi.pactffiNewSyncMessage(pactPtr, description); + const index = messageCount; + messageCount += 1; return { withPluginRequestInteractionContents: ( @@ -218,6 +234,18 @@ export const makeConsumerPact = ( ), withMetadata: (name: string, value: string) => ffi.pactffiMessageWithMetadata(interactionPtr, name, value), + getRequestContents: () => + ffi.pactffiGetSyncMessageRequestContents( + pactPtr, + messageCount, + index + ), + getResponseContents: () => + ffi.pactffiGetSyncMessageResponseContents( + pactPtr, + messageCount, + index + ), }; }, pactffiCreateMockServerForTransport( @@ -378,6 +406,9 @@ export const makeConsumerMessagePact = ( setLogLevel(logLevel); } const ffi = getFfiLib(logLevel, logFile); + // We need to track the number of messages so that we can + // correctly reference them when extracting contents + let messageCount = 0; const pactPtr = ffi.pactffiNewPact(consumer, provider); if (!ffi.pactffiWithSpecification(pactPtr, version) || version < 4) { @@ -407,15 +438,22 @@ export const makeConsumerMessagePact = ( // Alias for newAsynchronousMessage newMessage: (description: string): AsynchronousMessage => { const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description); + const index = messageCount; + messageCount += 1; - return asyncMessage(ffi, interactionPtr); + return asyncMessage(ffi, interactionPtr, pactPtr, messageCount, index); }, newAsynchronousMessage: (description: string): AsynchronousMessage => { const interactionPtr = ffi.pactffiNewAsyncMessage(pactPtr, description); + const index = messageCount; + messageCount += 1; - return asyncMessage(ffi, interactionPtr); + return asyncMessage(ffi, interactionPtr, pactPtr, messageCount, index); }, newSynchronousMessage: (description: string): SynchronousMessage => { + const index = messageCount; + messageCount += 1; + // TODO: will this automatically set the correct spec version? const interactionPtr = ffi.pactffiNewSyncMessage(pactPtr, description); @@ -493,6 +531,18 @@ export const makeConsumerMessagePact = ( ), withMetadata: (name: string, value: string) => ffi.pactffiMessageWithMetadata(interactionPtr, name, value), + getRequestContents: () => + ffi.pactffiGetSyncMessageRequestContents( + pactPtr, + messageCount, + index + ), + getResponseContents: () => + ffi.pactffiGetSyncMessageResponseContents( + pactPtr, + messageCount, + index + ), }; }, pactffiCreateMockServerForTransport( diff --git a/src/consumer/types.ts b/src/consumer/types.ts index bb8c4f9a..63bd2eef 100644 --- a/src/consumer/types.ts +++ b/src/consumer/types.ts @@ -240,6 +240,7 @@ export type AsynchronousMessage = RequestPluginInteraction & { withContents: (body: string, contentType: string) => void; withBinaryContents: (body: Buffer, contentType: string) => void; reifyMessage: () => string; + getRequestContents: () => Buffer; }; export type ConsumerMessage = AsynchronousMessage; @@ -253,9 +254,8 @@ export type SynchronousMessage = PluginInteraction & { withResponseContents: (body: string, contentType: string) => void; withRequestBinaryContents: (body: Buffer, contentType: string) => void; withResponseBinaryContents: (body: Buffer, contentType: string) => void; - // TODO: need a type to return the contents back to the test - // reify could be the way to do it - // reifyMessage: () => string; + getRequestContents: () => Buffer; + getResponseContents: () => Buffer[]; }; export type ConsumerMessagePact = PluginPact & { diff --git a/src/ffi/types.ts b/src/ffi/types.ts index 8db460ce..2a90268f 100644 --- a/src/ffi/types.ts +++ b/src/ffi/types.ts @@ -304,6 +304,43 @@ export type FfiConsumerFunctions = { value: string ): void; pactffiMessageReify(handle: FfiMessageHandle): string; + pactffiGetAsyncMessageRequestContents( + pact: FfiPactHandle, + messageCount: number, + messageIndex: number + ): Buffer; + pactffiGetSyncMessageRequestContents( + pact: FfiPactHandle, + messageCount: number, + messageIndex: number + ): Buffer; + pactffiGetSyncMessageResponseContents( + pact: FfiPactHandle, + messageCount: number, + messageIndex: number + ): Buffer[]; + // pactffiSyncMessageSetRequestContents( + // message: FfiInteractionHandle, + // contents: string, + // contentType: string + // ): void; + // pactffiSyncMessageSetRequestContentsBin( + // message: FfiInteractionHandle, + // contents: Buffer, + // contentType: string + // ): void; + // pactffiSyncMessageSetResponseContents( + // message: FfiInteractionHandle, + // index: number, + // contents: string, + // contentType: string + // ): void; + // pactffiSyncMessageSetResponseContentsBin( + // message: FfiInteractionHandle, + // index: number, + // contents: Buffer, + // contentType: string + // ): void; }; export type FfiVerificationFunctions = { diff --git a/test/message.integration.spec.ts b/test/message.integration.spec.ts index 429eb1a6..877f5398 100644 --- a/test/message.integration.spec.ts +++ b/test/message.integration.spec.ts @@ -5,7 +5,6 @@ import * as rimraf from 'rimraf'; import zlib = require('zlib'); import { load } from '@grpc/proto-loader'; import * as grpc from '@grpc/grpc-js'; - import { ConsumerMessagePact, makeConsumerMessagePact } from '../src'; import { FfiSpecificationVersion } from '../src/ffi/types'; import { setLogLevel } from '../src/logger'; @@ -117,14 +116,20 @@ describe('FFI integration test for the Message Consumer API', () => { 'application/json' ); message.withResponseContents( - JSON.stringify({ foo: 'bar' }), + JSON.stringify({ baz: 'bat' }), + 'application/json' + ); + message.withResponseContents( + JSON.stringify({ qux: 'quux' }), 'application/json' ); message.withMetadata('meta-key', 'meta-val'); - - // const reified = message.reifyMessage(); - - // expect(JSON.parse(reified).contents).to.have.property('foo', 'bar'); + const request = message.getRequestContents().toString(); + const response = message.getResponseContents()[0].toString(); + const response2 = message.getResponseContents()[1].toString(); + expect(JSON.parse(request)).to.deep.eq({ foo: 'bar' }); + expect(JSON.parse(response)).to.deep.eq({ baz: 'bat' }); + expect(JSON.parse(response2)).to.deep.eq({ qux: 'quux' }); pact.writePactFile(path.join(__dirname, '__testoutput__')); });