diff --git a/.github/workflows/async_server_tests.yaml b/.github/workflows/async_server_tests.yaml new file mode 100644 index 0000000..33c181b --- /dev/null +++ b/.github/workflows/async_server_tests.yaml @@ -0,0 +1,82 @@ +name: 'Run Async Server Tests' +on: + pull_request: + branches: + - main + +jobs: + run-tests: + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + python-version: + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + exclude: + - os: windows-latest + python-version: "3.12" + runs-on: ${{matrix.os}} + name: 'Run Tests on ${{matrix.os}} with Python ${{matrix.python-version}}' + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies from requirements.txt + shell: bash + run: | + python3 -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Install psycopg2 for non-Windows OS + if: matrix.os != 'windows-latest' + run: | + pip install psycopg2 + + # Windows specific + # whl files downloaded from https://www.lfd.uci.edu/~gohlke/pythonlibs/#psycopg + - name: Install psycopg2-binary for Windows using local wheel + if: matrix.os == 'windows-latest' + run: | + # Determine the wheel filename based on the Python version + $wheelFilename = switch ("${{ matrix.python-version }}") { + "3.7" { "psycopg2-2.9.3-cp37-cp37m-win_amd64.whl" } + "3.8" { "psycopg2-2.9.3-cp38-cp38-win_amd64.whl" } + "3.9" { "psycopg2-2.9.3-cp39-cp39-win_amd64.whl" } + "3.10" { "psycopg2-2.9.3-cp310-cp310-win_amd64.whl" } + "3.11" { "psycopg2-2.9.3-cp311-cp311-win_amd64.whl" } + } + + # Print the wheel filename for debugging + Write-Host "Determined wheel filename: $wheelFilename" + + # Install the wheel + pip install ./tests/whls/$wheelFilename + shell: powershell + # End Windows specific + + - name: Install pystackql + run: | + pip install . + + - name: Run tests + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }} + AWS_REGIONS: ${{ vars.AWS_REGIONS }} + GCP_PROJECT: ${{ vars.GCP_PROJECT }} + GCP_ZONE: ${{ vars.GCP_ZONE }} + run: | + python3 -m tests.pystackql_async_server_tests \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 56ce31e..8341d41 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -22,8 +22,6 @@ jobs: exclude: - os: windows-latest python-version: "3.12" - # - os: macos-latest - # python-version: "3.12" runs-on: ${{matrix.os}} name: 'Run Tests on ${{matrix.os}} with Python ${{matrix.python-version}}' diff --git a/run_async_server_tests b/run_async_server_tests new file mode 100644 index 0000000..5c66a63 --- /dev/null +++ b/run_async_server_tests @@ -0,0 +1,3 @@ +#!/bin/bash +. tests/creds/env_vars/test.env +python3 -m tests.pystackql_async_server_tests \ No newline at end of file diff --git a/tests/pystackql_async_server_tests.py b/tests/pystackql_async_server_tests.py new file mode 100644 index 0000000..e6480b2 --- /dev/null +++ b/tests/pystackql_async_server_tests.py @@ -0,0 +1,58 @@ +import sys, os, unittest, asyncio +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from pystackql import StackQL +from .test_params import * + +def async_test_decorator(func): + def wrapper(*args, **kwargs): + if asyncio.iscoroutinefunction(func): + return asyncio.run(func(*args, **kwargs)) + else: + return func(*args, **kwargs) + return wrapper + +class PyStackQLTestsBase(unittest.TestCase): + pass + +def setUpModule(): + print("downloading stackql binary...") + PyStackQLTestsBase.stackql = StackQL() + print("downloading aws provider for tests...") + res = PyStackQLTestsBase.stackql.executeStmt(registry_pull_aws_query) + print(res) + print("downloading google provider for tests...") + res = PyStackQLTestsBase.stackql.executeStmt(registry_pull_google_query) + print(res) + print("starting stackql server...") + PyStackQLTestsBase.server_process = subprocess.Popen([PyStackQLTestsBase.stackql.bin_path, "srv", "--pgsrv.address", server_address, "--pgsrv.port", str(server_port)]) + time.sleep(5) + +def tearDownModule(): + print("stopping stackql server...") + if PyStackQLTestsBase.server_process: + PyStackQLTestsBase.server_process.terminate() + PyStackQLTestsBase.server_process.wait() + +class PyStackQLAsyncTests(PyStackQLTestsBase): + + @async_test_decorator + async def test_executeQueriesAsync_server_mode_default_output(self): + stackql = StackQL(server_mode=True) + result = await stackql.executeQueriesAsync(async_queries) + is_valid_result = isinstance(result, list) and all(isinstance(res, dict) for res in result) + self.assertTrue(is_valid_result, f"Result is not a valid list of dicts: {result}") + print_test_result(f"[ASYNC] Test executeQueriesAsync in server_mode with default output\nRESULT_COUNT: {len(result)}", is_valid_result, True) + + @async_test_decorator + async def test_executeQueriesAsync_server_mode_pandas_output(self): + stackql = StackQL(server_mode=True, output='pandas') + result = await stackql.executeQueriesAsync(async_queries) + is_valid_dataframe = isinstance(result, pd.DataFrame) and not result.empty + self.assertTrue(is_valid_dataframe, f"Result is not a valid DataFrame: {result}") + print_test_result(f"[ASYNC] Test executeQueriesAsync in server_mode with pandas output\nRESULT_COUNT: {len(result)}", is_valid_dataframe, True) + +def main(): + unittest.main(verbosity=0) + +if __name__ == '__main__': + main() diff --git a/tests/pystackql_tests.py b/tests/pystackql_tests.py index 703c490..6420937 100644 --- a/tests/pystackql_tests.py +++ b/tests/pystackql_tests.py @@ -206,22 +206,6 @@ async def test_16_executeQueriesAsync_with_csv_output(self): pass print_test_result(f"[ASYNC] Test executeQueriesAsync with unsupported csv output", exception_caught) -# @async_test_decorator -# async def test_17_executeQueriesAsync_server_mode_default_output(self): -# stackql = StackQL(server_mode=True) -# result = await stackql.executeQueriesAsync(async_queries) -# is_valid_result = isinstance(result, list) and all(isinstance(res, dict) for res in result) -# self.assertTrue(is_valid_result, f"Result is not a valid list of dicts: {result}") -# print_test_result(f"[ASYNC] Test executeQueriesAsync in server_mode with default output\nRESULT_COUNT: {len(result)}", is_valid_result, True) - -# @async_test_decorator -# async def test_18_executeQueriesAsync_server_mode_pandas_output(self): -# stackql = StackQL(server_mode=True, output='pandas') -# result = await stackql.executeQueriesAsync(async_queries) -# is_valid_dataframe = isinstance(result, pd.DataFrame) and not result.empty -# self.assertTrue(is_valid_dataframe, f"Result is not a valid DataFrame: {result}") -# print_test_result(f"[ASYNC] Test executeQueriesAsync in server_mode with pandas output\nRESULT_COUNT: {len(result)}", is_valid_dataframe, True) - class PyStackQLServerModeNonAsyncTests(PyStackQLTestsBase): @pystackql_test_setup(server_mode=True)