• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pact-foundation / pact-go / 5141396736

pending completion
5141396736

push

github

mefellows
fix: set specification version on v4 message types

2 of 5 new or added lines in 3 files covered. (40.0%)

1843 of 4917 relevant lines covered (37.48%)

5.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.18
/internal/native/message_server.go
1
package native
2

3
/*
4
// Library headers
5
#include <stdlib.h>
6
#include <stdint.h>
7
typedef int bool;
8
#define true 1
9
#define false 0
10

11
/// Wraps a Pact model struct
12
typedef struct InteractionHandle InteractionHandle;
13
typedef struct PactMessageIterator PactMessageIterator;
14
typedef struct SynchronousMessage SynchronousMessage;
15
typedef struct Message Message;
16

17
struct InteractionHandle {
18
        unsigned int interaction_ref;
19
};
20

21
/// Wraps a Pact model struct
22
typedef struct PactHandle PactHandle;
23
struct PactHandle {
24
        unsigned int pact_ref;
25
};
26

27
PactHandle pactffi_new_message_pact(const char *consumer_name, const char *provider_name);
28
InteractionHandle pactffi_new_message(PactHandle pact, const char *description);
29
// Creates a new synchronous message interaction (request/response) and return a handle to it
30
InteractionHandle pactffi_new_sync_message_interaction(PactHandle pact, const char *description);
31
// Creates a new asynchronous message interaction (request/response) and return a handle to it
32
InteractionHandle pactffi_new_message_interaction(PactHandle pact, const char *description);
33
void pactffi_message_expects_to_receive(InteractionHandle message, const char *description);
34
void pactffi_message_given(InteractionHandle message, const char *description);
35
void pactffi_message_given_with_param(InteractionHandle message, const char *description, const char *name, const char *value);
36
void pactffi_message_with_contents(InteractionHandle message, const char *content_type, const char *body, int size);
37
void pactffi_message_with_metadata(InteractionHandle message, const char *key, const char *value);
38
int pactffi_write_message_pact_file(PactHandle pact, const char *directory, bool overwrite);
39
void pactffi_with_message_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value);
40
int pactffi_write_pact_file(int mock_server_port, const char *directory, bool overwrite);
41
bool pactffi_given(InteractionHandle interaction, const char *description);
42
bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value);
43
void pactffi_with_specification(PactHandle pact, int specification_version);
44

45
int pactffi_using_plugin(PactHandle pact, const char *plugin_name, const char *plugin_version);
46
void pactffi_cleanup_plugins(PactHandle pact);
47
int pactffi_interaction_contents(InteractionHandle interaction, int interaction_part, const char *content_type, const char *contents);
48

49
// Create a mock server for the provided Pact handle and transport.
50
int pactffi_create_mock_server_for_transport(PactHandle pact, const char *addr, int port, const char *transport, const char *transport_config);
51
bool pactffi_cleanup_mock_server(int mock_server_port);
52
char* pactffi_mock_server_mismatches(int mock_server_port);
53
bool pactffi_mock_server_matched(int mock_server_port);
54

55
// Functions to get message contents
56

57
// Get the length of the request contents of a `SynchronousMessage`.
58
size_t pactffi_sync_message_get_request_contents_length(SynchronousMessage *message);
59
struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact);
60
struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter);
61

62
// Async
63
// Get the length of the contents of a `Message`.
64
size_t pactffi_message_get_contents_length(Message *message);
65

66
//  Get the contents of a `Message` as a pointer to an array of bytes.
67
const unsigned char *pactffi_message_get_contents_bin(const Message *message);
68
struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact);
69
struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter);
70

71
// Need the index of the body to get
72
const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, size_t index);
73
size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, size_t index);
74

75
// Sync
76
// Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes.
77
// The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`.
78
const unsigned char *pactffi_sync_message_get_request_contents_bin(SynchronousMessage *message);
79
// Set Sync message request body - non binary
80
void pactffi_sync_message_set_request_contents(InteractionHandle *message, const char *contents, const char *content_type);
81

82
// Set Sync message request body - binary
83
void pactffi_sync_message_set_request_contents_bin(InteractionHandle *message, const unsigned char *contents, size_t len, const char *content_type);
84

85
// Set sync message response contents - non binary
86
void pactffi_sync_message_set_response_contents(InteractionHandle *message, size_t index, const char *contents, const char *content_type);
87

88
// Set sync message response contents - binary
89
void pactffi_sync_message_set_response_contents_bin(InteractionHandle *message, size_t index, const unsigned char *contents, size_t len, const char *content_type);
90

91
// Can be used instead of the above as a general abstraction for non-binary bodies
92
bool pactffi_with_body(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body);
93

94
// Can be used instead of the above as a general abstraction for binary bodies
95
// bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const uint8_t *body, size_t size);
96
bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, int size);
97
*/
98
import "C"
99

