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

pact-foundation / pact-go / 18960722150

31 Oct 2025 02:20AM UTC coverage: 30.702% (+2.4%) from 28.272%
18960722150

Pull #455

github

YOU54F
chore: make the linter happy
Pull Request #455: Feat/purego

386 of 514 new or added lines in 8 files covered. (75.1%)

3 existing lines in 2 files now uncovered.

2003 of 6524 relevant lines covered (30.7%)

16.44 hits per line

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

50.93
/internal/native/mock_server.go
1
package native
2

3
import (
4
        "crypto/tls"
5
        "crypto/x509"
6
        "encoding/json"
7
        "fmt"
8
        "log"
9
        "os"
10

11
        "strings"
12
)
13

14
type interactionPart int
15

16
const (
17
        INTERACTION_PART_REQUEST interactionPart = iota
18
        INTERACTION_PART_RESPONSE
19
)
20

21
const (
22
        RESULT_OK interactionPart = iota
23
        RESULT_FAILED
24
)
25

26
type specificationVersion int
27

28
const (
29
        SPECIFICATION_VERSION_UNKNOWN specificationVersion = iota
30
        SPECIFICATION_VERSION_V1
31
        SPECIFICATION_VERSION_V1_1
32
        SPECIFICATION_VERSION_V2
33
        SPECIFICATION_VERSION_V3
34
        SPECIFICATION_VERSION_V4
35
)
36

37
type logLevel int
38

39
const (
40
        LOG_LEVEL_OFF logLevel = iota
41
        LOG_LEVEL_ERROR
42
        LOG_LEVEL_WARN
43
        LOG_LEVEL_INFO
44
        LOG_LEVEL_DEBUG
45
        LOG_LEVEL_TRACE
46
)
47

48
var logLevelStringToInt = map[string]logLevel{
49
        "OFF":   LOG_LEVEL_OFF,
50
        "ERROR": LOG_LEVEL_ERROR,
51
        "WARN":  LOG_LEVEL_WARN,
52
        "INFO":  LOG_LEVEL_INFO,
53
        "DEBUG": LOG_LEVEL_DEBUG,
54
        "TRACE": LOG_LEVEL_TRACE,
55
}
56

57
// Pact is a Go representation of the PactHandle struct
58
type Pact struct {
59
        handle uintptr
60
}
61

62
// Interaction is a Go representation of the InteractionHandle struct
63
type Interaction struct {
64
        handle uintptr
65
}
66

67
// Version returns the current semver FFI interface version
68
func Version() string {
12✔
69
        v := pactffi_version()
12✔
70

12✔
71
        return v
12✔
72
}
12✔
73

74
var loggingInitialised string
75

76
// Init initialises the library
77
func Init(logLevel string) {
12✔
78
        log.Println("[DEBUG] initialising native interface")
12✔
79
        logLevel = strings.ToUpper(logLevel)
12✔
80

12✔
81
        if loggingInitialised != "" {
12✔
82
                log.Printf("log level ('%s') cannot be set to '%s' after initialisation\n", loggingInitialised, logLevel)
×
83
        } else {
12✔
84
                l, ok := logLevelStringToInt[logLevel]
12✔
85
                if !ok {
24✔
86
                        l = LOG_LEVEL_INFO
12✔
87
                }
12✔
88
                log.Printf("[DEBUG] initialised native log level to %s (%d)", logLevel, l)
12✔
89

12✔
90
                if os.Getenv("PACT_LOG_PATH") != "" {
12✔
91
                        log.Println("[DEBUG] initialised native log to log to file:", os.Getenv("PACT_LOG_PATH"))
×
92
                        err := logToFile(os.Getenv("PACT_LOG_PATH"), l)
×
93
                        if err != nil {
×
94
                                log.Println("[ERROR] failed to log to file:", err)
×
95
                        }
×
96
                } else {
12✔
97
                        log.Println("[DEBUG] initialised native log to log to stdout")
12✔
98
                        err := logToStdout(l)
12✔
99
                        if err != nil {
12✔
100
                                log.Println("[ERROR] failed to log to stdout:", err)
×
101
                        }
×
102
                }
103
        }
104
}
105

106
// MockServer is the public interface for managing the HTTP mock server
107
type MockServer struct {
108
        pact         *Pact
109
        // messagePact  *MessagePact
110
        interactions []*Interaction
111
}
112

