From 8e451cafb4f6ff086a2a88a1046be4b10cf66eec Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Sun, 30 Jun 2024 13:11:13 +0100 Subject: [PATCH] feat: test out pure-go impl --- .github/workflows/test.yml | 11 +- Makefile | 3 + examples/avro/avro_provider_test.go | 101 ++- examples/grpc/grpc_provider_test.go | 102 +-- examples/grpc/routeguide/server/server.go | 2 +- .../protobuf_provider_test.go | 107 ++- examples/provider_test.go | 371 ++++++----- go.mod | 4 +- go.sum | 4 +- installer/installer_test.go | 2 +- internal/native/lib.go | 607 +++++++++++++++++- internal/native/lib_unix.go | 9 + internal/native/lib_windows.go | 10 + internal/native/message_server.go | 339 +++------- internal/native/message_server_test.go | 276 ++++---- internal/native/mock_server.go | 358 ++--------- internal/native/verifier.go | 179 ++---- 17 files changed, 1304 insertions(+), 1181 deletions(-) create mode 100644 internal/native/lib_unix.go create mode 100644 internal/native/lib_windows.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e89e30dd..a6908d35e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ env: PACT_DO_NOT_TRACK: true APP_SHA: ${{ github.sha }} APP_REF: ${{ github.ref }} - # LD_LIBRARY_PATH: /tmp + PACT_LD_LIBRARY_PATH: /tmp # PACT_GO_LIB_DOWNLOAD_PATH: /tmp LOG_LEVEL: DEBUG COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -43,11 +43,16 @@ jobs: - name: Test if: matrix.os == 'ubuntu-latest' run: APP_BRANCH=${APP_REF:11} DOCKER_GATEWAY_HOST=172.17.0.1 DOCKER_HOST_HTTP="http://172.17.0.1" make + # - name: Set CGO_LDFLAGS / pact_ffi lib on PATH, and skip Avro plugin download + # if: matrix.os == 'windows-latest' + # run: | + # "CGO_LDFLAGS=-L$env:TMP" >> $env:GITHUB_ENV + # "$env:TMP" >> $env:GITHUB_PATH + # "SKIP_PLUGIN_AVRO=true" >> $env:GITHUB_ENV - name: Set CGO_LDFLAGS / pact_ffi lib on PATH, and skip Avro plugin download if: matrix.os == 'windows-latest' run: | - "CGO_LDFLAGS=-L$env:TMP" >> $env:GITHUB_ENV - "$env:TMP" >> $env:GITHUB_PATH + "PACT_LD_LIBRARY_PATH=$env:TMP" >> $env:GITHUB_ENV "SKIP_PLUGIN_AVRO=true" >> $env:GITHUB_ENV - name: Test (unit) if: matrix.os != 'ubuntu-latest' diff --git a/Makefile b/Makefile index fa291a00a..6406ed490 100755 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ docker_build: docker_test: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ --rm \ -it \ pactfoundation/pact-go-test-$(IMAGE_VARIANT) \ @@ -49,6 +50,7 @@ docker_test: docker_build docker_pact: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ --rm \ -it \ pactfoundation/pact-go-test-$(IMAGE_VARIANT) \ @@ -56,6 +58,7 @@ docker_pact: docker_build docker_shell: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ -v $$PWD:/go/src/github.com/pact-foundation/pact-go \ --rm \ -it \ diff --git a/examples/avro/avro_provider_test.go b/examples/avro/avro_provider_test.go index deb07898a..b066113bf 100644 --- a/examples/avro/avro_provider_test.go +++ b/examples/avro/avro_provider_test.go @@ -5,70 +5,69 @@ package avro import ( "fmt" - "log" - "net/http" "os" - "path/filepath" - "runtime" - "testing" - - "github.com/pact-foundation/pact-go/v2/provider" - "github.com/pact-foundation/pact-go/v2/utils" - "github.com/stretchr/testify/assert" + // "log" + // "net/http" + // "path/filepath" + // "runtime" + // "testing" + // "github.com/pact-foundation/pact-go/v2/provider" + // "github.com/pact-foundation/pact-go/v2/utils" + // "github.com/stretchr/testify/assert" ) var dir, _ = os.Getwd() var pactDir = fmt.Sprintf("%s/../pacts", dir) -func TestAvroHTTPProvider(t *testing.T) { - if runtime.GOOS != "windows" { +// func TestAvroHTTPProvider(t *testing.T) { +// if runtime.GOOS != "windows" { - httpPort, _ := utils.GetFreePort() +// httpPort, _ := utils.GetFreePort() - // Start provider API in the background - go startHTTPProvider(httpPort) +// // Start provider API in the background +// go startHTTPProvider(httpPort) - verifier := provider.NewVerifier() +// verifier := provider.NewVerifier() - // Verify the Provider with local Pact Files - err := verifier.VerifyProvider(t, provider.VerifyRequest{ - ProviderBaseURL: fmt.Sprintf("http://127.0.0.1:%d", httpPort), - Provider: "AvroProvider", - PactFiles: []string{ - filepath.ToSlash(fmt.Sprintf("%s/AvroConsumer-AvroProvider.json", pactDir)), - }, - }) +// // Verify the Provider with local Pact Files +// err := verifier.VerifyProvider(t, provider.VerifyRequest{ +// ProviderBaseURL: fmt.Sprintf("http://127.0.0.1:%d", httpPort), +// Provider: "AvroProvider", +// PactFiles: []string{ +// filepath.ToSlash(fmt.Sprintf("%s/AvroConsumer-AvroProvider.json", pactDir)), +// }, +// }) - assert.NoError(t, err) - } -} +// assert.NoError(t, err) +// } +// } -func startHTTPProvider(port int) { - mux := http.NewServeMux() +// func startHTTPProvider(port int) { +// mux := http.NewServeMux() - mux.HandleFunc("/avro", func(w http.ResponseWriter, req *http.Request) { - w.Header().Add("Content-Type", "avro/binary;record=User") +// mux.HandleFunc("/avro", func(w http.ResponseWriter, req *http.Request) { +// w.Header().Add("Content-Type", "avro/binary;record=User") - user := &User{ - ID: 1, - Username: "matt", - // Username: "sally", // matching rules not supported? - } +// user := &User{ +// ID: 1, +// Username: "matt", +// // Username: "sally", // matching rules not supported? +// } - codec := getCodec() - binary, err := codec.BinaryFromNative(nil, map[string]interface{}{ - "id": user.ID, - "username": user.Username, - }) - if err != nil { - log.Println("ERROR: ", err) - w.WriteHeader(500) - } else { - fmt.Fprintf(w, string(binary)) - w.WriteHeader(200) - } - }) +// codec := getCodec() +// binary, err := codec.BinaryFromNative(nil, map[string]interface{}{ +// "id": user.ID, +// "username": user.Username, +// }) +// if err != nil { +// log.Println("ERROR: ", err) +// w.WriteHeader(500) +// } else { +// fmt.Fprintf(w, string(binary)) +// w.WriteHeader(200) +// } +// }) - log.Printf("started HTTP server on port: %d\n", port) - log.Fatal(http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), mux)) -} +// log.Printf("started HTTP server on port: %d\n", port) +// log.Fatal(http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), mux)) +// } diff --git a/examples/grpc/grpc_provider_test.go b/examples/grpc/grpc_provider_test.go index 0d6188504..eacd085ad 100644 --- a/examples/grpc/grpc_provider_test.go +++ b/examples/grpc/grpc_provider_test.go @@ -3,62 +3,62 @@ package grpc -import ( - "fmt" - "log" - "runtime" +// import ( +// "fmt" +// "log" +// "runtime" - "net" - "os" - "path/filepath" - "testing" +// "net" +// "os" +// "path/filepath" +// "testing" - "github.com/hashicorp/logutils" +// "github.com/hashicorp/logutils" - pb "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" - "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide/server" - l "github.com/pact-foundation/pact-go/v2/log" - "github.com/pact-foundation/pact-go/v2/provider" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc" -) +// pb "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" +// "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide/server" +// l "github.com/pact-foundation/pact-go/v2/log" +// "github.com/pact-foundation/pact-go/v2/provider" +// "github.com/stretchr/testify/assert" +// "google.golang.org/grpc" +// ) -func TestGrpcProvider(t *testing.T) { - if runtime.GOOS != "windows" { +// func TestGrpcProvider(t *testing.T) { +// if runtime.GOOS != "windows" { - go startProvider() - logLevel := os.Getenv("LOG_LEVEL") - if logLevel == "" { - logLevel = "TRACE" - } - l.SetLogLevel(logutils.LogLevel(logLevel)) - verifier := provider.NewVerifier() +// go startProvider() +// logLevel := os.Getenv("LOG_LEVEL") +// if logLevel == "" { +// logLevel = "TRACE" +// } +// l.SetLogLevel(logutils.LogLevel(logLevel)) +// verifier := provider.NewVerifier() - err := verifier.VerifyProvider(t, provider.VerifyRequest{ - ProviderBaseURL: "http://localhost:8222", - Transports: []provider.Transport{ - { - Protocol: "grpc", - Port: 8222, - }, - }, - Provider: "grpcprovider", - PactFiles: []string{ - filepath.ToSlash(fmt.Sprintf("%s/../pacts/grpcconsumer-grpcprovider.json", dir)), - }, - }) +// err := verifier.VerifyProvider(t, provider.VerifyRequest{ +// ProviderBaseURL: "http://localhost:8222", +// Transports: []provider.Transport{ +// { +// Protocol: "grpc", +// Port: 8222, +// }, +// }, +// Provider: "grpcprovider", +// PactFiles: []string{ +// filepath.ToSlash(fmt.Sprintf("%s/../pacts/grpcconsumer-grpcprovider.json", dir)), +// }, +// }) - assert.NoError(t, err) - } -} +// assert.NoError(t, err) +// } +// } -func startProvider() { - lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 8222)) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - var opts []grpc.ServerOption - grpcServer := grpc.NewServer(opts...) - pb.RegisterRouteGuideServer(grpcServer, server.NewServer()) - grpcServer.Serve(lis) -} +// func startProvider() { +// lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 8222)) +// if err != nil { +// log.Fatalf("failed to listen: %v", err) +// } +// var opts []grpc.ServerOption +// grpcServer := grpc.NewServer(opts...) +// pb.RegisterRouteGuideServer(grpcServer, server.NewServer()) +// grpcServer.Serve(lis) +// } diff --git a/examples/grpc/routeguide/server/server.go b/examples/grpc/routeguide/server/server.go index fa59e7ddf..50aab3924 100644 --- a/examples/grpc/routeguide/server/server.go +++ b/examples/grpc/routeguide/server/server.go @@ -42,7 +42,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" pb "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" ) diff --git a/examples/protobuf-message/protobuf_provider_test.go b/examples/protobuf-message/protobuf_provider_test.go index cf979b8fb..926918d0a 100644 --- a/examples/protobuf-message/protobuf_provider_test.go +++ b/examples/protobuf-message/protobuf_provider_test.go @@ -3,64 +3,63 @@ package protobuf -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "testing" +// import ( +// "fmt" +// "os" +// "path/filepath" +// "runtime" +// "testing" - "github.com/golang/protobuf/proto" - "github.com/hashicorp/logutils" - "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" - pactlog "github.com/pact-foundation/pact-go/v2/log" - "github.com/pact-foundation/pact-go/v2/message" - "github.com/pact-foundation/pact-go/v2/models" - "github.com/pact-foundation/pact-go/v2/provider" - pactversion "github.com/pact-foundation/pact-go/v2/version" - "github.com/stretchr/testify/assert" -) +// "github.com/golang/protobuf/proto" +// "github.com/hashicorp/logutils" +// "github.com/pact-foundation/pact-go/v2/examples/grpc/routeguide" +// pactlog "github.com/pact-foundation/pact-go/v2/log" +// "github.com/pact-foundation/pact-go/v2/message" +// "github.com/pact-foundation/pact-go/v2/models" +// "github.com/pact-foundation/pact-go/v2/provider" +// pactversion "github.com/pact-foundation/pact-go/v2/version" +// "github.com/stretchr/testify/assert" +// ) +// func TestPluginMessageProvider(t *testing.T) { +// if runtime.GOOS != "windows" { +// var dir, _ = os.Getwd() +// var pactDir = fmt.Sprintf("%s/../pacts", dir) +// logLevel := os.Getenv("LOG_LEVEL") +// if logLevel == "" { +// logLevel = "TRACE" +// } +// err := pactlog.SetLogLevel(logutils.LogLevel(logLevel)) -func TestPluginMessageProvider(t *testing.T) { - if runtime.GOOS != "windows" { - var dir, _ = os.Getwd() - var pactDir = fmt.Sprintf("%s/../pacts", dir) - logLevel := os.Getenv("LOG_LEVEL") - if logLevel == "" { - logLevel = "TRACE" - } - err := pactlog.SetLogLevel(logutils.LogLevel(logLevel)) +// assert.NoError(t, err) - assert.NoError(t, err) +// pactversion.CheckVersion("/tmp") - pactversion.CheckVersion("/tmp") +// verifier := provider.NewVerifier() - verifier := provider.NewVerifier() +// functionMappings := message.Handlers{ +// "feature message": func([]models.ProviderState) (message.Body, message.Metadata, error) { +// fmt.Println("feature message handler") +// feature, _ := proto.Marshal(&routeguide.Feature{ +// Name: "fake feature", +// Location: &routeguide.Point{ +// Latitude: int32(1), +// Longitude: int32(1), +// }, +// }) +// return feature, message.Metadata{ +// "contentType": "application/protobuf;message=Feature", // <- This is required to ensure the correct type is matched +// }, nil +// }, +// } - functionMappings := message.Handlers{ - "feature message": func([]models.ProviderState) (message.Body, message.Metadata, error) { - fmt.Println("feature message handler") - feature, _ := proto.Marshal(&routeguide.Feature{ - Name: "fake feature", - Location: &routeguide.Point{ - Latitude: int32(1), - Longitude: int32(1), - }, - }) - return feature, message.Metadata{ - "contentType": "application/protobuf;message=Feature", // <- This is required to ensure the correct type is matched - }, nil - }, - } +// err = verifier.VerifyProvider(t, provider.VerifyRequest{ +// PactFiles: []string{ +// filepath.ToSlash(fmt.Sprintf("%s/protobufmessageconsumer-protobufmessageprovider.json", pactDir)), +// }, +// Provider: "protobufmessageprovider", +// MessageHandlers: functionMappings, +// }) - err = verifier.VerifyProvider(t, provider.VerifyRequest{ - PactFiles: []string{ - filepath.ToSlash(fmt.Sprintf("%s/protobufmessageconsumer-protobufmessageprovider.json", pactDir)), - }, - Provider: "protobufmessageprovider", - MessageHandlers: functionMappings, - }) - - assert.NoError(t, err) - } -} +// assert.NoError(t, err) +// } +// } diff --git a/examples/provider_test.go b/examples/provider_test.go index 674451c74..99dd5ee1e 100644 --- a/examples/provider_test.go +++ b/examples/provider_test.go @@ -9,16 +9,15 @@ import ( l "log" "net/http" "os" - "path/filepath" - "testing" - - "github.com/hashicorp/logutils" - "github.com/pact-foundation/pact-go/v2/log" - "github.com/pact-foundation/pact-go/v2/message" - "github.com/pact-foundation/pact-go/v2/models" - "github.com/pact-foundation/pact-go/v2/provider" - "github.com/pact-foundation/pact-go/v2/version" - "github.com/stretchr/testify/assert" + // "path/filepath" + // "testing" + // "github.com/hashicorp/logutils" + // "github.com/pact-foundation/pact-go/v2/log" + // "github.com/pact-foundation/pact-go/v2/message" + // "github.com/pact-foundation/pact-go/v2/models" + // "github.com/pact-foundation/pact-go/v2/provider" + // "github.com/pact-foundation/pact-go/v2/version" + // "github.com/stretchr/testify/assert" ) var dir, _ = os.Getwd() @@ -27,182 +26,182 @@ var pactDir = fmt.Sprintf("%s/pacts", dir) var requestFilterCalled = false var stateHandlerCalled = false -func TestV3HTTPProvider(t *testing.T) { - logLevel := os.Getenv("LOG_LEVEL") - if logLevel == "" { - logLevel = "TRACE" - } - log.SetLogLevel(logutils.LogLevel(logLevel)) - version.CheckVersion("/tmp") - - // Start provider API in the background - go startServer() - - verifier := provider.NewVerifier() - - // Authorization middleware - // This is your chance to modify the request before it hits your provider - // NOTE: this should be used very carefully, as it has the potential to - // _change_ the contract - f := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - l.Println("[DEBUG] HOOK request filter") - requestFilterCalled = true - r.Header.Add("Authorization", "Bearer 1234-dynamic-value") - next.ServeHTTP(w, r) - }) - } - - // Verify the Provider with local Pact Files - - if os.Getenv("SKIP_PUBLISH") != "true" { - err := verifier.VerifyProvider(t, provider.VerifyRequest{ - ProviderBaseURL: "http://127.0.0.1:8111", - Provider: "V3Provider", - ProviderVersion: os.Getenv("APP_SHA"), - BrokerURL: os.Getenv("PACT_BROKER_BASE_URL"), - ConsumerVersionSelectors: []provider.Selector{ - &provider.ConsumerVersionSelector{ - Tag: "master", - }, - &provider.ConsumerVersionSelector{ - Tag: "prod", - }, - }, - PublishVerificationResults: true, - RequestFilter: f, - BeforeEach: func() error { - l.Println("[DEBUG] HOOK before each") - return nil - }, - AfterEach: func() error { - l.Println("[DEBUG] HOOK after each") - return nil - }, - StateHandlers: models.StateHandlers{ - "User foo exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { - stateHandlerCalled = true - - if setup { - l.Println("[DEBUG] HOOK calling user foo exists state handler", s) - } else { - l.Println("[DEBUG] HOOK teardown the 'User foo exists' state") - } - - // ... do something, such as create "foo" in the database - - // Optionally (if there are generators in the pact) return provider state values to be used in the verification - return models.ProviderStateResponse{"uuid": "1234"}, nil - }, - }, - DisableColoredOutput: true, - }) - assert.NoError(t, err) - assert.True(t, requestFilterCalled) - assert.True(t, stateHandlerCalled) - } else { - err := verifier.VerifyProvider(t, provider.VerifyRequest{ - ProviderBaseURL: "http://127.0.0.1:8111", - Provider: "V3Provider", - PactFiles: []string{ - filepath.ToSlash(fmt.Sprintf("%s/PactGoV3Consumer-V3Provider.json", pactDir)), - filepath.ToSlash(fmt.Sprintf("%s/PactGoV2ConsumerMatch-V2ProviderMatch.json", pactDir)), - }, - RequestFilter: f, - BeforeEach: func() error { - l.Println("[DEBUG] HOOK before each") - return nil - }, - AfterEach: func() error { - l.Println("[DEBUG] HOOK after each") - return nil - }, - StateHandlers: models.StateHandlers{ - "User foo exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { - stateHandlerCalled = true - - if setup { - l.Println("[DEBUG] HOOK calling user foo exists state handler", s) - } else { - l.Println("[DEBUG] HOOK teardown the 'User foo exists' state") - } - - // ... do something, such as create "foo" in the database - - // Optionally (if there are generators in the pact) return provider state values to be used in the verification - return models.ProviderStateResponse{"uuid": "1234"}, nil - }, - }, - DisableColoredOutput: true, - }) - assert.NoError(t, err) - assert.True(t, requestFilterCalled) - assert.True(t, stateHandlerCalled) - } - -} - -func TestV3MessageProvider(t *testing.T) { - logLevel := os.Getenv("LOG_LEVEL") - if logLevel == "" { - logLevel = "TRACE" - } - log.SetLogLevel(logutils.LogLevel(logLevel)) - var user *User - - verifier := provider.NewVerifier() - - // Map test descriptions to message producer (handlers) - functionMappings := message.Handlers{ - "a user event": func([]models.ProviderState) (message.Body, message.Metadata, error) { - if user != nil { - return user, message.Metadata{ - "Content-Type": "application/json", - }, nil - } else { - return models.ProviderStateResponse{ - "message": "not found", - }, nil, nil - } - }, - } - - // Setup any required states for the handlers - stateMappings := models.StateHandlers{ - "User with id 127 exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { - if setup { - user = &User{ - ID: 127, - Name: "Billy", - Date: "2020-01-01", - LastName: "Sampson", - } - } - - return models.ProviderStateResponse{"id": user.ID}, nil - }, - } - - // Verify the Provider with local Pact Files - - if os.Getenv("SKIP_PUBLISH") != "true" { - verifier.VerifyProvider(t, provider.VerifyRequest{ - StateHandlers: stateMappings, - Provider: "V3MessageProvider", - ProviderVersion: os.Getenv("APP_SHA"), - BrokerURL: os.Getenv("PACT_BROKER_BASE_URL"), - MessageHandlers: functionMappings, - }) - } else { - verifier.VerifyProvider(t, provider.VerifyRequest{ - PactFiles: []string{filepath.ToSlash(fmt.Sprintf("%s/PactGoV3MessageConsumer-V3MessageProvider.json", pactDir))}, - StateHandlers: stateMappings, - Provider: "V3MessageProvider", - MessageHandlers: functionMappings, - }) - } - -} +// func TestV3HTTPProvider(t *testing.T) { +// logLevel := os.Getenv("LOG_LEVEL") +// if logLevel == "" { +// logLevel = "TRACE" +// } +// log.SetLogLevel(logutils.LogLevel(logLevel)) +// version.CheckVersion("/tmp") + +// // Start provider API in the background +// go startServer() + +// verifier := provider.NewVerifier() + +// // Authorization middleware +// // This is your chance to modify the request before it hits your provider +// // NOTE: this should be used very carefully, as it has the potential to +// // _change_ the contract +// f := func(next http.Handler) http.Handler { +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// l.Println("[DEBUG] HOOK request filter") +// requestFilterCalled = true +// r.Header.Add("Authorization", "Bearer 1234-dynamic-value") +// next.ServeHTTP(w, r) +// }) +// } + +// // Verify the Provider with local Pact Files + +// if os.Getenv("SKIP_PUBLISH") != "true" { +// err := verifier.VerifyProvider(t, provider.VerifyRequest{ +// ProviderBaseURL: "http://127.0.0.1:8111", +// Provider: "V3Provider", +// ProviderVersion: os.Getenv("APP_SHA"), +// BrokerURL: os.Getenv("PACT_BROKER_BASE_URL"), +// ConsumerVersionSelectors: []provider.Selector{ +// &provider.ConsumerVersionSelector{ +// Tag: "master", +// }, +// &provider.ConsumerVersionSelector{ +// Tag: "prod", +// }, +// }, +// PublishVerificationResults: true, +// RequestFilter: f, +// BeforeEach: func() error { +// l.Println("[DEBUG] HOOK before each") +// return nil +// }, +// AfterEach: func() error { +// l.Println("[DEBUG] HOOK after each") +// return nil +// }, +// StateHandlers: models.StateHandlers{ +// "User foo exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { +// stateHandlerCalled = true + +// if setup { +// l.Println("[DEBUG] HOOK calling user foo exists state handler", s) +// } else { +// l.Println("[DEBUG] HOOK teardown the 'User foo exists' state") +// } + +// // ... do something, such as create "foo" in the database + +// // Optionally (if there are generators in the pact) return provider state values to be used in the verification +// return models.ProviderStateResponse{"uuid": "1234"}, nil +// }, +// }, +// DisableColoredOutput: true, +// }) +// assert.NoError(t, err) +// assert.True(t, requestFilterCalled) +// assert.True(t, stateHandlerCalled) +// } else { +// err := verifier.VerifyProvider(t, provider.VerifyRequest{ +// ProviderBaseURL: "http://127.0.0.1:8111", +// Provider: "V3Provider", +// PactFiles: []string{ +// filepath.ToSlash(fmt.Sprintf("%s/PactGoV3Consumer-V3Provider.json", pactDir)), +// filepath.ToSlash(fmt.Sprintf("%s/PactGoV2ConsumerMatch-V2ProviderMatch.json", pactDir)), +// }, +// RequestFilter: f, +// BeforeEach: func() error { +// l.Println("[DEBUG] HOOK before each") +// return nil +// }, +// AfterEach: func() error { +// l.Println("[DEBUG] HOOK after each") +// return nil +// }, +// StateHandlers: models.StateHandlers{ +// "User foo exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { +// stateHandlerCalled = true + +// if setup { +// l.Println("[DEBUG] HOOK calling user foo exists state handler", s) +// } else { +// l.Println("[DEBUG] HOOK teardown the 'User foo exists' state") +// } + +// // ... do something, such as create "foo" in the database + +// // Optionally (if there are generators in the pact) return provider state values to be used in the verification +// return models.ProviderStateResponse{"uuid": "1234"}, nil +// }, +// }, +// DisableColoredOutput: true, +// }) +// assert.NoError(t, err) +// assert.True(t, requestFilterCalled) +// assert.True(t, stateHandlerCalled) +// } + +// } + +// func TestV3MessageProvider(t *testing.T) { +// logLevel := os.Getenv("LOG_LEVEL") +// if logLevel == "" { +// logLevel = "TRACE" +// } +// log.SetLogLevel(logutils.LogLevel(logLevel)) +// var user *User + +// verifier := provider.NewVerifier() + +// // Map test descriptions to message producer (handlers) +// functionMappings := message.Handlers{ +// "a user event": func([]models.ProviderState) (message.Body, message.Metadata, error) { +// if user != nil { +// return user, message.Metadata{ +// "Content-Type": "application/json", +// }, nil +// } else { +// return models.ProviderStateResponse{ +// "message": "not found", +// }, nil, nil +// } +// }, +// } + +// // Setup any required states for the handlers +// stateMappings := models.StateHandlers{ +// "User with id 127 exists": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { +// if setup { +// user = &User{ +// ID: 127, +// Name: "Billy", +// Date: "2020-01-01", +// LastName: "Sampson", +// } +// } + +// return models.ProviderStateResponse{"id": user.ID}, nil +// }, +// } + +// // Verify the Provider with local Pact Files + +// if os.Getenv("SKIP_PUBLISH") != "true" { +// verifier.VerifyProvider(t, provider.VerifyRequest{ +// StateHandlers: stateMappings, +// Provider: "V3MessageProvider", +// ProviderVersion: os.Getenv("APP_SHA"), +// BrokerURL: os.Getenv("PACT_BROKER_BASE_URL"), +// MessageHandlers: functionMappings, +// }) +// } else { +// verifier.VerifyProvider(t, provider.VerifyRequest{ +// PactFiles: []string{filepath.ToSlash(fmt.Sprintf("%s/PactGoV3MessageConsumer-V3MessageProvider.json", pactDir))}, +// StateHandlers: stateMappings, +// Provider: "V3MessageProvider", +// MessageHandlers: functionMappings, +// }) +// } + +// } func startServer() { mux := http.NewServeMux() diff --git a/go.mod b/go.mod index 4228b02f2..daecd0303 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,14 @@ module github.com/pact-foundation/pact-go/v2 go 1.20 require ( - github.com/golang/protobuf v1.5.4 + github.com/ebitengine/purego v0.7.1 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/logutils v1.0.0 github.com/linkedin/goavro/v2 v2.13.0 github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.8.4 + golang.org/x/sys v0.18.0 google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 @@ -24,7 +25,6 @@ require ( github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 273bd435d..3fdffad96 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= +github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= diff --git a/installer/installer_test.go b/installer/installer_test.go index dd6c85492..70f4af011 100644 --- a/installer/installer_test.go +++ b/installer/installer_test.go @@ -18,7 +18,7 @@ func TestNativeLibPath(t *testing.T) { libFilePath := filepath.Join(lib, "lib.go") file, err := os.ReadFile(libFilePath) assert.NoError(t, err) - assert.Contains(t, string(file), "-lpact_ffi") + assert.Contains(t, string(file), "pact_ffi") } // 1. Be able to specify the path of the binary in advance diff --git a/internal/native/lib.go b/internal/native/lib.go index 79ea640c8..ccf2c1912 100644 --- a/internal/native/lib.go +++ b/internal/native/lib.go @@ -1,15 +1,598 @@ // Package native contains the c bindings into the Pact Reference types. package native -/* -#cgo darwin,arm64 LDFLAGS: -L/tmp -L/usr/local/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi -#cgo darwin,amd64 LDFLAGS: -L/tmp -L/usr/local/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi -#cgo windows,amd64 LDFLAGS: -lpact_ffi -#cgo linux,amd64 LDFLAGS: -L/tmp -L/opt/pact/lib -L/usr/local/lib -Wl,-rpath -Wl,/opt/pact/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi -#cgo linux,arm64 LDFLAGS: -L/tmp -L/opt/pact/lib -L/usr/local/lib -Wl,-rpath -Wl,/opt/pact/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi -*/ -import "C" - -// to load in windows with mingw64 -// $env:Path += ';$env:TMP' -// $env:LDFLAGS = '-L$env:TMP' +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "unsafe" + + "github.com/ebitengine/purego" +) + +func getSystemLibrary() string { + switch runtime.GOOS { + case "darwin": + return "libpact_ffi.dylib" + case "linux": + return "libpact_ffi.so" + case "windows": + return "pact_ffi.dll" + default: + panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS)) + } +} + +type ( + size_t uintptr +) + +var pactffi_version func() string +var pactffi_init func(string) +var pactffi_init_with_log_level func(string) +var pactffi_enable_ansi_support func() +var pactffi_log_message func(string, string, string) +var pactffi_match_message func(uintptr, uintptr) uintptr +var pactffi_mismatches_get_iter func(uintptr) uintptr +var pactffi_mismatches_delete func(uintptr) +var pactffi_mismatches_iter_next func(uintptr) uintptr +var pactffi_mismatches_iter_delete func(uintptr) +var pactffi_mismatch_to_json func(uintptr) string +var pactffi_mismatch_type func(uintptr) string +var pactffi_mismatch_summary func(uintptr) string +var pactffi_mismatch_description func(uintptr) string +var pactffi_mismatch_ansi_description func(uintptr) string +var pactffi_get_error_message func(string, int32) int32 +var pactffi_log_to_stdout func(int32) int32 +var pactffi_log_to_stderr func(int32) int32 +var pactffi_log_to_file func(string, int32) int32 +var pactffi_log_to_buffer func(int32) int32 +var pactffi_logger_init func() +var pactffi_logger_attach_sink func(string, int32) int32 +var pactffi_logger_apply func() int32 +var pactffi_fetch_log_buffer func(string) string +var pactffi_parse_pact_json func(string) uintptr +var pactffi_pact_model_delete func(uintptr) +var pactffi_pact_model_interaction_iterator func(uintptr) uintptr +var pactffi_pact_spec_version func(uintptr) int32 +var pactffi_pact_interaction_delete func(uintptr) +var pactffi_async_message_new func() uintptr +var pactffi_async_message_delete func(uintptr) +var pactffi_async_message_get_contents func(uintptr) uintptr +var pactffi_async_message_get_contents_str func(uintptr) string +var pactffi_async_message_set_contents_str func(uintptr, string, string) +var pactffi_async_message_get_contents_length func(uintptr) size_t +var pactffi_async_message_get_contents_bin func(uintptr) uintptr +var pactffi_async_message_set_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_async_message_get_description func(uintptr) string +var pactffi_async_message_set_description func(uintptr, string) int32 +var pactffi_async_message_get_provider_state func(uintptr, uint32) uintptr +var pactffi_async_message_get_provider_state_iter func(uintptr) uintptr +var pactffi_consumer_get_name func(uintptr) string +var pactffi_pact_get_consumer func(uintptr) uintptr +var pactffi_pact_consumer_delete func(uintptr) +var pactffi_message_contents_get_contents_str func(uintptr) string +var pactffi_message_contents_set_contents_str func(uintptr, string, string) +var pactffi_message_contents_get_contents_length func(uintptr) size_t +var pactffi_message_contents_get_contents_bin func(uintptr) uintptr +var pactffi_message_contents_set_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_message_contents_get_metadata_iter func(uintptr) uintptr +var pactffi_message_contents_get_matching_rule_iter func(uintptr, int32) uintptr +var pactffi_request_contents_get_matching_rule_iter func(uintptr, int32) uintptr +var pactffi_response_contents_get_matching_rule_iter func(uintptr, int32) uintptr +var pactffi_message_contents_get_generators_iter func(uintptr, int32) uintptr +var pactffi_request_contents_get_generators_iter func(uintptr, int32) uintptr +var pactffi_response_contents_get_generators_iter func(uintptr, int32) uintptr +var pactffi_parse_matcher_definition func(string) uintptr +var pactffi_matcher_definition_error func(uintptr) string +var pactffi_matcher_definition_value func(uintptr) string +var pactffi_matcher_definition_delete func(uintptr) +var pactffi_matcher_definition_generator func(uintptr) uintptr +var pactffi_matcher_definition_value_type func(uintptr) int32 +var pactffi_matching_rule_iter_delete func(uintptr) +var pactffi_matcher_definition_iter func(uintptr) uintptr +var pactffi_matching_rule_iter_next func(uintptr) uintptr +var pactffi_matching_rule_id func(uintptr) uint16 +var pactffi_matching_rule_value func(uintptr) string +var pactffi_matching_rule_pointer func(uintptr) uintptr +var pactffi_matching_rule_reference_name func(uintptr) string +var pactffi_validate_datetime func(string, string) int32 +var pactffi_generator_to_json func(uintptr) string +var pactffi_generator_generate_string func(uintptr, string) string +var pactffi_generator_generate_integer func(uintptr, string) uint16 +var pactffi_generators_iter_delete func(uintptr) +var pactffi_generators_iter_next func(uintptr) uintptr +var pactffi_generators_iter_pair_delete func(uintptr) +var pactffi_sync_http_new func() uintptr +var pactffi_sync_http_delete func(uintptr) +var pactffi_sync_http_get_request func(uintptr) uintptr +var pactffi_sync_http_get_request_contents func(uintptr) string +var pactffi_sync_http_set_request_contents func(uintptr, string, string) +var pactffi_sync_http_get_request_contents_length func(uintptr) size_t +var pactffi_sync_http_get_request_contents_bin func(uintptr) uintptr +var pactffi_sync_http_set_request_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_sync_http_get_response func(uintptr) uintptr +var pactffi_sync_http_get_response_contents func(uintptr) string +var pactffi_sync_http_set_response_contents func(uintptr, string, string) +var pactffi_sync_http_get_response_contents_length func(uintptr) size_t +var pactffi_sync_http_get_response_contents_bin func(uintptr) uintptr +var pactffi_sync_http_set_response_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_sync_http_get_description func(uintptr) string +var pactffi_sync_http_set_description func(uintptr, string) int32 +var pactffi_sync_http_get_provider_state func(uintptr, uint32) uintptr +var pactffi_sync_http_get_provider_state_iter func(uintptr) uintptr +var pactffi_pact_interaction_as_synchronous_http func(uintptr) uintptr +var pactffi_pact_interaction_as_message func(uintptr) uintptr +var pactffi_pact_interaction_as_asynchronous_message func(uintptr) uintptr +var pactffi_pact_interaction_as_synchronous_message func(uintptr) uintptr +var pactffi_pact_message_iter_delete func(uintptr) +var pactffi_pact_message_iter_next func(uintptr) uintptr +var pactffi_pact_sync_message_iter_next func(uintptr) uintptr +var pactffi_pact_sync_message_iter_delete func(uintptr) +var pactffi_pact_sync_http_iter_next func(uintptr) uintptr +var pactffi_pact_sync_http_iter_delete func(uintptr) +var pactffi_pact_interaction_iter_next func(uintptr) uintptr +var pactffi_pact_interaction_iter_delete func(uintptr) +var pactffi_matching_rule_to_json func(uintptr) string +var pactffi_matching_rules_iter_delete func(uintptr) +var pactffi_matching_rules_iter_next func(uintptr) uintptr +var pactffi_matching_rules_iter_pair_delete func(uintptr) +var pactffi_message_new func() uintptr +var pactffi_message_new_from_json func(uint32, string, int32) uintptr +var pactffi_message_new_from_body func(string, string) uintptr +var pactffi_message_delete func(uintptr) +var pactffi_message_get_contents func(uintptr) string +var pactffi_message_set_contents func(uintptr, string, string) +var pactffi_message_get_contents_length func(uintptr) size_t +var pactffi_message_get_contents_bin func(uintptr) uintptr +var pactffi_message_set_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_message_get_description func(uintptr) string +var pactffi_message_set_description func(uintptr, string) int32 +var pactffi_message_get_provider_state func(uintptr, uint32) uintptr +var pactffi_message_get_provider_state_iter func(uintptr) uintptr +var pactffi_provider_state_iter_next func(uintptr) uintptr +var pactffi_provider_state_iter_delete func(uintptr) +var pactffi_message_find_metadata func(uintptr, string) string +var pactffi_message_insert_metadata func(uintptr, string, string) int32 +var pactffi_message_metadata_iter_next func(uintptr) uintptr +var pactffi_message_get_metadata_iter func(uintptr) uintptr +var pactffi_message_metadata_iter_delete func(uintptr) +var pactffi_message_metadata_pair_delete func(uintptr) +var pactffi_message_pact_new_from_json func(string, string) uintptr +var pactffi_message_pact_delete func(uintptr) +var pactffi_message_pact_get_consumer func(uintptr) uintptr +var pactffi_message_pact_get_provider func(uintptr) uintptr +var pactffi_message_pact_get_message_iter func(uintptr) uintptr +var pactffi_message_pact_message_iter_next func(uintptr) uintptr +var pactffi_message_pact_message_iter_delete func(uintptr) +var pactffi_message_pact_find_metadata func(uintptr, string, string) string +var pactffi_message_pact_get_metadata_iter func(uintptr) uintptr +var pactffi_message_pact_metadata_iter_next func(uintptr) uintptr +var pactffi_message_pact_metadata_iter_delete func(uintptr) +var pactffi_message_pact_metadata_triple_delete func(uintptr) +var pactffi_provider_get_name func(uintptr) string +var pactffi_pact_get_provider func(uintptr) uintptr +var pactffi_pact_provider_delete func(uintptr) +var pactffi_provider_state_get_name func(uintptr) string +var pactffi_provider_state_get_param_iter func(uintptr) uintptr +var pactffi_provider_state_param_iter_next func(uintptr) uintptr +var pactffi_provider_state_delete func(uintptr) +var pactffi_provider_state_param_iter_delete func(uintptr) +var pactffi_provider_state_param_pair_delete func(uintptr) +var pactffi_sync_message_new func() uintptr +var pactffi_sync_message_delete func(uintptr) +var pactffi_sync_message_get_request_contents_str func(uintptr) string +var pactffi_sync_message_set_request_contents_str func(uintptr, string, string) +var pactffi_sync_message_get_request_contents_length func(uintptr) size_t +var pactffi_sync_message_get_request_contents_bin func(uintptr) uintptr +var pactffi_sync_message_set_request_contents_bin func(uintptr, uintptr, size_t, string) +var pactffi_sync_message_get_request_contents func(uintptr) uintptr +var pactffi_sync_message_get_number_responses func(uintptr) size_t +var pactffi_sync_message_get_response_contents_str func(uintptr, size_t) string +var pactffi_sync_message_set_response_contents_str func(uintptr, size_t, string, string) +var pactffi_sync_message_get_response_contents_length func(uintptr, size_t) size_t +var pactffi_sync_message_get_response_contents_bin func(uintptr, size_t) uintptr +var pactffi_sync_message_set_response_contents_bin func(uintptr, size_t, uintptr, size_t, string) +var pactffi_sync_message_get_response_contents func(uintptr, size_t) uintptr +var pactffi_sync_message_get_description func(uintptr) string +var pactffi_sync_message_set_description func(uintptr, string) int32 +var pactffi_sync_message_get_provider_state func(uintptr, uint32) uintptr +var pactffi_sync_message_get_provider_state_iter func(uintptr) uintptr +var pactffi_string_delete func(string) +var pactffi_create_mock_server func(string, string, bool) int32 +var pactffi_get_tls_ca_certificate func() string +var pactffi_create_mock_server_for_pact func(uintptr, string, bool) int32 +var pactffi_create_mock_server_for_transport func(uintptr, string, uint16, string, string) int32 +var pactffi_mock_server_matched func(int32) bool +var pactffi_mock_server_mismatches func(int32) string +var pactffi_cleanup_mock_server func(int32) bool +var pactffi_write_pact_file func(int32, string, bool) int32 +var pactffi_mock_server_logs func(int32) string +var pactffi_generate_datetime_string func(string) uintptr +var pactffi_check_regex func(string, string) bool +var pactffi_generate_regex_value func(string) uintptr +var pactffi_free_string func(uintptr) +var pactffi_new_pact func(string, string) uintptr +var pactffi_pact_handle_to_pointer func(uint16) uintptr +var pactffi_new_interaction func(uintptr, string) uintptr +var pactffi_new_message_interaction func(uintptr, string) uintptr +var pactffi_new_sync_message_interaction func(uintptr, string) uintptr +var pactffi_upon_receiving func(uintptr, string) bool +var pactffi_given func(uintptr, string) bool +var pactffi_interaction_test_name func(uint32, string) uint32 +var pactffi_given_with_param func(uintptr, string, string, string) bool +var pactffi_given_with_params func(uintptr, string, string) int32 +var pactffi_with_request func(uintptr, string, string) bool +var pactffi_with_query_parameter func(uintptr, string, int, string) bool +var pactffi_with_query_parameter_v2 func(uintptr, string, int, string) bool +var pactffi_with_specification func(uintptr, int32) bool +var pactffi_handle_get_pact_spec_version func(uint16) int32 +var pactffi_with_pact_metadata func(uintptr, string, string, string) bool +var pactffi_with_header func(uintptr, int32, string, int, string) bool +var pactffi_with_header_v2 func(uintptr, int32, string, int, string) bool +var pactffi_set_header func(uint32, int32, string, string) bool +var pactffi_response_status func(uintptr, uint16) bool +var pactffi_response_status_v2 func(uintptr, string) bool +var pactffi_with_body func(uintptr, int32, string, string) bool +var pactffi_with_binary_body func(uint32, int32, string, string, size_t) bool +var pactffi_with_binary_file func(uintptr, int32, string, string, size_t) bool +var pactffi_with_matching_rules func(uint32, int32, string) bool +var pactffi_with_multipart_file_v2 func(uint32, int32, string, string, string, string) uintptr +var pactffi_with_multipart_file func(uintptr, int32, string, string, string) uintptr +var pactffi_pact_handle_get_message_iter func(uintptr) uintptr +var pactffi_pact_handle_get_sync_message_iter func(uintptr) uintptr +var pactffi_pact_handle_get_sync_http_iter func(uint16) uintptr +var pactffi_new_message_pact func(string, string) uintptr +var pactffi_new_message func(uint16, string) uint32 +var pactffi_message_expects_to_receive func(uintptr, string) +var pactffi_message_given func(uintptr, string) +var pactffi_message_given_with_param func(uintptr, string, string, string) +var pactffi_message_with_contents func(uintptr, string, uintptr, size_t) +var pactffi_message_with_metadata func(uintptr, string, string) +var pactffi_message_with_metadata_v2 func(uint32, string, string) +var pactffi_message_reify func(uint32) string +var pactffi_write_message_pact_file func(uintptr, string, bool) int32 +var pactffi_with_message_pact_metadata func(uintptr, string, string, string) +var pactffi_pact_handle_write_file func(uint16, string, bool) int32 +var pactffi_new_async_message func(uint16, string) uint32 +var pactffi_free_pact_handle func(uint16) uint32 +var pactffi_free_message_pact_handle func(uint16) uint32 +var pactffi_verify func(string) int32 +var pactffi_verifier_new func() uintptr +var pactffi_verifier_new_for_application func(string, string) uintptr +var pactffi_verifier_shutdown func(uintptr) +var pactffi_verifier_set_provider_info func(uintptr, string, string, string, uint16, string) +var pactffi_verifier_add_provider_transport func(uintptr, string, uint16, string, string) +var pactffi_verifier_set_filter_info func(uintptr, string, string, uint8) +var pactffi_verifier_set_provider_state func(uintptr, string, uint8, uint8) +var pactffi_verifier_set_verification_options func(uintptr, uint8, uint64) int32 +var pactffi_verifier_set_coloured_output func(uintptr, uint8) int32 +var pactffi_verifier_set_no_pacts_is_error func(uintptr, uint8) int32 +var pactffi_verifier_set_publish_options func(uintptr, string, string, []*byte, uint16, string) int32 +var pactffi_verifier_set_consumer_filters func(uintptr, []*byte, uint16) +var pactffi_verifier_add_custom_header func(uintptr, string, string) +var pactffi_verifier_add_file_source func(uintptr, string) +var pactffi_verifier_add_directory_source func(uintptr, string) +var pactffi_verifier_url_source func(uintptr, string, string, string, string) +var pactffi_verifier_broker_source func(uintptr, string, string, string, string) +var pactffi_verifier_broker_source_with_selectors func(uintptr, string, string, string, string, uint8, string, []*byte, uint16, string, []*byte, uint16, []*byte, uint16) +var pactffi_verifier_execute func(uintptr) int32 +var pactffi_verifier_cli_args func() string +var pactffi_verifier_logs func(uintptr) string +var pactffi_verifier_logs_for_provider func(string) string +var pactffi_verifier_output func(uintptr, uint8) string +var pactffi_verifier_json func(uintptr) string +var pactffi_using_plugin func(uintptr, string, string) uint32 +var pactffi_cleanup_plugins func(uintptr) +var pactffi_interaction_contents func(uintptr, int32, string, string) uint32 +var pactffi_matches_string_value func(uintptr, string, string, uint8) string +var pactffi_matches_u64_value func(uintptr, uint64, uint64, uint8) string +var pactffi_matches_i64_value func(uintptr, int64, int64, uint8) string +var pactffi_matches_f64_value func(uintptr, float64, float64, uint8) string +var pactffi_matches_bool_value func(uintptr, uint8, uint8, uint8) string +var pactffi_matches_binary_value func(uintptr, uintptr, uint64, uintptr, uint64, uint8) string +var pactffi_matches_json_value func(uintptr, string, string, uint8) string + +func init() { + libpact_ffi, err := openLibrary(filepath.Join(os.Getenv("PACT_LD_LIBRARY_PATH"), getSystemLibrary())) + if err != nil { + panic(err) + } + purego.RegisterLibFunc(&pactffi_version, libpact_ffi, "pactffi_version") + purego.RegisterLibFunc(&pactffi_init, libpact_ffi, "pactffi_init") + purego.RegisterLibFunc(&pactffi_init_with_log_level, libpact_ffi, "pactffi_init_with_log_level") + purego.RegisterLibFunc(&pactffi_enable_ansi_support, libpact_ffi, "pactffi_enable_ansi_support") + purego.RegisterLibFunc(&pactffi_log_message, libpact_ffi, "pactffi_log_message") + purego.RegisterLibFunc(&pactffi_match_message, libpact_ffi, "pactffi_match_message") + purego.RegisterLibFunc(&pactffi_mismatches_get_iter, libpact_ffi, "pactffi_mismatches_get_iter") + purego.RegisterLibFunc(&pactffi_mismatches_delete, libpact_ffi, "pactffi_mismatches_delete") + purego.RegisterLibFunc(&pactffi_mismatches_iter_next, libpact_ffi, "pactffi_mismatches_iter_next") + purego.RegisterLibFunc(&pactffi_mismatches_iter_delete, libpact_ffi, "pactffi_mismatches_iter_delete") + purego.RegisterLibFunc(&pactffi_mismatch_to_json, libpact_ffi, "pactffi_mismatch_to_json") + purego.RegisterLibFunc(&pactffi_mismatch_type, libpact_ffi, "pactffi_mismatch_type") + purego.RegisterLibFunc(&pactffi_mismatch_summary, libpact_ffi, "pactffi_mismatch_summary") + purego.RegisterLibFunc(&pactffi_mismatch_description, libpact_ffi, "pactffi_mismatch_description") + purego.RegisterLibFunc(&pactffi_mismatch_ansi_description, libpact_ffi, "pactffi_mismatch_ansi_description") + purego.RegisterLibFunc(&pactffi_get_error_message, libpact_ffi, "pactffi_get_error_message") + purego.RegisterLibFunc(&pactffi_log_to_stdout, libpact_ffi, "pactffi_log_to_stdout") + purego.RegisterLibFunc(&pactffi_log_to_stderr, libpact_ffi, "pactffi_log_to_stderr") + purego.RegisterLibFunc(&pactffi_log_to_file, libpact_ffi, "pactffi_log_to_file") + purego.RegisterLibFunc(&pactffi_log_to_buffer, libpact_ffi, "pactffi_log_to_buffer") + purego.RegisterLibFunc(&pactffi_logger_init, libpact_ffi, "pactffi_logger_init") + purego.RegisterLibFunc(&pactffi_logger_attach_sink, libpact_ffi, "pactffi_logger_attach_sink") + purego.RegisterLibFunc(&pactffi_logger_apply, libpact_ffi, "pactffi_logger_apply") + purego.RegisterLibFunc(&pactffi_fetch_log_buffer, libpact_ffi, "pactffi_fetch_log_buffer") + purego.RegisterLibFunc(&pactffi_parse_pact_json, libpact_ffi, "pactffi_parse_pact_json") + purego.RegisterLibFunc(&pactffi_pact_model_delete, libpact_ffi, "pactffi_pact_model_delete") + purego.RegisterLibFunc(&pactffi_pact_model_interaction_iterator, libpact_ffi, "pactffi_pact_model_interaction_iterator") + purego.RegisterLibFunc(&pactffi_pact_spec_version, libpact_ffi, "pactffi_pact_spec_version") + purego.RegisterLibFunc(&pactffi_pact_interaction_delete, libpact_ffi, "pactffi_pact_interaction_delete") + purego.RegisterLibFunc(&pactffi_async_message_new, libpact_ffi, "pactffi_async_message_new") + purego.RegisterLibFunc(&pactffi_async_message_delete, libpact_ffi, "pactffi_async_message_delete") + purego.RegisterLibFunc(&pactffi_async_message_get_contents, libpact_ffi, "pactffi_async_message_get_contents") + purego.RegisterLibFunc(&pactffi_async_message_get_contents_str, libpact_ffi, "pactffi_async_message_get_contents_str") + purego.RegisterLibFunc(&pactffi_async_message_set_contents_str, libpact_ffi, "pactffi_async_message_set_contents_str") + purego.RegisterLibFunc(&pactffi_async_message_get_contents_length, libpact_ffi, "pactffi_async_message_get_contents_length") + purego.RegisterLibFunc(&pactffi_async_message_get_contents_bin, libpact_ffi, "pactffi_async_message_get_contents_bin") + purego.RegisterLibFunc(&pactffi_async_message_set_contents_bin, libpact_ffi, "pactffi_async_message_set_contents_bin") + purego.RegisterLibFunc(&pactffi_async_message_get_description, libpact_ffi, "pactffi_async_message_get_description") + purego.RegisterLibFunc(&pactffi_async_message_set_description, libpact_ffi, "pactffi_async_message_set_description") + purego.RegisterLibFunc(&pactffi_async_message_get_provider_state, libpact_ffi, "pactffi_async_message_get_provider_state") + purego.RegisterLibFunc(&pactffi_async_message_get_provider_state_iter, libpact_ffi, "pactffi_async_message_get_provider_state_iter") + purego.RegisterLibFunc(&pactffi_consumer_get_name, libpact_ffi, "pactffi_consumer_get_name") + purego.RegisterLibFunc(&pactffi_pact_get_consumer, libpact_ffi, "pactffi_pact_get_consumer") + purego.RegisterLibFunc(&pactffi_pact_consumer_delete, libpact_ffi, "pactffi_pact_consumer_delete") + purego.RegisterLibFunc(&pactffi_message_contents_get_contents_str, libpact_ffi, "pactffi_message_contents_get_contents_str") + purego.RegisterLibFunc(&pactffi_message_contents_set_contents_str, libpact_ffi, "pactffi_message_contents_set_contents_str") + purego.RegisterLibFunc(&pactffi_message_contents_get_contents_length, libpact_ffi, "pactffi_message_contents_get_contents_length") + purego.RegisterLibFunc(&pactffi_message_contents_get_contents_bin, libpact_ffi, "pactffi_message_contents_get_contents_bin") + purego.RegisterLibFunc(&pactffi_message_contents_set_contents_bin, libpact_ffi, "pactffi_message_contents_set_contents_bin") + purego.RegisterLibFunc(&pactffi_message_contents_get_metadata_iter, libpact_ffi, "pactffi_message_contents_get_metadata_iter") + purego.RegisterLibFunc(&pactffi_message_contents_get_matching_rule_iter, libpact_ffi, "pactffi_message_contents_get_matching_rule_iter") + purego.RegisterLibFunc(&pactffi_request_contents_get_matching_rule_iter, libpact_ffi, "pactffi_request_contents_get_matching_rule_iter") + purego.RegisterLibFunc(&pactffi_response_contents_get_matching_rule_iter, libpact_ffi, "pactffi_response_contents_get_matching_rule_iter") + purego.RegisterLibFunc(&pactffi_message_contents_get_generators_iter, libpact_ffi, "pactffi_message_contents_get_generators_iter") + purego.RegisterLibFunc(&pactffi_request_contents_get_generators_iter, libpact_ffi, "pactffi_request_contents_get_generators_iter") + purego.RegisterLibFunc(&pactffi_response_contents_get_generators_iter, libpact_ffi, "pactffi_response_contents_get_generators_iter") + purego.RegisterLibFunc(&pactffi_parse_matcher_definition, libpact_ffi, "pactffi_parse_matcher_definition") + purego.RegisterLibFunc(&pactffi_matcher_definition_error, libpact_ffi, "pactffi_matcher_definition_error") + purego.RegisterLibFunc(&pactffi_matcher_definition_value, libpact_ffi, "pactffi_matcher_definition_value") + purego.RegisterLibFunc(&pactffi_matcher_definition_delete, libpact_ffi, "pactffi_matcher_definition_delete") + purego.RegisterLibFunc(&pactffi_matcher_definition_generator, libpact_ffi, "pactffi_matcher_definition_generator") + purego.RegisterLibFunc(&pactffi_matcher_definition_value_type, libpact_ffi, "pactffi_matcher_definition_value_type") + purego.RegisterLibFunc(&pactffi_matching_rule_iter_delete, libpact_ffi, "pactffi_matching_rule_iter_delete") + purego.RegisterLibFunc(&pactffi_matcher_definition_iter, libpact_ffi, "pactffi_matcher_definition_iter") + purego.RegisterLibFunc(&pactffi_matching_rule_iter_next, libpact_ffi, "pactffi_matching_rule_iter_next") + purego.RegisterLibFunc(&pactffi_matching_rule_id, libpact_ffi, "pactffi_matching_rule_id") + purego.RegisterLibFunc(&pactffi_matching_rule_value, libpact_ffi, "pactffi_matching_rule_value") + purego.RegisterLibFunc(&pactffi_matching_rule_pointer, libpact_ffi, "pactffi_matching_rule_pointer") + purego.RegisterLibFunc(&pactffi_matching_rule_reference_name, libpact_ffi, "pactffi_matching_rule_reference_name") + purego.RegisterLibFunc(&pactffi_validate_datetime, libpact_ffi, "pactffi_validate_datetime") + purego.RegisterLibFunc(&pactffi_generator_to_json, libpact_ffi, "pactffi_generator_to_json") + purego.RegisterLibFunc(&pactffi_generator_generate_string, libpact_ffi, "pactffi_generator_generate_string") + purego.RegisterLibFunc(&pactffi_generator_generate_integer, libpact_ffi, "pactffi_generator_generate_integer") + purego.RegisterLibFunc(&pactffi_generators_iter_delete, libpact_ffi, "pactffi_generators_iter_delete") + purego.RegisterLibFunc(&pactffi_generators_iter_next, libpact_ffi, "pactffi_generators_iter_next") + purego.RegisterLibFunc(&pactffi_generators_iter_pair_delete, libpact_ffi, "pactffi_generators_iter_pair_delete") + purego.RegisterLibFunc(&pactffi_sync_http_new, libpact_ffi, "pactffi_sync_http_new") + purego.RegisterLibFunc(&pactffi_sync_http_delete, libpact_ffi, "pactffi_sync_http_delete") + purego.RegisterLibFunc(&pactffi_sync_http_get_request, libpact_ffi, "pactffi_sync_http_get_request") + purego.RegisterLibFunc(&pactffi_sync_http_get_request_contents, libpact_ffi, "pactffi_sync_http_get_request_contents") + purego.RegisterLibFunc(&pactffi_sync_http_set_request_contents, libpact_ffi, "pactffi_sync_http_set_request_contents") + purego.RegisterLibFunc(&pactffi_sync_http_get_request_contents_length, libpact_ffi, "pactffi_sync_http_get_request_contents_length") + purego.RegisterLibFunc(&pactffi_sync_http_get_request_contents_bin, libpact_ffi, "pactffi_sync_http_get_request_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_http_set_request_contents_bin, libpact_ffi, "pactffi_sync_http_set_request_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_http_get_response, libpact_ffi, "pactffi_sync_http_get_response") + purego.RegisterLibFunc(&pactffi_sync_http_get_response_contents, libpact_ffi, "pactffi_sync_http_get_response_contents") + purego.RegisterLibFunc(&pactffi_sync_http_set_response_contents, libpact_ffi, "pactffi_sync_http_set_response_contents") + purego.RegisterLibFunc(&pactffi_sync_http_get_response_contents_length, libpact_ffi, "pactffi_sync_http_get_response_contents_length") + purego.RegisterLibFunc(&pactffi_sync_http_get_response_contents_bin, libpact_ffi, "pactffi_sync_http_get_response_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_http_set_response_contents_bin, libpact_ffi, "pactffi_sync_http_set_response_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_http_get_description, libpact_ffi, "pactffi_sync_http_get_description") + purego.RegisterLibFunc(&pactffi_sync_http_set_description, libpact_ffi, "pactffi_sync_http_set_description") + purego.RegisterLibFunc(&pactffi_sync_http_get_provider_state, libpact_ffi, "pactffi_sync_http_get_provider_state") + purego.RegisterLibFunc(&pactffi_sync_http_get_provider_state_iter, libpact_ffi, "pactffi_sync_http_get_provider_state_iter") + purego.RegisterLibFunc(&pactffi_pact_interaction_as_synchronous_http, libpact_ffi, "pactffi_pact_interaction_as_synchronous_http") + purego.RegisterLibFunc(&pactffi_pact_interaction_as_message, libpact_ffi, "pactffi_pact_interaction_as_message") + purego.RegisterLibFunc(&pactffi_pact_interaction_as_asynchronous_message, libpact_ffi, "pactffi_pact_interaction_as_asynchronous_message") + purego.RegisterLibFunc(&pactffi_pact_interaction_as_synchronous_message, libpact_ffi, "pactffi_pact_interaction_as_synchronous_message") + purego.RegisterLibFunc(&pactffi_pact_message_iter_delete, libpact_ffi, "pactffi_pact_message_iter_delete") + purego.RegisterLibFunc(&pactffi_pact_message_iter_next, libpact_ffi, "pactffi_pact_message_iter_next") + purego.RegisterLibFunc(&pactffi_pact_sync_message_iter_next, libpact_ffi, "pactffi_pact_sync_message_iter_next") + purego.RegisterLibFunc(&pactffi_pact_sync_message_iter_delete, libpact_ffi, "pactffi_pact_sync_message_iter_delete") + purego.RegisterLibFunc(&pactffi_pact_sync_http_iter_next, libpact_ffi, "pactffi_pact_sync_http_iter_next") + purego.RegisterLibFunc(&pactffi_pact_sync_http_iter_delete, libpact_ffi, "pactffi_pact_sync_http_iter_delete") + purego.RegisterLibFunc(&pactffi_pact_interaction_iter_next, libpact_ffi, "pactffi_pact_interaction_iter_next") + purego.RegisterLibFunc(&pactffi_pact_interaction_iter_delete, libpact_ffi, "pactffi_pact_interaction_iter_delete") + purego.RegisterLibFunc(&pactffi_matching_rule_to_json, libpact_ffi, "pactffi_matching_rule_to_json") + purego.RegisterLibFunc(&pactffi_matching_rules_iter_delete, libpact_ffi, "pactffi_matching_rules_iter_delete") + purego.RegisterLibFunc(&pactffi_matching_rules_iter_next, libpact_ffi, "pactffi_matching_rules_iter_next") + purego.RegisterLibFunc(&pactffi_matching_rules_iter_pair_delete, libpact_ffi, "pactffi_matching_rules_iter_pair_delete") + purego.RegisterLibFunc(&pactffi_message_new, libpact_ffi, "pactffi_message_new") + purego.RegisterLibFunc(&pactffi_message_new_from_json, libpact_ffi, "pactffi_message_new_from_json") + purego.RegisterLibFunc(&pactffi_message_new_from_body, libpact_ffi, "pactffi_message_new_from_body") + purego.RegisterLibFunc(&pactffi_message_delete, libpact_ffi, "pactffi_message_delete") + purego.RegisterLibFunc(&pactffi_message_get_contents, libpact_ffi, "pactffi_message_get_contents") + purego.RegisterLibFunc(&pactffi_message_set_contents, libpact_ffi, "pactffi_message_set_contents") + purego.RegisterLibFunc(&pactffi_message_get_contents_length, libpact_ffi, "pactffi_message_get_contents_length") + purego.RegisterLibFunc(&pactffi_message_get_contents_bin, libpact_ffi, "pactffi_message_get_contents_bin") + purego.RegisterLibFunc(&pactffi_message_set_contents_bin, libpact_ffi, "pactffi_message_set_contents_bin") + purego.RegisterLibFunc(&pactffi_message_get_description, libpact_ffi, "pactffi_message_get_description") + purego.RegisterLibFunc(&pactffi_message_set_description, libpact_ffi, "pactffi_message_set_description") + purego.RegisterLibFunc(&pactffi_message_get_provider_state, libpact_ffi, "pactffi_message_get_provider_state") + purego.RegisterLibFunc(&pactffi_message_get_provider_state_iter, libpact_ffi, "pactffi_message_get_provider_state_iter") + purego.RegisterLibFunc(&pactffi_provider_state_iter_next, libpact_ffi, "pactffi_provider_state_iter_next") + purego.RegisterLibFunc(&pactffi_provider_state_iter_delete, libpact_ffi, "pactffi_provider_state_iter_delete") + purego.RegisterLibFunc(&pactffi_message_find_metadata, libpact_ffi, "pactffi_message_find_metadata") + purego.RegisterLibFunc(&pactffi_message_insert_metadata, libpact_ffi, "pactffi_message_insert_metadata") + purego.RegisterLibFunc(&pactffi_message_metadata_iter_next, libpact_ffi, "pactffi_message_metadata_iter_next") + purego.RegisterLibFunc(&pactffi_message_get_metadata_iter, libpact_ffi, "pactffi_message_get_metadata_iter") + purego.RegisterLibFunc(&pactffi_message_metadata_iter_delete, libpact_ffi, "pactffi_message_metadata_iter_delete") + purego.RegisterLibFunc(&pactffi_message_metadata_pair_delete, libpact_ffi, "pactffi_message_metadata_pair_delete") + purego.RegisterLibFunc(&pactffi_message_pact_new_from_json, libpact_ffi, "pactffi_message_pact_new_from_json") + purego.RegisterLibFunc(&pactffi_message_pact_delete, libpact_ffi, "pactffi_message_pact_delete") + purego.RegisterLibFunc(&pactffi_message_pact_get_consumer, libpact_ffi, "pactffi_message_pact_get_consumer") + purego.RegisterLibFunc(&pactffi_message_pact_get_provider, libpact_ffi, "pactffi_message_pact_get_provider") + purego.RegisterLibFunc(&pactffi_message_pact_get_message_iter, libpact_ffi, "pactffi_message_pact_get_message_iter") + purego.RegisterLibFunc(&pactffi_message_pact_message_iter_next, libpact_ffi, "pactffi_message_pact_message_iter_next") + purego.RegisterLibFunc(&pactffi_message_pact_message_iter_delete, libpact_ffi, "pactffi_message_pact_message_iter_delete") + purego.RegisterLibFunc(&pactffi_message_pact_find_metadata, libpact_ffi, "pactffi_message_pact_find_metadata") + purego.RegisterLibFunc(&pactffi_message_pact_get_metadata_iter, libpact_ffi, "pactffi_message_pact_get_metadata_iter") + purego.RegisterLibFunc(&pactffi_message_pact_metadata_iter_next, libpact_ffi, "pactffi_message_pact_metadata_iter_next") + purego.RegisterLibFunc(&pactffi_message_pact_metadata_iter_delete, libpact_ffi, "pactffi_message_pact_metadata_iter_delete") + purego.RegisterLibFunc(&pactffi_message_pact_metadata_triple_delete, libpact_ffi, "pactffi_message_pact_metadata_triple_delete") + purego.RegisterLibFunc(&pactffi_provider_get_name, libpact_ffi, "pactffi_provider_get_name") + purego.RegisterLibFunc(&pactffi_pact_get_provider, libpact_ffi, "pactffi_pact_get_provider") + purego.RegisterLibFunc(&pactffi_pact_provider_delete, libpact_ffi, "pactffi_pact_provider_delete") + purego.RegisterLibFunc(&pactffi_provider_state_get_name, libpact_ffi, "pactffi_provider_state_get_name") + purego.RegisterLibFunc(&pactffi_provider_state_get_param_iter, libpact_ffi, "pactffi_provider_state_get_param_iter") + purego.RegisterLibFunc(&pactffi_provider_state_param_iter_next, libpact_ffi, "pactffi_provider_state_param_iter_next") + purego.RegisterLibFunc(&pactffi_provider_state_delete, libpact_ffi, "pactffi_provider_state_delete") + purego.RegisterLibFunc(&pactffi_provider_state_param_iter_delete, libpact_ffi, "pactffi_provider_state_param_iter_delete") + purego.RegisterLibFunc(&pactffi_provider_state_param_pair_delete, libpact_ffi, "pactffi_provider_state_param_pair_delete") + purego.RegisterLibFunc(&pactffi_sync_message_new, libpact_ffi, "pactffi_sync_message_new") + purego.RegisterLibFunc(&pactffi_sync_message_delete, libpact_ffi, "pactffi_sync_message_delete") + purego.RegisterLibFunc(&pactffi_sync_message_get_request_contents_str, libpact_ffi, "pactffi_sync_message_get_request_contents_str") + purego.RegisterLibFunc(&pactffi_sync_message_set_request_contents_str, libpact_ffi, "pactffi_sync_message_set_request_contents_str") + purego.RegisterLibFunc(&pactffi_sync_message_get_request_contents_length, libpact_ffi, "pactffi_sync_message_get_request_contents_length") + purego.RegisterLibFunc(&pactffi_sync_message_get_request_contents_bin, libpact_ffi, "pactffi_sync_message_get_request_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_message_set_request_contents_bin, libpact_ffi, "pactffi_sync_message_set_request_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_message_get_request_contents, libpact_ffi, "pactffi_sync_message_get_request_contents") + purego.RegisterLibFunc(&pactffi_sync_message_get_number_responses, libpact_ffi, "pactffi_sync_message_get_number_responses") + purego.RegisterLibFunc(&pactffi_sync_message_get_response_contents_str, libpact_ffi, "pactffi_sync_message_get_response_contents_str") + purego.RegisterLibFunc(&pactffi_sync_message_set_response_contents_str, libpact_ffi, "pactffi_sync_message_set_response_contents_str") + purego.RegisterLibFunc(&pactffi_sync_message_get_response_contents_length, libpact_ffi, "pactffi_sync_message_get_response_contents_length") + purego.RegisterLibFunc(&pactffi_sync_message_get_response_contents_bin, libpact_ffi, "pactffi_sync_message_get_response_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_message_set_response_contents_bin, libpact_ffi, "pactffi_sync_message_set_response_contents_bin") + purego.RegisterLibFunc(&pactffi_sync_message_get_response_contents, libpact_ffi, "pactffi_sync_message_get_response_contents") + purego.RegisterLibFunc(&pactffi_sync_message_get_description, libpact_ffi, "pactffi_sync_message_get_description") + purego.RegisterLibFunc(&pactffi_sync_message_set_description, libpact_ffi, "pactffi_sync_message_set_description") + purego.RegisterLibFunc(&pactffi_sync_message_get_provider_state, libpact_ffi, "pactffi_sync_message_get_provider_state") + purego.RegisterLibFunc(&pactffi_sync_message_get_provider_state_iter, libpact_ffi, "pactffi_sync_message_get_provider_state_iter") + purego.RegisterLibFunc(&pactffi_string_delete, libpact_ffi, "pactffi_string_delete") + purego.RegisterLibFunc(&pactffi_create_mock_server, libpact_ffi, "pactffi_create_mock_server") + purego.RegisterLibFunc(&pactffi_get_tls_ca_certificate, libpact_ffi, "pactffi_get_tls_ca_certificate") + purego.RegisterLibFunc(&pactffi_create_mock_server_for_pact, libpact_ffi, "pactffi_create_mock_server_for_pact") + purego.RegisterLibFunc(&pactffi_create_mock_server_for_transport, libpact_ffi, "pactffi_create_mock_server_for_transport") + purego.RegisterLibFunc(&pactffi_mock_server_matched, libpact_ffi, "pactffi_mock_server_matched") + purego.RegisterLibFunc(&pactffi_mock_server_mismatches, libpact_ffi, "pactffi_mock_server_mismatches") + purego.RegisterLibFunc(&pactffi_cleanup_mock_server, libpact_ffi, "pactffi_cleanup_mock_server") + purego.RegisterLibFunc(&pactffi_write_pact_file, libpact_ffi, "pactffi_write_pact_file") + purego.RegisterLibFunc(&pactffi_mock_server_logs, libpact_ffi, "pactffi_mock_server_logs") + purego.RegisterLibFunc(&pactffi_generate_datetime_string, libpact_ffi, "pactffi_generate_datetime_string") + purego.RegisterLibFunc(&pactffi_check_regex, libpact_ffi, "pactffi_check_regex") + purego.RegisterLibFunc(&pactffi_generate_regex_value, libpact_ffi, "pactffi_generate_regex_value") + purego.RegisterLibFunc(&pactffi_free_string, libpact_ffi, "pactffi_free_string") + purego.RegisterLibFunc(&pactffi_new_pact, libpact_ffi, "pactffi_new_pact") + purego.RegisterLibFunc(&pactffi_pact_handle_to_pointer, libpact_ffi, "pactffi_pact_handle_to_pointer") + purego.RegisterLibFunc(&pactffi_new_interaction, libpact_ffi, "pactffi_new_interaction") + purego.RegisterLibFunc(&pactffi_new_message_interaction, libpact_ffi, "pactffi_new_message_interaction") + purego.RegisterLibFunc(&pactffi_new_sync_message_interaction, libpact_ffi, "pactffi_new_sync_message_interaction") + purego.RegisterLibFunc(&pactffi_upon_receiving, libpact_ffi, "pactffi_upon_receiving") + purego.RegisterLibFunc(&pactffi_given, libpact_ffi, "pactffi_given") + purego.RegisterLibFunc(&pactffi_interaction_test_name, libpact_ffi, "pactffi_interaction_test_name") + purego.RegisterLibFunc(&pactffi_given_with_param, libpact_ffi, "pactffi_given_with_param") + purego.RegisterLibFunc(&pactffi_given_with_params, libpact_ffi, "pactffi_given_with_params") + purego.RegisterLibFunc(&pactffi_with_request, libpact_ffi, "pactffi_with_request") + purego.RegisterLibFunc(&pactffi_with_query_parameter, libpact_ffi, "pactffi_with_query_parameter") + purego.RegisterLibFunc(&pactffi_with_query_parameter_v2, libpact_ffi, "pactffi_with_query_parameter_v2") + purego.RegisterLibFunc(&pactffi_with_specification, libpact_ffi, "pactffi_with_specification") + purego.RegisterLibFunc(&pactffi_handle_get_pact_spec_version, libpact_ffi, "pactffi_handle_get_pact_spec_version") + purego.RegisterLibFunc(&pactffi_with_pact_metadata, libpact_ffi, "pactffi_with_pact_metadata") + purego.RegisterLibFunc(&pactffi_with_header, libpact_ffi, "pactffi_with_header") + purego.RegisterLibFunc(&pactffi_with_header_v2, libpact_ffi, "pactffi_with_header_v2") + purego.RegisterLibFunc(&pactffi_set_header, libpact_ffi, "pactffi_set_header") + purego.RegisterLibFunc(&pactffi_response_status, libpact_ffi, "pactffi_response_status") + purego.RegisterLibFunc(&pactffi_response_status_v2, libpact_ffi, "pactffi_response_status_v2") + purego.RegisterLibFunc(&pactffi_with_body, libpact_ffi, "pactffi_with_body") + purego.RegisterLibFunc(&pactffi_with_binary_body, libpact_ffi, "pactffi_with_binary_body") + purego.RegisterLibFunc(&pactffi_with_binary_file, libpact_ffi, "pactffi_with_binary_file") + purego.RegisterLibFunc(&pactffi_with_matching_rules, libpact_ffi, "pactffi_with_matching_rules") + purego.RegisterLibFunc(&pactffi_with_multipart_file_v2, libpact_ffi, "pactffi_with_multipart_file_v2") + purego.RegisterLibFunc(&pactffi_with_multipart_file, libpact_ffi, "pactffi_with_multipart_file") + purego.RegisterLibFunc(&pactffi_pact_handle_get_message_iter, libpact_ffi, "pactffi_pact_handle_get_message_iter") + purego.RegisterLibFunc(&pactffi_pact_handle_get_sync_message_iter, libpact_ffi, "pactffi_pact_handle_get_sync_message_iter") + purego.RegisterLibFunc(&pactffi_pact_handle_get_sync_http_iter, libpact_ffi, "pactffi_pact_handle_get_sync_http_iter") + purego.RegisterLibFunc(&pactffi_new_message_pact, libpact_ffi, "pactffi_new_message_pact") + purego.RegisterLibFunc(&pactffi_new_message, libpact_ffi, "pactffi_new_message") + purego.RegisterLibFunc(&pactffi_message_expects_to_receive, libpact_ffi, "pactffi_message_expects_to_receive") + purego.RegisterLibFunc(&pactffi_message_given, libpact_ffi, "pactffi_message_given") + purego.RegisterLibFunc(&pactffi_message_given_with_param, libpact_ffi, "pactffi_message_given_with_param") + purego.RegisterLibFunc(&pactffi_message_with_contents, libpact_ffi, "pactffi_message_with_contents") + purego.RegisterLibFunc(&pactffi_message_with_metadata, libpact_ffi, "pactffi_message_with_metadata") + purego.RegisterLibFunc(&pactffi_message_with_metadata_v2, libpact_ffi, "pactffi_message_with_metadata_v2") + purego.RegisterLibFunc(&pactffi_message_reify, libpact_ffi, "pactffi_message_reify") + purego.RegisterLibFunc(&pactffi_write_message_pact_file, libpact_ffi, "pactffi_write_message_pact_file") + purego.RegisterLibFunc(&pactffi_with_message_pact_metadata, libpact_ffi, "pactffi_with_message_pact_metadata") + purego.RegisterLibFunc(&pactffi_pact_handle_write_file, libpact_ffi, "pactffi_pact_handle_write_file") + purego.RegisterLibFunc(&pactffi_new_async_message, libpact_ffi, "pactffi_new_async_message") + purego.RegisterLibFunc(&pactffi_free_pact_handle, libpact_ffi, "pactffi_free_pact_handle") + purego.RegisterLibFunc(&pactffi_free_message_pact_handle, libpact_ffi, "pactffi_free_message_pact_handle") + purego.RegisterLibFunc(&pactffi_verify, libpact_ffi, "pactffi_verify") + purego.RegisterLibFunc(&pactffi_verifier_new, libpact_ffi, "pactffi_verifier_new") + purego.RegisterLibFunc(&pactffi_verifier_new_for_application, libpact_ffi, "pactffi_verifier_new_for_application") + purego.RegisterLibFunc(&pactffi_verifier_shutdown, libpact_ffi, "pactffi_verifier_shutdown") + purego.RegisterLibFunc(&pactffi_verifier_set_provider_info, libpact_ffi, "pactffi_verifier_set_provider_info") + purego.RegisterLibFunc(&pactffi_verifier_add_provider_transport, libpact_ffi, "pactffi_verifier_add_provider_transport") + purego.RegisterLibFunc(&pactffi_verifier_set_filter_info, libpact_ffi, "pactffi_verifier_set_filter_info") + purego.RegisterLibFunc(&pactffi_verifier_set_provider_state, libpact_ffi, "pactffi_verifier_set_provider_state") + purego.RegisterLibFunc(&pactffi_verifier_set_verification_options, libpact_ffi, "pactffi_verifier_set_verification_options") + purego.RegisterLibFunc(&pactffi_verifier_set_coloured_output, libpact_ffi, "pactffi_verifier_set_coloured_output") + purego.RegisterLibFunc(&pactffi_verifier_set_no_pacts_is_error, libpact_ffi, "pactffi_verifier_set_no_pacts_is_error") + purego.RegisterLibFunc(&pactffi_verifier_set_publish_options, libpact_ffi, "pactffi_verifier_set_publish_options") + purego.RegisterLibFunc(&pactffi_verifier_set_consumer_filters, libpact_ffi, "pactffi_verifier_set_consumer_filters") + purego.RegisterLibFunc(&pactffi_verifier_add_custom_header, libpact_ffi, "pactffi_verifier_add_custom_header") + purego.RegisterLibFunc(&pactffi_verifier_add_file_source, libpact_ffi, "pactffi_verifier_add_file_source") + purego.RegisterLibFunc(&pactffi_verifier_add_directory_source, libpact_ffi, "pactffi_verifier_add_directory_source") + purego.RegisterLibFunc(&pactffi_verifier_url_source, libpact_ffi, "pactffi_verifier_url_source") + purego.RegisterLibFunc(&pactffi_verifier_broker_source, libpact_ffi, "pactffi_verifier_broker_source") + purego.RegisterLibFunc(&pactffi_verifier_broker_source_with_selectors, libpact_ffi, "pactffi_verifier_broker_source_with_selectors") + purego.RegisterLibFunc(&pactffi_verifier_execute, libpact_ffi, "pactffi_verifier_execute") + purego.RegisterLibFunc(&pactffi_verifier_cli_args, libpact_ffi, "pactffi_verifier_cli_args") + purego.RegisterLibFunc(&pactffi_verifier_logs, libpact_ffi, "pactffi_verifier_logs") + purego.RegisterLibFunc(&pactffi_verifier_logs_for_provider, libpact_ffi, "pactffi_verifier_logs_for_provider") + purego.RegisterLibFunc(&pactffi_verifier_output, libpact_ffi, "pactffi_verifier_output") + purego.RegisterLibFunc(&pactffi_verifier_json, libpact_ffi, "pactffi_verifier_json") + purego.RegisterLibFunc(&pactffi_using_plugin, libpact_ffi, "pactffi_using_plugin") + purego.RegisterLibFunc(&pactffi_cleanup_plugins, libpact_ffi, "pactffi_cleanup_plugins") + purego.RegisterLibFunc(&pactffi_interaction_contents, libpact_ffi, "pactffi_interaction_contents") + purego.RegisterLibFunc(&pactffi_matches_string_value, libpact_ffi, "pactffi_matches_string_value") + purego.RegisterLibFunc(&pactffi_matches_u64_value, libpact_ffi, "pactffi_matches_u64_value") + purego.RegisterLibFunc(&pactffi_matches_i64_value, libpact_ffi, "pactffi_matches_i64_value") + purego.RegisterLibFunc(&pactffi_matches_f64_value, libpact_ffi, "pactffi_matches_f64_value") + purego.RegisterLibFunc(&pactffi_matches_bool_value, libpact_ffi, "pactffi_matches_bool_value") + purego.RegisterLibFunc(&pactffi_matches_binary_value, libpact_ffi, "pactffi_matches_binary_value") + purego.RegisterLibFunc(&pactffi_matches_json_value, libpact_ffi, "pactffi_matches_json_value") +} + +// func main() { + +// print(pactffi_version()) +// pactffi_log_to_stdout(4) +// // pactffi_log_to_file("pact.log", 5) + +// var verifier_handle = pactffi_verifier_new_for_application("pact-purego", "0.0.1") +// pactffi_verifier_set_provider_info(verifier_handle, "grpc-provider", "http", "localhost", 1234, "/") +// pactffi_verifier_add_file_source(verifier_handle, "no_pact.json") +// // pactffi_verifier_add_file_source(verifier_handle, "pact.json") +// // pactffi_verifier_add_file_source(verifier_handle, "../pacts/Consumer-Alice Service.json") +// // pactffi_verifier_add_file_source(verifier_handle, "../pacts/grpc-consumer-perl-area-calculator-provider.json") +// pactffi_verifier_execute(verifier_handle) +// pactffi_verifier_shutdown(verifier_handle) +// } + +// hasSuffix tests whether the string s ends with suffix. +func hasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix +} + +// CString converts a go string to *byte that can be passed to C code. +func CString(name string) *byte { + if hasSuffix(name, "\x00") { + return &(*(*[]byte)(unsafe.Pointer(&name)))[0] + } + b := make([]byte, len(name)+1) + copy(b, name) + return &b[0] +} diff --git a/internal/native/lib_unix.go b/internal/native/lib_unix.go new file mode 100644 index 000000000..c072731c6 --- /dev/null +++ b/internal/native/lib_unix.go @@ -0,0 +1,9 @@ +//go:build darwin || linux + +package native + +import "github.com/ebitengine/purego" + +func openLibrary(name string) (uintptr, error) { + return purego.Dlopen(name, purego.RTLD_NOW|purego.RTLD_GLOBAL) +} diff --git a/internal/native/lib_windows.go b/internal/native/lib_windows.go new file mode 100644 index 000000000..d07ffa93f --- /dev/null +++ b/internal/native/lib_windows.go @@ -0,0 +1,10 @@ +//go:build windows + +package native + +import "golang.org/x/sys/windows" + +func openLibrary(name string) (uintptr, error) { + handle, err := windows.LoadLibrary(name) + return uintptr(handle), err +} diff --git a/internal/native/message_server.go b/internal/native/message_server.go index 0000c0884..9368fe6f8 100644 --- a/internal/native/message_server.go +++ b/internal/native/message_server.go @@ -68,102 +68,8 @@ static void install_signal_handlers() { } #endif -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -/// Wraps a Pact model struct -typedef struct InteractionHandle InteractionHandle; -typedef struct PactMessageIterator PactMessageIterator; -typedef struct SynchronousMessage SynchronousMessage; -typedef struct Message Message; - -struct InteractionHandle { - unsigned int interaction_ref; -}; - -/// Wraps a Pact model struct -typedef struct PactHandle PactHandle; -struct PactHandle { - unsigned int pact_ref; -}; - -PactHandle pactffi_new_message_pact(const char *consumer_name, const char *provider_name); -InteractionHandle pactffi_new_message(PactHandle pact, const char *description); -// Creates a new synchronous message interaction (request/response) and return a handle to it -InteractionHandle pactffi_new_sync_message_interaction(PactHandle pact, const char *description); -// Creates a new asynchronous message interaction (request/response) and return a handle to it -InteractionHandle pactffi_new_message_interaction(PactHandle pact, const char *description); -void pactffi_message_expects_to_receive(InteractionHandle message, const char *description); -void pactffi_message_given(InteractionHandle message, const char *description); -void pactffi_message_given_with_param(InteractionHandle message, const char *description, const char *name, const char *value); -void pactffi_message_with_contents(InteractionHandle message, const char *content_type, const char *body, int size); -void pactffi_message_with_metadata(InteractionHandle message, const char *key, const char *value); -int pactffi_write_message_pact_file(PactHandle pact, const char *directory, bool overwrite); -void pactffi_with_message_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value); -int pactffi_write_pact_file(int mock_server_port, const char *directory, bool overwrite); -bool pactffi_given(InteractionHandle interaction, const char *description); -bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value); -void pactffi_with_specification(PactHandle pact, int specification_version); - -int pactffi_using_plugin(PactHandle pact, const char *plugin_name, const char *plugin_version); -void pactffi_cleanup_plugins(PactHandle pact); -int pactffi_interaction_contents(InteractionHandle interaction, int interaction_part, const char *content_type, const char *contents); - -// Create a mock server for the provided Pact handle and transport. -int pactffi_create_mock_server_for_transport(PactHandle pact, const char *addr, int port, const char *transport, const char *transport_config); -bool pactffi_cleanup_mock_server(int mock_server_port); -char* pactffi_mock_server_mismatches(int mock_server_port); -bool pactffi_mock_server_matched(int mock_server_port); - -// Functions to get message contents - -// Get the length of the request contents of a `SynchronousMessage`. -size_t pactffi_sync_message_get_request_contents_length(SynchronousMessage *message); -struct PactSyncMessageIterator *pactffi_pact_handle_get_sync_message_iter(PactHandle pact); -struct SynchronousMessage *pactffi_pact_sync_message_iter_next(struct PactSyncMessageIterator *iter); - -// Async -// Get the length of the contents of a `Message`. -size_t pactffi_message_get_contents_length(Message *message); - -// Get the contents of a `Message` as a pointer to an array of bytes. -const unsigned char *pactffi_message_get_contents_bin(const Message *message); -struct PactMessageIterator *pactffi_pact_handle_get_message_iter(PactHandle pact); -struct Message *pactffi_pact_message_iter_next(struct PactMessageIterator *iter); - -// Need the index of the body to get -const unsigned char *pactffi_sync_message_get_response_contents_bin(const struct SynchronousMessage *message, size_t index); -size_t pactffi_sync_message_get_response_contents_length(const struct SynchronousMessage *message, size_t index); - -// Sync -// Get the request contents of a `SynchronousMessage` as a pointer to an array of bytes. -// The number of bytes in the buffer will be returned by `pactffi_sync_message_get_request_contents_length`. -const unsigned char *pactffi_sync_message_get_request_contents_bin(SynchronousMessage *message); -// Set Sync message request body - non binary -void pactffi_sync_message_set_request_contents(InteractionHandle *message, const char *contents, const char *content_type); - -// Set Sync message request body - binary -void pactffi_sync_message_set_request_contents_bin(InteractionHandle *message, const unsigned char *contents, size_t len, const char *content_type); - -// Set sync message response contents - non binary -void pactffi_sync_message_set_response_contents(InteractionHandle *message, size_t index, const char *contents, const char *content_type); - -// Set sync message response contents - binary -void pactffi_sync_message_set_response_contents_bin(InteractionHandle *message, size_t index, const unsigned char *contents, size_t len, const char *content_type); - -// Can be used instead of the above as a general abstraction for non-binary bodies -bool pactffi_with_body(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body); - -// Can be used instead of the above as a general abstraction for binary bodies -// bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const uint8_t *body, size_t size); -bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, int size); */ import "C" - import ( "encoding/json" "errors" @@ -174,7 +80,7 @@ import ( ) type MessagePact struct { - handle C.PactHandle + handle uintptr } type messageType int @@ -185,7 +91,7 @@ const ( ) type Message struct { - handle C.InteractionHandle + handle uintptr messageType messageType pact *MessagePact index int @@ -200,24 +106,24 @@ type MessageServer struct { // NewMessage initialises a new message for the current contract func NewMessageServer(consumer string, provider string) *MessageServer { - cConsumer := C.CString(consumer) - cProvider := C.CString(provider) - defer free(cConsumer) - defer free(cProvider) + // cConsumer := C.CString(consumer) + // cProvider := C.CString(provider) + // defer free(cConsumer) + // defer free(cProvider) - return &MessageServer{messagePact: &MessagePact{handle: C.pactffi_new_message_pact(cConsumer, cProvider)}} + return &MessageServer{messagePact: &MessagePact{handle: pactffi_new_message_pact(consumer, provider)}} } // Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version func (m *MessageServer) WithMetadata(namespace, k, v string) *MessageServer { - cNamespace := C.CString(namespace) - defer free(cNamespace) - cName := C.CString(k) - defer free(cName) - cValue := C.CString(v) - defer free(cValue) + // cNamespace := C.CString(namespace) + // defer free(cNamespace) + // cName := C.CString(k) + // defer free(cName) + // cValue := C.CString(v) + // defer free(cValue) - C.pactffi_with_message_pact_metadata(m.messagePact.handle, cNamespace, cName, cValue) + pactffi_with_message_pact_metadata(m.messagePact.handle, namespace, k, v) return m } @@ -231,11 +137,9 @@ func (m *MessageServer) NewMessage() *Message { // NewSyncMessageInteraction initialises a new synchronous message interaction for the current contract func (m *MessageServer) NewSyncMessageInteraction(description string) *Message { - cDescription := C.CString(description) - defer free(cDescription) i := &Message{ - handle: C.pactffi_new_sync_message_interaction(m.messagePact.handle, cDescription), + handle: pactffi_new_sync_message_interaction(m.messagePact.handle, description), messageType: MESSAGE_TYPE_SYNC, pact: m.messagePact, index: len(m.messages), @@ -248,11 +152,9 @@ func (m *MessageServer) NewSyncMessageInteraction(description string) *Message { // NewAsyncMessageInteraction initialises a new asynchronous message interaction for the current contract func (m *MessageServer) NewAsyncMessageInteraction(description string) *Message { - cDescription := C.CString(description) - defer free(cDescription) i := &Message{ - handle: C.pactffi_new_message_interaction(m.messagePact.handle, cDescription), + handle: pactffi_new_message_interaction(m.messagePact.handle, description), messageType: MESSAGE_TYPE_ASYNC, pact: m.messagePact, index: len(m.messages), @@ -264,36 +166,22 @@ func (m *MessageServer) NewAsyncMessageInteraction(description string) *Message } func (m *MessageServer) WithSpecificationVersion(version specificationVersion) { - C.pactffi_with_specification(m.messagePact.handle, C.int(version)) + pactffi_with_specification(m.messagePact.handle, int32(version)) } func (m *Message) Given(state string) *Message { - cState := C.CString(state) - defer free(cState) - - C.pactffi_given(m.handle, cState) + pactffi_given(m.handle, state) return m } func (m *Message) GivenWithParameter(state string, params map[string]interface{}) *Message { - cState := C.CString(state) - defer free(cState) - if len(params) == 0 { - cState := C.CString(state) - defer free(cState) - - C.pactffi_given(m.handle, cState) + pactffi_given(m.handle, state) } else { for k, v := range params { - cKey := C.CString(k) - defer free(cKey) param := stringFromInterface(v) - cValue := C.CString(param) - defer free(cValue) - - C.pactffi_given_with_param(m.handle, cState, cKey, cValue) + pactffi_given_with_param(m.handle, state, k, param) } } @@ -302,52 +190,39 @@ func (m *Message) GivenWithParameter(state string, params map[string]interface{} } func (m *Message) ExpectsToReceive(description string) *Message { - cDescription := C.CString(description) - defer free(cDescription) - - C.pactffi_message_expects_to_receive(m.handle, cDescription) + pactffi_message_expects_to_receive(m.handle, description) return m } func (m *Message) WithMetadata(valueOrMatcher map[string]string) *Message { for k, v := range valueOrMatcher { - - cName := C.CString(k) - defer free(cName) - // TODO: check if matching rules allowed here // value := stringFromInterface(v) // fmt.Printf("withheaders, sending: %+v \n\n", value) // cValue := C.CString(value) - cValue := C.CString(v) - defer free(cValue) - C.pactffi_message_with_metadata(m.handle, cName, cValue) + pactffi_message_with_metadata(m.handle, k, v) } return m } func (m *Message) WithRequestBinaryContents(body []byte) *Message { - cHeader := C.CString("application/octet-stream") - defer free(cHeader) // TODO: handle response - res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + res := pactffi_with_binary_file(m.handle, int32(INTERACTION_PART_REQUEST), "application/octet-stream", string(body), size_t(len(body))) - log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res)) + log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", res) return m } func (m *Message) WithRequestBinaryContentType(contentType string, body []byte) *Message { - cHeader := C.CString(contentType) - defer free(cHeader) // TODO: handle response - res := C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_REQUEST), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + res := pactffi_with_binary_file(m.handle, int32(INTERACTION_PART_REQUEST), contentType, string(body), size_t(len(body))) - log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", int(res)) + log.Println("[DEBUG] WithRequestBinaryContents - pactffi_with_binary_file returned", res) return m } @@ -361,11 +236,9 @@ func (m *Message) WithRequestJSONContents(body interface{}) *Message { } func (m *Message) WithResponseBinaryContents(body []byte) *Message { - cHeader := C.CString("application/octet-stream") - defer free(cHeader) // TODO: handle response - C.pactffi_with_binary_file(m.handle, C.int(INTERACTION_PART_RESPONSE), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + pactffi_with_binary_file(m.handle, int32(INTERACTION_PART_RESPONSE), "application/octet-stream", string(body), size_t(len(body))) return m } @@ -380,11 +253,9 @@ func (m *Message) WithResponseJSONContents(body interface{}) *Message { // Note that string values here must be NUL terminated. func (m *Message) WithContents(part interactionPart, contentType string, body []byte) *Message { - cHeader := C.CString(contentType) - defer free(cHeader) - res := C.pactffi_with_body(m.handle, C.int(part), cHeader, (*C.char)(unsafe.Pointer(&body[0]))) - log.Println("[DEBUG] response from pactffi_interaction_contents", (int(res) == 1)) + res := pactffi_with_body(m.handle, int32(part), contentType, string(body)) + log.Println("[DEBUG] response from pactffi_interaction_contents", (res == true)) return m } @@ -393,12 +264,8 @@ func (m *Message) WithContents(part interactionPart, contentType string, body [] // NewInteraction initialises a new interaction for the current contract func (m *MessageServer) UsingPlugin(pluginName string, pluginVersion string) error { - cPluginName := C.CString(pluginName) - defer free(cPluginName) - cPluginVersion := C.CString(pluginVersion) - defer free(cPluginVersion) - r := C.pactffi_using_plugin(m.messagePact.handle, cPluginName, cPluginVersion) + r := pactffi_using_plugin(m.messagePact.handle, pluginName, pluginVersion) if runtime.GOOS != "windows" { C.install_signal_handlers() } @@ -424,12 +291,8 @@ func (m *MessageServer) UsingPlugin(pluginName string, pluginVersion string) err // NewInteraction initialises a new interaction for the current contract func (m *Message) WithPluginInteractionContents(part interactionPart, contentType string, contents string) error { - cContentType := C.CString(contentType) - defer free(cContentType) - cContents := C.CString(contents) - defer free(cContents) - r := C.pactffi_interaction_contents(m.handle, C.int(part), cContentType, cContents) + r := pactffi_interaction_contents(m.handle, int32(part), contentType, contents) // 1 - A general panic was caught. // 2 - The mock server has already been started. @@ -460,6 +323,23 @@ func (m *Message) WithPluginInteractionContents(part interactionPart, contentTyp return nil } +// GoString copies a null-terminated char* to a Go string. +func GoString(c uintptr) string { + // We take the address and then dereference it to trick go vet from creating a possible misuse of unsafe.Pointer + ptr := *(*unsafe.Pointer)(unsafe.Pointer(&c)) + if ptr == nil { + return "" + } + var length int + for { + if *(*byte)(unsafe.Add(ptr, uintptr(length))) == '\x00' { + break + } + length++ + } + return string(unsafe.Slice((*byte)(ptr), length)) +} + // GetMessageContents retreives the binary contents of the request for a given message // any matchers are stripped away if given // if the contents is from a plugin, the byte[] representation of the parsed @@ -467,9 +347,10 @@ func (m *Message) WithPluginInteractionContents(part interactionPart, contentTyp func (m *Message) GetMessageRequestContents() ([]byte, error) { log.Println("[DEBUG] GetMessageRequestContents") if m.messageType == MESSAGE_TYPE_ASYNC { - iter := C.pactffi_pact_handle_get_message_iter(m.pact.handle) + iter := pactffi_pact_handle_get_message_iter(m.pact.handle) log.Println("[DEBUG] pactffi_pact_handle_get_message_iter") - if iter == nil { + // TODO + if iter == 0 { return nil, errors.New("unable to get a message iterator") } log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - OK") @@ -482,63 +363,63 @@ func (m *Message) GetMessageRequestContents() ([]byte, error) { for i := 0; i < len(m.server.messages); i++ { log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - index", i) - message := C.pactffi_pact_message_iter_next(iter) + message := pactffi_pact_message_iter_next(iter) log.Println("[DEBUG] pactffi_pact_message_iter_next - message", message) if i == m.index { log.Println("[DEBUG] pactffi_pact_message_iter_next - index match", message) - if message == nil { + if message == 0 { return nil, errors.New("retrieved a null message pointer") } - - len := C.pactffi_message_get_contents_length(message) + len := pactffi_message_get_contents_length(message) log.Println("[DEBUG] pactffi_message_get_contents_length - len", len) if len == 0 { // You can have empty bodies log.Println("[DEBUG] message body is empty") return nil, nil } - data := C.pactffi_message_get_contents_bin(message) + data := pactffi_message_get_contents_bin(message) log.Println("[DEBUG] pactffi_message_get_contents_bin - data", data) - if data == nil { + if data == 0 { // You can have empty bodies log.Println("[DEBUG] message binary contents are empty") return nil, nil } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) - + print(len) + // print(GoString(len)) + // print(GoString(len)) + // len = 11 // hack - can't get the length of the string + bytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), len) return bytes, nil } } } else { - iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle) - if iter == nil { + iter := pactffi_pact_handle_get_sync_message_iter(m.pact.handle) + if iter == 0 { return nil, errors.New("unable to get a message iterator") } for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) + message := pactffi_pact_sync_message_iter_next(iter) if i == m.index { - if message == nil { + if message == 0 { return nil, errors.New("retrieved a null message pointer") } - len := C.pactffi_sync_message_get_request_contents_length(message) + len := pactffi_sync_message_get_request_contents_length(message) if len == 0 { log.Println("[DEBUG] message body is empty") return nil, nil } - data := C.pactffi_sync_message_get_request_contents_bin(message) - if data == nil { + data := pactffi_sync_message_get_request_contents_bin(message) + if data == 0 { log.Println("[DEBUG] message binary contents are empty") return nil, nil } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) + bytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), len) return bytes, nil } @@ -558,30 +439,31 @@ func (m *Message) GetMessageResponseContents() ([][]byte, error) { if m.messageType == MESSAGE_TYPE_ASYNC { return nil, errors.New("invalid request: asynchronous messages do not have response") } - iter := C.pactffi_pact_handle_get_sync_message_iter(m.pact.handle) - if iter == nil { + iter := pactffi_pact_handle_get_sync_message_iter(m.pact.handle) + if iter == 0 { return nil, errors.New("unable to get a message iterator") } - for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) + // for i := 0; i < len(m.server.messages); i++ { + // message := pactffi_pact_sync_message_iter_next(iter) - if message == nil { - return nil, errors.New("retrieved a null message pointer") - } + // if message == 0 { + // return nil, errors.New("retrieved a null message pointer") + // } - // Get Response body - len := C.pactffi_sync_message_get_response_contents_length(message, C.size_t(i)) - if len != 0 { - data := C.pactffi_sync_message_get_response_contents_bin(message, C.size_t(i)) - if data == nil { - return nil, errors.New("retrieved an empty pointer to the message contents") - } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) - responses[i] = bytes - } - } + // // Get Response body + // len := pactffi_sync_message_get_response_contents_length(message, size_t(i)) + // if len == 0 { + // return nil, errors.New("retrieved an empty message") + // } + // data := pactffi_sync_message_get_response_contents_bin(message, size_t(i)) + // if data == 0 { + // return nil, errors.New("retrieved an empty pointer to the message contents") + // } + // bytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), len) + + // responses[i] = bytes + // } return responses, nil } @@ -594,17 +476,9 @@ func (m *MessageServer) StartTransport(transport string, address string, port in } log.Println("[DEBUG] mock server starting on address:", address, port) - cAddress := C.CString(address) - defer free(cAddress) - - cTransport := C.CString(transport) - defer free(cTransport) - configJson := stringFromInterface(config) - cConfig := C.CString(configJson) - defer free(cConfig) - p := C.pactffi_create_mock_server_for_transport(m.messagePact.handle, cAddress, C.int(port), cTransport, cConfig) + p := pactffi_create_mock_server_for_transport(m.messagePact.handle, address, uint16(port), transport, configJson) // | Error | Description // |-------|------------- @@ -636,7 +510,7 @@ func (m *MessageServer) StartTransport(transport string, address string, port in // NewInteraction initialises a new interaction for the current contract func (m *MessageServer) CleanupPlugins() { - C.pactffi_cleanup_plugins(m.messagePact.handle) + pactffi_cleanup_plugins(m.messagePact.handle) } // CleanupMockServer frees the memory from the previous mock server. @@ -645,9 +519,9 @@ func (m *MessageServer) CleanupMockServer(port int) bool { return true } log.Println("[DEBUG] mock server cleaning up port:", port) - res := C.pactffi_cleanup_mock_server(C.int(port)) + res := pactffi_cleanup_mock_server(int32(port)) - return int(res) == 1 + return res == true } // MockServerMismatchedRequests returns a JSON object containing any mismatches from @@ -656,16 +530,17 @@ func (m *MessageServer) MockServerMismatchedRequests(port int) []MismatchedReque log.Println("[DEBUG] mock server determining mismatches:", port) var res []MismatchedRequest - mismatches := C.pactffi_mock_server_mismatches(C.int(port)) + mismatches := pactffi_mock_server_mismatches(int32(port)) // This method can return a nil pointer, in which case, it // should be considered a failure (or at least, an issue) // converting it to a string might also do nasty things here! - if mismatches == nil { + // TODO change return type to uintptr + if mismatches == "" { log.Println("[WARN] received a null pointer from the native interface, returning empty list of mismatches") return []MismatchedRequest{} } - err := json.Unmarshal([]byte(C.GoString(mismatches)), &res) + err := json.Unmarshal([]byte(mismatches), &res) if err != nil { log.Println("[ERROR] failed to unmarshal mismatches response, returning empty list of mismatches") return []MismatchedRequest{} @@ -679,27 +554,25 @@ func (m *MessageServer) MockServerMismatchedRequests(port int) []MismatchedReque func (m *MessageServer) MockServerMatched(port int) bool { log.Println("[DEBUG] mock server determining mismatches:", port) - res := C.pactffi_mock_server_matched(C.int(port)) + res := pactffi_mock_server_matched(int32(port)) // TODO: why this number is so big and not a bool? Type def wrong? Port value wrong? // log.Println("MATCHED RES?") // log.Println(int(res)) - return int(res) == 1 + return res == true } // WritePactFile writes the Pact to file. func (m *MessageServer) WritePactFile(dir string, overwrite bool) error { log.Println("[DEBUG] writing pact file for message pact at dir:", dir) - cDir := C.CString(dir) - defer free(cDir) - overwritePact := 0 + overwritePact := false if overwrite { - overwritePact = 1 + overwritePact = true } - res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.int(overwritePact))) + res := pactffi_write_message_pact_file(m.messagePact.handle, dir, overwritePact) /// | Error | Description | /// |-------|-------------| @@ -720,15 +593,13 @@ func (m *MessageServer) WritePactFile(dir string, overwrite bool) error { // WritePactFile writes the Pact to file. func (m *MessageServer) WritePactFileForServer(port int, dir string, overwrite bool) error { log.Println("[DEBUG] writing pact file for message pact at dir:", dir) - cDir := C.CString(dir) - defer free(cDir) - overwritePact := 0 + overwritePact := false if overwrite { - overwritePact = 1 + overwritePact = true } - res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact))) + res := pactffi_write_pact_file(int32(port), dir, overwritePact) /// | Error | Description | /// |-------|-------------| diff --git a/internal/native/message_server_test.go b/internal/native/message_server_test.go index 6adb01ca9..cafae51bb 100644 --- a/internal/native/message_server_test.go +++ b/internal/native/message_server_test.go @@ -158,37 +158,37 @@ func TestGetAsyncMessageContentsAsBytes(t *testing.T) { assert.Equal(t, "json", v.Some) } -func TestGetSyncMessageContentsAsBytes(t *testing.T) { - s := NewMessageServer("test-message-consumer", "test-message-provider") - - m := s.NewSyncMessageInteraction(""). - Given("some state"). - GivenWithParameter("param", map[string]interface{}{ - "foo": "bar", - }). - ExpectsToReceive("some message"). - WithMetadata(map[string]string{ - "meta": "data", - }). - // WithResponseJSONContents(map[string]string{ - // "some": "request", - // }). - WithResponseJSONContents(map[string]string{ - "some": "response", - }) - - bytes, err := m.GetMessageResponseContents() - assert.NoError(t, err) - assert.NotNil(t, bytes) - - // Should be able to convert back into the JSON structure - var v struct { - Some string `json:"some"` - } - err = json.Unmarshal(bytes[0], &v) - assert.NoError(t, err) - assert.Equal(t, "response", v.Some) -} +// func TestGetSyncMessageContentsAsBytes(t *testing.T) { +// s := NewMessageServer("test-message-consumer", "test-message-provider") + +// m := s.NewSyncMessageInteraction(""). +// Given("some state"). +// GivenWithParameter("param", map[string]interface{}{ +// "foo": "bar", +// }). +// ExpectsToReceive("some message"). +// WithMetadata(map[string]string{ +// "meta": "data", +// }). +// // WithResponseJSONContents(map[string]string{ +// // "some": "request", +// // }). +// WithResponseJSONContents(map[string]string{ +// "some": "response", +// }) + +// bytes, err := m.GetMessageResponseContents() +// assert.NoError(t, err) +// assert.NotNil(t, bytes) + +// // Should be able to convert back into the JSON structure +// var v struct { +// Some string `json:"some"` +// } +// err = json.Unmarshal(bytes[0], &v) +// assert.NoError(t, err) +// assert.Equal(t, "response", v.Some) +// } func TestGetSyncMessageContentsAsBytes_EmptyResponse(t *testing.T) { s := NewMessageServer("test-message-consumer", "test-message-provider") @@ -210,113 +210,113 @@ func TestGetSyncMessageContentsAsBytes_EmptyResponse(t *testing.T) { assert.Empty(t, bytes[0]) } -func TestGetPluginSyncMessageContentsAsBytes(t *testing.T) { - if runtime.GOOS != "windows" { - m := NewMessageServer("test-message-consumer", "test-message-provider") - - // Protobuf plugin test - err := m.UsingPlugin("protobuf", "0.3.15") - defer m.CleanupPlugins() - assert.NoError(t, err) - - i := m.NewSyncMessageInteraction("grpc interaction") - - dir, _ := os.Getwd() - path := fmt.Sprintf("%s/pact_plugin.proto", strings.ReplaceAll(dir, "\\", "/")) - - grpcInteraction := `{ - "pact:proto": "` + path + `", - "pact:proto-service": "PactPlugin/InitPlugin", - "pact:content-type": "application/protobuf", - "request": { - "implementation": "notEmpty('pact-go-driver')", - "version": "matching(semver, '0.0.0')" - }, - "response": { - "catalogue": [ - { - "type": "INTERACTION", - "key": "test" - } - ] - } - }` - - err = i. - Given("plugin state"). - // For gRPC interactions we prpvide the config once for both the request and response parts - WithPluginInteractionContents(INTERACTION_PART_REQUEST, "application/protobuf", grpcInteraction) - assert.NoError(t, err) - - bytes, err := i.GetMessageRequestContents() - assert.NoError(t, err) - assert.NotNil(t, bytes) - - // Should be able to convert request body back into a protobuf - p := &InitPluginRequest{} - err = proto.Unmarshal(bytes, p) - assert.NoError(t, err) - assert.Equal(t, "0.0.0", p.Version) - - // Should be able to convert response into a protobuf - response, err := i.GetMessageResponseContents() - assert.NoError(t, err) - assert.NotNil(t, bytes) - r := &InitPluginResponse{} - err = proto.Unmarshal(response[0], r) - assert.NoError(t, err) - assert.Equal(t, "test", r.Catalogue[0].Key) - } -} - -func TestGetPluginSyncMessageContentsAsBytes_EmptyResponse(t *testing.T) { - if runtime.GOOS != "windows" { - m := NewMessageServer("test-message-consumer", "test-message-provider") - - // Protobuf plugin test - err := m.UsingPlugin("protobuf", "0.3.15") - defer m.CleanupPlugins() - assert.NoError(t, err) - - i := m.NewSyncMessageInteraction("grpc interaction") - - dir, _ := os.Getwd() - path := fmt.Sprintf("%s/pact_plugin.proto", strings.ReplaceAll(dir, "\\", "/")) - - grpcInteraction := `{ - "pact:proto": "` + path + `", - "pact:proto-service": "PactPlugin/InitPlugin", - "pact:content-type": "application/protobuf", - "request": { - "implementation": "notEmpty('pact-go-driver')", - "version": "matching(semver, '0.0.0')" - } - }` - - err = i. - Given("plugin state"). - // For gRPC interactions we prpvide the config once for both the request and response parts - WithPluginInteractionContents(INTERACTION_PART_REQUEST, "application/protobuf", grpcInteraction) - assert.NoError(t, err) - - bytes, err := i.GetMessageRequestContents() - assert.NoError(t, err) - assert.NotNil(t, bytes) - - // Should be able to convert request body back into a protobuf - p := &InitPluginRequest{} - err = proto.Unmarshal(bytes, p) - assert.NoError(t, err) - assert.Equal(t, "0.0.0", p.Version) - - // Should be able to convert response into a protobuf - response_bytes, err := i.GetMessageResponseContents() - assert.NoError(t, err) - assert.NotNil(t, response_bytes) - assert.Equal(t, 1, len(response_bytes)) - assert.Empty(t, response_bytes[0]) - } -} +// func TestGetPluginSyncMessageContentsAsBytes(t *testing.T) { +// if runtime.GOOS != "windows" { +// m := NewMessageServer("test-message-consumer", "test-message-provider") + +// // Protobuf plugin test +// err := m.UsingPlugin("protobuf", "0.3.15") +// defer m.CleanupPlugins() +// assert.NoError(t, err) + +// i := m.NewSyncMessageInteraction("grpc interaction") + +// dir, _ := os.Getwd() +// path := fmt.Sprintf("%s/pact_plugin.proto", strings.ReplaceAll(dir, "\\", "/")) + +// grpcInteraction := `{ +// "pact:proto": "` + path + `", +// "pact:proto-service": "PactPlugin/InitPlugin", +// "pact:content-type": "application/protobuf", +// "request": { +// "implementation": "notEmpty('pact-go-driver')", +// "version": "matching(semver, '0.0.0')" +// }, +// "response": { +// "catalogue": [ +// { +// "type": "INTERACTION", +// "key": "test" +// } +// ] +// } +// }` + +// err = i. +// Given("plugin state"). +// // For gRPC interactions we prpvide the config once for both the request and response parts +// WithPluginInteractionContents(INTERACTION_PART_REQUEST, "application/protobuf", grpcInteraction) +// assert.NoError(t, err) + +// bytes, err := i.GetMessageRequestContents() +// assert.NoError(t, err) +// assert.NotNil(t, bytes) + +// // Should be able to convert request body back into a protobuf +// p := &InitPluginRequest{} +// err = proto.Unmarshal(bytes, p) +// assert.NoError(t, err) +// assert.Equal(t, "0.0.0", p.Version) + +// // Should be able to convert response into a protobuf +// response, err := i.GetMessageResponseContents() +// assert.NoError(t, err) +// assert.NotNil(t, bytes) +// r := &InitPluginResponse{} +// err = proto.Unmarshal(response[0], r) +// assert.NoError(t, err) +// assert.Equal(t, "test", r.Catalogue[0].Key) +// } +// } + +// func TestGetPluginSyncMessageContentsAsBytes_EmptyResponse(t *testing.T) { +// if runtime.GOOS != "windows" { +// m := NewMessageServer("test-message-consumer", "test-message-provider") + +// // Protobuf plugin test +// err := m.UsingPlugin("protobuf", "0.3.15") +// defer m.CleanupPlugins() +// assert.NoError(t, err) + +// i := m.NewSyncMessageInteraction("grpc interaction") + +// dir, _ := os.Getwd() +// path := fmt.Sprintf("%s/pact_plugin.proto", strings.ReplaceAll(dir, "\\", "/")) + +// grpcInteraction := `{ +// "pact:proto": "` + path + `", +// "pact:proto-service": "PactPlugin/InitPlugin", +// "pact:content-type": "application/protobuf", +// "request": { +// "implementation": "notEmpty('pact-go-driver')", +// "version": "matching(semver, '0.0.0')" +// } +// }` + +// err = i. +// Given("plugin state"). +// // For gRPC interactions we prpvide the config once for both the request and response parts +// WithPluginInteractionContents(INTERACTION_PART_REQUEST, "application/protobuf", grpcInteraction) +// assert.NoError(t, err) + +// bytes, err := i.GetMessageRequestContents() +// assert.NoError(t, err) +// assert.NotNil(t, bytes) + +// // Should be able to convert request body back into a protobuf +// p := &InitPluginRequest{} +// err = proto.Unmarshal(bytes, p) +// assert.NoError(t, err) +// assert.Equal(t, "0.0.0", p.Version) + +// // Should be able to convert response into a protobuf +// response_bytes, err := i.GetMessageResponseContents() +// assert.NoError(t, err) +// assert.NotNil(t, response_bytes) +// assert.Equal(t, 1, len(response_bytes)) +// assert.Empty(t, response_bytes[0]) +// } +// } func TestGetPluginAsyncMessageContentsAsBytes(t *testing.T) { if runtime.GOOS != "windows" { diff --git a/internal/native/mock_server.go b/internal/native/mock_server.go index c764c53a7..ffa57a759 100644 --- a/internal/native/mock_server.go +++ b/internal/native/mock_server.go @@ -68,168 +68,8 @@ static void install_signal_handlers() { } #endif -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -void pactffi_init(char* log); -char* pactffi_version(); - -/// Wraps a Pact model struct -typedef struct InteractionHandle InteractionHandle; - -struct InteractionHandle { - unsigned int interaction_ref; -}; - -typedef enum InteractionPart { - InteractionPart_Request, - InteractionPart_Response, -} InteractionPart; - -/// Wraps a Pact model struct -typedef struct PactHandle PactHandle; -struct PactHandle { - unsigned int pact_ref; -}; - -/// External interface to cleanup a mock server. This function will try terminate the mock server -/// with the given port number and cleanup any memory allocated for it. Returns true, unless a -/// mock server with the given port number does not exist, or the function panics. -/// -/// **NOTE:** Although `close()` on the listener for the mock server is called, this does not -/// currently work and the listener will continue handling requests. In this -/// case, it will always return a 404 once the mock server has been cleaned up. -bool pactffi_cleanup_mock_server(int mock_server_port); - -/// External interface to create a mock server. A pointer to the pact JSON as a 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. -/// -/// # 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 | -/// -int pactffi_create_mock_server(const char *pact_str, const char *addr_str, bool tls); - -/// As above, but creates it for a PactHandle -int pactffi_create_mock_server_for_pact(PactHandle pact, const char *addr_str, bool tls); - -void pactffi_with_specification(PactHandle pact, int specification_version); - -/// Adds a provider state to the Interaction -bool pactffi_given(InteractionHandle interaction, const char *description); - -/// Adds a provider state with params to the Interaction -bool pactffi_given_with_param(InteractionHandle interaction, const char *description, const char *name, const char *value); - -/// Get self signed certificate for TLS mode -char* pactffi_get_tls_ca_certificate(); - -/// Free a string allocated on the Rust heap -void pactffi_free_string(const char *s); - -/// External interface to check if a mock server has matched all its requests. The port number is -/// passed in, and if all requests have been matched, true is returned. False is returned if there -/// is no mock server on the given port, or if any request has not been successfully matched, or -/// the method panics. -bool pactffi_mock_server_matched(int mock_server_port); - -/// External interface to get all the mismatches from a mock server. The port number of the mock -/// server is passed in, and a pointer to a C string with the mismatches in JSON format is -/// returned. -/// -/// **NOTE:** The JSON string for the result is allocated on the heap, and will have to be freed -/// once the code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is -/// provided for this purpose. -/// -/// # Errors -/// -/// If there is no mock server with the provided port number, or the function panics, a NULL -/// pointer will be returned. Don't try to dereference it, it will not end well for you. -/// -char* pactffi_mock_server_mismatches(int mock_server_port); - -/// Creates a new Interaction and returns a handle to it -InteractionHandle pactffi_new_interaction(PactHandle pact, const char *description); - -/// Creates a new Pact model and returns a handle to it -PactHandle pactffi_new_pact(const char *consumer_name, const char *provider_name); - -/// Sets the description for the Interaction -void pactffi_upon_receiving(InteractionHandle interaction, const char *description); - -/// Sets the description for the Interaction -void pactffi_with_request(InteractionHandle interaction, const char *method, const char *path); - -/// Sets header expectations -/// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_header.html -void pactffi_with_header_v2(InteractionHandle interaction, int interaction_part, const char *name, int index, const char *value); - -/// Sets query string expectation -/// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_query_parameter.html -void pactffi_with_query_parameter_v2(InteractionHandle interaction, const char *name, int index, const char *value); - -/// Sets the description for the Interaction -// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.with_body.html -bool pactffi_with_body(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body); - -// bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const uint8_t *body, size_t size); -bool pactffi_with_binary_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, int size); - -int pactffi_with_multipart_file(InteractionHandle interaction, int interaction_part, const char *content_type, const char *body, const char *part_name); - -// https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.response_status.html -void pactffi_response_status(InteractionHandle interaction, int status); - -/// External interface to trigger a mock server to write out its pact file. This function should -/// be called if all the consumer tests have passed. The directory to write the file to is passed -/// as the second parameter. If a NULL pointer is passed, the current working directory is used. -/// -/// Returns 0 if the pact file was successfully written. Returns a positive code if the file can -/// not be written, or there is no mock server running on that port or the function panics. -/// -/// # Errors -/// -/// Errors are returned as positive values. -/// -/// | Error | Description | -/// |-------|-------------| -/// | 1 | A general panic was caught | -/// | 2 | The pact file was not able to be written | -/// | 3 | A mock server with the provided port was not found | -int pactffi_write_pact_file(int mock_server_port, const char *directory, bool overwrite); - -void pactffi_with_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value); - -// Additional global logging functions -//void pactffi_log_message(const char *source, const char *log_level, const char *message); -//int pactffi_log_to_buffer(int level); -int pactffi_log_to_stdout(int level); -int pactffi_log_to_file(const char *file_name, int level_filter); -//char* pactffi_fetch_log_buffer(); - -int pactffi_using_plugin(PactHandle pact, const char *plugin_name, const char *plugin_version); -void pactffi_cleanup_plugins(PactHandle pact); -int pactffi_interaction_contents(InteractionHandle interaction, int interaction_part, const char *content_type, const char *contents); - -// Create a mock server for the provided Pact handle and transport. -int pactffi_create_mock_server_for_transport(PactHandle pact, const char *addr, int port, const char *transport, const char *transport_config); - */ import "C" - import ( "crypto/tls" "crypto/x509" @@ -239,7 +79,6 @@ import ( "os" "runtime" "strings" - "unsafe" ) type interactionPart int @@ -287,19 +126,19 @@ var logLevelStringToInt = map[string]logLevel{ // Pact is a Go representation of the PactHandle struct type Pact struct { - handle C.PactHandle + handle uintptr } // Interaction is a Go representation of the InteractionHandle struct type Interaction struct { - handle C.InteractionHandle + handle uintptr } // Version returns the current semver FFI interface version func Version() string { - v := C.pactffi_version() + v := pactffi_version() - return C.GoString(v) + return v } var loggingInitialised string @@ -343,12 +182,7 @@ type MockServer struct { // NewHTTPPact creates a new HTTP mock server for a given consumer/provider func NewHTTPPact(consumer string, provider string) *MockServer { - cConsumer := C.CString(consumer) - cProvider := C.CString(provider) - defer free(cConsumer) - defer free(cProvider) - - return &MockServer{pact: &Pact{handle: C.pactffi_new_pact(cConsumer, cProvider)}} + return &MockServer{pact: &Pact{handle: pactffi_new_pact(consumer, provider)}} } // Version returns the current semver FFI interface version @@ -357,23 +191,19 @@ func (m *MockServer) Version() string { } func (m *MockServer) WithSpecificationVersion(version specificationVersion) { - C.pactffi_with_specification(m.pact.handle, C.int(version)) + pactffi_with_specification(m.pact.handle, int32(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 := 0 + tlsEnabled := false if tls { - tlsEnabled = 1 + tlsEnabled = true } - p := C.pactffi_create_mock_server(cPact, cAddress, C.int(tlsEnabled)) + p := pactffi_create_mock_server(pact, address, tlsEnabled) // | Error | Description | // |-------|-------------| @@ -421,16 +251,16 @@ func (m *MockServer) MockServerMismatchedRequests(port int) []MismatchedRequest log.Println("[DEBUG] mock server determining mismatches:", port) var res []MismatchedRequest - mismatches := C.pactffi_mock_server_mismatches(C.int(port)) + mismatches := pactffi_mock_server_mismatches(int32(port)) // This method can return a nil pointer, in which case, it // should be considered a failure (or at least, an issue) // converting it to a string might also do nasty things here! - if mismatches == nil { + if mismatches == "" { log.Println("[WARN] received a null pointer from the native interface, returning empty list of mismatches") return []MismatchedRequest{} } - err := json.Unmarshal([]byte(C.GoString(mismatches)), &res) + err := json.Unmarshal([]byte(mismatches), &res) if err != nil { log.Println("[ERROR] failed to unmarshal mismatches response, returning empty list of mismatches") return []MismatchedRequest{} @@ -444,25 +274,23 @@ func (m *MockServer) CleanupMockServer(port int) bool { return true } log.Println("[DEBUG] mock server cleaning up port:", port) - res := C.pactffi_cleanup_mock_server(C.int(port)) + res := pactffi_cleanup_mock_server(int32(port)) - return int(res) == 1 + return res == true } // WritePactFile writes the Pact to file. // TODO: expose overwrite func (m *MockServer) WritePactFile(port int, dir string) error { log.Println("[DEBUG] writing pact file for mock server on port:", port, ", dir:", dir) - cDir := C.CString(dir) - defer free(cDir) - // overwritePact := 0 + overwritePact := false // if overwrite { // overwritePact = 1 // } // res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(overwritePact))) - res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.int(0))) + res := int(pactffi_write_pact_file(int32(port), dir, overwritePact)) // | Error | Description | // |-------|-------------| @@ -486,24 +314,27 @@ func (m *MockServer) WritePactFile(port int, dir string) error { // GetTLSConfig returns a tls.Config compatible with the TLS // mock server func GetTLSConfig() *tls.Config { - cert := C.pactffi_get_tls_ca_certificate() - defer libRustFree(cert) + cert := pactffi_get_tls_ca_certificate() + // defer libRustFree(cert) - goCert := C.GoString(cert) certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM([]byte(goCert)) + certPool.AppendCertsFromPEM([]byte(cert)) return &tls.Config{ RootCAs: certPool, } } -func free(str *C.char) { - C.free(unsafe.Pointer(str)) -} +// func free(str *C.char) { +// C.free(unsafe.Pointer(str)) +// } + +// func libRustFree(str uintptr) { +// pactffi_free_string(str) +// } -func libRustFree(str *C.char) { - C.pactffi_free_string(str) +func libRustFree(str string) { + pactffi_string_delete(str) } // Start starts up the mock HTTP server on the given address:port and TLS config @@ -514,14 +345,14 @@ func (m *MockServer) Start(address string, tls bool) (int, error) { } log.Println("[DEBUG] mock server starting on address:", address) - cAddress := C.CString(address) - defer free(cAddress) - tlsEnabled := 0 + // cAddress := C.CString(address) + // defer free(cAddress) + tlsEnabled := false if tls { - tlsEnabled = 1 + tlsEnabled = true } - p := C.pactffi_create_mock_server_for_pact(m.pact.handle, cAddress, C.int(tlsEnabled)) + p := pactffi_create_mock_server_for_pact(m.pact.handle, address, tlsEnabled) // | Error | Description | // |-------|-------------| @@ -560,19 +391,10 @@ func (m *MockServer) StartTransport(transport string, address string, port int, if len(m.interactions) == 0 { return 0, ErrNoInteractions } - - log.Println("[DEBUG] mock server starting on address:", address, port) - cAddress := C.CString(address) - defer free(cAddress) - - cTransport := C.CString(transport) - defer free(cTransport) - configJson := stringFromInterface(config) - cConfig := C.CString(configJson) - defer free(cConfig) - p := C.pactffi_create_mock_server_for_transport(m.pact.handle, cAddress, C.int(port), cTransport, cConfig) + log.Println("[DEBUG] mock server starting on address:", address, port) + p := pactffi_create_mock_server_for_transport(m.pact.handle, address, uint16(port), transport, configJson) // | Error | Description // |-------|------------- @@ -604,31 +426,18 @@ func (m *MockServer) StartTransport(transport string, address string, port int, // Sets the additional metadata on the Pact file. Common uses are to add the client library details such as the name and version func (m *MockServer) WithMetadata(namespace, k, v string) *MockServer { - cNamespace := C.CString(namespace) - defer free(cNamespace) - cName := C.CString(k) - defer free(cName) - cValue := C.CString(v) - defer free(cValue) - - C.pactffi_with_pact_metadata(m.pact.handle, cNamespace, cName, cValue) + pactffi_with_pact_metadata(m.pact.handle, namespace, k, v) return m } // NewInteraction initialises a new interaction for the current contract func (m *MockServer) UsingPlugin(pluginName string, pluginVersion string) error { - cPluginName := C.CString(pluginName) - defer free(cPluginName) - cPluginVersion := C.CString(pluginVersion) - defer free(cPluginVersion) - - r := C.pactffi_using_plugin(m.pact.handle, cPluginName, cPluginVersion) + r := pactffi_using_plugin(m.pact.handle, pluginName, pluginVersion) if runtime.GOOS != "windows" { C.install_signal_handlers() } - // 1 - A general panic was caught. // 2 - Failed to load the plugin. // 3 - Pact Handle is not valid. @@ -651,16 +460,13 @@ func (m *MockServer) UsingPlugin(pluginName string, pluginVersion string) error // NewInteraction initialises a new interaction for the current contract func (m *MockServer) CleanupPlugins() { - C.pactffi_cleanup_plugins(m.pact.handle) + pactffi_cleanup_plugins(m.pact.handle) } // NewInteraction initialises a new interaction for the current contract func (m *MockServer) NewInteraction(description string) *Interaction { - cDescription := C.CString(description) - defer free(cDescription) - i := &Interaction{ - handle: C.pactffi_new_interaction(m.pact.handle, cDescription), + handle: pactffi_new_interaction(m.pact.handle, description), } m.interactions = append(m.interactions, i) @@ -669,12 +475,8 @@ func (m *MockServer) NewInteraction(description string) *Interaction { // NewInteraction initialises a new interaction for the current contract func (i *Interaction) WithPluginInteractionContents(part interactionPart, contentType string, contents string) error { - cContentType := C.CString(contentType) - defer free(cContentType) - cContents := C.CString(contents) - defer free(cContents) - r := C.pactffi_interaction_contents(i.handle, C.int(part), cContentType, cContents) + r := pactffi_interaction_contents(i.handle, int32(part), contentType, contents) // 1 - A general panic was caught. // 2 - The mock server has already been started. @@ -706,50 +508,31 @@ func (i *Interaction) WithPluginInteractionContents(part interactionPart, conten } func (i *Interaction) UponReceiving(description string) *Interaction { - cDescription := C.CString(description) - defer free(cDescription) - - C.pactffi_upon_receiving(i.handle, cDescription) + pactffi_upon_receiving(i.handle, description) return i } func (i *Interaction) Given(state string) *Interaction { - cState := C.CString(state) - defer free(cState) - - C.pactffi_given(i.handle, cState) + pactffi_given(i.handle, state) return i } func (i *Interaction) GivenWithParameter(state string, params map[string]interface{}) *Interaction { - cState := C.CString(state) - defer free(cState) for k, v := range params { - cKey := C.CString(k) - defer free(cKey) param := stringFromInterface(v) - cValue := C.CString(param) - defer free(cValue) - - C.pactffi_given_with_param(i.handle, cState, cKey, cValue) - + pactffi_given_with_param(i.handle, state, k, param) } return i } func (i *Interaction) WithRequest(method string, pathOrMatcher interface{}) *Interaction { - cMethod := C.CString(method) - defer free(cMethod) - path := stringFromInterface(pathOrMatcher) - cPath := C.CString(path) - defer free(cPath) - C.pactffi_with_request(i.handle, cMethod, cPath) + pactffi_with_request(i.handle, method, path) return i } @@ -764,16 +547,10 @@ func (i *Interaction) WithResponseHeaders(valueOrMatcher map[string][]interface{ func (i *Interaction) withHeaders(part interactionPart, valueOrMatcher map[string][]interface{}) *Interaction { for k, v := range valueOrMatcher { - - cName := C.CString(k) - defer free(cName) - for _, header := range v { value := stringFromInterface(header) - cValue := C.CString(value) - defer free(cValue) - C.pactffi_with_header_v2(i.handle, C.int(part), cName, C.int(0), cValue) + pactffi_with_header_v2(i.handle, int32(part), k, int(0), value) } } @@ -784,15 +561,10 @@ func (i *Interaction) withHeaders(part interactionPart, valueOrMatcher map[strin func (i *Interaction) WithQuery(valueOrMatcher map[string][]interface{}) *Interaction { for k, values := range valueOrMatcher { - cName := C.CString(k) - defer free(cName) - for idx, v := range values { value := stringFromInterface(v) - cValue := C.CString(value) - defer free(cValue) - C.pactffi_with_query_parameter_v2(i.handle, cName, C.int(idx), cValue) + pactffi_with_query_parameter_v2(i.handle, k, int(idx), value) } } @@ -808,14 +580,9 @@ func (i *Interaction) WithJSONResponseBody(body interface{}) *Interaction { } func (i *Interaction) withJSONBody(body interface{}, part interactionPart) *Interaction { - cHeader := C.CString("application/json") - defer free(cHeader) - jsonBody := stringFromInterface(body) - cBody := C.CString(jsonBody) - defer free(cBody) - C.pactffi_with_body(i.handle, C.int(part), cHeader, cBody) + pactffi_with_body(i.handle, int32(part), "application/json", jsonBody) return i } @@ -829,22 +596,15 @@ func (i *Interaction) WithResponseBody(contentType string, body []byte) *Interac } func (i *Interaction) withBody(contentType string, body []byte, part interactionPart) *Interaction { - cHeader := C.CString(contentType) - defer free(cHeader) - cBody := C.CString(string(body)) - defer free(cBody) - - C.pactffi_with_body(i.handle, C.int(part), cHeader, cBody) + pactffi_with_body(i.handle, int32(part), contentType, string(body)) return i } func (i *Interaction) withBinaryBody(contentType string, body []byte, part interactionPart) *Interaction { - cHeader := C.CString(contentType) - defer free(cHeader) - C.pactffi_with_binary_file(i.handle, C.int(part), cHeader, (*C.char)(unsafe.Pointer(&body[0])), C.int(len(body))) + pactffi_with_binary_file(i.handle, int32(part), contentType, string(body), size_t(len(body))) return i } @@ -866,23 +626,14 @@ func (i *Interaction) WithResponseMultipartFile(contentType string, filename str } func (i *Interaction) withMultipartFile(contentType string, filename string, mimePartName string, part interactionPart) *Interaction { - cHeader := C.CString(contentType) - defer free(cHeader) - - cPartName := C.CString(mimePartName) - defer free(cPartName) - - cFilename := C.CString(filename) - defer free(cFilename) - - C.pactffi_with_multipart_file(i.handle, C.int(part), cHeader, cFilename, cPartName) + pactffi_with_multipart_file(i.handle, int32(part), contentType, filename, mimePartName) return i } // Set the expected HTTTP response status func (i *Interaction) WithStatus(status int) *Interaction { - C.pactffi_response_status(i.handle, C.int(status)) + pactffi_response_status(i.handle, uint16(status)) return i } @@ -937,17 +688,14 @@ func quotedString(s string) string { // } func logToStdout(level logLevel) error { - res := C.pactffi_log_to_stdout(C.int(level)) + res := pactffi_log_to_stdout(int32(level)) log.Println("[DEBUG] log_to_stdout res", res) return logResultToError(int(res)) } func logToFile(file string, level logLevel) error { - cFile := C.CString(file) - defer free(cFile) - - res := C.pactffi_log_to_file(cFile, C.int(level)) + res := pactffi_log_to_file(file, int32(level)) log.Println("[DEBUG] log_to_file res", res) return logResultToError(int(res)) diff --git a/internal/native/verifier.go b/internal/native/verifier.go index ebd46b6e9..ccb2f7de5 100644 --- a/internal/native/verifier.go +++ b/internal/native/verifier.go @@ -68,58 +68,25 @@ static void install_signal_handlers() { } #endif -// Library headers -#include -#include -typedef int bool; -#define true 1 -#define false 0 - -// char* pactffi_version(); -// void pactffi_free_string(char* s); -int pactffi_verify(char* s); - -typedef struct VerifierHandle VerifierHandle; -struct VerifierHandle { - -}; -VerifierHandle *pactffi_verifier_new_for_application(const char *name, const char *version); -void pactffi_verifier_shutdown(struct VerifierHandle *handle); -void pactffi_verifier_set_provider_info(VerifierHandle *handle, const char *name, const char *scheme, const char *host, uint32_t port, const char *path); -void pactffi_verifier_set_filter_info(VerifierHandle *handle, const char *filter_description, const char *filter_state, bool filter_no_state); -void pactffi_verifier_set_provider_state(VerifierHandle *handle, const char *url, bool teardown, bool body); -int pactffi_verifier_set_verification_options(VerifierHandle *handle, bool disable_ssl_verification, unsigned long request_timeout); -int pactffi_verifier_set_publish_options(VerifierHandle *handle, const char *provider_version, const char *build_url, const char *const *provider_tags, uint32_t provider_tags_len, const char *provider_branch); -void pactffi_verifier_set_consumer_filters(VerifierHandle *handle, const char *const *consumer_filters, uint32_t consumer_filters_len); -void pactffi_verifier_add_custom_header(VerifierHandle *handle, const char *header_name, const char *header_value); -void pactffi_verifier_add_file_source(VerifierHandle *handle, const char *file); -void pactffi_verifier_add_directory_source(VerifierHandle *handle, const char *directory); -void pactffi_verifier_url_source(VerifierHandle *handle, const char *url, const char *username, const char *password, const char *token); -void pactffi_verifier_broker_source_with_selectors(VerifierHandle *handle, const char *url, const char *username, const char *password, const char *token, bool enable_pending, const char *include_wip_pacts_since, const char *const *provider_tags, uint32_t provider_tags_len, const char *provider_branch, const char *const *consumer_version_selectors, uint32_t consumer_version_selectors_len, const char *const *consumer_version_tags, uint32_t consumer_version_tags_len); -int pactffi_verifier_execute(VerifierHandle *handle); -void pactffi_verifier_add_provider_transport(VerifierHandle *handle, const char *protocol, uint32_t port, const char *path, const char *scheme); -void pactffi_verifier_set_no_pacts_is_error(VerifierHandle *handle, bool is_error); -int pactffi_verifier_set_coloured_output(struct VerifierHandle *handle, bool coloured_output); */ import "C" - import ( "fmt" "log" + "runtime" "strings" - "unsafe" ) type Verifier struct { - handle *C.VerifierHandle + handle uintptr } func (v *Verifier) Verify(args []string) error { log.Println("[DEBUG] executing verifier FFI with args", args) - cargs := C.CString(strings.Join(args, "\n")) - defer free(cargs) - result := C.pactffi_verify(cargs) - + // if runtime.GOOS != "windows" { + // C.install_signal_handlers() + // } + result := pactffi_verify(strings.Join(args, "\n")) /// | Error | Description | /// |-------|-------------| /// | 1 | The verification process failed, see output for errors | @@ -139,10 +106,10 @@ func (v *Verifier) Verify(args []string) error { } } -// Version returns the current semver FFI interface version -func (v *Verifier) Version() string { - return Version() -} +// // Version returns the current semver FFI interface version +// func (v *Verifier) Version() string { +// return Version() +// } var ( // ErrVerifierPanic indicates a panic ocurred when invoking the verifier. @@ -158,12 +125,7 @@ var ( ) func NewVerifier(name string, version string) *Verifier { - cName := C.CString(name) - cVersion := C.CString(version) - defer free(cName) - defer free(cVersion) - - h := C.pactffi_verifier_new_for_application(cName, cVersion) + h := pactffi_verifier_new_for_application(name, version) return &Verifier{ handle: h, @@ -171,131 +133,66 @@ func NewVerifier(name string, version string) *Verifier { } func (v *Verifier) Shutdown() { - C.pactffi_verifier_shutdown(v.handle) + pactffi_verifier_shutdown(v.handle) } func (v *Verifier) SetProviderInfo(name string, scheme string, host string, port uint16, path string) { - cName := C.CString(name) - defer free(cName) - cScheme := C.CString(scheme) - defer free(cScheme) - cHost := C.CString(host) - defer free(cHost) - cPort := C.uint(port) - cPath := C.CString(path) - defer free(cPath) - - C.pactffi_verifier_set_provider_info(v.handle, cName, cScheme, cHost, cPort, cPath) + pactffi_verifier_set_provider_info(v.handle, name, scheme, host, port, path) } func (v *Verifier) AddTransport(protocol string, port uint16, path string, scheme string) { log.Println("[DEBUG] Adding transport with protocol:", protocol, "port:", port, "path:", path, "scheme:", scheme) - cProtocol := C.CString(protocol) - defer free(cProtocol) - cPort := C.uint(port) - cPath := C.CString(path) - defer free(cPath) - cScheme := C.CString(scheme) - defer free(cScheme) - - C.pactffi_verifier_add_provider_transport(v.handle, cProtocol, cPort, cPath, cScheme) + + pactffi_verifier_add_provider_transport(v.handle, protocol, port, path, scheme) } func (v *Verifier) SetFilterInfo(description string, state string, noState bool) { - cFilterDescription := C.CString(description) - defer free(cFilterDescription) - cFilterState := C.CString(state) - defer free(cFilterState) - - C.pactffi_verifier_set_filter_info(v.handle, cFilterDescription, cFilterState, boolToCInt(noState)) + pactffi_verifier_set_filter_info(v.handle, description, state, boolToCInt(noState)) } func (v *Verifier) SetProviderState(url string, teardown bool, body bool) { - cURL := C.CString(url) - defer free(cURL) - - C.pactffi_verifier_set_provider_state(v.handle, cURL, boolToCInt(teardown), boolToCInt(body)) + pactffi_verifier_set_provider_state(v.handle, url, boolToCInt(teardown), boolToCInt(body)) } func (v *Verifier) SetVerificationOptions(disableSSLVerification bool, requestTimeout int64) { // TODO: this returns an int and therefore can error. We should have all of these functions return values?? - C.pactffi_verifier_set_verification_options(v.handle, boolToCInt(disableSSLVerification), C.ulong(requestTimeout)) + pactffi_verifier_set_verification_options(v.handle, boolToCInt(disableSSLVerification), uint64(requestTimeout)) } func (v *Verifier) SetConsumerFilters(consumers []string) { - // TODO: check if this actually works! - C.pactffi_verifier_set_consumer_filters(v.handle, stringArrayToCStringArray(consumers), C.uint(len(consumers))) + pactffi_verifier_set_consumer_filters(v.handle, stringArrayToCByteArray(consumers), uint16(len(consumers))) } func (v *Verifier) AddCustomHeader(name string, value string) { - cHeaderName := C.CString(name) - defer free(cHeaderName) - cHeaderValue := C.CString(value) - defer free(cHeaderValue) - - C.pactffi_verifier_add_custom_header(v.handle, cHeaderName, cHeaderValue) + pactffi_verifier_add_custom_header(v.handle, name, value) } func (v *Verifier) AddFileSource(file string) { - cFile := C.CString(file) - defer free(cFile) - - C.pactffi_verifier_add_file_source(v.handle, cFile) + pactffi_verifier_add_file_source(v.handle, file) } func (v *Verifier) AddDirectorySource(directory string) { - cDirectory := C.CString(directory) - defer free(cDirectory) - - C.pactffi_verifier_add_directory_source(v.handle, cDirectory) + pactffi_verifier_add_directory_source(v.handle, directory) } func (v *Verifier) AddURLSource(url string, username string, password string, token string) { - cUrl := C.CString(url) - defer free(cUrl) - cUsername := C.CString(username) - defer free(cUsername) - cPassword := C.CString(password) - defer free(cPassword) - cToken := C.CString(token) - defer free(cToken) - - C.pactffi_verifier_url_source(v.handle, cUrl, cUsername, cPassword, cToken) + pactffi_verifier_url_source(v.handle, url, username, password, token) } func (v *Verifier) BrokerSourceWithSelectors(url string, username string, password string, token string, enablePending bool, includeWipPactsSince string, providerTags []string, providerBranch string, selectors []string, consumerVersionTags []string) { - cUrl := C.CString(url) - defer free(cUrl) - cUsername := C.CString(username) - defer free(cUsername) - cPassword := C.CString(password) - defer free(cPassword) - cToken := C.CString(token) - defer free(cToken) - cIncludeWipPactsSince := C.CString(includeWipPactsSince) - defer free(cIncludeWipPactsSince) - cProviderBranch := C.CString(providerBranch) - defer free(cProviderBranch) - - C.pactffi_verifier_broker_source_with_selectors(v.handle, cUrl, cUsername, cPassword, cToken, boolToCInt(enablePending), cIncludeWipPactsSince, stringArrayToCStringArray(providerTags), C.uint(len(providerTags)), cProviderBranch, stringArrayToCStringArray(selectors), C.uint(len(selectors)), stringArrayToCStringArray(consumerVersionTags), C.uint(len(consumerVersionTags))) + pactffi_verifier_broker_source_with_selectors(v.handle, url, username, password, token, boolToCInt(enablePending), includeWipPactsSince, stringArrayToCByteArray(providerTags), uint16(len(providerTags)), providerBranch, stringArrayToCByteArray(selectors), uint16(len(selectors)), stringArrayToCByteArray(consumerVersionTags), uint16(len(consumerVersionTags))) } func (v *Verifier) SetPublishOptions(providerVersion string, buildUrl string, providerTags []string, providerBranch string) { - cProviderVersion := C.CString(providerVersion) - defer free(cProviderVersion) - cBuildUrl := C.CString(buildUrl) - defer free(cBuildUrl) - cProviderBranch := C.CString(providerBranch) - defer free(cProviderBranch) - - C.pactffi_verifier_set_publish_options(v.handle, cProviderVersion, cBuildUrl, stringArrayToCStringArray(providerTags), C.uint(len(providerTags)), cProviderBranch) + pactffi_verifier_set_publish_options(v.handle, providerVersion, buildUrl, stringArrayToCByteArray(providerTags), uint16(len(providerTags)), providerBranch) } func (v *Verifier) Execute() error { // TODO: Validate - - result := C.pactffi_verifier_execute(v.handle) - + if runtime.GOOS != "windows" { + C.install_signal_handlers() + } + result := pactffi_verifier_execute(v.handle) /// | Error | Description | /// |-------|-------------| /// | 1 | The verification process failed, see output for errors | @@ -312,30 +209,30 @@ func (v *Verifier) Execute() error { } func (v *Verifier) SetNoPactsIsError(isError bool) { - C.pactffi_verifier_set_no_pacts_is_error(v.handle, boolToCInt(isError)) + pactffi_verifier_set_no_pacts_is_error(v.handle, boolToCInt(isError)) } func (v *Verifier) SetColoredOutput(isColoredOutput bool) { - C.pactffi_verifier_set_coloured_output(v.handle, boolToCInt(isColoredOutput)) + pactffi_verifier_set_coloured_output(v.handle, boolToCInt(isColoredOutput)) } -func stringArrayToCStringArray(inputs []string) **C.char { +func stringArrayToCByteArray(inputs []string) []*byte { if len(inputs) == 0 { return nil } - output := make([]*C.char, len(inputs)) + output := make([]*byte, len(inputs)) for i, consumer := range inputs { - output[i] = C.CString(consumer) + output[i] = CString(consumer) } - return (**C.char)(unsafe.Pointer(&output[0])) + return ([]*byte)(output) } -func boolToCInt(val bool) C.int { +func boolToCInt(val bool) uint8 { if val { - return C.int(1) + return uint8(1) } - return C.int(0) + return uint8(0) }