100
import (
101
        "encoding/json"
102
        "errors"
103
        "fmt"
104
        "log"
105
        "unsafe"
106
)
107

108
type MessagePact struct {
109
        handle C.PactHandle
110
}
111

112
type messageType int
113

114
const (
115
        MESSAGE_TYPE_ASYNC messageType = iota
116
        MESSAGE_TYPE_SYNC
117
)
118

119
type Message struct {
120
        handle      C.InteractionHandle
121
        messageType messageType
122
        pact        *MessagePact
123
        index       int
124
        server      *MessageServer
125
}
126

127
// MessageServer is the public interface for managing the message based interface
128
type MessageServer struct {
129
        messagePact *MessagePact
130
        messages    []*Message
131
}
132

133
// NewMessage initialises a new message for the current contract
134
func NewMessageServer(consumer string, provider string) *MessageServer {
24✔
135
        cConsumer := C.CString(consumer)
24✔
136
        cProvider := C.CString(provider)
24✔
137
        defer free(cConsumer)
24✔
138
        defer free(cProvider)
24✔
139

24✔
140
        return &MessageServer{messagePact: &MessagePact{handle: C.pactffi_new_message_pact(cConsumer, cProvider)}}
24✔
141
}
24✔
142

143
// Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version
144
func (m *MessageServer) WithMetadata(namespace, k, v string) *MessageServer {
3✔
145
        cNamespace := C.CString(namespace)
3✔
146
        defer free(cNamespace)
3✔
147
        cName := C.CString(k)
3✔
148
        defer free(cName)
3✔
149
        cValue := C.CString(v)
3✔
150
        defer free(cValue)
3✔
151

3✔
152
        C.pactffi_with_message_pact_metadata(m.messagePact.handle, cNamespace, cName, cValue)
3✔
153

3✔
154
        return m
3✔
155
}
3✔
156

157
// NewMessage initialises a new message for the current contract
158
// Deprecated: use NewAsyncMessageInteraction instead
159
func (m *MessageServer) NewMessage() *Message {
12✔
160
        // Alias
12✔
161
        return m.NewAsyncMessageInteraction("")
12✔
162
}
12✔
163

164
// NewSyncMessageInteraction initialises a new synchronous message interaction for the current contract
165
func (m *MessageServer) NewSyncMessageInteraction(description string) *Message {
9✔
166
        cDescription := C.CString(description)
9✔
167
        defer free(cDescription)
9✔
168

9✔
169
        i := &Message{
9✔
170
                handle:      C.pactffi_new_sync_message_interaction(m.messagePact.handle, cDescription),
9✔
171
                messageType: MESSAGE_TYPE_SYNC,
9✔
172
                pact:        m.messagePact,
9✔
173
                index:       len(m.messages),
9✔
174
                server:      m,
9✔
175
        }
9✔
176
        m.messages = append(m.messages, i)
9✔
177

9✔
178
        return i
9✔
179
}
9✔
180

181
// NewAsyncMessageInteraction initialises a new asynchronous message interaction for the current contract
182
func (m *MessageServer) NewAsyncMessageInteraction(description string) *Message {
15✔
183
        cDescription := C.CString(description)
15✔
184
        defer free(cDescription)
15✔
185

15✔
186
        i := &Message{
15✔
187
                handle:      C.pactffi_new_message_interaction(m.messagePact.handle, cDescription),
15✔
188
                messageType: MESSAGE_TYPE_ASYNC,
15✔
189
                pact:        m.messagePact,
15✔
190
                index:       len(m.messages),
15✔
191
                server:      m,
15✔
192
        }
15✔
193
        m.messages = append(m.messages, i)
15✔
194

15✔
195
        return i
15✔
196
}
15✔
197