113
// NewHTTPPact creates a new HTTP mock server for a given consumer/provider
114
func NewHTTPPact(consumer string, provider string) *MockServer {
24✔
115
        return &MockServer{pact: &Pact{handle: pactffi_new_pact(consumer, provider)}}
24✔
116
}
24✔
117

118
// Version returns the current semver FFI interface version
119
func (m *MockServer) Version() string {
×
120
        return Version()
×
121
}
×
122

123
func (m *MockServer) WithSpecificationVersion(version specificationVersion) {
12✔
124
        pactffi_with_specification(m.pact.handle, int32(version))
12✔
125
}
12✔
126

127
// CreateMockServer creates a new Mock Server from a given Pact file.
128
// Returns the port number it started on or an error if failed
129
func (m *MockServer) CreateMockServer(pact string, address string, tls bool) (int, error) {
72✔
130
        log.Println("[DEBUG] mock server starting on address:", address)
72✔
131
        tlsEnabled := false
72✔
132
        if tls {
72✔
133
                tlsEnabled = true
×
134
        }
×
135

136
        p := pactffi_create_mock_server(pact, address, tlsEnabled)
72✔
137

72✔
138
        // | Error | Description |
72✔
139
        // |-------|-------------|
72✔
140
        // | -1 | A null pointer was received |
72✔
141
        // | -2 | The pact JSON could not be parsed |
72✔
142
        // | -3 | The mock server could not be started |
72✔
143
        // | -4 | The method panicked |
72✔
144
        // | -5 | The address is not valid |
72✔
145
        // | -6 | Could not create the TLS configuration with the self-signed certificate |
72✔
146
        port := int(p)
72✔
147
        switch port {
72✔
148
        case -1:
×
149
                return 0, ErrInvalidMockServerConfig
×
150
        case -2:
×
151
                return 0, ErrInvalidPact
×
152
        case -3:
×
153
                return 0, ErrMockServerUnableToStart
×
154
        case -4:
×
155
                return 0, ErrMockServerPanic
×
156
        case -5:
×
157
                return 0, ErrInvalidAddress
×
158
        case -6:
×
159
                return 0, ErrMockServerTLSConfiguration
×
160
        default:
72✔
161
                if port > 0 {
144✔
162
                        log.Println("[DEBUG] mock server running on port:", port)
72✔
163
                        return port, nil
72✔
164
                }
72✔
165
                return port, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", port)
×
166
        }
167
}
168

169
// Verify verifies that all interactions were successful. If not, returns a slice
170
// of Mismatch-es. Does not write the pact or cleanup server.
171
func (m *MockServer) Verify(port int, dir string) (bool, []MismatchedRequest) {
24✔
172
        mismatches := m.MockServerMismatchedRequests(port)
24✔
173
        log.Println("[DEBUG] mock server mismatches:", len(mismatches))
24✔
174

24✔
175
        return len(mismatches) == 0, mismatches
24✔
176
}
24✔
177

178
// MockServerMismatchedRequests returns a JSON object containing any mismatches from
179
// the last set of interactions.
180
func (m *MockServer) MockServerMismatchedRequests(port int) []MismatchedRequest {
72✔
181
        log.Println("[DEBUG] mock server determining mismatches:", port)
72✔
182
        var res []MismatchedRequest
72✔
183

72✔
184
        mismatches := pactffi_mock_server_mismatches(int32(port))
72✔
185
        // This method can return a nil pointer, in which case, it
72✔
186
        // should be considered a failure (or at least, an issue)
72✔
187
        // converting it to a string might also do nasty things here!
72✔
188
        if mismatches == "" {
72✔
189
                log.Println("[WARN] received a null pointer from the native interface, returning empty list of mismatches")
×
190
                return []MismatchedRequest{}
×
191
        }
×
192

193
        err := json.Unmarshal([]byte(mismatches), &res)
72✔
194
        if err != nil {
72✔
195
                log.Println("[ERROR] failed to unmarshal mismatches response, returning empty list of mismatches")
×
196
                return []MismatchedRequest{}
×
197
        }
×
198
        return res
72✔
199
}
200

