From 9ef8bd7b4a628f57c128cb02387ba369997eee5e Mon Sep 17 00:00:00 2001 From: General Kroll Date: Thu, 1 May 2025 17:09:00 +1000 Subject: [PATCH 01/10] json-response-preprocess Summary: - Support for JSON respopnse preprocessing. - Added robot testing capability. - Added robot test `Select Google Cloud Storage Buckets with CLI`. --- .github/workflows/build.yml | 58 +++++++++++++- .gitignore | 5 ++ anysdk/operation_store.go | 33 +++++--- cicd/scripts/local/01-gather.sh | 12 +++ .../local/02-build-stackql-test-package.sh | 26 +++++++ .../local/03-install-stackql-test-package.sh | 36 +++++++++ .../local/04-setup-testing-dependencies.sh | 21 ++++++ cicd/scripts/local/11-run-mocked.sh | 16 ++++ cicd/scripts/local/99-clean.sh | 13 ++++ cicd/scripts/local/context.sh | 17 +++++ cicd/scripts/local/local_scripts.md | 15 ++++ cicd/testing-requirements.txt | 4 + cmd/argparse/query.go | 44 +++++++---- .../template_stream_transform.go | 75 ++++++++++++++++--- .../aws/functional-test-dummy-aws-key.txt | 1 + .../credentials/dummy/azure/azure-token.txt | 1 + .../dummy/digitalocean/digitalocean-token.txt | 1 + .../credentials/dummy/github/github-key.txt | 1 + .../docker-functional-test-dummy-sa-key.json | 12 +++ .../dummy/google/dummy-sa-key.json | 12 +++ .../google/functional-test-dummy-sa-key.json | 12 +++ .../credentials/dummy/k8s/k8s-token.txt | 1 + .../dummy/netlify/netlify-token.txt | 1 + .../assets/credentials/dummy/okta/api-key.txt | 1 + .../dummy/sumologic/sumologic-token.txt | 1 + test/credentials/.gitignore | 2 + test/python/any_sdk_test_utils/__init__.py | 0 .../any_sdk_test_utils/any_sdk_cli_testing.py | 71 ++++++++++++++++++ test/robot/README.md | 14 ++++ test/robot/cli/mocked/__init__.robot | 5 ++ test/robot/cli/mocked/adhoc.robot | 27 +++++++ test/robot/cli/mocked/log/.gitignore | 2 + test/robot/cli/mocked/stackql.resource | 68 +++++++++++++++++ test/robot/cli/mocked/tmp/.gitignore | 2 + test/robot/reports/mocked/.gitignore | 2 + 35 files changed, 575 insertions(+), 37 deletions(-) create mode 100755 cicd/scripts/local/01-gather.sh create mode 100755 cicd/scripts/local/02-build-stackql-test-package.sh create mode 100755 cicd/scripts/local/03-install-stackql-test-package.sh create mode 100755 cicd/scripts/local/04-setup-testing-dependencies.sh create mode 100755 cicd/scripts/local/11-run-mocked.sh create mode 100755 cicd/scripts/local/99-clean.sh create mode 100755 cicd/scripts/local/context.sh create mode 100644 cicd/scripts/local/local_scripts.md create mode 100644 cicd/testing-requirements.txt create mode 100644 test/assets/credentials/dummy/aws/functional-test-dummy-aws-key.txt create mode 100644 test/assets/credentials/dummy/azure/azure-token.txt create mode 100644 test/assets/credentials/dummy/digitalocean/digitalocean-token.txt create mode 100644 test/assets/credentials/dummy/github/github-key.txt create mode 100644 test/assets/credentials/dummy/google/docker-functional-test-dummy-sa-key.json create mode 100644 test/assets/credentials/dummy/google/dummy-sa-key.json create mode 100644 test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json create mode 100644 test/assets/credentials/dummy/k8s/k8s-token.txt create mode 100644 test/assets/credentials/dummy/netlify/netlify-token.txt create mode 100644 test/assets/credentials/dummy/okta/api-key.txt create mode 100644 test/assets/credentials/dummy/sumologic/sumologic-token.txt create mode 100644 test/credentials/.gitignore create mode 100644 test/python/any_sdk_test_utils/__init__.py create mode 100644 test/python/any_sdk_test_utils/any_sdk_cli_testing.py create mode 100644 test/robot/README.md create mode 100644 test/robot/cli/mocked/__init__.robot create mode 100644 test/robot/cli/mocked/adhoc.robot create mode 100644 test/robot/cli/mocked/log/.gitignore create mode 100644 test/robot/cli/mocked/stackql.resource create mode 100644 test/robot/cli/mocked/tmp/.gitignore create mode 100644 test/robot/reports/mocked/.gitignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e298baa..82ab56b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,49 @@ env: jobs: + + test_python_package_build: + # id: test_python_package_build + name: Test Python Package Build + runs-on: ubuntu-22.04 + timeout-minutes: ${{ vars.DEFAULT_JOB_TIMEOUT_MIN == '' && 120 || vars.DEFAULT_JOB_TIMEOUT_MIN }} + steps: + + - name: Check out code into the Go module directory + uses: actions/checkout@v4.1.1 + with: + repository: ${{ env.STACKQL_CORE_REPOSITORY }} + ref: ${{ env.STACKQL_CORE_REF }} + token: ${{ secrets.CI_STACKQL_PACKAGE_DOWNLOAD_TOKEN }} + path: stackql-core-pkg + + - name: Setup Python + uses: actions/setup-python@v5.0.0 + with: + cache: pip + python-version: '3.12' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 1.8.3 + virtualenvs-create: true + virtualenvs-in-project: false + virtualenvs-path: stackql-core-pkg/my-custom-path + installer-parallel: true + + + - name: Build package + working-directory: stackql-core-pkg + run: | + cicd/util/01-build-robot-lib.sh + + - name: Upload python package artifact + uses: actions/upload-artifact@v4.3.1 + with: + name: python-package-dist-folder + path: stackql-core-pkg/test/dist + winbuild: name: Windows Build runs-on: windows-latest @@ -106,7 +149,20 @@ jobs: uses: actions/setup-python@v5.0.0 with: # cache: pip # this requires requirements in source control - python-version: '3.11' + python-version: '3.12' + + - name: Download python package dist folder + uses: actions/download-artifact@v4.1.2 + with: + name: python-package-dist-folder + path: test/dist + + - name: Install python testing package + run: | + echo "Inspecting python package" + for file in test/dist/*.whl; do + pip3 install "$file" --force-reinstall + done - name: Get dependencies run: | diff --git a/.gitignore b/.gitignore index 22e7414..a460198 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,8 @@ *.prof opint .DS_Store +dist/ +.venv/ +__pycache__/ +*.py[co] +stackql-core/ diff --git a/anysdk/operation_store.go b/anysdk/operation_store.go index aa3a90a..3ead8b5 100644 --- a/anysdk/operation_store.go +++ b/anysdk/operation_store.go @@ -1432,7 +1432,14 @@ func (op *standardOpenAPIOperationStore) isOverridable(httpResponse *http.Respon if isExpectedResponse { responseTransform, responseTransformExists := expectedResponse.GetTransform() overrideMediaType := expectedResponse.GetOverrrideBodyMediaType() - return responseTransformExists && responseTransform.GetType() == "golang_template_mxj_v0.1.0" && overrideMediaType != "" + if !responseTransformExists { + return false + } + streamTransformerFactory := stream_transform.NewStreamTransformerFactory( + responseTransform.GetType(), + responseTransform.GetBody(), + ) + return overrideMediaType != "" && streamTransformerFactory.IsTransformable() } return false } @@ -1447,19 +1454,25 @@ func (op *standardOpenAPIOperationStore) getOverridenResponse(httpResponse *http if isExpectedResponse { responseTransform, responseTransformExists := expectedResponse.GetTransform() overrideMediaType := expectedResponse.GetOverrrideBodyMediaType() - if responseTransformExists && responseTransform.GetType() == "golang_template_mxj_v0.1.0" { + if responseTransformExists { input := string(bodyBytes) - tmpl := responseTransform.GetBody() - inStream := stream_transform.NewXMLBestEffortReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := stream_transform.NewTemplateStreamTransformer(tmpl, inStream, outStream) - if err != nil { - return nil, fmt.Errorf("template stream transform error: %v", err) + streamTransformerFactory := stream_transform.NewStreamTransformerFactory( + responseTransform.GetType(), + responseTransform.GetBody(), + ) + if !streamTransformerFactory.IsTransformable() { + return nil, fmt.Errorf("unsupported template type: %s", responseTransform.GetType()) } - if err := tfm.Transform(); err != nil { + tfm, err := streamTransformerFactory.GetTransformer(input) + if err != nil { return nil, fmt.Errorf("failed to transform: %v", err) } - // bodyBytes = outStream.Bytes() + outStream := tfm.GetOutStream() + outBytes, err := io.ReadAll(outStream) + if err != nil { + return nil, fmt.Errorf("failed to read out stream: %v", err) + } + bodyBytes = outBytes if overrideMediaType == "" { overrideMediaType = media.MediaTypeJson } diff --git a/cicd/scripts/local/01-gather.sh b/cicd/scripts/local/01-gather.sh new file mode 100755 index 0000000..d465038 --- /dev/null +++ b/cicd/scripts/local/01-gather.sh @@ -0,0 +1,12 @@ +#! /usr/bin/env bash + +>&2 echo "requires git version >= 2.45" + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +source "${SCRIPT_DIR}/context.sh" + +cd "${REPOSITORY_ROOT_DIR}" + +git clone --revision=refs/heads/main https://github.com/stackql/stackql.git stackql-core + diff --git a/cicd/scripts/local/02-build-stackql-test-package.sh b/cicd/scripts/local/02-build-stackql-test-package.sh new file mode 100755 index 0000000..449cfaa --- /dev/null +++ b/cicd/scripts/local/02-build-stackql-test-package.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +>&2 echo "requires all of requirements.txt" + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +source "${SCRIPT_DIR}/context.sh" + +PACKAGE_ROOT="${STACKQL_CORE_DIR}/test" + +rm -f ${PACKAGE_ROOT}/dist/*.whl || true + +${STACKQL_CORE_DIR}/cicd/util/01-build-robot-lib.sh + +filez="$(ls ${PACKAGE_ROOT}/dist/*.whl)" || true + +if [ "${filez}" = "" ]; then + >&2 echo "No wheel files found in ${PACKAGE_ROOT}/dist. Please check the build process." + exit 1 +else + echo "Wheel files found in ${PACKAGE_ROOT}/dist: ${filez}" +fi + + + + diff --git a/cicd/scripts/local/03-install-stackql-test-package.sh b/cicd/scripts/local/03-install-stackql-test-package.sh new file mode 100755 index 0000000..3b00fe3 --- /dev/null +++ b/cicd/scripts/local/03-install-stackql-test-package.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +>&2 echo "requires all of requirements.txt" + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +source "${SCRIPT_DIR}/context.sh" + +if [ ! -d "${REPOSITORY_ROOT_DIR}/.venv" ]; then + >&2 echo "No existing virtual environment, creating one..." + >&2 echo "Creating virtual environment in ${REPOSITORY_ROOT_DIR}/.venv" + python -m venv "${REPOSITORY_ROOT_DIR}/.venv" + >&2 echo "Virtual environment created." +else + >&2 echo "Using existing virtual environment in ${REPOSITORY_ROOT_DIR}/.venv" +fi + +source "${REPOSITORY_ROOT_DIR}/.venv/bin/activate" + +pip install -r "${REPOSITORY_ROOT_DIR}/cicd/testing-requirements.txt" + +PACKAGE_ROOT="${STACKQL_CORE_DIR}/test" + +filez="$(ls ${PACKAGE_ROOT}/dist/*.whl)" || true + +if [ "${filez}" = "" ]; then + >&2 echo "No wheel files found in ${PACKAGE_ROOT}/dist. Please check the build process." + exit 1 +else + echo "Wheel files found in ${PACKAGE_ROOT}/dist: ${filez}" +fi + + +for file in ${PACKAGE_ROOT}/dist/*.whl; do + pip3 install "$file" --force-reinstall +done diff --git a/cicd/scripts/local/04-setup-testing-dependencies.sh b/cicd/scripts/local/04-setup-testing-dependencies.sh new file mode 100755 index 0000000..c09b1f9 --- /dev/null +++ b/cicd/scripts/local/04-setup-testing-dependencies.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +>&2 echo "requires all of requirements.txt" + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +source "${SCRIPT_DIR}/context.sh" + +# Check if the virtual environment exists +if [ ! -d "${STACKQL_CORE_DIR}/.venv" ]; then + >&2 echo "Virtual environment not found. Please create it first." + exit 1 +fi + +source "${STACKQL_CORE_DIR}/.venv/bin/activate" + +python ${STACKQL_CORE_DIR}/test/python/stackql_test_tooling/registry_rewrite.py --srcdir "${REPOSITORY_ROOT_DIR}/test/registry/src" --destdir "${REPOSITORY_ROOT_DIR}/test/registry-mocked/src" + +openssl req -x509 -keyout ${REPOSITORY_ROOT_DIR}/test/credentials/pg_server_key.pem -out ${REPOSITORY_ROOT_DIR}/test/credentials/pg_server_cert.pem -config ${STACKQL_CORE_DIR}/test/server/mtls/openssl.cnf -days 365 +openssl req -x509 -keyout ${REPOSITORY_ROOT_DIR}/test/credentials/pg_client_key.pem -out ${REPOSITORY_ROOT_DIR}/test/credentials/pg_client_cert.pem -config ${STACKQL_CORE_DIR}/test/server/mtls/openssl.cnf -days 365 +openssl req -x509 -keyout ${REPOSITORY_ROOT_DIR}/test/credentials/pg_rubbish_key.pem -out ${REPOSITORY_ROOT_DIR}/test/credentials/pg_rubbish_cert.pem -config ${STACKQL_CORE_DIR}/test/server/mtls/openssl.cnf -days 365 \ No newline at end of file diff --git a/cicd/scripts/local/11-run-mocked.sh b/cicd/scripts/local/11-run-mocked.sh new file mode 100755 index 0000000..178cff0 --- /dev/null +++ b/cicd/scripts/local/11-run-mocked.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +>&2 echo "requires all of requirements.txt" + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +source "${SCRIPT_DIR}/context.sh" + +cd "${REPOSITORY_ROOT_DIR}" + +source "${REPOSITORY_ROOT_DIR}/.venv/bin/activate" + +export PYTHONPATH="${PYTHONPATH}:${REPOSITORY_ROOT_DIR}/test/python" + +robot -d test/robot/reports/mocked test/robot/cli/mocked + diff --git a/cicd/scripts/local/99-clean.sh b/cicd/scripts/local/99-clean.sh new file mode 100755 index 0000000..1048987 --- /dev/null +++ b/cicd/scripts/local/99-clean.sh @@ -0,0 +1,13 @@ +#! /usr/bin/env bash + +>&2 echo "cleaning dependent repositories from local file system" + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +REPOSITORY_ROOT_DIR="$(realpath ${SCRIPT_DIR}/../../..)" + +cd "${REPOSITORY_ROOT_DIR}" + +rm -rf stackql-core || true +rm -rf stackql-any-sdk || true + diff --git a/cicd/scripts/local/context.sh b/cicd/scripts/local/context.sh new file mode 100755 index 0000000..06cf06e --- /dev/null +++ b/cicd/scripts/local/context.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +export REPOSITORY_ROOT_DIR="$(realpath ${SCRIPT_DIR}/../../..)" + +export STACKQL_CORE_DIR="${STACKQL_CORE_DIR:-"${REPOSITORY_ROOT_DIR}/stackql-core}"}" + + +checkPoetry () { + if ! command -v poetry &> /dev/null + then + >&2 echo "Poetry is not installed. Please install it first." + exit 1 + fi +} diff --git a/cicd/scripts/local/local_scripts.md b/cicd/scripts/local/local_scripts.md new file mode 100644 index 0000000..d53c20e --- /dev/null +++ b/cicd/scripts/local/local_scripts.md @@ -0,0 +1,15 @@ + + +Here is a typical example, from the root oif this repository, assuming you have the core repository locally at `../stackql-devel`: + +```bash + +env STACKQL_CORE_DIR="$(realpath ../stackql-devel)" cicd/scripts/local/02-build-stackql-test-package.sh + +env STACKQL_CORE_DIR="$(realpath ../stackql-devel)" cicd/scripts/local/03-install-stackql-test-package.sh + +env STACKQL_CORE_DIR="$(realpath ../stackql-devel)" cicd/scripts/local/04-setup-testing-dependencies.sh + +env GCP_SERVICE_ACCOUNT_KEY="$(cat test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json)" cicd/scripts/local/11-run-mocked.sh + +``` \ No newline at end of file diff --git a/cicd/testing-requirements.txt b/cicd/testing-requirements.txt new file mode 100644 index 0000000..3e75e9f --- /dev/null +++ b/cicd/testing-requirements.txt @@ -0,0 +1,4 @@ +PyYaml==6.0.2 +requests==2.32.3 +robotframework==7.0.1 +tabulate==0.9.0 diff --git a/cmd/argparse/query.go b/cmd/argparse/query.go index dbda5d9..9583ce4 100644 --- a/cmd/argparse/query.go +++ b/cmd/argparse/query.go @@ -1,7 +1,6 @@ package argparse import ( - "bytes" "encoding/json" "fmt" "io" @@ -164,17 +163,23 @@ func runQueryCommand(authCtx *dto.AuthCtx, payload *queryCmdPayload) error { responseTransform, responseTransformExists := expectedResponse.GetTransform() if responseTransformExists && responseTransform.GetType() == "golang_template_v0.1.0" { input := stdoutStr - tmpl := responseTransform.GetBody() - inStream := stream_transform.NewTextReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := stream_transform.NewTemplateStreamTransformer(tmpl, inStream, outStream) - if err != nil { - return fmt.Errorf("template stream transform error: %v", err) + streamTransformerFactory := stream_transform.NewStreamTransformerFactory( + responseTransform.GetType(), + responseTransform.GetBody(), + ) + if !streamTransformerFactory.IsTransformable() { + return fmt.Errorf("unsupported template type: %s", responseTransform.GetType()) } - if err := tfm.Transform(); err != nil { + tfm, err := streamTransformerFactory.GetTransformer(input) + if err != nil { return fmt.Errorf("failed to transform: %v", err) } - outputStr := outStream.String() + outStream := tfm.GetOutStream() + outBytes, err := io.ReadAll(outStream) + if err != nil { + return fmt.Errorf("failed to read out stream: %v", err) + } + outputStr := string(outBytes) stdoutStr = outputStr } } @@ -225,19 +230,26 @@ func runQueryCommand(authCtx *dto.AuthCtx, payload *queryCmdPayload) error { expectedResponse, isExpectedResponse := opStore.GetResponse() if isExpectedResponse { responseTransform, responseTransformExists := expectedResponse.GetTransform() - if responseTransformExists && responseTransform.GetType() == "golang_template_mxj_v0.1.0" { - input := string(bodyBytes) - tmpl := responseTransform.GetBody() - inStream := stream_transform.NewXMLBestEffortReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := stream_transform.NewTemplateStreamTransformer(tmpl, inStream, outStream) + if responseTransformExists { + streamTransformerFactory := stream_transform.NewStreamTransformerFactory( + responseTransform.GetType(), + responseTransform.GetBody(), + ) + if !streamTransformerFactory.IsTransformable() { + return fmt.Errorf("unsupported template type: %s", responseTransform.GetType()) + } + tfm, err := streamTransformerFactory.GetTransformer(string(bodyBytes)) if err != nil { return fmt.Errorf("template stream transform error: %v", err) } if err := tfm.Transform(); err != nil { return fmt.Errorf("failed to transform: %v", err) } - bodyBytes = outStream.Bytes() + outStream := tfm.GetOutStream() + bodyBytes, err = io.ReadAll(outStream) + if err != nil { + return fmt.Errorf("failed to read out stream: %v", err) + } } } fmt.Fprintf(os.Stdout, "%s", string(bodyBytes)) diff --git a/pkg/stream_transform/template_stream_transform.go b/pkg/stream_transform/template_stream_transform.go index 51654dd..21b7ccb 100644 --- a/pkg/stream_transform/template_stream_transform.go +++ b/pkg/stream_transform/template_stream_transform.go @@ -10,6 +10,53 @@ import ( "github.com/clbanning/mxj/v2" ) +const ( + GolangTemplateXMLV1 = "golang_template_mxj_v0.1.0" + GolangTemplateJSONV1 = "golang_template_json_v0.1.0" +) + +type StreamTransformerFactory interface { + IsTransformable() bool + GetTransformer(input string) (StreamTransformer, error) +} + +type streamTransformerFactory struct { + tplType string + tplStr string +} + +func NewStreamTransformerFactory(tplType string, tplStr string) StreamTransformerFactory { + return &streamTransformerFactory{ + tplType: tplType, + tplStr: tplStr, + } +} + +func (stf *streamTransformerFactory) IsTransformable() bool { + switch stf.tplType { + case GolangTemplateXMLV1: + return true + case GolangTemplateJSONV1: + return true + default: + return false + } +} + +func (stf *streamTransformerFactory) GetTransformer(input string) (StreamTransformer, error) { + switch stf.tplType { + case GolangTemplateXMLV1: + return nil, fmt.Errorf("unsupported template type: %s", stf.tplType) + case GolangTemplateJSONV1: + inStream := newXMLBestEffortReader(bytes.NewBufferString(input)) + outStream := bytes.NewBuffer(nil) + tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) + return tfm, err + default: + return nil, fmt.Errorf("unsupported template type: %s", stf.tplType) + } +} + // full acknowledgment to https://stackoverflow.com/a/42663928 func separator(s string) func() string { i := -1 @@ -115,7 +162,7 @@ func (xer *xmlBestEffortReader) Read() (interface{}, error) { return mv, nil } -func NewXMLBestEffortReader(inStream io.Reader) ObjectReader { +func newXMLBestEffortReader(inStream io.Reader) ObjectReader { return &xmlBestEffortReader{ inStream: inStream, } @@ -145,26 +192,27 @@ func jsonMapFromString(s string) (map[string]interface{}, error) { type StreamTransformer interface { Transform() error + GetOutStream() io.Reader } type templateStreamTransfomer struct { tpl *template.Template inStream ObjectReader - outStream io.Writer + outStream io.ReadWriter } -func NewTemplateStreamTransformer( - tplStr string, - inStream ObjectReader, - outStream io.Writer, -) (StreamTransformer, error) { - return newTemplateStreamTransformer(tplStr, inStream, outStream) -} +// func NewTemplateStreamTransformer( +// tplStr string, +// inStream ObjectReader, +// outStream io.Writer, +// ) (StreamTransformer, error) { +// return newTemplateStreamTransformer(tplStr, inStream, outStream) +// } func newTemplateStreamTransformer( tplStr string, inStream ObjectReader, - outStream io.Writer, + outStream io.ReadWriter, ) (StreamTransformer, error) { tpl, tplErr := template.New("__stream_tfm__").Funcs(template.FuncMap{ "separator": separator, @@ -190,6 +238,13 @@ func newTemplateStreamTransformer( }, nil } +func (tst *templateStreamTransfomer) GetOutStream() io.Reader { + if tst.outStream == nil { + return bytes.NewBuffer(nil) + } + return tst.outStream +} + func (tst *templateStreamTransfomer) Transform() error { for { obj, readErr := tst.inStream.Read() diff --git a/test/assets/credentials/dummy/aws/functional-test-dummy-aws-key.txt b/test/assets/credentials/dummy/aws/functional-test-dummy-aws-key.txt new file mode 100644 index 0000000..f9ee992 --- /dev/null +++ b/test/assets/credentials/dummy/aws/functional-test-dummy-aws-key.txt @@ -0,0 +1 @@ +some-secret-key \ No newline at end of file diff --git a/test/assets/credentials/dummy/azure/azure-token.txt b/test/assets/credentials/dummy/azure/azure-token.txt new file mode 100644 index 0000000..4e34b90 --- /dev/null +++ b/test/assets/credentials/dummy/azure/azure-token.txt @@ -0,0 +1 @@ +dummy_azure_token \ No newline at end of file diff --git a/test/assets/credentials/dummy/digitalocean/digitalocean-token.txt b/test/assets/credentials/dummy/digitalocean/digitalocean-token.txt new file mode 100644 index 0000000..80d1282 --- /dev/null +++ b/test/assets/credentials/dummy/digitalocean/digitalocean-token.txt @@ -0,0 +1 @@ +somedigitaloceantoken \ No newline at end of file diff --git a/test/assets/credentials/dummy/github/github-key.txt b/test/assets/credentials/dummy/github/github-key.txt new file mode 100644 index 0000000..b4f77ae --- /dev/null +++ b/test/assets/credentials/dummy/github/github-key.txt @@ -0,0 +1 @@ +some-dummy-github-key \ No newline at end of file diff --git a/test/assets/credentials/dummy/google/docker-functional-test-dummy-sa-key.json b/test/assets/credentials/dummy/google/docker-functional-test-dummy-sa-key.json new file mode 100644 index 0000000..511d01a --- /dev/null +++ b/test/assets/credentials/dummy/google/docker-functional-test-dummy-sa-key.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "silly-project-01", + "private_key_id": "silly-key-id", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAsTfIs92qRg+srgviU9EHJfcgjn/38QFJTa0xYPSNSLSj4hXw\niyPyZ4ih6nIfW2NP4tvwK3piQrmHx/pQesrp5exKF3b97tf+Cvf9gM+i/3wJGhEb\nE24Py91+/5aXf6TfkuhNutZ3v5qzHYRtWcr3AXcD2WAThF6hxmvQTFTYqcyUb6vl\nt7evG6OleifU5rAKmD8Odk8Hs1skwAmlWjWT1uouWVegFv53a8eUilNiBSnYy/PA\nYchL2fGI8Os+CFyju+ns6dG9H7bAOywvZZaTzlVNvJ42gop03l5xzEwHkUKlcukg\nhyDtP5FTeD5liYUJ/Xqq6Xn6Rjck/AgTwqYePwIDAQABAoIBAQCdS08X3oJ4hwcU\nwDWVgW1f1DYQZSLzxdmDWVr/nHAefT8Mt752MWTBYnOcfMi6O663Q9GrNYgrgzMy\nW0m9g4cRbaXhp9sBeLLil3RpNWKOc1A807v9he39W86SGt7DC9rpMMl1MVC+PxgF\n9fl8/no40aMX+H+6OKhMTntmlNRt+E1WUIGBk9cScb37e+oAStfS0Z6c8kQ9CkOZ\nHwydCtq8gQDpkRYMM3m7j3j9mr2Rma1o8xcBbgbomYn6y2xPQf1B4rs9fb8txngv\nGxA+QSRSXNMQmQFLmoc6d3XHFZQ5LX7atRhHsnt4blb8GNqJg8FsTFED68cWKoNp\n0Lk7c/9xAoGBAOLplpGdg3ezAMtFR5gAi8pV9vGJairJsuBij22uK0rItNkaff4G\nYyciybCKJZfXTcOzYq/CGh8KwxhN6RECmHm+bHfnxFDdHXS8e0bs8oTlR7w3yHs4\nhrplBMCwyAgSsma7s8aNBfdkDlPMxYmvytWdHf3T4mj6C5LGlFzpTLmpAoGBAMfv\naHNPLCoJjvQmNlzboN0sLZYhRl2YgW86mM0MoW7pO4cY4On5twbdFD7AtHIKF4j5\nomsMVfTDvKZ+jbHoJFuvvhozq0T/LpEx5b6d27A4pfacmG0zNaLaopoDYQ6wBvYD\n4L9OScFRrtf/X3ZgLzsmNpEVlqyUU2tbCAJVa5mnAoGBAI7ODVmVNPD3Mc+7ySPr\nbA6p7WDzZ2KIT9ARl0yiqVJGYDKmDpb5NBukNCSrvJ8D/EfmtHwCf2f74O6B0eVH\nqegspJ0NuqpdjjUyja8EXliu52eX/880su3Jt6UBXNJf2fD3vlt90zxvtuicXdGa\nVd/8IqzlVX9VpkT4PtT+arAJAoGAZkmknYG+7Y7QVTaLj3xJ0327oNhLQK06YyaO\ncDFrEew/KUHgJ7Q7IEbRCb3bU5C4M7rLjorUGxJdHK0YXxGOMF48GvmeQQFw2JW3\nnYrzjzecKQw6q3uMkFHc6ICcEkCafxjCzf0GnOHmWtlrBIv2/gLx3c42tPp5py3+\nbfs3vncCgYEA0x6tF67q3zt+daUMUox6LimkkDJLsfqnmKjvHFAhKQaqOObWaody\nfGOzlf/KLX15uicYWeCwRrs03OjBfk6LEtVddsZOrjJEp8+6gA8KEf58MJhNuRVj\no3qSe9po1TMj0/hvzd32klXslpqQjXFjm9U3lAxfcRdgWsG7SciOAAs=\n-----END RSA PRIVATE KEY-----\n", + "client_email": "silly-sa@silly-project-01.iam.gserviceaccount.com", + "client_id": "11", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://host.docker.internal:2091/google/simple/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/silly-sa%40silly-project-01.iam.gserviceaccount.com" +} \ No newline at end of file diff --git a/test/assets/credentials/dummy/google/dummy-sa-key.json b/test/assets/credentials/dummy/google/dummy-sa-key.json new file mode 100644 index 0000000..bc52a71 --- /dev/null +++ b/test/assets/credentials/dummy/google/dummy-sa-key.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "silly-project-01", + "private_key_id": "silly-key-id", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAsTfIs92qRg+srgviU9EHJfcgjn/38QFJTa0xYPSNSLSj4hXw\niyPyZ4ih6nIfW2NP4tvwK3piQrmHx/pQesrp5exKF3b97tf+Cvf9gM+i/3wJGhEb\nE24Py91+/5aXf6TfkuhNutZ3v5qzHYRtWcr3AXcD2WAThF6hxmvQTFTYqcyUb6vl\nt7evG6OleifU5rAKmD8Odk8Hs1skwAmlWjWT1uouWVegFv53a8eUilNiBSnYy/PA\nYchL2fGI8Os+CFyju+ns6dG9H7bAOywvZZaTzlVNvJ42gop03l5xzEwHkUKlcukg\nhyDtP5FTeD5liYUJ/Xqq6Xn6Rjck/AgTwqYePwIDAQABAoIBAQCdS08X3oJ4hwcU\nwDWVgW1f1DYQZSLzxdmDWVr/nHAefT8Mt752MWTBYnOcfMi6O663Q9GrNYgrgzMy\nW0m9g4cRbaXhp9sBeLLil3RpNWKOc1A807v9he39W86SGt7DC9rpMMl1MVC+PxgF\n9fl8/no40aMX+H+6OKhMTntmlNRt+E1WUIGBk9cScb37e+oAStfS0Z6c8kQ9CkOZ\nHwydCtq8gQDpkRYMM3m7j3j9mr2Rma1o8xcBbgbomYn6y2xPQf1B4rs9fb8txngv\nGxA+QSRSXNMQmQFLmoc6d3XHFZQ5LX7atRhHsnt4blb8GNqJg8FsTFED68cWKoNp\n0Lk7c/9xAoGBAOLplpGdg3ezAMtFR5gAi8pV9vGJairJsuBij22uK0rItNkaff4G\nYyciybCKJZfXTcOzYq/CGh8KwxhN6RECmHm+bHfnxFDdHXS8e0bs8oTlR7w3yHs4\nhrplBMCwyAgSsma7s8aNBfdkDlPMxYmvytWdHf3T4mj6C5LGlFzpTLmpAoGBAMfv\naHNPLCoJjvQmNlzboN0sLZYhRl2YgW86mM0MoW7pO4cY4On5twbdFD7AtHIKF4j5\nomsMVfTDvKZ+jbHoJFuvvhozq0T/LpEx5b6d27A4pfacmG0zNaLaopoDYQ6wBvYD\n4L9OScFRrtf/X3ZgLzsmNpEVlqyUU2tbCAJVa5mnAoGBAI7ODVmVNPD3Mc+7ySPr\nbA6p7WDzZ2KIT9ARl0yiqVJGYDKmDpb5NBukNCSrvJ8D/EfmtHwCf2f74O6B0eVH\nqegspJ0NuqpdjjUyja8EXliu52eX/880su3Jt6UBXNJf2fD3vlt90zxvtuicXdGa\nVd/8IqzlVX9VpkT4PtT+arAJAoGAZkmknYG+7Y7QVTaLj3xJ0327oNhLQK06YyaO\ncDFrEew/KUHgJ7Q7IEbRCb3bU5C4M7rLjorUGxJdHK0YXxGOMF48GvmeQQFw2JW3\nnYrzjzecKQw6q3uMkFHc6ICcEkCafxjCzf0GnOHmWtlrBIv2/gLx3c42tPp5py3+\nbfs3vncCgYEA0x6tF67q3zt+daUMUox6LimkkDJLsfqnmKjvHFAhKQaqOObWaody\nfGOzlf/KLX15uicYWeCwRrs03OjBfk6LEtVddsZOrjJEp8+6gA8KEf58MJhNuRVj\no3qSe9po1TMj0/hvzd32klXslpqQjXFjm9U3lAxfcRdgWsG7SciOAAs=\n-----END RSA PRIVATE KEY-----\n", + "client_email": "silly-sa@silly-project-01.iam.gserviceaccount.com", + "client_id": "11", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/silly-sa%40silly-project-01.iam.gserviceaccount.com" +} \ No newline at end of file diff --git a/test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json b/test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json new file mode 100644 index 0000000..dd994d4 --- /dev/null +++ b/test/assets/credentials/dummy/google/functional-test-dummy-sa-key.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "silly-project-01", + "private_key_id": "silly-key-id", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAsTfIs92qRg+srgviU9EHJfcgjn/38QFJTa0xYPSNSLSj4hXw\niyPyZ4ih6nIfW2NP4tvwK3piQrmHx/pQesrp5exKF3b97tf+Cvf9gM+i/3wJGhEb\nE24Py91+/5aXf6TfkuhNutZ3v5qzHYRtWcr3AXcD2WAThF6hxmvQTFTYqcyUb6vl\nt7evG6OleifU5rAKmD8Odk8Hs1skwAmlWjWT1uouWVegFv53a8eUilNiBSnYy/PA\nYchL2fGI8Os+CFyju+ns6dG9H7bAOywvZZaTzlVNvJ42gop03l5xzEwHkUKlcukg\nhyDtP5FTeD5liYUJ/Xqq6Xn6Rjck/AgTwqYePwIDAQABAoIBAQCdS08X3oJ4hwcU\nwDWVgW1f1DYQZSLzxdmDWVr/nHAefT8Mt752MWTBYnOcfMi6O663Q9GrNYgrgzMy\nW0m9g4cRbaXhp9sBeLLil3RpNWKOc1A807v9he39W86SGt7DC9rpMMl1MVC+PxgF\n9fl8/no40aMX+H+6OKhMTntmlNRt+E1WUIGBk9cScb37e+oAStfS0Z6c8kQ9CkOZ\nHwydCtq8gQDpkRYMM3m7j3j9mr2Rma1o8xcBbgbomYn6y2xPQf1B4rs9fb8txngv\nGxA+QSRSXNMQmQFLmoc6d3XHFZQ5LX7atRhHsnt4blb8GNqJg8FsTFED68cWKoNp\n0Lk7c/9xAoGBAOLplpGdg3ezAMtFR5gAi8pV9vGJairJsuBij22uK0rItNkaff4G\nYyciybCKJZfXTcOzYq/CGh8KwxhN6RECmHm+bHfnxFDdHXS8e0bs8oTlR7w3yHs4\nhrplBMCwyAgSsma7s8aNBfdkDlPMxYmvytWdHf3T4mj6C5LGlFzpTLmpAoGBAMfv\naHNPLCoJjvQmNlzboN0sLZYhRl2YgW86mM0MoW7pO4cY4On5twbdFD7AtHIKF4j5\nomsMVfTDvKZ+jbHoJFuvvhozq0T/LpEx5b6d27A4pfacmG0zNaLaopoDYQ6wBvYD\n4L9OScFRrtf/X3ZgLzsmNpEVlqyUU2tbCAJVa5mnAoGBAI7ODVmVNPD3Mc+7ySPr\nbA6p7WDzZ2KIT9ARl0yiqVJGYDKmDpb5NBukNCSrvJ8D/EfmtHwCf2f74O6B0eVH\nqegspJ0NuqpdjjUyja8EXliu52eX/880su3Jt6UBXNJf2fD3vlt90zxvtuicXdGa\nVd/8IqzlVX9VpkT4PtT+arAJAoGAZkmknYG+7Y7QVTaLj3xJ0327oNhLQK06YyaO\ncDFrEew/KUHgJ7Q7IEbRCb3bU5C4M7rLjorUGxJdHK0YXxGOMF48GvmeQQFw2JW3\nnYrzjzecKQw6q3uMkFHc6ICcEkCafxjCzf0GnOHmWtlrBIv2/gLx3c42tPp5py3+\nbfs3vncCgYEA0x6tF67q3zt+daUMUox6LimkkDJLsfqnmKjvHFAhKQaqOObWaody\nfGOzlf/KLX15uicYWeCwRrs03OjBfk6LEtVddsZOrjJEp8+6gA8KEf58MJhNuRVj\no3qSe9po1TMj0/hvzd32klXslpqQjXFjm9U3lAxfcRdgWsG7SciOAAs=\n-----END RSA PRIVATE KEY-----\n", + "client_email": "silly-sa@silly-project-01.iam.gserviceaccount.com", + "client_id": "11", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://localhost:2091/google/simple/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/silly-sa%40silly-project-01.iam.gserviceaccount.com" +} \ No newline at end of file diff --git a/test/assets/credentials/dummy/k8s/k8s-token.txt b/test/assets/credentials/dummy/k8s/k8s-token.txt new file mode 100644 index 0000000..3d85c29 --- /dev/null +++ b/test/assets/credentials/dummy/k8s/k8s-token.txt @@ -0,0 +1 @@ +some-k8s-token \ No newline at end of file diff --git a/test/assets/credentials/dummy/netlify/netlify-token.txt b/test/assets/credentials/dummy/netlify/netlify-token.txt new file mode 100644 index 0000000..9d0e0c7 --- /dev/null +++ b/test/assets/credentials/dummy/netlify/netlify-token.txt @@ -0,0 +1 @@ +some-netlify-token \ No newline at end of file diff --git a/test/assets/credentials/dummy/okta/api-key.txt b/test/assets/credentials/dummy/okta/api-key.txt new file mode 100644 index 0000000..17bee3a --- /dev/null +++ b/test/assets/credentials/dummy/okta/api-key.txt @@ -0,0 +1 @@ +some-dummy-api-key \ No newline at end of file diff --git a/test/assets/credentials/dummy/sumologic/sumologic-token.txt b/test/assets/credentials/dummy/sumologic/sumologic-token.txt new file mode 100644 index 0000000..bc4bf67 --- /dev/null +++ b/test/assets/credentials/dummy/sumologic/sumologic-token.txt @@ -0,0 +1 @@ +somesumologictoken \ No newline at end of file diff --git a/test/credentials/.gitignore b/test/credentials/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/test/credentials/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/test/python/any_sdk_test_utils/__init__.py b/test/python/any_sdk_test_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/python/any_sdk_test_utils/any_sdk_cli_testing.py b/test/python/any_sdk_test_utils/any_sdk_cli_testing.py new file mode 100644 index 0000000..3da42f0 --- /dev/null +++ b/test/python/any_sdk_test_utils/any_sdk_cli_testing.py @@ -0,0 +1,71 @@ +from asyncio import subprocess +import json +import os +import time +import typing + +from robot.api.deco import keyword, library +from robot.libraries.BuiltIn import BuiltIn +from robot.libraries.Collections import Collections +from robot.libraries.Process import Process +from robot.libraries.OperatingSystem import OperatingSystem + +from .registry_cfg import RegistryCfg +from .ShellSession import ShellSession +from .psycopg_client import PsycoPGClient +from .psycopg2_client import PsycoPG2Client +from .sqlalchemy_client import SQLAlchemyClient + +SQL_BACKEND_CANONICAL_SQLITE_EMBEDDED :str = 'sqlite_embedded' +SQL_BACKEND_POSTGRES_TCP :str = 'postgres_tcp' +SQL_CONCURRENCT_LIMIT_DEFAULT :int = 1 + +_TEST_APP_CACHE_ROOT = os.path.join("test", ".stackql") + +PSQL_EXE :str = os.environ.get('PSQL_EXE', 'psql') +SQLITE_EXE :str = os.environ.get('SQLITE_EXE', 'sqlite3') + + +@library(scope='SUITE', version='0.1.0', doc_format='reST') +class any_sdk_cli_testing(OperatingSystem, Process, BuiltIn, Collections): + ROBOT_LISTENER_API_VERSION = 2 + + def __init__(self, execution_platform='native', sql_backend=SQL_BACKEND_CANONICAL_SQLITE_EMBEDDED, concurrency_limit=SQL_CONCURRENCT_LIMIT_DEFAULT): + self._counter = 0 + self._execution_platform=execution_platform + self._sql_backend=sql_backend + self._concurrency_limit=concurrency_limit + self.ROBOT_LIBRARY_LISTENER = self + Process.__init__(self) + + @keyword + def should_any_sdk_cli_inline_equal_both_streams( + self, + stackql_exe :str, + okta_secret_str :str, + github_secret_str :str, + k8s_secret_str :str, + registry_cfg :RegistryCfg, + auth_cfg_str :str, + sql_backend_cfg_str :str, + query :str, + expected_output :str, + expected_stderr_output :str, + *args, + **cfg + ): + repeat_count = int(cfg.pop('repeat_count', 1)) + for _ in range(repeat_count): + result = self._run_stackql_exec_command( + stackql_exe, + okta_secret_str, + github_secret_str, + k8s_secret_str, + registry_cfg, + auth_cfg_str, + sql_backend_cfg_str, + query, + *args, + **cfg + ) + return self._verify_both_streams(result, expected_output, expected_stderr_output) \ No newline at end of file diff --git a/test/robot/README.md b/test/robot/README.md new file mode 100644 index 0000000..32dc505 --- /dev/null +++ b/test/robot/README.md @@ -0,0 +1,14 @@ + +# Robot framework testing foor the any-sdk + +The following simple keywords are available: + +- `Stock Stackql Exec Inline Equals Both Streams`. +- `Stock Stackql Exec Inline Contains Both Streams`. + +Working examples are present, and you can add to them: + +- For live tests, add to [`stackql/live/live.robot`](/test/robot/stackql/live/live.robot). Authentication credentials must be supplied in the environment for any query under test. +- For moocked tests, add to [`stackql/mocked/adhoc.robot`](/test/robot/stackql/mocked/adhoc.robot). Mocking capability must be present for any query under test. + +Additionally, more complex keywords are available and more complex scenarios are supported. Examples of such will be added on a needs basis, for corner cases. diff --git a/test/robot/cli/mocked/__init__.robot b/test/robot/cli/mocked/__init__.robot new file mode 100644 index 0000000..cb2865f --- /dev/null +++ b/test/robot/cli/mocked/__init__.robot @@ -0,0 +1,5 @@ +*** Settings *** +Resource ${CURDIR}/stackql.resource +Suite Setup Prepare StackQL Environment +Suite Teardown Terminate All Processes kill=True + diff --git a/test/robot/cli/mocked/adhoc.robot b/test/robot/cli/mocked/adhoc.robot new file mode 100644 index 0000000..387b7f8 --- /dev/null +++ b/test/robot/cli/mocked/adhoc.robot @@ -0,0 +1,27 @@ +*** Settings *** +Resource ${CURDIR}/stackql.resource +Test Teardown Stackql Per Test Teardown + +*** Test Cases *** +Select Google Cloud Storage Buckets with CLI + [Documentation] Test CLI Working + [Tags] cli + ${google_credentials} = Get File ${REPOSITORY_ROOT}${/}test${/}assets${/}credentials${/}dummy${/}google${/}functional-test-dummy-sa-key.json + Set Environment Variable GCP_SERVICE_ACCOUNT_KEY ${google_credentials} + ${result} = Run Process + ... ${CLI_EXE} + ... query + ... \-\-svc-file-path test/registry\-mocked/src/googleapis.com/v0\.1\.2/services/storage\-v1\.yaml + ... \-\-tls.allowInsecure + ... \-\-prov-file-path test/registry\-mocked/src/googleapis\.com/v0\.1\.2/provider\.yaml + ... \-\-resource buckets + ... \-\-method list + ... \-\-parameters {"project": "stackql\-demo"} + ... \-\-auth {"google": {"credentialsenvvar": "GCP_SERVICE_ACCOUNT_KEY"}} + ... cwd=${CWD_FOR_EXEC} + ... stdout=${CURDIR}${/}/tmp${/}Select-Google-Cloud-Storage-Buckets-with-CLI.txt + ... stderr=${CURDIR}${/}/tmp${/}Select-Google-Cloud-Storage-Buckets-with-CLI_stderr.txt + Should Contain ${result.stdout} + ... stackql\-demo + Should Be Equal As Strings ${result.rc} 0 + Should Be Equal ${result.stderr} ${EMPTY} diff --git a/test/robot/cli/mocked/log/.gitignore b/test/robot/cli/mocked/log/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/test/robot/cli/mocked/log/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/test/robot/cli/mocked/stackql.resource b/test/robot/cli/mocked/stackql.resource new file mode 100644 index 0000000..74fee07 --- /dev/null +++ b/test/robot/cli/mocked/stackql.resource @@ -0,0 +1,68 @@ +*** Variables *** +${REPOSITORY_ROOT} ${CURDIR}${/}..${/}..${/}..${/}.. +${LOCAL_LIB_HOME} ${REPOSITORY_ROOT}${/}test${/}python +${EXECUTION_PLATFORM} native # to be overridden from command line, eg "docker" +${SQL_BACKEND} sqlite_embedded # to be overridden from command line, eg "postgres_tcp" +${IS_WSL} false # to be overridden from command line, with string "true" +${SHOULD_RUN_DOCKER_EXTERNAL_TESTS} false # to be overridden from command line, with string "true" +${CONCURRENCY_LIMIT} 1 # to be overridden from command line, with integer value, -1 for no limit +${USE_STACKQL_PREINSTALLED} false # to be overridden from command line, with string "true" +${SUNDRY_CONFIG} {} # to be overridden from command line, with string value +${CORE_PREFIX} stackql-core +${CWD_FOR_EXEC} ${REPOSITORY_ROOT} # works for self repository, can be overwritten when shared +${WEB_SERVICE_LIBRARY} stackql_test_tooling.web_service_keywords +${STACKQL_INTERFACE_LIBRARY} stackql_test_tooling.StackQLInterfaces +${CLOUD_INTEGRATION_LIBRARY} stackql_test_tooling.CloudIntegration +${CLI_EXE} ${REPOSITORY_ROOT}${/}build${/}anysdk +${MOCKSERVER_PORT_OAUTH_CLIENT_CREDENTIALS_TOKEN} 2091 +${MOCKSERVER_PORT_GITHUB} 1093 +${MOCKSERVER_PORT_GOOGLE} 1080 +${MOCKSERVER_PORT_OKTA} 1090 +${MOCKSERVER_PORT_AWS} 1091 +${MOCKSERVER_PORT_STACKQL_AUTH_TESTING} 1170 +${MOCKSERVER_PORT_GOOGLEADMIN} 1098 +${MOCKSERVER_PORT_K8S} 1092 +${MOCKSERVER_PORT_REGISTRY} 1094 +${MOCKSERVER_PORT_AZURE} 1095 +${MOCKSERVER_PORT_SUMOLOGIC} 1096 +${MOCKSERVER_PORT_DIGITALOCEAN} 1097 + + +*** Settings *** +Library Process +Library OperatingSystem +Library Process +Library OperatingSystem +Library String +Library ${STACKQL_INTERFACE_LIBRARY} ${EXECUTION_PLATFORM} ${SQL_BACKEND} ${CONCURRENCY_LIMIT} +Library ${CLOUD_INTEGRATION_LIBRARY} +Library ${WEB_SERVICE_LIBRARY} ${CWD_FOR_EXEC} +... tls_key_path=${REPOSITORY_ROOT}${/}test${/}credentials${/}pg_server_key.pem +... tls_cert_path=${REPOSITORY_ROOT}${/}test${/}credentials${/}pg_server_cert.pem +... log_root=${REPOSITORY_ROOT}${/}test${/}robot${/}cli${/}mocked${/}log + +*** Keywords *** +Start All Mock Servers + ${port_dict} = Create Dictionary + ... oauth_client_credentials_token=${MOCKSERVER_PORT_OAUTH_CLIENT_CREDENTIALS_TOKEN} + ... github=${MOCKSERVER_PORT_GITHUB} + ... google=${MOCKSERVER_PORT_GOOGLE} + ... okta=${MOCKSERVER_PORT_OKTA} + ... aws=${MOCKSERVER_PORT_AWS} + ... stackql_auth_testing=${MOCKSERVER_PORT_STACKQL_AUTH_TESTING} + ... googleadmin=${MOCKSERVER_PORT_GOOGLEADMIN} + ... k8s=${MOCKSERVER_PORT_K8S} + ... registry=${MOCKSERVER_PORT_REGISTRY} + ... azure=${MOCKSERVER_PORT_AZURE} + ... sumologic=${MOCKSERVER_PORT_SUMOLOGIC} + ... digitalocean=${MOCKSERVER_PORT_DIGITALOCEAN} + Start All Webservers port_dict=${port_dict} + +Prepare StackQL Environment + [Documentation] Prepare StackQL Environment + Start All Mock Servers + Sleep 50s + +Stackql Per Test Teardown + [Documentation] Stackql Per Test Teardown + Log Stackql Per Test Teardown Placeholder run diff --git a/test/robot/cli/mocked/tmp/.gitignore b/test/robot/cli/mocked/tmp/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/test/robot/cli/mocked/tmp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/test/robot/reports/mocked/.gitignore b/test/robot/reports/mocked/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/test/robot/reports/mocked/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From 74c930fdfbd19f13333b2f019dba604b1919c35e Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 00:36:24 +1000 Subject: [PATCH 02/10] - Robot tests incorporated into CI. --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 82ab56b..57fa43f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -318,6 +318,19 @@ jobs: echo "Core Test passed with matching public key algorithm: '$publicKeyAlgorithm'" fi + - name: Prepare for robot test run + run: | + pgrep -f flask | xargs kill -9 || true + + - name: Run mocked robot tests + run: | + robot -d test/robot/reports/mocked test/robot/cli/mocked + + - name: Output from mocked robot tests + if: always() + run: | + cat test/robot/reports/mocked/output.xml + macosbuild: name: MacOS Build runs-on: macos-latest From e42ba0483197970d4b8686e9071ffe2ddd18a30c Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 00:48:11 +1000 Subject: [PATCH 03/10] - Consume python testing package through package manager. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57fa43f..3472c9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,6 +128,7 @@ jobs: run: go test -timeout 240s -v ./... linuxbuild: + needs: test_python_package_build name: Linux Build runs-on: ubuntu-latest steps: From ef4a9b7d6777788fe0cb99339fb644fa7b204d53 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 18:29:33 +1000 Subject: [PATCH 04/10] - Fix unit tests and bugs. --- anysdk/operation_store.go | 9 ++- anysdk/operation_store_test.go | 1 + pkg/stream_transform/stream_transform_test.go | 71 +++++++++++++------ .../template_stream_transform.go | 19 +++-- 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/anysdk/operation_store.go b/anysdk/operation_store.go index 3ead8b5..a3448ed 100644 --- a/anysdk/operation_store.go +++ b/anysdk/operation_store.go @@ -1467,12 +1467,11 @@ func (op *standardOpenAPIOperationStore) getOverridenResponse(httpResponse *http if err != nil { return nil, fmt.Errorf("failed to transform: %v", err) } - outStream := tfm.GetOutStream() - outBytes, err := io.ReadAll(outStream) - if err != nil { - return nil, fmt.Errorf("failed to read out stream: %v", err) + tfmErr := tfm.Transform() + if tfmErr != nil { + return nil, fmt.Errorf("failed to transform: %v", tfmErr) } - bodyBytes = outBytes + outStream := tfm.GetOutStream() if overrideMediaType == "" { overrideMediaType = media.MediaTypeJson } diff --git a/anysdk/operation_store_test.go b/anysdk/operation_store_test.go index b379ec8..776239a 100644 --- a/anysdk/operation_store_test.go +++ b/anysdk/operation_store_test.go @@ -109,6 +109,7 @@ func TestTransformedXMLHTTPHandle(t *testing.T) { assert.Assert(t, ops != nil) processed, err := ops.ProcessResponse(res) + t.Logf("err: %v", err) assert.NilError(t, err) processedResponse, ok := processed.GetResponse() assert.Assert(t, ok) diff --git a/pkg/stream_transform/stream_transform_test.go b/pkg/stream_transform/stream_transform_test.go index a315de2..01e206b 100644 --- a/pkg/stream_transform/stream_transform_test.go +++ b/pkg/stream_transform/stream_transform_test.go @@ -264,16 +264,21 @@ func TestSimpleStreamTransform(t *testing.T) { input := fmt.Sprintf(`"Hello, %s!"`, "World") t.Log("TestSimpleStream") tmpl := `{{.}}` - inStream := NewJSONReader(bytes.NewBufferString(input)) outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateJSONV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) if outputStr != "Hello, World!" { t.Fatalf("unexpected output: %s", outStream.String()) } @@ -283,16 +288,20 @@ func TestMeaningfulStreamTransform(t *testing.T) { input := jsonExample t.Log("TestSimpleStream") tmpl := jsonTmpl - inStream := NewJSONReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateJSONV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) if outputStr != expectedJsonOutput { t.Fatalf("unexpected output: '%s' != '%s'", outputStr, expectedJsonOutput) } @@ -302,16 +311,20 @@ func TestSimpleTextXMLStreamTransform(t *testing.T) { input := xmlExample t.Log("v") tmpl := xmlTmpl - inStream := NewTextReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateTextV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) expected := `[{ "name": "Platypus"}]` if outputStr != expected { t.Fatalf("unexpected output: '%s' != '%s'", outputStr, expected) @@ -322,16 +335,20 @@ func TestBestEffortXMLStreamTransform(t *testing.T) { input := xmlEc2SinglePageExample t.Log("v") tmpl := xmlBestEffortTmpl - inStream := NewXMLBestEffortReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateXMLV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) expected := expectedBestEffortSinglePageOutput if outputStr != expected { t.Fatalf("unexpected output: '%s' != '%s'", outputStr, expected) @@ -352,16 +369,20 @@ func TestMeaningfulXMLStreamTransform(t *testing.T) { {"name": "{{ $animalName }}", "democratic_votes": {{ $animalVotes }}} {{- end -}} ]` - inStream := NewTextReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateTextV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) expected := `[{"name": "Platypus", "democratic_votes": 1}, {"name": "Quokka", "democratic_votes": 3}, {"name": "Quoll", "democratic_votes": 2}]` if outputStr != expected { t.Fatalf("unexpected output: '%s' != '%s'", outputStr, expected) @@ -378,16 +399,20 @@ func TestOpensslCertTextStreamTransform(t *testing.T) { {{- $notBefore := getRegexpFirstMatch $root "Not Before: (.*)" -}} {{- $notAfter := getRegexpFirstMatch $root "Not After(?:[ ]*): (.*)" -}} { "type": "x509", "public_key_algorithm": "{{ $pubKeyAlgo }}", "not_before": "{{ $notBefore }}", "not_after": "{{ $notAfter }}"}` - inStream := NewTextReader(bytes.NewBufferString(input)) - outStream := bytes.NewBuffer(nil) - tfm, err := NewTemplateStreamTransformer(tmpl, inStream, outStream) + tfmFactory := NewStreamTransformerFactory(GolangTemplateTextV1, tmpl) + if !tfmFactory.IsTransformable() { + t.Fatalf("failed to create transformer factory: is not transformable") + } + tfm, err := tfmFactory.GetTransformer(input) if err != nil { t.Fatalf("failed to create transformer: %v", err) } if err := tfm.Transform(); err != nil { t.Fatalf("failed to transform: %v", err) } - outputStr := outStream.String() + tfmOut := tfm.GetOutStream() + outputBytes, _ := io.ReadAll(tfmOut) + outputStr := string(outputBytes) expected := `{ "type": "x509", "public_key_algorithm": "rsaEncryption", "not_before": "Mar 22 02:50:46 2025 GMT", "not_after": "Jun 20 02:50:46 2025 GMT"}` if outputStr != expected { t.Fatalf("unexpected output: '%s' != '%s'", outputStr, expected) diff --git a/pkg/stream_transform/template_stream_transform.go b/pkg/stream_transform/template_stream_transform.go index 21b7ccb..bfb1fa8 100644 --- a/pkg/stream_transform/template_stream_transform.go +++ b/pkg/stream_transform/template_stream_transform.go @@ -13,6 +13,7 @@ import ( const ( GolangTemplateXMLV1 = "golang_template_mxj_v0.1.0" GolangTemplateJSONV1 = "golang_template_json_v0.1.0" + GolangTemplateTextV1 = "golang_template_text_v0.1.0" ) type StreamTransformerFactory interface { @@ -38,6 +39,8 @@ func (stf *streamTransformerFactory) IsTransformable() bool { return true case GolangTemplateJSONV1: return true + case GolangTemplateTextV1: + return true default: return false } @@ -46,12 +49,20 @@ func (stf *streamTransformerFactory) IsTransformable() bool { func (stf *streamTransformerFactory) GetTransformer(input string) (StreamTransformer, error) { switch stf.tplType { case GolangTemplateXMLV1: - return nil, fmt.Errorf("unsupported template type: %s", stf.tplType) - case GolangTemplateJSONV1: inStream := newXMLBestEffortReader(bytes.NewBufferString(input)) outStream := bytes.NewBuffer(nil) tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) return tfm, err + case GolangTemplateJSONV1: + inStream := newJSONReader(bytes.NewBufferString(input)) + outStream := bytes.NewBuffer(nil) + tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) + return tfm, err + case GolangTemplateTextV1: + inStream := newTextReader(bytes.NewBufferString(input)) + outStream := bytes.NewBuffer(nil) + tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) + return tfm, err default: return nil, fmt.Errorf("unsupported template type: %s", stf.tplType) } @@ -128,7 +139,7 @@ type jsonReader struct { inStream io.Reader } -func NewJSONReader(inStream io.Reader) ObjectReader { +func newJSONReader(inStream io.Reader) ObjectReader { return &jsonReader{ inStream: inStream, } @@ -168,7 +179,7 @@ func newXMLBestEffortReader(inStream io.Reader) ObjectReader { } } -func NewTextReader(inStream io.Reader) ObjectReader { +func newTextReader(inStream io.Reader) ObjectReader { return &textReader{ inStream: inStream, } From a9bba388f034c3b2ceee4597ef0f84d1c4f9147c Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 19:00:07 +1000 Subject: [PATCH 05/10] - Shim legacy template type. --- pkg/stream_transform/template_stream_transform.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/stream_transform/template_stream_transform.go b/pkg/stream_transform/template_stream_transform.go index bfb1fa8..52597ed 100644 --- a/pkg/stream_transform/template_stream_transform.go +++ b/pkg/stream_transform/template_stream_transform.go @@ -11,9 +11,10 @@ import ( ) const ( - GolangTemplateXMLV1 = "golang_template_mxj_v0.1.0" - GolangTemplateJSONV1 = "golang_template_json_v0.1.0" - GolangTemplateTextV1 = "golang_template_text_v0.1.0" + GolangTemplateXMLV1 = "golang_template_mxj_v0.1.0" + GolangTemplateJSONV1 = "golang_template_json_v0.1.0" + GolangTemplateTextV1 = "golang_template_text_v0.1.0" + GolangTemplateUnspecifiedV1 = "golang_template_v0.1.0" ) type StreamTransformerFactory interface { @@ -41,6 +42,8 @@ func (stf *streamTransformerFactory) IsTransformable() bool { return true case GolangTemplateTextV1: return true + case GolangTemplateUnspecifiedV1: + return true default: return false } @@ -58,7 +61,7 @@ func (stf *streamTransformerFactory) GetTransformer(input string) (StreamTransfo outStream := bytes.NewBuffer(nil) tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) return tfm, err - case GolangTemplateTextV1: + case GolangTemplateTextV1, GolangTemplateUnspecifiedV1: inStream := newTextReader(bytes.NewBufferString(input)) outStream := bytes.NewBuffer(nil) tfm, err := newTemplateStreamTransformer(stf.tplStr, inStream, outStream) From 7c57f49d9bafa6abe053f13110225301a4c607e5 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 19:30:23 +1000 Subject: [PATCH 06/10] - Restore output from describe query. --- cmd/argparse/query.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/argparse/query.go b/cmd/argparse/query.go index 9583ce4..71f21e2 100644 --- a/cmd/argparse/query.go +++ b/cmd/argparse/query.go @@ -174,6 +174,10 @@ func runQueryCommand(authCtx *dto.AuthCtx, payload *queryCmdPayload) error { if err != nil { return fmt.Errorf("failed to transform: %v", err) } + transformError := tfm.Transform() + if transformError != nil { + return fmt.Errorf("failed to transform: %v", transformError) + } outStream := tfm.GetOutStream() outBytes, err := io.ReadAll(outStream) if err != nil { From c635bcb7fe6d47c69affcebeed1cc3a4f09ee0e7 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 19:44:57 +1000 Subject: [PATCH 07/10] - Python env. --- .github/workflows/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3472c9c..953c20e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -152,6 +152,11 @@ jobs: # cache: pip # this requires requirements in source control python-version: '3.12' + - name: Install python dependencies + run: | + echo "Installing python dependencies" + pip3 install -r cicd/testing-requirements.txt + - name: Download python package dist folder uses: actions/download-artifact@v4.1.2 with: @@ -325,6 +330,7 @@ jobs: - name: Run mocked robot tests run: | + export PYTHONPATH="${PYTHONPATH}:${{ github.workspace }}/test/python" robot -d test/robot/reports/mocked test/robot/cli/mocked - name: Output from mocked robot tests From 09a54b662c67c145d7e079e079152a38a6e07598 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 20:00:13 +1000 Subject: [PATCH 08/10] - Python env. --- test/robot/cli/mocked/adhoc.robot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/robot/cli/mocked/adhoc.robot b/test/robot/cli/mocked/adhoc.robot index 387b7f8..493e972 100644 --- a/test/robot/cli/mocked/adhoc.robot +++ b/test/robot/cli/mocked/adhoc.robot @@ -21,6 +21,9 @@ Select Google Cloud Storage Buckets with CLI ... cwd=${CWD_FOR_EXEC} ... stdout=${CURDIR}${/}/tmp${/}Select-Google-Cloud-Storage-Buckets-with-CLI.txt ... stderr=${CURDIR}${/}/tmp${/}Select-Google-Cloud-Storage-Buckets-with-CLI_stderr.txt + Log Stderr = ${result.stderr} + Log Stdout = ${result.stdout} + Log RC = ${result.rc} Should Contain ${result.stdout} ... stackql\-demo Should Be Equal As Strings ${result.rc} 0 From 90d99a6b835ec4fbab0ea34dcb7f6b79db694003 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 20:09:52 +1000 Subject: [PATCH 09/10] - Testing setup improve. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 953c20e..5066b25 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -327,6 +327,7 @@ jobs: - name: Prepare for robot test run run: | pgrep -f flask | xargs kill -9 || true + python ${{ github.workspace }}/stackql-core/test/python/stackql_test_tooling/registry_rewrite.py --srcdir "${{ github.workspace }}/test/registry/src" --destdir "${{ github.workspace }}/test/registry-mocked/src" - name: Run mocked robot tests run: | From 637f299a1b7bbdf0bbd31c82a7f1a4c5e524b6d5 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Fri, 2 May 2025 22:27:39 +1000 Subject: [PATCH 10/10] - Testing setup improve. --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5066b25..2e64388 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -328,6 +328,9 @@ jobs: run: | pgrep -f flask | xargs kill -9 || true python ${{ github.workspace }}/stackql-core/test/python/stackql_test_tooling/registry_rewrite.py --srcdir "${{ github.workspace }}/test/registry/src" --destdir "${{ github.workspace }}/test/registry-mocked/src" + openssl req -x509 -keyout ${{ github.workspace }}/test/credentials/pg_server_key.pem -out ${{ github.workspace }}/test/credentials/pg_server_cert.pem -config ${{ github.workspace }}/stackql-core/test/server/mtls/openssl.cnf -days 365 + openssl req -x509 -keyout ${{ github.workspace }}/test/credentials/pg_client_key.pem -out ${{ github.workspace }}/test/credentials/pg_client_cert.pem -config ${{ github.workspace }}/stackql-core/test/server/mtls/openssl.cnf -days 365 + openssl req -x509 -keyout ${{ github.workspace }}/test/credentials/pg_rubbish_key.pem -out ${{ github.workspace }}/test/credentials/pg_rubbish_cert.pem -config ${{ github.workspace }}/stackql-core/test/server/mtls/openssl.cnf -days 365 - name: Run mocked robot tests run: |