NEW
198
func (m *MessageServer) WithSpecificationVersion(version specificationVersion) {
×
NEW
199
        C.pactffi_with_specification(m.messagePact.handle, C.int(version))
×
NEW
200
}
×
201

202
func (m *Message) Given(state string) *Message {
24✔
203
        cState := C.CString(state)
24✔
204
        defer free(cState)
24✔
205

24✔
206
        C.pactffi_given(m.handle, cState)
24✔
207

24✔
208
        return m
24✔
209
}
24✔
210

211
func (m *Message) GivenWithParameter(state string, params map[string]interface{}) *Message {
15✔
212
        cState := C.CString(state)
15✔
213
        defer free(cState)
15✔
214

15✔
215
        if len(params) == 0 {
15✔
216
                cState := C.CString(state)
×
217
                defer free(cState)
×
218

×
219
                C.pactffi_given(m.handle, cState)
×
220
        } else {
15✔
221
                for k, v := range params {
30✔
222
                        cKey := C.CString(k)
15✔
223
                        defer free(cKey)
15✔
224
                        param := stringFromInterface(v)
15✔
225
                        cValue := C.CString(param)
15✔
226
                        defer free(cValue)
15✔
227

15✔
228
                        C.pactffi_given_with_param(m.handle, cState, cKey, cValue)
15✔
229

15✔
230
                }
15✔
231
        }
232

233
        return m
15✔
234
}
235

236
func (m *Message) ExpectsToReceive(description string) *Message {
15✔
237
        cDescription := C.CString(description)
15✔
238
        defer free(cDescription)
15✔
239

15✔
240
        C.pactffi_message_expects_to_receive(m.handle, cDescription)
15✔
241

15✔
242
        return m
15✔
243
}
15✔
244

245
func (m *Message) WithMetadata(valueOrMatcher map[string]string) *Message {
15✔
246
        for k, v := range valueOrMatcher {
30✔
247

15✔
248
                cName := C.CString(k)
15✔
249
                defer free(cName)
15✔
250

15✔
251
                // TODO: check if matching rules allowed here
15✔
252
                // value := stringFromInterface(v)
15✔
253
                // fmt.Printf("withheaders, sending: %+v \n\n", value)
15✔
254
                // cValue := C.CString(value)
15✔
255
                cValue := C.CString(v)
15✔
256
                defer free(cValue)
15✔
257

15✔
258
                C.pactffi_message_with_metadata(m.handle, cName, cValue)
15✔
259
        }
15✔
260

261
        return m
15✔
262
}
263

264
func (m *Message) WithRequestBinaryContents(body []byte) *Message {
×
265
        cHeader := C.CString("application/octet-stream")
×
266
        defer free(cHeader)
×
267

×
268
        // TODO: handle response
×
269
        res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body)))
×
270

×
271
        log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res))
×
272

×
273
        return m
×
274
}
×
275
func (m *Message) WithRequestBinaryContentType(contentType string, body []byte) *Message {
3✔
276
        cHeader := C.CString(contentType)
3✔
277
        defer free(cHeader)
3✔
278

3✔
279
        // TODO: handle response
3✔
280
        res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body)))
3✔
281

3✔
282
        log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res))
3✔
283

3✔
284
        return m
3✔
285
}
3✔
286

287
func (m *Message) WithRequestJSONContents(body interface{}) *Message {
6✔
288
        value := stringFromInterface(body)
6✔
289

6✔
290
        log.Println("[DEBUG] message WithJSONContents", value)
6✔
291

6✔
292
        return m.WithContents(INTERACTION_PART_REQUEST, "application/json", []byte(value))
6✔
293
}
6✔
294

295
func (m *Message) WithResponseBinaryContents(body []byte) *Message {
×
296
        cHeader := C.CString("application/octet-stream")
×
297
        defer free(cHeader)
×
298

×
299
        // TODO: handle response
×
300
        C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_RESPONSE), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body)))