201
// CleanupMockServer frees the memory from the previous mock server.
202
func (m *MockServer) CleanupMockServer(port int) bool {
84✔
203
        if len(m.interactions) == 0 {
144✔
204
                return true
60✔
205
        }
60✔
206
        log.Println("[DEBUG] mock server cleaning up port:", port)
24✔
207
        res := pactffi_cleanup_mock_server(int32(port))
24✔
208

24✔
209
        return res
24✔
210
}
211

212
// WritePactFile writes the Pact to file.
213
// TODO: expose overwrite
214
func (m *MockServer) WritePactFile(port int, dir string) error {
36✔
215
        log.Println("[DEBUG] writing pact file for mock server on port:", port, ", dir:", dir)
36✔
216

36✔
217
        overwritePact := false
36✔
218
        // if overwrite {
36✔
219
        //         overwritePact = 1
36✔
220
        // }
36✔
221

36✔
222
        // res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact)))
36✔
223
        res := int(pactffi_write_pact_file(int32(port), dir, overwritePact))
36✔
224

36✔
225
        // | Error | Description |
36✔
226
        // |-------|-------------|
36✔
227
        // | 1 | A general panic was caught |
36✔
228
        // | 2 | The pact file was not able to be written |
36✔
229
        // | 3 | A mock server with the provided port was not found |
36✔
230
        switch res {
36✔
231
        case 0:
36✔
232
                return nil
36✔
233
        case 1:
×
234
                return ErrMockServerPanic
×
235
        case 2:
×
236
                return ErrUnableToWritePactFile
×
237
        case 3:
×
238
                return ErrMockServerNotfound
×
239
        default:
×
240
                return fmt.Errorf("an unknown error ocurred when writing to pact file")
×
241
        }
242
}
243

244
// GetTLSConfig returns a tls.Config compatible with the TLS
245
// mock server
246
func GetTLSConfig() *tls.Config {
12✔
247
        cert := pactffi_get_tls_ca_certificate()
12✔
248
        // defer libRustFree(cert)
12✔
249

12✔
250
        certPool := x509.NewCertPool()
12✔
251
        certPool.AppendCertsFromPEM([]byte(cert))
12✔
252

12✔
253
        return &tls.Config{
12✔
254
                RootCAs: certPool,
12✔
255
        }
12✔
256
}
12✔
257

258
// func free(str *C.char) {
259
//         C.free(unsafe.Pointer(str))
260
// }
261

262
// func libRustFree(str uintptr) {
263
//         pactffi_free_string(str)
264
// }
265

266
// func libRustFree(str string) {
267
//         pactffi_string_delete(str)
268
// }
269

270
// Start starts up the mock HTTP server on the given address:port and TLS config
271
// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.create_mock_server_for_pact.html
272
func (m *MockServer) Start(address string, tls bool) (int, error) {
24✔
273
        if len(m.interactions) == 0 {
24✔
274
                return 0, ErrNoInteractions
×
275
        }
×
276

277
        log.Println("[DEBUG] mock server starting on address:", address)
24✔
278
        // cAddress := C.CString(address)
24✔
279
        // defer free(cAddress)
24✔
280
        tlsEnabled := false
24✔
281
        if tls {
24✔
282
                tlsEnabled = true
×
283
        }
×
284

285
        p := pactffi_create_mock_server_for_pact(m.pact.handle, address, tlsEnabled)
24✔
286

24✔
287
        // | Error | Description |
24✔
288
        // |-------|-------------|
24✔
289
        // | -1 | A null pointer was received |
24✔
290
        // | -2 | The pact JSON could not be parsed |
24✔
291
        // | -3 | The mock server could not be started |
24✔
292
        // | -4 | The method panicked |
24✔
293
        // | -5 | The address is not valid |
24✔
294
        // | -6 | Could not create the TLS configuration with the self-signed certificate |
24✔
295
        port := int(p)
24✔
296
        switch port {
24✔
297
        case -1:
×
298
                return 0, ErrInvalidMockServerConfig
×
299
        case -2:
×
300
                return 0, ErrInvalidPact
×
301
        case -3:
×
302
                return 0, ErrMockServerUnableToStart
×
303
        case -4:
×
304
                return 0, ErrMockServerPanic
×
305
        case -5:
×
306
                return 0, ErrInvalidAddress
×
307
        case -6:
×
308
                return 0, ErrMockServerTLSConfiguration
×
309
        default:
24✔
310
                if port > 0 {
48✔
311
                        log.Println("[DEBUG] mock server running on port:", port)
24✔
312
                        return port, nil
24✔
313
                }
24✔
314
                return port, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", port)
×
315
        }
316
}
317

