From 110e62584fd81be6848db9951f971995da047286 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:14:39 +0100 Subject: [PATCH 1/6] feat: support CGO_ENABLED=0 - see notes users now required to set PACT_LD_LIBRARY_PATH env var with location of download pact ffi lib. It can exist anywhere on the filesystem --- .github/workflows/test.yml | 20 +- Makefile | 18 +- go.mod | 3 +- go.sum | 2 + installer/installer_test.go | 2 +- internal/native/lib.go | 603 +++++++++++++++++++++++++++++- internal/native/lib_unix.go | 9 + internal/native/lib_windows.go | 10 + internal/native/message_server.go | 229 +++++------- internal/native/mock_server.go | 196 +++------- internal/native/verifier.go | 142 ++----- 11 files changed, 825 insertions(+), 409 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 928ece2ac..39aec7e45 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,9 +7,8 @@ env: REACT_APP_API_BASE_URL: http://localhost:8080 APP_SHA: ${{ github.sha }} APP_REF: ${{ github.ref }} - LD_LIBRARY_PATH: /tmp - PACT_GO_LIB_DOWNLOAD_PATH: /tmp - LOG_LEVEL: debug + PACT_LD_LIBRARY_PATH: /tmp + LOG_LEVEL: DEBUG COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: @@ -26,6 +25,7 @@ jobs: 1.22.x, ] os: [ubuntu-latest, macos-12, macos-14, windows-latest] + cgo: [0,1] runs-on: ${{ matrix.os }} steps: - name: Checkout code @@ -38,6 +38,14 @@ jobs: with: distribution: 'zulu' java-version: '17' + - name: "Set CGO_ENABLED: ${{ matrix.cgo }}" + if: matrix.os == 'windows-latest' + run: | + "CGO_ENABLED=${{ matrix.cgo }}" >> $env:GITHUB_ENV + - name: "Set CGO_ENABLED: ${{ matrix.cgo }}" + if: matrix.os != 'windows-latest' + run: | + echo "CGO_ENABLED=${{ matrix.cgo }}" >> $GITHUB_ENV - if: matrix.os == 'macos-14' run: brew install protobuf - name: Test @@ -62,17 +70,18 @@ jobs: run: goveralls -coverprofile=coverage.txt -service=github -parallel - uses: actions/upload-artifact@v4 with: - name: logs-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.go-version }}-${{ matrix.os }}.zip + name: logs-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.go-version }}-${{ matrix.os }}-${{matrix.cgo}}.zip path: ~/.pact/plugins/**/plugin.log if: ${{ always() }} test-containers: runs-on: ubuntu-latest - name: ${{ matrix.go-version }}-test-container + name: ${{ matrix.go-version }}-test-container-cgo-${{ matrix.cgo }} strategy: fail-fast: false matrix: go-version: ["1.21", "1.22"] + cgo: [0,1] steps: - uses: actions/checkout@v4 @@ -80,6 +89,7 @@ jobs: run: make docker_test_all env: GO_VERSION: ${{ matrix.go-version }} + CGO_ENABLED: ${{ matrix.cgo }} finish: needs: [test,test-containers] diff --git a/Makefile b/Makefile index 7f90ddbb2..a6860466d 100755 --- a/Makefile +++ b/Makefile @@ -16,6 +16,16 @@ ifeq ($(OS),Windows_NT) PACT_DOWNLOAD_DIR=$$TMP endif +CGO_ENABLED?=1 +ifeq ($(CGO_ENABLED),0) + SKIP_RACE=true +endif +SKIP_RACE?=false +RACE?=-race +SKIP_SIGNAL_HANDLERS?=false +ifeq ($(SKIP_RACE),true) + RACE= +endif # Run the ci target from a developer machine with the environment variables # set as if it was on Travis CI. # Use this for quick feedback when playing around with your workflows. @@ -41,18 +51,24 @@ docker_build: docker_test: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e CGO_ENABLED=$(CGO_ENABLED) \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ --rm \ pactfoundation/pact-go-test \ /bin/sh -c "make test" docker_pact: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e CGO_ENABLED=$(CGO_ENABLED) \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ --rm \ pactfoundation/pact-go-test \ /bin/sh -c "make pact_local" docker_test_all: docker_build docker run \ -e LOG_LEVEL=INFO \ + -e CGO_ENABLED=$(CGO_ENABLED) \ + -e PACT_LD_LIBRARY_PATH=$(PACT_DOWNLOAD_DIR) \ --rm \ pactfoundation/pact-go-test \ /bin/sh -c "make test && make pact_local" @@ -130,7 +146,7 @@ test: deps install @echo "mode: count" > coverage.txt @for d in $$(go list ./... | grep -v vendor | grep -v examples); \ do \ - go test -v -race -coverprofile=profile.out -covermode=atomic $$d; \ + go test -v $(RACE) -coverprofile=profile.out -covermode=atomic $$d; \ if [ $$? != 0 ]; then \ exit 1; \ fi; \ diff --git a/go.mod b/go.mod index 012fb7239..d88da25cd 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/pact-foundation/pact-go/v2 go 1.21 require ( + github.com/ebitengine/purego v0.7.1 github.com/golang/protobuf v1.5.4 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/logutils v1.0.0 @@ -10,6 +11,7 @@ require ( 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.21.0 google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 @@ -24,7 +26,6 @@ require ( github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index ea60e2bf8..743fbd822 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +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/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= +github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= diff --git a/installer/installer_test.go b/installer/installer_test.go index b492af492..e5002263f 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), "libpact_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 d4324ff52..ccf2c1912 100644 --- a/internal/native/lib.go +++ b/internal/native/lib.go @@ -1,11 +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" +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 31629ba84..4f3481daa 100644 --- a/internal/native/message_server.go +++ b/internal/native/message_server.go @@ -1,20 +1,16 @@ package native -/* -#include "pact.h" -*/ -import "C" - import ( "encoding/json" "errors" "fmt" "log" + "unsafe" ) type MessagePact struct { - handle C.PactHandle + handle uintptr } type messageType int @@ -25,7 +21,7 @@ const ( ) type Message struct { - handle C.InteractionHandle + handle uintptr messageType messageType pact *MessagePact index int @@ -40,24 +36,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 } @@ -71,11 +67,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), @@ -88,11 +82,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), @@ -104,35 +96,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 { - C.pactffi_given(m.handle, cState) + pactffi_given(m.handle, state) } else { for k, v := range params { - cKey := C.CString(k) - param := stringFromInterface(v) - cValue := C.CString(param) - - C.pactffi_given_with_param(m.handle, cState, cKey, cValue) - - free(cValue) - free(cKey) + pactffi_given_with_param(m.handle, state, k, param) } } @@ -140,50 +119,37 @@ 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) - // 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) - C.pactffi_message_with_metadata(m.handle, cName, cValue) - - free(cValue) - free(cName) + 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.uchar)(unsafe.Pointer(&body[0])), CUlong(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", bool(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.uchar)(unsafe.Pointer(&body[0])), CUlong(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", res) @@ -199,11 +165,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.uchar)(unsafe.Pointer(&body[0])), CUlong(len(body))) + pactffi_with_binary_file(m.handle, int32(INTERACTION_PART_RESPONSE), "application/octet-stream", string(body), size_t(len(body))) return m } @@ -218,11 +182,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", (bool(res))) + res := pactffi_with_body(m.handle, int32(part), contentType, string(body)) + log.Println("[DEBUG] response from pactffi_interaction_contents", (res == true)) return m } @@ -231,13 +193,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) // 1 - A general panic was caught. // 2 - Failed to load the plugin. // 3 - Pact Handle is not valid. @@ -260,12 +217,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. @@ -296,6 +249,18 @@ func (m *Message) WithPluginInteractionContents(part interactionPart, contentTyp return nil } +func GoByteArrayFromC(ptr uintptr, length int) []byte { + if unsafe.Pointer(ptr) == nil || length == 0 { + return []byte{} + } + // Create a Go byte slice from the C string + b := make([]byte, length) + for i := 0; i < length; i++ { + b[i] = *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + uintptr(i))) + } + return b +} + // 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 @@ -303,9 +268,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 unsafe.Pointer(iter) == nil { return nil, errors.New("unable to get a message iterator") } log.Println("[DEBUG] pactffi_pact_handle_get_message_iter - OK") @@ -318,63 +284,59 @@ 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 unsafe.Pointer(message) == nil { 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 + return []byte{}, 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 unsafe.Pointer(data) == nil { // 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)) - + bytes := GoByteArrayFromC(data, int(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 unsafe.Pointer(iter) == nil { return nil, errors.New("unable to get a message iterator") } for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) + message := pactffi_pact_sync_message_iter_next(iter) if i == m.index { - if message == nil { + if unsafe.Pointer(message) == nil { 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 + return []byte{}, nil } - data := C.pactffi_sync_message_get_request_contents_bin(message) - if data == nil { + data := pactffi_sync_message_get_request_contents_bin(message) + if unsafe.Pointer(data) == nil { log.Println("[DEBUG] message binary contents are empty") return nil, nil } - ptr := unsafe.Pointer(data) - bytes := C.GoBytes(ptr, C.int(len)) + bytes := GoByteArrayFromC(data, int(len)) return bytes, nil } @@ -394,29 +356,35 @@ 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 unsafe.Pointer(iter) == nil { return nil, errors.New("unable to get a message iterator") } for i := 0; i < len(m.server.messages); i++ { - message := C.pactffi_pact_sync_message_iter_next(iter) + message := pactffi_pact_sync_message_iter_next(iter) - if message == nil { + if unsafe.Pointer(message) == nil { 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 + len := pactffi_sync_message_get_response_contents_length(message, size_t(i)) + // if len == 0 { + // return nil, errors.New("retrieved an empty message") + // } + if len == 0 { + // You can have empty bodies + log.Println("[DEBUG] message body is empty") + responses[i] = []byte{} + return responses, nil } + data := pactffi_sync_message_get_response_contents_bin(message, size_t(i)) + if unsafe.Pointer(data) == nil { + return nil, errors.New("retrieved an empty pointer to the message contents") + } + bytes := GoByteArrayFromC(data, int(len)) + responses[i] = bytes } return responses, nil @@ -430,17 +398,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.ushort(port), cTransport, cConfig) + p := pactffi_create_mock_server_for_transport(m.messagePact.handle, address, uint16(port), transport, configJson) // | Error | Description // |-------|------------- @@ -472,7 +432,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. @@ -481,9 +441,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 bool(res) + return res == true } // MockServerMismatchedRequests returns a JSON object containing any mismatches from @@ -492,16 +452,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{} @@ -515,27 +476,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 bool(res) + 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 := false if overwrite { overwritePact = true } - res := int(C.pactffi_write_message_pact_file(m.messagePact.handle, cDir, C.bool(overwritePact))) + res := pactffi_write_message_pact_file(m.messagePact.handle, dir, overwritePact) /// | Error | Description | /// |-------|-------------| @@ -556,15 +515,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 := false if overwrite { overwritePact = true } - res := int(C.pactffi_write_pact_file(C.int(port), cDir, C.bool(overwritePact))) + res := pactffi_write_pact_file(int32(port), dir, overwritePact) /// | Error | Description | /// |-------|-------------| diff --git a/internal/native/mock_server.go b/internal/native/mock_server.go index 2429301c1..0e343dff8 100644 --- a/internal/native/mock_server.go +++ b/internal/native/mock_server.go @@ -1,10 +1,5 @@ package native -/* -#include "pact.h" -*/ -import "C" - import ( "crypto/tls" "crypto/x509" @@ -12,8 +7,8 @@ import ( "fmt" "log" "os" + "strings" - "unsafe" ) type interactionPart int @@ -61,19 +56,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 @@ -117,12 +112,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 @@ -131,23 +121,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 := false if tls { tlsEnabled = true } - p := C.pactffi_create_mock_server(cPact, cAddress, C.bool(tlsEnabled)) + p := pactffi_create_mock_server(pact, address, tlsEnabled) // | Error | Description | // |-------|-------------| @@ -195,16 +181,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{} @@ -218,25 +204,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 bool(res) + 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.bool(false))) + res := int(pactffi_write_pact_file(int32(port), dir, overwritePact)) // | Error | Description | // |-------|-------------| @@ -260,24 +244,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 @@ -288,14 +275,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) + // cAddress := C.CString(address) + // defer free(cAddress) tlsEnabled := false if tls { tlsEnabled = true } - p := C.pactffi_create_mock_server_for_pact(m.pact.handle, cAddress, C.bool(tlsEnabled)) + p := pactffi_create_mock_server_for_pact(m.pact.handle, address, tlsEnabled) // | Error | Description | // |-------|-------------| @@ -334,19 +321,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.ushort(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 // |-------|------------- @@ -378,27 +356,15 @@ 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) // 1 - A general panic was caught. // 2 - Failed to load the plugin. // 3 - Pact Handle is not valid. @@ -421,16 +387,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) @@ -439,12 +402,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. @@ -476,50 +435,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) param := stringFromInterface(v) - cValue := C.CString(param) - - C.pactffi_given_with_param(i.handle, cState, cKey, cValue) - - free(cValue) - free(cKey) + 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 } @@ -534,18 +474,12 @@ 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) - for _, header := range v { value := stringFromInterface(header) - cValue := C.CString(value) - C.pactffi_with_header_v2(i.handle, C.int(part), cName, CUlong(0), cValue) - - free(cValue) + pactffi_with_header_v2(i.handle, int32(part), k, int(0), value) } - free(cName) } return i @@ -553,18 +487,12 @@ 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) for idx, v := range values { value := stringFromInterface(v) - cValue := C.CString(value) - - C.pactffi_with_query_parameter_v2(i.handle, cName, CUlong(idx), cValue) - free(cValue) + pactffi_with_query_parameter_v2(i.handle, k, int(idx), value) } - - free(cName) } return i @@ -579,14 +507,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 } @@ -600,22 +523,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.uchar)(unsafe.Pointer(&body[0])), CUlong(len(body))) + pactffi_with_binary_file(i.handle, int32(part), contentType, string(body), size_t(len(body))) return i } @@ -637,23 +553,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.ushort(status)) + pactffi_response_status(i.handle, uint16(status)) return i } @@ -708,17 +615,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 3f03df269..ccc155777 100644 --- a/internal/native/verifier.go +++ b/internal/native/verifier.go @@ -1,27 +1,19 @@ package native -/* -#include "pact.h" -*/ -import "C" - import ( "fmt" "log" + "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) - + result := pactffi_verify(strings.Join(args, "\n")) /// | Error | Description | /// |-------|-------------| /// | 1 | The verification process failed, see output for errors | @@ -41,10 +33,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. @@ -60,12 +52,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, @@ -73,130 +60,63 @@ 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.ushort(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.ushort(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, boolToCUchar(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, boolToCUchar(teardown), boolToCUchar(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, boolToCUchar(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.ushort(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, boolToCUchar(enablePending), cIncludeWipPactsSince, stringArrayToCStringArray(providerTags), C.ushort(len(providerTags)), cProviderBranch, stringArrayToCStringArray(selectors), C.ushort(len(selectors)), stringArrayToCStringArray(consumerVersionTags), C.ushort(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.ushort(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) - + result := pactffi_verifier_execute(v.handle) /// | Error | Description | /// |-------|-------------| /// | 1 | The verification process failed, see output for errors | @@ -213,30 +133,30 @@ func (v *Verifier) Execute() error { } func (v *Verifier) SetNoPactsIsError(isError bool) { - C.pactffi_verifier_set_no_pacts_is_error(v.handle, boolToCUchar(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, boolToCUchar(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 boolToCUchar(val bool) C.uchar { +func boolToCInt(val bool) uint8 { if val { - return C.uchar(1) + return uint8(1) } - return C.uchar(0) + return uint8(0) } From 7e506db71da3728b00f7b699de1fbf07dea5e86f Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:20:14 +0100 Subject: [PATCH 2/6] chore: set log level to info --- .github/workflows/test.yml | 2 +- examples/provider_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 39aec7e45..ffa1b5064 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ env: APP_SHA: ${{ github.sha }} APP_REF: ${{ github.ref }} PACT_LD_LIBRARY_PATH: /tmp - LOG_LEVEL: DEBUG + LOG_LEVEL: INFO COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: diff --git a/examples/provider_test.go b/examples/provider_test.go index bd3ca53f9..e02a031f9 100644 --- a/examples/provider_test.go +++ b/examples/provider_test.go @@ -27,7 +27,7 @@ var requestFilterCalled = false var stateHandlerCalled = false func TestV3HTTPProvider(t *testing.T) { - log.SetLogLevel("TRACE") + log.SetLogLevel("INFO") version.CheckVersion() // Start provider API in the background @@ -138,7 +138,7 @@ func TestV3HTTPProvider(t *testing.T) { } func TestV3MessageProvider(t *testing.T) { - log.SetLogLevel("TRACE") + log.SetLogLevel("INFO") var user *User verifier := provider.NewVerifier() From 3ff17713bdfd43b07e8afdc49061963f2d2ed163 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:24:20 +0100 Subject: [PATCH 3/6] chore: add PACT_GO_LIB_DOWNLOAD_PATH back in --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ffa1b5064..b4c86be84 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,7 @@ env: REACT_APP_API_BASE_URL: http://localhost:8080 APP_SHA: ${{ github.sha }} APP_REF: ${{ github.ref }} + PACT_GO_LIB_DOWNLOAD_PATH: /tmp PACT_LD_LIBRARY_PATH: /tmp LOG_LEVEL: INFO COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 38c80dddfe7573d868f5d991d1e65bcb02fce2fc Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:27:39 +0100 Subject: [PATCH 4/6] chore(ci): allow log level to configured when triggering job --- .github/workflows/test.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b4c86be84..4423b3bd5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,18 @@ -on: [push, pull_request, workflow_dispatch] +on: + push: + pull_request: + workflow_dispatch: + inputs: + log_level: + description: 'Log level' + type: choice + required: true + default: 'INFO' + options: + - 'INFO' + - 'DEBUG' + - 'TRACE' + name: Test env: @@ -9,7 +23,7 @@ env: APP_REF: ${{ github.ref }} PACT_GO_LIB_DOWNLOAD_PATH: /tmp PACT_LD_LIBRARY_PATH: /tmp - LOG_LEVEL: INFO + LOG_LEVEL: ${{ github.event.inputs.log_level || 'INFO' }} COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: From 5f0e6c4b1619f9bf1ac094c286cf61956cba8d05 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:30:09 +0100 Subject: [PATCH 5/6] ci(win): add PACT_LD_LIBRARY_PATH --- .github/workflows/test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4423b3bd5..faabfdc72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -66,11 +66,10 @@ 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 + - name: Set PACT_LD_LIBRARY_PATH 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 - name: Test (unit) if: matrix.os != 'ubuntu-latest' run: make test From a5f810fd17bd6a4a54b7cb362ad84f0d0d2be560 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Fri, 6 Sep 2024 00:55:32 +0100 Subject: [PATCH 6/6] chore: fix golint errors / remove ci lib.go exclusion --- .github/workflows/golangci-lint.yml | 3 +-- internal/native/message_server.go | 6 +++--- internal/native/mock_server.go | 16 ++++++++-------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3a7f09a1f..eb6b10828 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -39,8 +39,7 @@ jobs: # working-directory: somedir # Optional: golangci-lint command line arguments. - # ignore the lib.go file as it only contains cgo annotations - args: --skip-files internal/native/lib.go --timeout 2m + args: --timeout 2m # Optional: show only new issues if it's a pull request. The default value is `false`. # only-new-issues: true diff --git a/internal/native/message_server.go b/internal/native/message_server.go index 4f3481daa..7f64ada1d 100644 --- a/internal/native/message_server.go +++ b/internal/native/message_server.go @@ -184,7 +184,7 @@ func (m *Message) WithResponseJSONContents(body interface{}) *Message { func (m *Message) WithContents(part interactionPart, contentType string, body []byte) *Message { res := pactffi_with_body(m.handle, int32(part), contentType, string(body)) - log.Println("[DEBUG] response from pactffi_interaction_contents", (res == true)) + log.Println("[DEBUG] response from pactffi_interaction_contents", res) return m } @@ -443,7 +443,7 @@ func (m *MessageServer) CleanupMockServer(port int) bool { log.Println("[DEBUG] mock server cleaning up port:", port) res := pactffi_cleanup_mock_server(int32(port)) - return res == true + return res } // MockServerMismatchedRequests returns a JSON object containing any mismatches from @@ -482,7 +482,7 @@ func (m *MessageServer) MockServerMatched(port int) bool { // log.Println("MATCHED RES?") // log.Println(int(res)) - return res == true + return res } // WritePactFile writes the Pact to file. diff --git a/internal/native/mock_server.go b/internal/native/mock_server.go index 0e343dff8..dcf179387 100644 --- a/internal/native/mock_server.go +++ b/internal/native/mock_server.go @@ -106,7 +106,7 @@ func Init(logLevel string) { // MockServer is the public interface for managing the HTTP mock server type MockServer struct { pact *Pact - messagePact *MessagePact + // messagePact *MessagePact interactions []*Interaction } @@ -206,7 +206,7 @@ func (m *MockServer) CleanupMockServer(port int) bool { log.Println("[DEBUG] mock server cleaning up port:", port) res := pactffi_cleanup_mock_server(int32(port)) - return res == true + return res } // WritePactFile writes the Pact to file. @@ -263,9 +263,9 @@ func GetTLSConfig() *tls.Config { // pactffi_free_string(str) // } -func libRustFree(str string) { - pactffi_string_delete(str) -} +// func libRustFree(str string) { +// pactffi_string_delete(str) +// } // Start starts up the mock HTTP server on the given address:port and TLS config // https://docs.rs/pact_mock_server_ffi/0.0.7/pact_mock_server_ffi/fn.create_mock_server_for_pact.html @@ -565,9 +565,9 @@ func (i *Interaction) WithStatus(status int) *Interaction { return i } -type stringLike interface { - String() string -} +// type stringLike interface { +// String() string +// } func stringFromInterface(obj interface{}) string { switch t := obj.(type) {