×
301

×
302
        return m
×
303
}
×
304

305
func (m *Message) WithResponseJSONContents(body interface{}) *Message {
3✔
306
        value := stringFromInterface(body)
3✔
307

3✔
308
        log.Println("[DEBUG] message WithJSONContents", value)
3✔
309

3✔
310
        return m.WithContents(INTERACTION_PART_RESPONSE, "application/json", []byte(value))
3✔
311
}
3✔
312

313
// TODO: note that string values here must be NUL terminated.
314
// Only accepts JSON
315
func (m *Message) WithContents(part interactionPart, contentType string, body []byte) *Message {
12✔
316
        cHeader := C.CString(contentType)
12✔
317
        defer free(cHeader)
12✔
318

12✔
319
        res := C.pactffi_with_body(m.handle, C.int(part), cHeader, (*C.char)(unsafe.Pointer(&body[0])))
12✔
320
        log.Println("[DEBUG] response from pactffi_interaction_contents", (int(res) == 1))
12✔
321

12✔
322
        return m
12✔
323
}
12✔
324

325
// TODO: migrate plugin code to shared struct/code?
326

327
// NewInteraction initialises a new interaction for the current contract
328
func (m *MessageServer) UsingPlugin(pluginName string, pluginVersion string) error {
9✔
329
        cPluginName := C.CString(pluginName)
9✔
330
        defer free(cPluginName)
9✔
331
        cPluginVersion := C.CString(pluginVersion)
9✔
332
        defer free(cPluginVersion)
9✔
333

9✔
334
        r := C.pactffi_using_plugin(m.messagePact.handle, cPluginName, cPluginVersion)
9✔
335

9✔
336
        // 1 - A general panic was caught.
9✔
337
        // 2 - Failed to load the plugin.
9✔
338
        // 3 - Pact Handle is not valid.
9✔
339
        res := int(r)
9✔
340
        switch res {
9✔
341
        case 1:
×
342
                return ErrPluginGenericPanic
×
343
        case 2:
×
344
                return ErrPluginFailed
×
345
        case 3:
×
346
                return ErrHandleNotFound
×
347
        default:
9✔
348
                if res != 0 {
9✔
349
                        return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res)
×
350
                }
×
351
        }
352

353
        return nil
9✔
354
}
355

356
// NewInteraction initialises a new interaction for the current contract
357
func (m *Message) WithPluginInteractionContents(part interactionPart, contentType string, contents string) error {
9✔
358
        cContentType := C.CString(contentType)
9✔
359
        defer free(cContentType)
9✔
360
        cContents := C.CString(contents)
9✔
361
        defer free(cContents)
9✔
362

9✔
363
        r := C.pactffi_interaction_contents(m.handle, C.int(part), cContentType, cContents)
9✔
364

9✔
365
        // 1 - A general panic was caught.
9✔
366
        // 2 - The mock server has already been started.
9✔
367
        // 3 - The interaction handle is invalid.
9✔
368
        // 4 - The content type is not valid.
9✔
369
        // 5 - The contents JSON is not valid JSON.
9✔
370
        // 6 - The plugin returned an error.
9✔
371
        res := int(r)
9✔
372
        switch res {
9✔
373
        case 1:
×
374
                return ErrPluginGenericPanic
×
375
        case 2:
×
376
                return ErrPluginMockServerStarted
×
377
        case 3:
×
378
                return ErrPluginInteractionHandleInvalid
×
379
        case 4:
×
380
                return ErrPluginInvalidContentType
×
381
        case 5:
×
382
                return ErrPluginInvalidJson
×
383
        case 6:
×
384
                return ErrPluginSpecificError
×
385
        default:
9✔
386
                if res != 0 {
9✔
387
                        return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res)
×
388
                }
×
389
        }
390

391
        return nil
9✔
392
}
393