318
// StartTransport starts up a mock server on the given address:port for the given transport
319
// https://docs.rs/pact_ffi/latest/pact_ffi/mock_server/fn.pactffi_create_mock_server_for_transport.html
320
func (m *MockServer) StartTransport(transport string, address string, port int, config map[string][]interface{}) (int, error) {
×
321
        if len(m.interactions) == 0 {
×
322
                return 0, ErrNoInteractions
×
323
        }
×
UNCOV
324
        configJson := stringFromInterface(config)
×
325

×
NEW
326
        log.Println("[DEBUG] mock server starting on address:", address, port)
×
NEW
327
        p := pactffi_create_mock_server_for_transport(m.pact.handle, address, uint16(port), transport, configJson)
×
328

×
329
        // | Error | Description
×
330
        // |-------|-------------
×
331
        // | -1           | An invalid handle was received. Handles should be created with pactffi_new_pact
×
332
        // | -2           | transport_config is not valid JSON
×
333
        // | -3           | The mock server could not be started
×
334
        // | -4           | The method panicked
×
335
        // | -5           | The address is not valid
×
336
        msPort := int(p)
×
337
        switch msPort {
×
338
        case -1:
×
339
                return 0, ErrInvalidMockServerConfig
×
340
        case -2:
×
341
                return 0, ErrInvalidMockServerConfig
×
342
        case -3:
×
343
                return 0, ErrMockServerUnableToStart
×
344
        case -4:
×
345
                return 0, ErrMockServerPanic
×
346
        case -5:
×
347
                return 0, ErrInvalidAddress
×
348
        default:
×
349
                if msPort > 0 {
×
350
                        log.Println("[DEBUG] mock server running on port:", msPort)
×
351
                        return msPort, nil
×
352
                }
×
353
                return msPort, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", msPort)
×
354
        }
355
}
356

357
// Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version
358
func (m *MockServer) WithMetadata(namespace, k, v string) *MockServer {
×
NEW
359
        pactffi_with_pact_metadata(m.pact.handle, namespace, k, v)
×
360

×
361
        return m
×
362
}
×
363

364
// NewInteraction initialises a new interaction for the current contract
365
func (m *MockServer) UsingPlugin(pluginName string, pluginVersion string) error {
12✔
366

12✔
367
        r := pactffi_using_plugin(m.pact.handle, pluginName, pluginVersion)
12✔
368
        // 1 - A general panic was caught.
12✔
369
        // 2 - Failed to load the plugin.
12✔
370
        // 3 - Pact Handle is not valid.
12✔
371
        res := int(r)
12✔
372
        switch res {
12✔
373
        case 1:
×
374
                return ErrPluginGenericPanic
×
375
        case 2:
×
376
                return ErrPluginFailed
×
377
        case 3:
×
378
                return ErrHandleNotFound
×
379
        default:
12✔
380
                if res != 0 {
12✔
381
                        return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res)
×
382
                }
×
383
        }
384

385
        return nil
12✔
386
}
387

388
// NewInteraction initialises a new interaction for the current contract
389
func (m *MockServer) CleanupPlugins() {
12✔
390
        pactffi_cleanup_plugins(m.pact.handle)
12✔
391
}
12✔
392

393
// NewInteraction initialises a new interaction for the current contract
394
func (m *MockServer) NewInteraction(description string) *Interaction {
24✔
395
        i := &Interaction{
24✔
396
                handle: pactffi_new_interaction(m.pact.handle, description),
24✔
397
        }
24✔
398
        m.interactions = append(m.interactions, i)
24✔
399

24✔
400
        return i
24✔
401
}
24✔
402

