diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 6d6216576..7569e5025 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -26,8 +26,6 @@ concurrency: jobs: lint: runs-on: ubuntu-latest - strategy: - fail-fast: false name: Check linter steps: - uses: actions/checkout@v4 @@ -52,6 +50,10 @@ jobs: name: ${{ matrix.cloud }} Go ${{ matrix.go }} on Ubuntu steps: - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 # for wiremock + with: + java-version: 11 + distribution: 'temurin' - name: Setup go uses: actions/setup-go@v5 with: @@ -78,6 +80,10 @@ jobs: name: ${{ matrix.cloud }} Go ${{ matrix.go }} on Mac steps: - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 # for wiremock + with: + java-version: 11 + distribution: 'temurin' - name: Setup go uses: actions/setup-go@v5 with: @@ -103,6 +109,10 @@ jobs: name: ${{ matrix.cloud }} Go ${{ matrix.go }} on Windows steps: - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 # for wiremock + with: + java-version: 11 + distribution: 'temurin' - name: Setup go uses: actions/setup-go@v5 with: diff --git a/ci/test.bat b/ci/test.bat index c8343b75a..af46ea5b6 100644 --- a/ci/test.bat +++ b/ci/test.bat @@ -4,6 +4,9 @@ setlocal EnableDelayedExpansion start /b python ci\scripts\hang_webserver.py 12345 +curl -O https://repo1.maven.org/maven2/org/wiremock/wiremock-standalone/3.11.0/wiremock-standalone-3.11.0.jar +START /B java -jar wiremock-standalone-3.11.0.jar --port 14355 + if "%CLOUD_PROVIDER%"=="AWS" set PARAMETER_FILENAME=parameters_aws_golang.json.gpg if "%CLOUD_PROVIDER%"=="AZURE" set PARAMETER_FILENAME=parameters_azure_golang.json.gpg if "%CLOUD_PROVIDER%"=="GCP" set PARAMETER_FILENAME=parameters_gcp_golang.json.gpg diff --git a/ci/test.sh b/ci/test.sh index efbd1de0e..454df4feb 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -7,6 +7,9 @@ set -o pipefail CI_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +curl -O https://repo1.maven.org/maven2/org/wiremock/wiremock-standalone/3.11.0/wiremock-standalone-3.11.0.jar +java -jar wiremock-standalone-3.11.0.jar --port 14355 & + if [[ -n "$JENKINS_HOME" ]]; then ROOT_DIR="$(cd "${CI_DIR}/.." && pwd)" export WORKSPACE=${WORKSPACE:-/tmp} diff --git a/test_data/wiremock/mappings/select1.json b/test_data/wiremock/mappings/select1.json new file mode 100644 index 000000000..4de4d4c48 --- /dev/null +++ b/test_data/wiremock/mappings/select1.json @@ -0,0 +1,204 @@ +{ + "mappings": [ + { + "scenarioName": "Successful SELECT 1 flow", + "request": { + "urlPathPattern": "/queries/v1/query-request.*", + "method": "POST", + "headers": { + "Authorization": { + "equalTo": "%AUTHORIZATION_HEADER%" + } + } + }, + "response": { + "status": 200, + "jsonBody": { + "data": { + "parameters": [ + { + "name": "TIMESTAMP_OUTPUT_FORMAT", + "value": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM" + }, + { + "name": "CLIENT_PREFETCH_THREADS", + "value": 4 + }, + { + "name": "TIME_OUTPUT_FORMAT", + "value": "HH24:MI:SS" + }, + { + "name": "CLIENT_RESULT_CHUNK_SIZE", + "value": 16 + }, + { + "name": "TIMESTAMP_TZ_OUTPUT_FORMAT", + "value": "" + }, + { + "name": "CLIENT_SESSION_KEEP_ALIVE", + "value": false + }, + { + "name": "QUERY_CONTEXT_CACHE_SIZE", + "value": 5 + }, + { + "name": "CLIENT_METADATA_USE_SESSION_DATABASE", + "value": false + }, + { + "name": "CLIENT_OUT_OF_BAND_TELEMETRY_ENABLED", + "value": false + }, + { + "name": "ENABLE_STAGE_S3_PRIVATELINK_FOR_US_EAST_1", + "value": true + }, + { + "name": "TIMESTAMP_NTZ_OUTPUT_FORMAT", + "value": "YYYY-MM-DD HH24:MI:SS.FF3" + }, + { + "name": "CLIENT_RESULT_PREFETCH_THREADS", + "value": 1 + }, + { + "name": "CLIENT_METADATA_REQUEST_USE_CONNECTION_CTX", + "value": false + }, + { + "name": "CLIENT_HONOR_CLIENT_TZ_FOR_TIMESTAMP_NTZ", + "value": true + }, + { + "name": "CLIENT_MEMORY_LIMIT", + "value": 1536 + }, + { + "name": "CLIENT_TIMESTAMP_TYPE_MAPPING", + "value": "TIMESTAMP_LTZ" + }, + { + "name": "TIMEZONE", + "value": "America/Los_Angeles" + }, + { + "name": "SERVICE_NAME", + "value": "" + }, + { + "name": "CLIENT_RESULT_PREFETCH_SLOTS", + "value": 2 + }, + { + "name": "CLIENT_TELEMETRY_ENABLED", + "value": true + }, + { + "name": "CLIENT_DISABLE_INCIDENTS", + "value": true + }, + { + "name": "CLIENT_USE_V1_QUERY_API", + "value": true + }, + { + "name": "CLIENT_RESULT_COLUMN_CASE_INSENSITIVE", + "value": false + }, + { + "name": "CSV_TIMESTAMP_FORMAT", + "value": "" + }, + { + "name": "BINARY_OUTPUT_FORMAT", + "value": "HEX" + }, + { + "name": "CLIENT_ENABLE_LOG_INFO_STATEMENT_PARAMETERS", + "value": false + }, + { + "name": "CLIENT_TELEMETRY_SESSIONLESS_ENABLED", + "value": true + }, + { + "name": "DATE_OUTPUT_FORMAT", + "value": "YYYY-MM-DD" + }, + { + "name": "CLIENT_STAGE_ARRAY_BINDING_THRESHOLD", + "value": 65280 + }, + { + "name": "CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY", + "value": 3600 + }, + { + "name": "CLIENT_SESSION_CLONE", + "value": false + }, + { + "name": "AUTOCOMMIT", + "value": true + }, + { + "name": "TIMESTAMP_LTZ_OUTPUT_FORMAT", + "value": "" + } + ], + "rowtype": [ + { + "name": "1", + "database": "", + "schema": "", + "table": "", + "nullable": false, + "length": null, + "type": "fixed", + "scale": 0, + "precision": 1, + "byteLength": null, + "collation": null + } + ], + "rowset": [ + [ + "1" + ] + ], + "total": 1, + "returned": 1, + "queryId": "01ba13b4-0104-e9fd-0000-0111029ca00e", + "databaseProvider": null, + "finalDatabaseName": null, + "finalSchemaName": null, + "finalWarehouseName": "TEST_XSMALL", + "finalRoleName": "ACCOUNTADMIN", + "numberOfBinds": 0, + "arrayBindSupported": false, + "statementTypeId": 4096, + "version": 1, + "sendResultTime": 1738317395581, + "queryResultFormat": "json", + "queryContext": { + "entries": [ + { + "id": 0, + "timestamp": 1738317395574564, + "priority": 0, + "context": "CPbPTg==" + } + ] + } + }, + "code": null, + "message": null, + "success": true + } + } + } + ] +} \ No newline at end of file diff --git a/test_data/wiremock/mappings/telemetry.json b/test_data/wiremock/mappings/telemetry.json new file mode 100644 index 000000000..a61c2b6b0 --- /dev/null +++ b/test_data/wiremock/mappings/telemetry.json @@ -0,0 +1,22 @@ +{ + "mappings": [ + { + "scenarioName": "Successful telemetry flow", + "request": { + "urlPathPattern": "/telemetry/send", + "method": "POST" + }, + "response": { + "status": 200, + "jsonBody": { + "data": { + "code": null, + "data": "Log Received", + "message": null, + "success": true + } + } + } + } + ] +} \ No newline at end of file diff --git a/wiremock_test.go b/wiremock_test.go new file mode 100644 index 000000000..dc312ae7e --- /dev/null +++ b/wiremock_test.go @@ -0,0 +1,77 @@ +package gosnowflake + +import ( + "fmt" + "io" + "net/http" + "os" + "strings" + "testing" +) + +var wiremock *wiremockClient = newWiremock() + +type wiremockClient struct { + host string + port int + client http.Client +} + +func newWiremock() *wiremockClient { + return &wiremockClient{ + host: "127.0.0.1", + port: 14355, + } +} + +func (wm *wiremockClient) connectionConfig() *Config { + return &Config{ + User: "testUser", + Host: wm.host, + Port: wm.port, + Account: "testAccount", + Protocol: "http", + } +} + +type wiremockMapping struct { + filePath string + params map[string]string +} + +func (wm *wiremockClient) registerMappings(t *testing.T, mappings ...wiremockMapping) { + for _, mapping := range wm.enrichWithTelemetry(mappings) { + f, err := os.Open("test_data/wiremock/mappings/" + mapping.filePath) + assertNilF(t, err) + defer f.Close() + mappingBodyBytes, err := io.ReadAll(f) + assertNilF(t, err) + mappingBody := string(mappingBodyBytes) + for key, val := range mapping.params { + mappingBody = strings.Replace(mappingBody, key, val, 1) + } + resp, err := wm.client.Post(fmt.Sprintf("%v/import", wm.mappingsURL()), "application/json", strings.NewReader(mappingBody)) + assertNilF(t, err) + if resp.StatusCode != http.StatusOK { + respBody, err := io.ReadAll(resp.Body) + assertNilF(t, err) + t.Fatalf("cannot create mapping.\n%v", string(respBody)) + } + } + t.Cleanup(func() { + req, err := http.NewRequest("DELETE", wm.mappingsURL(), nil) + assertNilE(t, err) + _, err = wm.client.Do(req) + assertNilE(t, err) + }) +} + +func (wm *wiremockClient) enrichWithTelemetry(mappings []wiremockMapping) []wiremockMapping { + return append(mappings, wiremockMapping{ + filePath: "telemetry.json", + }) +} + +func (wm *wiremockClient) mappingsURL() string { + return fmt.Sprintf("http://%v:%v/__admin/mappings", wm.host, wm.port) +}