394
// GetMessageContents retreives the binary contents of the request for a given message
395
// any matchers are stripped away if given
396
// if the contents is from a plugin, the byte[] representation of the parsed
397
// plugin data is returned, again, with any matchers etc. removed
398
func (m *Message) GetMessageRequestContents() ([]byte, error) {
18✔
399
        log.Println("[DEBUG] GetMessageRequestContents")
18✔
400
        if m.messageType == MESSAGE_TYPE_ASYNC {
33✔
401
                iter := C.pactffi_pact_handle_get_message_iter(m.pact.handle)
15✔
402
                log.Println("[DEBUG] pactffi_pact_handle_get_message_iter")
15✔
403
                if iter == nil {
15✔
404
                        return nil, errors.New("unable to get a message iterator")
×
405
                }
×
406
                log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - OK")
15✔
407

15✔
408
                ///////
15✔
409
                // TODO: some debugging in here to see what's exploding.......
15✔
410
                ///////
15✔
411

15✔
412
                log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - len", len(m.server.messages))
15✔
413

15✔
414
                for i := 0; i < len(m.server.messages); i++ {
30✔
415
                        log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - index", i)
15✔
416
                        message := C.pactffi_pact_message_iter_next(iter)
15✔
417
                        log.Println("[DEBUG] pactffi_pact_message_iter_next - message", message)
15✔
418

15✔
419
                        if i == m.index {
30✔
420
                                log.Println("[DEBUG] pactffi_pact_message_iter_next - index match", message)
15✔
421

15✔
422
                                if message == nil {
15✔
423
                                        return nil, errors.New("retrieved a null message pointer")
×
424
                                }
×
425

426
                                len := C.pactffi_message_get_contents_length(message)
15✔
427
                                log.Println("[DEBUG] pactffi_message_get_contents_length - len", len)
15✔
428
                                if len == 0 {
15✔
429
                                        // You can have empty bodies
×
430
                                        log.Println("[DEBUG] message body is empty")
×
431
                                        return nil, nil
×
432
                                }
×
433
                                data := C.pactffi_message_get_contents_bin(message)
15✔
434
                                log.Println("[DEBUG] pactffi_message_get_contents_bin - data", data)
15✔
435
                                if data == nil {
15✔
436
                                        // You can have empty bodies
×
437
                                        log.Println("[DEBUG] message binary contents are empty")
×
438
                                        return nil, nil
×
439
                                }
×
440
                                ptr := unsafe.Pointer(data)
15✔
441
                                bytes := C.GoBytes(ptr, C.int(len))
15✔
442

15✔
443
                                return bytes, nil
15✔
444
                        }
445
                }
446

447
        } else {
3✔
448
                iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle)
3✔
449
                if iter == nil {
3✔
450
                        return nil, errors.New("unable to get a message iterator")
×
451
                }
×
452

453
                for i := 0; i < len(m.server.messages); i++ {
6✔
454
                        message := C.pactffi_pact_sync_message_iter_next(iter)
3✔
455

3✔
456
                        if i == m.index {
6✔
457
                                if message == nil {
3✔
458
                                        return nil, errors.New("retrieved a null message pointer")
×
459
                                }
×
460

461
                                len := C.pactffi_sync_message_get_request_contents_length(message)
3✔
462
                                if len == 0 {
3✔
463
                                        log.Println("[DEBUG] message body is empty")
×
464
                                        return nil, nil
×
465
                                }
×
466
                                data := C.pactffi_sync_message_get_request_contents_bin(message)
3✔
467
                                if data == nil {
3✔
468
                                        log.Println("[DEBUG] message binary contents are empty")
×
469
                                        return nil, nil
×
470
                                }
×
471
                                ptr := unsafe.Pointer(data)
3✔
472
                                bytes := C.GoBytes(ptr, C.int(len))
3✔
473

3✔
474
                                return bytes, nil
3✔
475
                        }
476
                }
477
        }
478

479
        return nil, errors.New("unable to find the message")
×
480
}
481

482
// GetMessageResponseContents retreives the binary contents of the response for a given message
483
// any matchers are stripped away if given
484
// if the contents is from a plugin, the byte[] representation of the parsed
485
// plugin data is returned, again, with any matchers etc. removed
486
func (m *Message) GetMessageResponseContents() ([][]byte, error) {
6✔
487

6✔
488
        responses := make([][]byte, len(m.server.messages))
6✔
489
        if m.messageType == MESSAGE_TYPE_ASYNC {
6✔
490
                return nil, errors.New("invalid request: asynchronous messages do not have response")
×
491
        }
×
492
        iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle)