403
// NewInteraction initialises a new interaction for the current contract
404
func (i *Interaction) WithPluginInteractionContents(part interactionPart, contentType string, contents string) error {
12✔
405

12✔
406
        r := pactffi_interaction_contents(i.handle, int32(part), contentType, contents)
12✔
407

12✔
408
        // 1 - A general panic was caught.
12✔
409
        // 2 - The mock server has already been started.
12✔
410
        // 3 - The interaction handle is invalid.
12✔
411
        // 4 - The content type is not valid.
12✔
412
        // 5 - The contents JSON is not valid JSON.
12✔
413
        // 6 - The plugin returned an error.
12✔
414
        res := int(r)
12✔
415
        switch res {
12✔
416
        case 1:
×
417
                return ErrPluginGenericPanic
×
418
        case 2:
×
419
                return ErrPluginMockServerStarted
×
420
        case 3:
×
421
                return ErrPluginInteractionHandleInvalid
×
422
        case 4:
×
423
                return ErrPluginInvalidContentType
×
424
        case 5:
×
425
                return ErrPluginInvalidJson
×
426
        case 6:
×
427
                return ErrPluginSpecificError
×
428
        default:
12✔
429
                if res != 0 {
12✔
430
                        return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res)
×
431
                }
×
432
        }
433

434
        return nil
12✔
435
}
436

437
func (i *Interaction) UponReceiving(description string) *Interaction {
24✔
438
        pactffi_upon_receiving(i.handle, description)
24✔
439

24✔
440
        return i
24✔
441
}
24✔
442

443
func (i *Interaction) Given(state string) *Interaction {
24✔
444
        pactffi_given(i.handle, state)
24✔
445

24✔
446
        return i
24✔
447
}
24✔
448

449
func (i *Interaction) GivenWithParameter(state string, params map[string]interface{}) *Interaction {
×
450

×
451
        for k, v := range params {
×
452
                param := stringFromInterface(v)
×
NEW
453
                pactffi_given_with_param(i.handle, state, k, param)
×
454
        }
×
455

456
        return i
×
457
}
458

459
func (i *Interaction) WithRequest(method string, pathOrMatcher interface{}) *Interaction {
24✔
460
        path := stringFromInterface(pathOrMatcher)
24✔
461

24✔
462
        pactffi_with_request(i.handle, method, path)
24✔
463

24✔
464
        return i
24✔
465
}
24✔
466

467
func (i *Interaction) WithRequestHeaders(valueOrMatcher map[string][]interface{}) *Interaction {
×
468
        return i.withHeaders(INTERACTION_PART_REQUEST, valueOrMatcher)
×
469
}
×
470

471
func (i *Interaction) WithResponseHeaders(valueOrMatcher map[string][]interface{}) *Interaction {
×
472
        return i.withHeaders(INTERACTION_PART_RESPONSE, valueOrMatcher)
×
473
}
×
474

475
func (i *Interaction) withHeaders(part interactionPart, valueOrMatcher map[string][]interface{}) *Interaction {
×
476
        for k, v := range valueOrMatcher {
×
477
                for _, header := range v {
×
478
                        value := stringFromInterface(header)
×
479

×
NEW
480
                        pactffi_with_header_v2(i.handle, int32(part), k, int(0), value)
×
481
                }
×
482

483
        }
484

485
        return i
×
486
}
487

488
func (i *Interaction) WithQuery(valueOrMatcher map[string][]interface{}) *Interaction {
×
489
        for k, values := range valueOrMatcher {
×
490

×
491
                for idx, v := range values {
×
492
                        value := stringFromInterface(v)
×
493

×
NEW
494
                        pactffi_with_query_parameter_v2(i.handle, k, int(idx), value)
×
495
                }
×
496
        }
497

498
        return i
×
499
}
500

501
func (i *Interaction) WithJSONRequestBody(body interface{}) *Interaction {
×
502
        return i.withJSONBody(body, INTERACTION_PART_REQUEST)
×
503
}
×
504

505
func (i *Interaction) WithJSONResponseBody(body interface{}) *Interaction {
12✔
506
        return i.withJSONBody(body, INTERACTION_PART_RESPONSE)
12✔
507
}
12✔
508

509
func (i *Interaction) withJSONBody(body interface{}, part interactionPart) *Interaction {
12✔
510
        jsonBody := stringFromInterface(body)
12✔
511

12✔
512
        pactffi_with_body(i.handle, int32(part), "application/json", jsonBody)
12✔
513

12✔
514
        return i
12✔
515
}
12✔
516

517
func (i *Interaction) WithRequestBody(contentType string, body []byte) *Interaction {
×
518
        return i.withBody(contentType, body, 0)
×
519
}
×
520

