From 5cba332539c082cfb4daebac3127808026bb8baf Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Thu, 30 Jan 2025 14:26:13 +0100 Subject: [PATCH] SNOW-1883649 Added manual integration test --- ci/image/Dockerfile | 2 +- ci/image/build.sh | 4 +- ci/test_windows.bat | 2 + .../testOauthAuthorizationCode.js | 199 ++++++++++++++++++ 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 test/integration/authentication_mock/testOauthAuthorizationCode.js diff --git a/ci/image/Dockerfile b/ci/image/Dockerfile index 8c7574950..943ec62ff 100644 --- a/ci/image/Dockerfile +++ b/ci/image/Dockerfile @@ -3,7 +3,7 @@ FROM $IMAGE USER root -RUN apk update && apk add python3 jq aws-cli gosu +RUN apk update && apk add python3 python3-dev py3-pip jq aws-cli gosu openjdk-17 RUN pip install -U snowflake-connector-python # workspace diff --git a/ci/image/build.sh b/ci/image/build.sh index 1c42aa950..1553b5f72 100755 --- a/ci/image/build.sh +++ b/ci/image/build.sh @@ -6,8 +6,10 @@ set -o pipefail THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $THIS_DIR/../_init.sh +echo 'INIT SH DONE' + for name in "${!BUILD_IMAGE_NAMES[@]}"; do - docker build \ + docker --debug build \ --platform=linux/amd64 \ --file $THIS_DIR/Dockerfile \ --label snowflake \ diff --git a/ci/test_windows.bat b/ci/test_windows.bat index bf68e9e87..3f04dc3af 100644 --- a/ci/test_windows.bat +++ b/ci/test_windows.bat @@ -39,6 +39,8 @@ echo [INFO] Schema: %SNOWFLAKE_TEST_SCHEMA% echo [INFO] Warehouse: %SNOWFLAKE_TEST_WAREHOUSE% echo [INFO] Role: %SNOWFLAKE_TEST_ROLE% +echo [INFO] JAVA_HOME %JAVA_HOME% + echo [INFO] Creating schema %SNOWFLAKE_TEST_SCHEMA% pushd %GITHUB_WORKSPACE%\ci\container python create_schema.py diff --git a/test/integration/authentication_mock/testOauthAuthorizationCode.js b/test/integration/authentication_mock/testOauthAuthorizationCode.js new file mode 100644 index 000000000..4f8065689 --- /dev/null +++ b/test/integration/authentication_mock/testOauthAuthorizationCode.js @@ -0,0 +1,199 @@ +const assert = require('assert'); +const fs = require('fs'); +const net = require('net'); +const connParameters = require('../../authentication/connectionParameters'); +const axios = require('axios'); +const AuthTest = require('../../authentication/authTestsBaseClass'); +const WireMockRestClient = require('wiremock-rest-client').WireMockRestClient; +const { exec } = require('child_process'); +const Os = require("os"); + + + +async function runWireMockAsync(port) { + let timeoutHandle; + const waitingWireMockPromise = new Promise(async (resolve, reject) => { + try { + exec(`npx wiremock --enable-browser-proxying --proxy-pass-through false --port ${port} `, (error, stdout, stderr) => { + if (error) { + console.error(`exec error: ${error}`); + return; + } + console.log(`stdout: ${stdout}`); + console.error(`stderr: ${stderr}`); + }); + const wireMock = new WireMockRestClient(`http://localhost:${port}`); + const readyWireMock = await waitForWiremockStarted(wireMock); + resolve(readyWireMock); + } catch (err) { + reject(err); + } + }); + + + const timeout = new Promise((resolve, reject) => + timeoutHandle = setTimeout( + () => reject('Wiremock unavailable after 26000 ms.'), + 26000)); + return Promise.race([waitingWireMockPromise, timeout]) + .then(result => { + clearTimeout(timeoutHandle); + return result; + }); +} + +async function waitForWiremockStarted(wireMock) { + return fetch(wireMock.baseUri) + .then(async (resp) => { + if (resp.ok) { + return Promise.resolve(wireMock); + } else { + await new Promise(resolve => setTimeout(resolve, 1000)); + console.log(`Retry connection to WireMock after wrong response status: ${resp.status}`); + return await waitForWiremockStarted(wireMock); + } + }) + .catch(async (err) => { + await new Promise(resolve => setTimeout(resolve, 1000)); + console.log(`Retry connection to WireMock after error: ${err}`); + return await waitForWiremockStarted(wireMock); + }); +} + +if (Os.platform() === 'linux') { + describe('Wiremock test', function () { + let port, wireMock; + before(async () => { + port = await getPortFree(); + wireMock = await runWireMockAsync(port); + }); + after(async () => { + await wireMock.global.shutdown(); + }); + it('Run Wiremock instance, wait, verify connection and shutdown', async function () { + assert.doesNotReject(async () => await wireMock.mappings.getAllMappings()); + }); + it('Add mappings', async function () { + const requests = JSON.parse(fs.readFileSync('wiremock/mappings/test.json', 'utf8')); + for (const mapping of requests.mappings) { + await wireMock.mappings.createMapping(mapping); + } + const mappings = await wireMock.mappings.getAllMappings(); + assert.strictEqual(mappings.mappings.length, 2); + const response = await axios.get(`http://localhost:${port}/test/authorize.html`); + assert.strictEqual(response.status, 200); + }); + }); + + describe.only('Oauth PAT authentication', function () { + let port; + let authTest; + let wireMock; + before(async () => { + port = await getPortFree(); + wireMock = await runWireMockAsync(port); + }); + beforeEach(async () => { + authTest = new AuthTest(); + }); + afterEach(async () => { + wireMock.scenarios.resetAllScenarios(); + }); + after(async () => { + await wireMock.global.shutdown(); + }); + + + it('Successful flow scenario PAT as token', async function () { + await addWireMockMappingsFromFile('wiremock/mappings/pat/successful_flow.json'); + const connectionOption = {...connParameters.oauthPATOnWiremock, token: 'MOCK_TOKEN', port: port}; + authTest.createConnection(connectionOption); + await authTest.connectAsync(); + authTest.verifyNoErrorWasThrown(); + }); + + it('Successful flow scenario PAT as password', async function () { + await addWireMockMappingsFromFile('wiremock/mappings/pat/successful_flow.json'); + const connectionOption = {...connParameters.oauthPATOnWiremock, password: 'MOCK_TOKEN', port: port}; + authTest.createConnection(connectionOption); + await authTest.connectAsync(); + authTest.verifyNoErrorWasThrown(); + }); + + it('Invalid token', async function () { + await addWireMockMappingsFromFile('wiremock/mappings/pat/invalid_pat_token.json'); + const connectionOption = {...connParameters.oauthPATOnWiremock, token: 'INVALID_TOKEN', port: port}; + authTest.createConnection(connectionOption); + await authTest.connectAsync(); + authTest.verifyErrorWasThrown('Programmatic access token is invalid.'); + }); + + async function addWireMockMappingsFromFile(filePath) { + const requests = JSON.parse(fs.readFileSync(filePath, 'utf8')); + for (const mapping of requests.mappings) { + await wireMock.mappings.createMapping(mapping); + } + } + }); + + // describe('Oauth PAT authentication', function () { + // let port; + // let authTest; + // let wireMock; + // before(async () => { + // port = await getPortFree(); + // wireMock = await runWireMockAsync(port); + // }); + // beforeEach(async () => { + // authTest = new AuthTest(); + // }); + // afterEach(async () => { + // wireMock.scenarios.resetAllScenarios(); + // }); + // after(async () => { + // await wireMock.global.shutdown(); + // }); + // + // + // it('Successful flow scenario PAT as token', async function () { + // await addWireMockMappingsFromFile('wiremock/mappings/pat/successful_flow.json'); + // const connectionOption = {...connParameters.oauthPATOnWiremock, token: 'MOCK_TOKEN', port: port}; + // authTest.createConnection(connectionOption); + // await authTest.connectAsync(); + // authTest.verifyNoErrorWasThrown(); + // }); + // + // it('Successful flow scenario PAT as password', async function () { + // await addWireMockMappingsFromFile('wiremock/mappings/pat/successful_flow.json'); + // const connectionOption = {...connParameters.oauthPATOnWiremock, password: 'MOCK_TOKEN', port: port}; + // authTest.createConnection(connectionOption); + // await authTest.connectAsync(); + // authTest.verifyNoErrorWasThrown(); + // }); + // + // it('Invalid token', async function () { + // await addWireMockMappingsFromFile('wiremock/mappings/pat/invalid_pat_token.json'); + // const connectionOption = {...connParameters.oauthPATOnWiremock, token: 'INVALID_TOKEN', port: port}; + // authTest.createConnection(connectionOption); + // await authTest.connectAsync(); + // authTest.verifyErrorWasThrown('Programmatic access token is invalid.'); + // }); + // + // async function addWireMockMappingsFromFile(filePath) { + // const requests = JSON.parse(fs.readFileSync(filePath, 'utf8')); + // for (const mapping of requests.mappings) { + // await wireMock.mappings.createMapping(mapping); + // } + // } + // }); + + async function getPortFree() { + return new Promise(res => { + const srv = net.createServer(); + srv.listen(0, () => { + const port = srv.address().port; + srv.close((err) => res(port)); + }); + }); + } +}