6✔
493
        if iter == nil {
6✔
494
                return nil, errors.New("unable to get a message iterator")
×
495
        }
×
496

497
        for i := 0; i < len(m.server.messages); i++ {
12✔
498
                message := C.pactffi_pact_sync_message_iter_next(iter)
6✔
499

6✔
500
                if message == nil {
6✔
501
                        return nil, errors.New("retrieved a null message pointer")
×
502
                }
×
503

504
                // Get Response body
505
                len := C.pactffi_sync_message_get_response_contents_length(message, C.ulong(i))
6✔
506
                if len == 0 {
6✔
507
                        return nil, errors.New("retrieved an empty message")
×
508
                }
×
509
                data := C.pactffi_sync_message_get_response_contents_bin(message, C.ulong(i))
6✔
510
                if data == nil {
6✔
511
                        return nil, errors.New("retrieved an empty pointer to the message contents")
×
512
                }
×
513
                ptr := unsafe.Pointer(data)
6✔
514
                bytes := C.GoBytes(ptr, C.int(len))
6✔
515

6✔
516
                responses[i] = bytes
6✔
517
        }
518

519
        return responses, nil
6✔
520
}
521

522
// StartTransport starts up a mock server on the given address:port for the given transport
523
// https://docs.rs/pact_ffi/latest/pact_ffi/mock_server/fn.pactffi_create_mock_server_for_transport.html
524
func (m *MessageServer) StartTransport(transport string, address string, port int, config map[string][]interface{}) (int, error) {
3✔
525
        if len(m.messages) == 0 {
3✔
526
                return 0, ErrNoInteractions
×
527
        }
×
528

529
        log.Println("[DEBUG] mock server starting on address:", address, port)
3✔
530
        cAddress := C.CString(address)
3✔
531
        defer free(cAddress)
3✔
532

3✔
533
        cTransport := C.CString(transport)
3✔
534
        defer free(cTransport)
3✔
535

3✔
536
        configJson := stringFromInterface(config)
3✔
537
        cConfig := C.CString(configJson)
3✔
538
        defer free(cConfig)
3✔
539

3✔
540
        p := C.pactffi_create_mock_server_for_transport(m.messagePact.handle, cAddress, C.int(port), cTransport, cConfig)
3✔
541

3✔
542
        // | Error | Description
3✔
543
        // |-------|-------------
3✔
544
        // | -1           | An invalid handle was received. Handles should be created with pactffi_new_pact
3✔
545
        // | -2           | transport_config is not valid JSON
3✔
546
        // | -3           | The mock server could not be started
3✔
547
        // | -4           | The method panicked
3✔
548
        // | -5           | The address is not valid
3✔
549
        msPort := int(p)
3✔
550
        switch msPort {
3✔
551
        case -1:
×
552
                return 0, ErrInvalidMockServerConfig
×
553
        case -2:
×
554
                return 0, ErrInvalidMockServerConfig
×
555
        case -3:
×
556
                return 0, ErrMockServerUnableToStart
×
557
        case -4:
×
558
                return 0, ErrMockServerPanic
×
559
        case -5:
×
560
                return 0, ErrInvalidAddress
×
561
        default:
3✔
562
                if msPort > 0 {
6✔
563
                        log.Println("[DEBUG] mock server running on port:", msPort)
3✔
564
                        return msPort, nil
3✔
565
                }
3✔
566
                return msPort, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", msPort)
×
567
        }
568
}
569

570
// NewInteraction initialises a new interaction for the current contract
571
func (m *MessageServer) CleanupPlugins() {
×
572
        C.pactffi_cleanup_plugins(m.messagePact.handle)
×
573
}
×
574

575
// CleanupMockServer frees the memory from the previous mock server.
576
func (m *MessageServer) CleanupMockServer(port int) bool {
3✔
577
        if len(m.messages) == 0 {
3✔
578
                return true
×
579
        }
×
580
        log.Println("[DEBUG] mock server cleaning up port:", port)
3✔
581
        res := C.pactffi_cleanup_mock_server(C.int(port))
3✔
582

3✔
583
        return int(res) == 1
3✔
584
}
585