521
func (i *Interaction) WithResponseBody(contentType string, body []byte) *Interaction {
×
522
        return i.withBody(contentType, body, 1)
×
523
}
×
524

525
func (i *Interaction) withBody(contentType string, body []byte, part interactionPart) *Interaction {
×
526

×
NEW
527
        pactffi_with_body(i.handle, int32(part), contentType, string(body))
×
528

×
529
        return i
×
530
}
×
531

532
func (i *Interaction) withBinaryBody(contentType string, body []byte, part interactionPart) *Interaction {
×
533

×
NEW
534
        pactffi_with_binary_file(i.handle, int32(part), contentType, string(body), size_t(len(body)))
×
535

×
536
        return i
×
537
}
×
538

539
func (i *Interaction) WithBinaryRequestBody(body []byte) *Interaction {
×
540
        return i.withBinaryBody("application/octet-stream", body, INTERACTION_PART_REQUEST)
×
541
}
×
542

543
func (i *Interaction) WithBinaryResponseBody(body []byte) *Interaction {
×
544
        return i.withBinaryBody("application/octet-stream", body, INTERACTION_PART_RESPONSE)
×
545
}
×
546

547
func (i *Interaction) WithRequestMultipartFile(contentType string, filename string, mimePartName string) *Interaction {
×
548
        return i.withMultipartFile(contentType, filename, mimePartName, INTERACTION_PART_REQUEST)
×
549
}
×
550

551
func (i *Interaction) WithResponseMultipartFile(contentType string, filename string, mimePartName string) *Interaction {
×
552
        return i.withMultipartFile(contentType, filename, mimePartName, INTERACTION_PART_RESPONSE)
×
553
}
×
554

555
func (i *Interaction) withMultipartFile(contentType string, filename string, mimePartName string, part interactionPart) *Interaction {
×
NEW
556
        pactffi_with_multipart_file(i.handle, int32(part), contentType, filename, mimePartName)
×
557

×
558
        return i
×
559
}
×
560

561
// Set the expected HTTTP response status
562
func (i *Interaction) WithStatus(status int) *Interaction {
24✔
563
        pactffi_response_status(i.handle, uint16(status))
24✔
564

24✔
565
        return i
24✔
566
}
24✔
567

568
// type stringLike interface {
569
//         String() string
570
// }
571

572
func stringFromInterface(obj interface{}) string {
168✔
573
        switch t := obj.(type) {
168✔
574
        case string:
108✔
575
                return t
108✔
576
        default:
60✔
577
                bytes, err := json.Marshal(obj)
60✔
578
                if err != nil {
60✔
579
                        panic(fmt.Sprintln("unable to marshal body to JSON:", err))
×
580
                }
581
                return quotedString(string(bytes))
60✔
582
        }
583
}
584

585
// This fixes a quirk where certain "matchers" (e.g. matchers.S/String) are
586
// really just strings. However, whene we JSON encode them they get wrapped in quotes
587
// and the rust core sees them as plain strings, requiring then the quotes to be matched
588
func quotedString(s string) string {
60✔
589
        if s[0] == '"' && s[len(s)-1] == '"' {
60✔
590
                return s[1 : len(s)-1]
×
591
        }
×
592
        return s
60✔
593
}
594

595
// Experimental logging options
596
// func LogMessage(pkg, level, message string) {
597
//         cPkg := C.CString(pkg)
598
//         defer free(cPkg)
599

600
//         cLevel := C.CString(level)
601
//         defer free(cLevel)
602

603
//         cMessage := C.CString(message)
604
//         defer free(cMessage)
605

606
//         res := C.pactffi_log_message(cPkg, cLevel, cMessage)
607
//         log.Println("[DEBUG] log_to_buffer res", res)
608
// }
609

610
// func logToBuffer(level logLevel) error {
611
//         res := C.pactffi_log_to_buffer(C.int(level))
612
//         log.Println("[DEBUG] log_to_buffer res", res)
613

614
//         return logResultToError(int(res))
615
// }
616

617
func logToStdout(level logLevel) error {
12✔
618
        res := pactffi_log_to_stdout(int32(level))
12✔
619
        log.Println("[DEBUG] log_to_stdout res", res)
12✔
620

12✔
621
        return logResultToError(int(res))
12✔
622
}
12✔
623

624
func logToFile(file string, level logLevel) error {
×
NEW
625
        res := pactffi_log_to_file(file, int32(level))
×
626
        log.Println("[DEBUG] log_to_file res", res)
×
627

×
628
        return logResultToError(int(res))
×
629
}
×
630

631
// func getLogBuffer() string {
632
//         buf := C.pactffi_fetch_log_buffer()
633
//         defer free(buf)
634

635
//         return C.GoString(buf)
636
// }
637

638
func logResultToError(res int) error {
12✔
639
        switch res {
12✔
640
        case 0:
12✔
641
                return nil
12✔
642
        case -1:
×
643
                return ErrCantSetLogger
×
644
        case -2:
×
645
                return ErrNoLogger
×
646
        case -3:
×
647
                return ErrSpecifierNotUtf8
×
648
        case -4:
×
649
                return ErrUnknownSinkType
×
650
        case -5:
×
651
                return ErrMissingFilePath
×
652
        case -6:
×
653
                return ErrCantOpenSinkToFile
×
654
        case -7:
×
655
                return ErrCantConstructSink
×
656
        default:
×
657
                return fmt.Errorf("an unknown error ocurred when writing to pact file")
×
658
        }
659
}
660

661
// Errors
662
var (
663
        // ErrHandleNotFound indicates the underlying handle was not found, and a logic error in the framework
664
        ErrHandleNotFound = fmt.Errorf("unable to find the native interface handle (this indicates a defect in the framework)")
665

666
        // ErrMockServerPanic indicates a panic ocurred when invoking the remote Mock Server.
667
        ErrMockServerPanic = fmt.Errorf("a general panic occured when starting/invoking mock service (this indicates a defect in the framework)")
668

669
        // ErrUnableToWritePactFile indicates an error when writing the pact file to disk.
670
        ErrUnableToWritePactFile = fmt.Errorf("unable to write to file")
671

672
        // ErrMockServerNotfound indicates the Mock Server could not be found.
673
        ErrMockServerNotfound = fmt.Errorf("unable to find mock server with the given port")
674

675
        // ErrInvalidMockServerConfig indicates an issue configuring the mock server
676
        ErrInvalidMockServerConfig = fmt.Errorf("configuration for the mock server was invalid and an unknown error occurred (this is most likely a defect in the framework)")
677

678
        // ErrInvalidPact indicates the pact file provided to the mock server was not a valid pact file
679
        ErrInvalidPact = fmt.Errorf("pact given to mock server is invalid")
680

681
        // ErrMockServerUnableToStart means the mock server could not be started in the rust library
682
        ErrMockServerUnableToStart = fmt.Errorf("unable to start the mock server")
683

684
        // ErrInvalidAddress means the address provided to the mock server was invalid and could not be understood
685
        ErrInvalidAddress = fmt.Errorf("invalid address provided to the mock server")
686

687
        // ErrMockServerTLSConfiguration indicates a TLS mock server could not be started
688
        // and is likely a framework level problem
689
        ErrMockServerTLSConfiguration = fmt.Errorf("a tls mock server could not be started (this is likely a defect in the framework)")
690

691
        // ErrNoInteractions indicates no Interactions have been registered to a mock server, and cannot be started/stopped until at least one is added
692
        ErrNoInteractions = fmt.Errorf("no interactions have been registered for the mock server")
693

694
        // ErrPluginFailed indicates the plugin could not be started
695
        ErrPluginFailed = fmt.Errorf("the plugin could not be started")
696
)
697

698
// Log Errors
699
var (
700
        ErrCantSetLogger      = fmt.Errorf("can't set logger (applying the logger failed, perhaps because one is applied already).")
701
        ErrNoLogger           = fmt.Errorf("no logger has been initialized (call `logger_init` before any other log function).")
702
        ErrSpecifierNotUtf8   = fmt.Errorf("The sink specifier was not UTF-8 encoded.")
703
        ErrUnknownSinkType    = fmt.Errorf(`the sink type specified is not a known type (known types: "buffer", "stdout", "stderr", or "file /some/path").`)
704
        ErrMissingFilePath    = fmt.Errorf("no file path was specified in a file-type sink specification.")
705
        ErrCantOpenSinkToFile = fmt.Errorf("opening a sink to the specified file path failed (check permissions).")
706
        ErrCantConstructSink  = fmt.Errorf("can't construct the log sink")
707
)
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