From de379ad7c1068ca4290396a22f786262dea9c4fd Mon Sep 17 00:00:00 2001 From: Matt Fellows Date: Sun, 30 May 2021 22:48:50 +1000 Subject: [PATCH] feat: add experimental log packages to ffi interface --- v3/internal/native/mockserver/mock_server.go | 95 ++++++++++++++++++- .../native/mockserver/mock_server_test.go | 28 ++---- 2 files changed, 102 insertions(+), 21 deletions(-) diff --git a/v3/internal/native/mockserver/mock_server.go b/v3/internal/native/mockserver/mock_server.go index 33a9dcb76..af8d33ced 100644 --- a/v3/internal/native/mockserver/mock_server.go +++ b/v3/internal/native/mockserver/mock_server.go @@ -152,6 +152,13 @@ void response_status(InteractionHandle interaction, int status); int write_pact_file(int mock_server_port, const char *directory); void with_pact_metadata(PactHandle pact, const char *namespace, const char *name, const char *value); + +// Additional global logging functions +int log_to_buffer(int level); +int log_to_stdout(int level); +int log_to_file(const char *file_name, int level_filter); +char* fetch_memory_buffer(); + */ import "C" @@ -187,6 +194,17 @@ const ( SPECIFICATION_VERSION_V4 ) +type logLevel int + +const ( + LOG_LEVEL_OFF logLevel = iota + LOG_LEVEL_ERROR + LOG_LEVEL_WARN + LOG_LEVEL_INFO + LOG_LEVEL_DEBUG + LOG_LEVEL_TRACE +) + // Pact is a Go representation of the PactHandle struct type Pact struct { handle C.PactHandle @@ -207,10 +225,15 @@ func Version() string { // Init initialises the library func Init() { log.Println("[DEBUG] initialising rust mock server interface") - logLevel := C.CString("LOG_LEVEL") - defer free(logLevel) + l := C.CString("LOG_LEVEL") + defer free(l) + + C.init(l) - C.init(logLevel) + // Alternative log destinations + // NOTE: only one can be applied + // logToBuffer(LOG_LEVEL_INFO) + // logToFile("/tmp/pact.log", LOG_LEVEL_TRACE) } // MockServer is the public interface for managing the HTTP mock server @@ -649,6 +672,61 @@ func stringFromInterface(obj interface{}) string { } } +// Experimental logging options +func logToBuffer(level logLevel) error { + res := C.log_to_buffer(C.int(level)) + log.Println("[DEBUG] log_to_buffer res", res) + + return logResultToError(int(res)) +} + +func logToStdout(level logLevel) error { + res := C.log_to_stdout(C.int(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.log_to_file(cFile, C.int(level)) + log.Println("[DEBUG] log_to_file res", res) + + return logResultToError(int(res)) +} + +func getLogBuffer() string { + buf := C.fetch_memory_buffer() + defer free(buf) + + return C.GoString(buf) +} + +func logResultToError(res int) error { + switch res { + case 0: + return nil + case -1: + return ErrCantSetLogger + case -2: + return ErrNoLogger + case -3: + return ErrSpecifierNotUtf8 + case -4: + return ErrUnknownSinkType + case -5: + return ErrMissingFilePath + case -6: + return ErrCantOpenSinkToFile + case -7: + return ErrCantConstructSink + default: + return fmt.Errorf("an unknown error ocurred when writing to pact file") + } +} + // Errors var ( // ErrHandleNotFound indicates the underlying handle was not found, and a logic error in the framework @@ -682,3 +760,14 @@ var ( // ErrNoInteractions indicates no Interactions have been registered to a mock server, and cannot be started/stopped until at least one is added ErrNoInteractions = fmt.Errorf("no interactions have been registered for the mock server") ) + +// Log Errors +var ( + ErrCantSetLogger = fmt.Errorf("can't set logger (applying the logger failed, perhaps because one is applied already).") + ErrNoLogger = fmt.Errorf("no logger has been initialized (call `logger_init` before any other log function).") + ErrSpecifierNotUtf8 = fmt.Errorf("The sink specifier was not UTF-8 encoded.") + ErrUnknownSinkType = fmt.Errorf(`the sink type specified is not a known type (known types: "buffer", "stdout", "stderr", or "file /some/path").`) + ErrMissingFilePath = fmt.Errorf("no file path was specified in a file-type sink specification.") + ErrCantOpenSinkToFile = fmt.Errorf("opening a sink to the specified file path failed (check permissions).") + ErrCantConstructSink = fmt.Errorf("can't construct the log sink") +) diff --git a/v3/internal/native/mockserver/mock_server_test.go b/v3/internal/native/mockserver/mock_server_test.go index 3feba3758..0717a2564 100644 --- a/v3/internal/native/mockserver/mock_server_test.go +++ b/v3/internal/native/mockserver/mock_server_test.go @@ -115,11 +115,11 @@ func TestMockServer_WritePactfile(t *testing.T) { func TestMockServer_GetTLSConfig(t *testing.T) { config := GetTLSConfig() - fmt.Println("tls config", config) + t.Log("tls config", config) } func TestVersion(t *testing.T) { - fmt.Println("version: ", Version()) + t.Log("version: ", Version()) } func TestHandleBasedHTTPTests(t *testing.T) { @@ -128,25 +128,19 @@ func TestHandleBasedHTTPTests(t *testing.T) { m := NewHTTPMockServer("test-http-consumer", "test-http-provider") - fmt.Println("pact struct:", m) - i := m.NewInteraction("some interaction") - fmt.Println("pact interaction:", i) i.UponReceiving("some interaction"). Given("some state"). WithRequest("GET", "/products"). - // withRequestHeader("x-special-header", 0, "header") - // withQuery("someParam", 0, "someValue") WithJSONResponseBody(`{ - "name": { - "pact:matcher:type": "type", - "value": "some name" - }, - "age": 23, - "alive": true - }`). - // withResponseHeader(i, "x-special-header", 0, "header") + "name": { + "pact:matcher:type": "type", + "value": "some name" + }, + "age": 23, + "alive": true + }`). WithStatus(200) // // Start the mock service @@ -155,7 +149,7 @@ func TestHandleBasedHTTPTests(t *testing.T) { assert.NoError(t, err) defer m.CleanupMockServer(port) - r, err := http.Get(fmt.Sprintf("http://0.0.0.0:%d/products", port)) + _, err = http.Get(fmt.Sprintf("http://0.0.0.0:%d/products", port)) assert.NoError(t, err) mismatches := m.MockServerMismatchedRequests(port) @@ -165,8 +159,6 @@ func TestHandleBasedHTTPTests(t *testing.T) { err = m.WritePactFile(port, tmpPactFolder) assert.NoError(t, err) - - fmt.Println(r) } var pactSimple = `{