586
// MockServerMismatchedRequests returns a JSON object containing any mismatches from
587
// the last set of interactions.
588
func (m *MessageServer) MockServerMismatchedRequests(port int) []MismatchedRequest {
3✔
589
        log.Println("[DEBUG] mock server determining mismatches:", port)
3✔
590
        var res []MismatchedRequest
3✔
591

3✔
592
        mismatches := C.pactffi_mock_server_mismatches(C.int(port))
3✔
593
        // This method can return a nil pointer, in which case, it
3✔
594
        // should be considered a failure (or at least, an issue)
3✔
595
        // converting it to a string might also do nasty things here!
3✔
596
        if mismatches == nil {
3✔
597
                log.Println("[WARN] received a null pointer from the native interface, returning empty list of mismatches")
×
598
                return []MismatchedRequest{}
×
599
        }
×
600

601
        json.Unmarshal([]byte(C.GoString(mismatches)), &res)
3✔
602

3✔
603
        return res
3✔
604
}
605

606
// MockServerMismatchedRequests returns a JSON object containing any mismatches from
607
// the last set of interactions.
608
func (m *MessageServer) MockServerMatched(port int) bool {
×
609
        log.Println("[DEBUG] mock server determining mismatches:", port)
×
610

×
611
        res := C.pactffi_mock_server_matched(C.int(port))
×
612

×
613
        // TODO: why this number is so big and not a bool? Type def wrong? Port value wrong?
×
614
        // log.Println("MATCHED RES?")
×
615
        // log.Println(int(res))
×
616

×
617
        return int(res) == 1
×
618
}
×
619

620
// WritePactFile writes the Pact to file.
621
func (m *MessageServer) WritePactFile(dir string, overwrite bool) error {
9✔
622
        log.Println("[DEBUG] writing pact file for message pact at dir:", dir)
9✔
623
        cDir := C.CString(dir)
9✔
624
        defer free(cDir)
9✔
625

9✔
626
        overwritePact := 0
9✔
627
        if overwrite {
9✔
628
                overwritePact = 1
×
629
        }
×
630

631
        res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.int(overwritePact)))
9✔
632

9✔
633
        /// | Error | Description |
9✔
634
        /// |-------|-------------|
9✔
635
        /// | 1 | The pact file was not able to be written |
9✔
636
        /// | 2 | The message pact for the given handle was not found |
9✔
637
        switch res {
9✔
638
        case 0:
9✔
639
                return nil
9✔
640
        case 1:
×
641
                return ErrUnableToWritePactFile
×
642
        case 2:
×
643
                return ErrHandleNotFound
×
644
        default:
×
645
                return fmt.Errorf("an unknown error ocurred when writing to pact file")
×
646
        }
647
}
648

649
// WritePactFile writes the Pact to file.
650
func (m *MessageServer) WritePactFileForServer(port int, dir string, overwrite bool) error {
3✔
651
        log.Println("[DEBUG] writing pact file for message pact at dir:", dir)
3✔
652
        cDir := C.CString(dir)
3✔
653
        defer free(cDir)
3✔
654

3✔
655
        overwritePact := 0
3✔
656
        if overwrite {
6✔
657
                overwritePact = 1
3✔
658
        }
3✔
659

660
        res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact)))
3✔
661

3✔
662
        /// | Error | Description |
3✔
663
        /// |-------|-------------|
3✔
664
        /// | 1 | The pact file was not able to be written |
3✔
665
        /// | 2 | The message pact for the given handle was not found |
3✔
666
        switch res {
3✔
667
        case 0:
3✔
668
                return nil
3✔
669
        case 1:
×
670
                return ErrMockServerPanic
×
671
        case 2:
×
672
                return ErrUnableToWritePactFile
×
673
        case 3:
×
674
                return ErrHandleNotFound
×
675
        default:
×
676
                return fmt.Errorf("an unknown error ocurred when writing to pact file")
×
677
        }
678
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc