diff --git a/command/root_test.go b/command/root_test.go index 305afb291..aa786e684 100644 --- a/command/root_test.go +++ b/command/root_test.go @@ -54,7 +54,7 @@ func captureOutput(action func()) string { action() - _ = w.Close() + w.Close() out, _ := io.ReadAll(r) os.Stderr = rescueStderr diff --git a/consumer/http.go b/consumer/http.go index 303087f23..77c36fd7a 100644 --- a/consumer/http.go +++ b/consumer/http.go @@ -201,7 +201,7 @@ func (p *httpMockProvider) displayMismatches(t *testing.T, mismatches []native.M fmt.Println("\t\tDiff:") log.Println("[INFO] pact validation failed, errors: ") for _, m := range mismatches { - formattedRequest := fmt.Sprintf("%s %s", m.Method, m.Path) + formattedRequest := fmt.Sprintf("%s %s", m.Request.Method, m.Request.Path) switch m.Type { case "missing-request": fmt.Printf("\t\texpected: \t%s (Expected request that was not received)\n", formattedRequest) diff --git a/consumer/http_v2.go b/consumer/http_v2.go index 276a403ef..6d4c224fa 100644 --- a/consumer/http_v2.go +++ b/consumer/http_v2.go @@ -35,7 +35,7 @@ func NewV2Pact(config MockHTTPProviderConfig) (*V2HTTPMockProvider, error) { // AddInteraction to the pact func (p *V2HTTPMockProvider) AddInteraction() *V2UnconfiguredInteraction { log.Println("[DEBUG] pact add V2 interaction") - interaction := p.mockserver.NewInteraction("") + interaction := p.httpMockProvider.mockserver.NewInteraction("") i := &V2UnconfiguredInteraction{ interaction: &Interaction{ diff --git a/consumer/http_v3.go b/consumer/http_v3.go index 32d25fb9c..bccce0bac 100644 --- a/consumer/http_v3.go +++ b/consumer/http_v3.go @@ -35,7 +35,7 @@ func NewV3Pact(config MockHTTPProviderConfig) (*V3HTTPMockProvider, error) { // AddInteraction to the pact func (p *V3HTTPMockProvider) AddInteraction() *V3UnconfiguredInteraction { log.Println("[DEBUG] pact add V3 interaction") - interaction := p.mockserver.NewInteraction("") + interaction := p.httpMockProvider.mockserver.NewInteraction("") i := &V3UnconfiguredInteraction{ interaction: &Interaction{ diff --git a/consumer/http_v4.go b/consumer/http_v4.go index 55a79c9a4..8dd986b79 100644 --- a/consumer/http_v4.go +++ b/consumer/http_v4.go @@ -36,7 +36,7 @@ func NewV4Pact(config MockHTTPProviderConfig) (*V4HTTPMockProvider, error) { // AddInteraction to the pact func (p *V4HTTPMockProvider) AddInteraction() *V4UnconfiguredInteraction { log.Println("[DEBUG] pact add V4 interaction") - interaction := p.mockserver.NewInteraction("") + interaction := p.httpMockProvider.mockserver.NewInteraction("") i := &V4UnconfiguredInteraction{ interaction: &Interaction{ @@ -92,15 +92,6 @@ func (i *V4UnconfiguredInteraction) UponReceiving(description string) *V4Unconfi return i } -// AddExternalReference records a reference to an external resource (such as a ticket or -// pull request) against the interaction. References appear under -// comments.references[group][name] in the Pact file. May be called multiple times. -func (i *V4UnconfiguredInteraction) AddExternalReference(group, name, value string) *V4UnconfiguredInteraction { - i.interaction.interaction.WithReference(group, name, value) - - return i -} - // WithRequest provides a builder for the expected request func (i *V4UnconfiguredInteraction) WithCompleteRequest(request Request) *V4InteractionWithCompleteRequest { i.interaction.WithCompleteRequest(request) diff --git a/consumer/http_v4_test.go b/consumer/http_v4_test.go index efb421bde..33165496b 100644 --- a/consumer/http_v4_test.go +++ b/consumer/http_v4_test.go @@ -2,7 +2,6 @@ package consumer import ( "fmt" - "net/http" "os" "strings" "testing" @@ -86,25 +85,6 @@ func TestHttpV4TypeSystem(t *testing.T) { } -func TestV4HTTPAddExternalReference(t *testing.T) { - p, err := NewV4Pact(MockHTTPProviderConfig{ - Consumer: "consumer", - Provider: "provider", - }) - assert.NoError(t, err) - - err = p.AddInteraction(). - UponReceiving("a request with an external reference"). - AddExternalReference("Jira", "TICKET-123", "https://jira.example.com/browse/TICKET-123"). - WithRequest("GET", "/", func(b *V4RequestBuilder) {}). - WillRespondWith(200, func(b *V4ResponseBuilder) {}). - ExecuteTest(t, func(msc MockServerConfig) error { - _, err := http.Get(fmt.Sprintf("http://%s:%d/", msc.Host, msc.Port)) - return err - }) - assert.NoError(t, err) -} - var Like = matchers.Like var EachLike = matchers.EachLike var Term = matchers.Term diff --git a/examples/avro/codec.go b/examples/avro/codec.go index 4ad4798ac..fb4d2aca8 100644 --- a/examples/avro/codec.go +++ b/examples/avro/codec.go @@ -1,12 +1,11 @@ package avro import ( + "os" - "github.com/linkedin/goavro/v2" ) -//nolint:unused // Retained as a reusable helper for the example package. func getCodec() *goavro.Codec { schema, err := os.ReadFile("user.avsc") if err != nil { diff --git a/examples/grpc/routeguide/server/server.go b/examples/grpc/routeguide/server/server.go index 0751994b1..fa59e7ddf 100644 --- a/examples/grpc/routeguide/server/server.go +++ b/examples/grpc/routeguide/server/server.go @@ -40,8 +40,9 @@ import ( "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide/data" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" + "google.golang.org/grpc/status" + + "github.com/golang/protobuf/proto" pb "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" ) @@ -54,15 +55,6 @@ var ( port = flag.Int("port", 50051, "The server port") ) -// Keep example flags/entrypoint available for standalone usage. -var ( - _ = tls - _ = certFile - _ = keyFile - _ = port - _ = main -) - type routeGuideServer struct { pb.UnimplementedRouteGuideServer savedFeatures []*pb.Feature // read-only after initialized @@ -255,9 +247,7 @@ func main() { } grpcServer := grpc.NewServer(opts...) pb.RegisterRouteGuideServer(grpcServer, NewServer()) - if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } + grpcServer.Serve(lis) } // exampleData is a copy of testdata/route_guide_db.json. It's to avoid diff --git a/installer/installer.go b/installer/installer.go index 5e421d089..30965e1fa 100644 --- a/installer/installer.go +++ b/installer/installer.go @@ -302,7 +302,7 @@ var setMacOSInstallName = func(file string) error { return fmt.Errorf("error setting install name on pact lib: %s", err) } - log.Println("[DEBUG] output from command", string(stdoutStderr)) + log.Println("[DEBUG] output from command", stdoutStderr) return err } @@ -388,7 +388,7 @@ const ( var packages = map[string]packageInfo{ FFIPackage: { libName: "libpact_ffi", - version: "0.5.6", + version: "0.4.28", semverRange: ">= 0.4.0, < 1.0.0", }, } @@ -417,17 +417,13 @@ func (d *defaultDownloader) download(src string, dst string) error { if err != nil { return fmt.Errorf("failed to create output file; %w", err) } - defer func() { - _ = f.Close() - }() + defer f.Close() resp, err := http.Get(src) if err != nil { return fmt.Errorf("failed http call to %s; %w", src, err) } - defer func() { - _ = resp.Body.Close() - }() + defer resp.Body.Close() archive, err := gzip.NewReader(resp.Body) if err != nil { @@ -527,9 +523,7 @@ func (d *defaultHasher) hash(src string) (string, error) { if err != nil { return "", err } - defer func() { - _ = f.Close() - }() + defer f.Close() h := md5.New() if _, err := io.Copy(h, f); err != nil { diff --git a/internal/native/message_server.go b/internal/native/message_server.go index e32b84cca..bd6e6ec3a 100644 --- a/internal/native/message_server.go +++ b/internal/native/message_server.go @@ -232,7 +232,7 @@ func (m *Message) WithContents(part interactionPart, contentType string, body [] defer free(cHeader) cBody := C.CString(string(body)) - defer free(cBody) + defer free(cBody) res := C.pactffi_with_body(m.handle, C.int(part), cHeader, cBody) log.Println("[DEBUG] response from pactffi_interaction_contents", (bool(res))) @@ -264,7 +264,7 @@ func (m *MessageServer) UsingPlugin(pluginName string, pluginVersion string) err return ErrHandleNotFound default: if res != 0 { - return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code", res) + return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res) } } @@ -302,7 +302,7 @@ func (m *Message) WithPluginInteractionContents(part interactionPart, contentTyp return ErrPluginSpecificError default: if res != 0 { - return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code", res) + return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res) } } @@ -543,7 +543,10 @@ func (m *MessageServer) WritePactFile(dir string, overwrite bool) error { cDir := C.CString(dir) defer free(cDir) - overwritePact := overwrite + overwritePact := false + if overwrite { + overwritePact = true + } res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.bool(overwritePact))) @@ -569,7 +572,10 @@ func (m *MessageServer) WritePactFileForServer(port int, dir string, overwrite b cDir := C.CString(dir) defer free(cDir) - overwritePact := overwrite + overwritePact := false + if overwrite { + overwritePact = true + } res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.bool(overwritePact))) @@ -590,19 +596,3 @@ func (m *MessageServer) WritePactFileForServer(port int, dir string, overwrite b return fmt.Errorf("an unknown error ocurred when writing to pact file") } } - -// WithReference records an external reference (e.g. a ticket or pull request) -// against the interaction. References are stored under comments.references[group][name] -// in the Pact file. This is a V4-only feature. -func (m *Message) WithReference(group, name, value string) *Message { - cGroup := C.CString(group) - defer free(cGroup) - cName := C.CString(name) - defer free(cName) - cValue := C.CString(value) - defer free(cValue) - - C.pactffi_add_interaction_reference(m.handle, cGroup, cName, cValue) - - return m -} diff --git a/internal/native/message_server_test.go b/internal/native/message_server_test.go index 73f7d140b..0431b8e05 100644 --- a/internal/native/message_server_test.go +++ b/internal/native/message_server_test.go @@ -406,9 +406,7 @@ func TestGrpcPluginInteraction(t *testing.T) { if err != nil { l.Fatalf("did not connect: %v", err) } - defer func() { - _ = conn.Close() - }() + defer conn.Close() c := NewPactPluginClient(conn) // Contact the server and print out its response. @@ -482,9 +480,7 @@ func TestGrpcPluginInteraction_ErrorResponse(t *testing.T) { if err != nil { l.Fatalf("did not connect: %v", err) } - defer func() { - _ = conn.Close() - }() + defer conn.Close() c := NewPactPluginClient(conn) // Contact the server and print out its response. diff --git a/internal/native/mock_server.go b/internal/native/mock_server.go index b32321ee0..38ab72d36 100644 --- a/internal/native/mock_server.go +++ b/internal/native/mock_server.go @@ -11,9 +11,7 @@ import ( "encoding/json" "fmt" "log" - "net" "os" - "strconv" "strings" "unsafe" ) @@ -136,6 +134,52 @@ func (m *MockServer) WithSpecificationVersion(version specificationVersion) { C.pactffi_with_specification(m.pact.handle, C.int(version)) } +// CreateMockServer creates a new Mock Server from a given Pact file. +// Returns the port number it started on or an error if failed +func (m *MockServer) CreateMockServer(pact string, address string, tls bool) (int, error) { + log.Println("[DEBUG] mock server starting on address:", address) + cPact := C.CString(pact) + cAddress := C.CString(address) + defer free(cPact) + defer free(cAddress) + tlsEnabled := false + if tls { + tlsEnabled = true + } + + p := C.pactffi_create_mock_server(cPact, cAddress, C.bool(tlsEnabled)) + + // | Error | Description | + // |-------|-------------| + // | -1 | A null pointer was received | + // | -2 | The pact JSON could not be parsed | + // | -3 | The mock server could not be started | + // | -4 | The method panicked | + // | -5 | The address is not valid | + // | -6 | Could not create the TLS configuration with the self-signed certificate | + port := int(p) + switch port { + case -1: + return 0, ErrInvalidMockServerConfig + case -2: + return 0, ErrInvalidPact + case -3: + return 0, ErrMockServerUnableToStart + case -4: + return 0, ErrMockServerPanic + case -5: + return 0, ErrInvalidAddress + case -6: + return 0, ErrMockServerTLSConfiguration + default: + if port > 0 { + log.Println("[DEBUG] mock server running on port:", port) + return port, nil + } + return port, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", port) + } +} + // Verify verifies that all interactions were successful. If not, returns a slice // of Mismatch-es. Does not write the pact or cleanup server. func (m *MockServer) Verify(port int, dir string) (bool, []MismatchedRequest) { @@ -237,36 +281,21 @@ func libRustFree(str *C.char) { } // Start starts up the mock HTTP server on the given address:port and TLS config -// https://docs.rs/pact_ffi/latest/pact_ffi/mock_server/fn.pactffi_create_mock_server_for_transport.html +// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.create_mock_server_for_pact.html func (m *MockServer) Start(address string, tls bool) (int, error) { if len(m.interactions) == 0 { return 0, ErrNoInteractions } log.Println("[DEBUG] mock server starting on address:", address) - - host, portStr, err := net.SplitHostPort(address) - if err != nil { - return 0, ErrInvalidAddress - } - requestedPort, err := strconv.Atoi(portStr) - if err != nil { - return 0, ErrInvalidAddress - } - cHost := C.CString(host) - defer free(cHost) - var transport string + cAddress := C.CString(address) + defer free(cAddress) + tlsEnabled := false if tls { - transport = "https" - } else { - transport = "http" + tlsEnabled = true } - cTransport := C.CString(transport) - defer free(cTransport) - - cConfig := (*C.char)(nil) - msPort := int(C.pactffi_create_mock_server_for_transport(m.pact.handle, cHost, C.ushort(requestedPort), cTransport, cConfig)) + p := C.pactffi_create_mock_server_for_pact(m.pact.handle, cAddress, C.bool(tlsEnabled)) // | Error | Description | // |-------|-------------| @@ -276,23 +305,26 @@ func (m *MockServer) Start(address string, tls bool) (int, error) { // | -4 | The method panicked | // | -5 | The address is not valid | // | -6 | Could not create the TLS configuration with the self-signed certificate | - switch msPort { + port := int(p) + switch port { case -1: return 0, ErrInvalidMockServerConfig case -2: - return 0, ErrInvalidMockServerConfig + return 0, ErrInvalidPact case -3: return 0, ErrMockServerUnableToStart case -4: return 0, ErrMockServerPanic case -5: return 0, ErrInvalidAddress + case -6: + return 0, ErrMockServerTLSConfiguration default: - if msPort > 0 { - log.Println("[DEBUG] mock server running on port:", msPort) - return msPort, nil + if port > 0 { + log.Println("[DEBUG] mock server running on port:", port) + return port, nil } - return msPort, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", msPort) + return port, fmt.Errorf("an unknown error (code: %v) occurred when starting a mock server for the test", port) } } @@ -380,7 +412,7 @@ func (m *MockServer) UsingPlugin(pluginName string, pluginVersion string) error return ErrHandleNotFound default: if res != 0 { - return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code", res) + return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res) } } @@ -436,7 +468,7 @@ func (i *Interaction) WithPluginInteractionContents(part interactionPart, conten return ErrPluginSpecificError default: if res != 0 { - return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code", res) + return fmt.Errorf("an unknown error (code: %v) occurred when adding a plugin for the test. Received error code:", res) } } @@ -611,22 +643,6 @@ func (i *Interaction) WithStatus(status int) *Interaction { return i } -// WithReference records an external reference (e.g. a ticket or pull request) -// against the interaction. References are stored under comments.references[group][name] -// in the Pact file. This is a V4-only feature. -func (i *Interaction) WithReference(group, name, value string) *Interaction { - cGroup := C.CString(group) - defer free(cGroup) - cName := C.CString(name) - defer free(cName) - cValue := C.CString(value) - defer free(cValue) - - C.pactffi_add_interaction_reference(i.handle, cGroup, cName, cValue) - - return i -} - type stringLike interface { String() string } @@ -762,11 +778,11 @@ var ( // Log Errors var ( - ErrCantSetLogger = fmt.Errorf("can't set logger (applying the logger failed, perhaps because one is applied already)") - ErrNoLogger = fmt.Errorf("no logger has been initialized (call `logger_init` before any other log function)") - ErrSpecifierNotUtf8 = fmt.Errorf("the sink specifier was not UTF-8 encoded") - ErrUnknownSinkType = fmt.Errorf(`the sink type specified is not a known type (known types: "buffer", "stdout", "stderr", or "file /some/path")`) - ErrMissingFilePath = fmt.Errorf("no file path was specified in a file-type sink specification") - ErrCantOpenSinkToFile = fmt.Errorf("opening a sink to the specified file path failed (check permissions)") + ErrCantSetLogger = fmt.Errorf("can't set logger (applying the logger failed, perhaps because one is applied already).") + ErrNoLogger = fmt.Errorf("no logger has been initialized (call `logger_init` before any other log function).") + ErrSpecifierNotUtf8 = fmt.Errorf("The sink specifier was not UTF-8 encoded.") + ErrUnknownSinkType = fmt.Errorf(`the sink type specified is not a known type (known types: "buffer", "stdout", "stderr", or "file /some/path").`) + ErrMissingFilePath = fmt.Errorf("no file path was specified in a file-type sink specification.") + ErrCantOpenSinkToFile = fmt.Errorf("opening a sink to the specified file path failed (check permissions).") ErrCantConstructSink = fmt.Errorf("can't construct the log sink") ) diff --git a/internal/native/mock_server_test.go b/internal/native/mock_server_test.go index 7e53d8057..aa79a6373 100644 --- a/internal/native/mock_server_test.go +++ b/internal/native/mock_server_test.go @@ -17,34 +17,9 @@ func init() { Init("") } -// newSimpleMockServer creates a mock server with a simple GET /foobar → 200 interaction -// using the programmatic API, replacing the removed CreateMockServer function. -func newSimpleMockServer(t *testing.T) (*MockServer, int) { - t.Helper() - m := NewHTTPPact("consumer", "provider") - m.NewInteraction("Some name for the test"). - UponReceiving("Some name for the test"). - Given("Some state"). - WithRequest("GET", "/foobar"). - WithStatus(200) - port, err := m.Start("0.0.0.0:0", false) - if err != nil { - t.Fatalf("failed to start mock server: %v", err) - } - return m, port -} - func TestMockServer_CreateAndCleanupMockServer(t *testing.T) { - m := NewHTTPPact("consumer", "provider") - m.NewInteraction("Some complex interaction"). - UponReceiving("Some complex interaction"). - Given("Some state"). - WithRequest("GET", "/foobar"). - WithStatus(200) - port, err := m.Start("0.0.0.0:0", false) - if err != nil { - t.Fatal("failed to start mock server:", err) - } + m := MockServer{} + port, _ := m.CreateMockServer(pactComplex, "0.0.0.0:0", false) defer m.CleanupMockServer(port) if port <= 0 { @@ -53,7 +28,8 @@ func TestMockServer_CreateAndCleanupMockServer(t *testing.T) { } func TestMockServer_MismatchesSuccess(t *testing.T) { - m, port := newSimpleMockServer(t) + m := MockServer{} + port, _ := m.CreateMockServer(pactSimple, "0.0.0.0:0", false) defer m.CleanupMockServer(port) res, err := http.Get(fmt.Sprintf("http://localhost:%d/foobar", port)) @@ -72,7 +48,8 @@ func TestMockServer_MismatchesSuccess(t *testing.T) { } func TestMockServer_MismatchesFail(t *testing.T) { - m, port := newSimpleMockServer(t) + m := MockServer{} + port, _ := m.CreateMockServer(pactSimple, "0.0.0.0:0", false) defer m.CleanupMockServer(port) mismatches := m.MockServerMismatchedRequests(port) @@ -85,7 +62,8 @@ func TestMockServer_VerifySuccess(t *testing.T) { tmpPactFolder, err := os.MkdirTemp("", "pact-go") assert.NoError(t, err) - m, port := newSimpleMockServer(t) + m := MockServer{} + port, _ := m.CreateMockServer(pactSimple, "0.0.0.0:0", false) defer m.CleanupMockServer(port) _, err = http.Get(fmt.Sprintf("http://localhost:%d/foobar", port)) @@ -106,7 +84,8 @@ func TestMockServer_VerifySuccess(t *testing.T) { func TestMockServer_VerifyFail(t *testing.T) { tmpPactFolder, err := os.MkdirTemp("", "pact-go") assert.NoError(t, err) - m, port := newSimpleMockServer(t) + m := MockServer{} + port, _ := m.CreateMockServer(pactSimple, "0.0.0.0:0", false) success, mismatches := m.Verify(port, tmpPactFolder) if success { @@ -122,7 +101,8 @@ func TestMockServer_WritePactfile(t *testing.T) { tmpPactFolder, err := os.MkdirTemp("", "pact-go") assert.NoError(t, err) - m, port := newSimpleMockServer(t) + m := MockServer{} + port, _ := m.CreateMockServer(pactSimple, "0.0.0.0:0", false) defer m.CleanupMockServer(port) _, err = http.Get(fmt.Sprintf("http://localhost:%d/foobar", port)) @@ -175,6 +155,7 @@ func TestHandleBasedHTTPTests(t *testing.T) { _, err = http.Get(fmt.Sprintf("http://0.0.0.0:%d/products", port)) assert.NoError(t, err) + mismatches := m.MockServerMismatchedRequests(port) if len(mismatches) != 0 { t.Fatalf("want 0 mismatches, got '%d'", len(mismatches)) @@ -242,3 +223,73 @@ func TestPluginInteraction(t *testing.T) { err = m.WritePactFile(port, tmpPactFolder) assert.NoError(t, err) } + +var pactSimple = `{ + "consumer": { + "name": "consumer" + }, + "provider": { + "name": "provider" + }, + "interactions": [ + { + "description": "Some name for the test", + "request": { + "method": "GET", + "path": "/foobar" + }, + "response": { + "status": 200 + }, + "description": "Some name for the test", + "provider_state": "Some state" + }] +}` + +var pactComplex = `{ + "consumer": { + "name": "consumer" + }, + "provider": { + "name": "provider" + }, + "interactions": [ + { + "request": { + "method": "GET", + "path": "/foobar", + "body": { + "pass": 1234, + "user": { + "address": "some address", + "name": "someusername", + "phone": 12345678, + "plaintext": "plaintext" + } + } + }, + "response": { + "status": 200 + }, + "description": "Some name for the test", + "provider_state": "Some state", + "matchingRules": { + "$.body.pass": { + "match": "regex", + "regex": "\\d+" + }, + "$.body.user.address": { + "match": "regex", + "regex": "\\s+" + }, + "$.body.user.name": { + "match": "regex", + "regex": "\\s+" + }, + "$.body.user.phone": { + "match": "regex", + "regex": "\\d+" + } + } + }] +}` diff --git a/internal/native/pact.h b/internal/native/pact.h index 342a601e8..c5865d040 100644 --- a/internal/native/pact.h +++ b/internal/native/pact.h @@ -7,7 +7,7 @@ #ifndef pact_ffi_h #define pact_ffi_h -/* Generated with cbindgen:0.29.2 */ +/* Generated with cbindgen:0.26.0 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ @@ -657,32 +657,18 @@ int pactffi_get_error_message(char *buffer, /** * Convenience function to direct all logging to stdout. - * - * This function is equivalent to using [`pactffi_logger_init`] followed by the - * [`pactffi_logger_attach_sink`] with the appropriate sink specifier, and then - * [`pactffi_logger_apply`]. */ int pactffi_log_to_stdout(int level_filter); /** * Convenience function to direct all logging to stderr. - * - * This function is equivalent to using [`pactffi_logger_init`] followed by the - * [`pactffi_logger_attach_sink`] with the appropriate sink specifier, and then - * [`pactffi_logger_apply`]. */ int pactffi_log_to_stderr(int level_filter); /** * Convenience function to direct all logging to a file. * - * - * This function is equivalent to using [`pactffi_logger_init`] followed by the - * [`pactffi_logger_attach_sink`] with the appropriate sink specifier, and then - * [`pactffi_logger_apply`]. - * * # Safety - * * This function will fail if the file_name pointer is invalid or does not point to a NULL * terminated string. */ @@ -690,13 +676,6 @@ int pactffi_log_to_file(const char *file_name, int level_filter); /** * Convenience function to direct all logging to a task local memory buffer. - * - * This function is equivalent to using [`pactffi_logger_init`] followed by the - * [`pactffi_logger_attach_sink`] with the appropriate sink specifier, and then - * [`pactffi_logger_apply`]. - * - * The contents of the buffer can be fetched using - * [`pactffi_fetch_log_buffer`]. */ int pactffi_log_to_buffer(int level_filter); @@ -742,7 +721,7 @@ void pactffi_logger_init(void); * - `-1`: Can't set logger (applying the logger failed, perhaps because one is applied already). * - `-2`: No logger has been initialized (call `pactffi_logger_init` before any other log function). * - `-3`: The sink specifier was not UTF-8 encoded. - * - `-4`: The sink type specified is not a known type (known types: "stdout", "stderr", "buffer", or "file /some/path"). + * - `-4`: The sink type specified is not a known type (known types: "stdout", "stderr", or "file /some/path"). * - `-5`: No file path was specified in a file-type sink specification. * - `-6`: Opening a sink to the specified file path failed (check permissions). * @@ -761,12 +740,6 @@ int pactffi_logger_attach_sink(const char *sink_specifier, * * This function will install a global tracing subscriber. Any attempts to modify the logger * after the call to `logger_apply` will fail. - * - * # Error Handling - * - * The return error codes are as follows: - * - * - `-1`: Can't set logger (applying the logger failed, perhaps because one is applied already). */ int pactffi_logger_apply(void); @@ -820,7 +793,7 @@ struct PactInteractionIterator *pactffi_pact_model_interaction_iterator(struct P /** * Returns the Pact specification enum that the Pact is for. */ -enum PactSpecification pactffi_pact_spec_version(const struct Pact *pact); +int pactffi_pact_spec_version(const struct Pact *pact); /** * Frees the memory used by the Pact interaction model @@ -3116,6 +3089,35 @@ struct ProviderStateIterator *pactffi_sync_message_get_provider_state_iter(struc */ void pactffi_string_delete(char *string); +/** + * [DEPRECATED] External interface to create a HTTP mock server. A pointer to the pact JSON as a NULL-terminated C + * string is passed in, as well as the port for the mock server to run on. A value of 0 for the + * port will result in a port being allocated by the operating system. The port of the mock server is returned. + * + * * `pact_str` - Pact JSON + * * `addr_str` - Address to bind to in the form name:port (i.e. 127.0.0.1:0) + * * `tls` - boolean flag to indicate of the mock server should use TLS (using a self-signed certificate) + * + * This function is deprecated and replaced with `pactffi_create_mock_server_for_transport`. + * + * # Errors + * + * Errors are returned as negative values. + * + * | Error | Description | + * |-------|-------------| + * | -1 | A null pointer was received | + * | -2 | The pact JSON could not be parsed | + * | -3 | The mock server could not be started | + * | -4 | The method panicked | + * | -5 | The address is not valid | + * | -6 | Could not create the TLS configuration with the self-signed certificate | + * + */ +int32_t pactffi_create_mock_server(const char *pact_str, + const char *addr_str, + bool tls); + /** * Fetch the CA Certificate used to generate the self-signed certificate for the TLS mock server. * @@ -3128,6 +3130,34 @@ void pactffi_string_delete(char *string); */ char *pactffi_get_tls_ca_certificate(void); +/** + * [DEPRECATED] External interface to create a HTTP mock server. A Pact handle is passed in, + * as well as the port for the mock server to run on. A value of 0 for the port will result in a + * port being allocated by the operating system. The port of the mock server is returned. + * + * * `pact` - Handle to a Pact model created with created with `pactffi_new_pact`. + * * `addr_str` - Address to bind to in the form name:port (i.e. 127.0.0.1:0). Must be a valid UTF-8 NULL-terminated string. + * * `tls` - boolean flag to indicate of the mock server should use TLS (using a self-signed certificate) + * + * This function is deprecated and replaced with `pactffi_create_mock_server_for_transport`. + * + * # Errors + * + * Errors are returned as negative values. + * + * | Error | Description | + * |-------|-------------| + * | -1 | An invalid handle was received. Handles should be created with `pactffi_new_pact` | + * | -3 | The mock server could not be started | + * | -4 | The method panicked | + * | -5 | The address is not valid | + * | -6 | Could not create the TLS configuration with the self-signed certificate | + * + */ +int32_t pactffi_create_mock_server_for_pact(PactHandle pact, + const char *addr_str, + bool tls); + /** * Create a mock server for the provided Pact handle and transport. If the transport is not * provided (it is a NULL pointer or an empty string), will default to an HTTP transport. The @@ -3518,12 +3548,11 @@ bool pactffi_with_specification(PactHandle pact, int pactffi_handle_get_pact_spec_version(PactHandle pact); /** - * Sets the additional metadata on the Pact file. Common uses are to add the client library - * details such as the name and version. Returns false if the interaction or Pact can't be - * modified (i.e. the mock server for it has already started) or the namespace is readonly. + * Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version + * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has already started) * * * `pact` - Handle to a Pact model - * * `namespace` - the top level metadata key to set any key values on + * * `namespace` - the top level metadat key to set any key values on * * `name` - the key to set * * `value` - the value to set */ @@ -3696,43 +3725,30 @@ bool pactffi_response_status_v2(InteractionHandle interaction, const char *status); /** - * Adds the body for the interaction. Returns false if the interaction or Pact - * can't be modified (i.e. the mock server for it has already started) - * - * * `part` - The part of the interaction to add the body to (Request or - * Response). This is ignored for asynchronous message interactions. - * * `content_type` - The content type of the body, or `NULL` to use the - * internal logic. - * * `body` - The body contents. For JSON payloads, matching rules can be - * embedded in the body. See - * [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) - * - * The payload's content type is determined as follows, whichever is first: - * - * - The `content_type` argument to this function if provided. If the provided - * value fails to parse, and error is logged and it will be ignored. - * - The `Content-Type` header for HTTP interaction, or `contentType` metadata - * entry for message interactions. - * - From automatic detection of the body contents. - * - Defaults to `text/plain` as a last resort. + * Adds the body for the interaction. Returns false if the interaction or Pact can't be + * modified (i.e. the mock server for it has already started) * - * Furthermore, the `Content-Type` header or `contentType` metadata entry will - * be updated with the above determined content type, _unless_ it is already - * set. + * * `part` - The part of the interaction to add the body to (Request or Response). + * * `content_type` - The content type of the body. Defaults to `text/plain`. Will be ignored if a content type + * header is already set. + * * `body` - The body contents. For JSON payloads, matching rules can be embedded in the body. See + * [IntegrationJson.md](https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md) * - * This function will overwrite the body contents if they exist, with the - * exception of the response part of synchronous message interactions, where a - * new response will be appended. + * For HTTP and async message interactions, this will overwrite the body. With asynchronous messages, the + * part parameter will be ignored. With synchronous messages, the request contents will be overwritten, + * while a new response will be appended to the message. * * # Safety * - * The interaction contents and content type must either be NULL pointers, or - * point to valid UTF-8 encoded NULL-terminated strings. Otherwise, behaviour - * is undefined. + * The interaction contents and content type must either be NULL pointers, or point to valid + * UTF-8 encoded NULL-terminated strings. Otherwise, behaviour is undefined. * * # Error Handling * - * If the contents is a NULL pointer, it will set the body contents as null. + * If the contents is a NULL pointer, it will set the body contents as null. If the content + * type is a null pointer, or can't be parsed, it will set the content type as TEXT. + * Returns false if the interaction or Pact can't be modified (i.e. the mock server for it has + * already started) or an error has occurred. */ bool pactffi_with_body(InteractionHandle interaction, int part, @@ -3776,14 +3792,6 @@ bool pactffi_with_binary_body(InteractionHandle interaction, size_t size); /** - *