From 61af7729feb92a97a5e73567da8fc9bffab4d808 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 13:22:02 +0530 Subject: [PATCH 01/21] Added a workflow to parallelise the E2E tests. Updated E2E tests to create new table names for each run to avoid issue in parallelisation --- .../coverage-check-dynamic-e2e-parallel.yml | 178 ++++++++++++++++++ tests/e2e/test_complex_types.py | 20 +- tests/e2e/test_parameterized_queries.py | 16 +- tests/e2e/test_variant_types.py | 11 +- 4 files changed, 207 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/coverage-check-dynamic-e2e-parallel.yml diff --git a/.github/workflows/coverage-check-dynamic-e2e-parallel.yml b/.github/workflows/coverage-check-dynamic-e2e-parallel.yml new file mode 100644 index 000000000..61e0ea8ee --- /dev/null +++ b/.github/workflows/coverage-check-dynamic-e2e-parallel.yml @@ -0,0 +1,178 @@ +name: Code Coverage (Dynamic E2E Tests - SEA & Thrift) + +permissions: + contents: read + +on: [pull_request, workflow_dispatch] + +jobs: + discover-tests: + runs-on: ubuntu-latest + outputs: + test-files: ${{ steps.discover.outputs.test-files }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + + - name: Discover test files + id: discover + run: | + # Find all test files in e2e directory and create JSON array + TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') + echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT + echo "Discovered test files: $TEST_FILES" + + e2e-tests: + runs-on: ubuntu-latest + environment: azure-prod + needs: discover-tests + strategy: + matrix: + test_file: ${{ fromJson(needs.discover-tests.outputs.test-files) }} + mode: ["thrift", "sea"] + env: + DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} + DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }} + DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} + DATABRICKS_CATALOG: peco + DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction --all-extras + + - name: Run ${{ matrix.mode }} tests for ${{ matrix.test_file }} + run: | + echo "Running ${{ matrix.mode }} tests for ${{ matrix.test_file }}" + + # Set test filter based on mode + if [ "${{ matrix.mode }}" = "sea" ]; then + TEST_FILTER="-k 'extra_params1 or extra_params2'" + else + TEST_FILTER="-k 'extra_params0 or not extra_params'" + fi + + TEST_NAME=$(basename "${{ matrix.test_file }}" .py) + COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" + + poetry run pytest "${{ matrix.test_file }}" $TEST_FILTER \ + --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ + -v + continue-on-error: true + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-$(basename "${{ matrix.test_file }}" .py)-${{ matrix.mode }} + path: | + .coverage + coverage-*-${{ matrix.mode }}.xml + + merge-coverage: + runs-on: ubuntu-latest + needs: [e2e-tests] + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction --all-extras + + - name: Download all coverage artifacts + uses: actions/download-artifact@v4 + with: + path: coverage_files + + - name: Merge coverage + run: | + # Install xmllint if not available + if ! command -v xmllint &> /dev/null; then + sudo apt-get update && sudo apt-get install -y libxml2-utils + fi + + # Copy all coverage files with unique names + for artifact_dir in coverage_files/*/; do + if [ -f "$artifact_dir/.coverage" ]; then + artifact_name=$(basename "$artifact_dir") + cp "$artifact_dir/.coverage" ".coverage.$artifact_name" + fi + done + + # Combine all coverage data + poetry run coverage combine .coverage.* + poetry run coverage xml + poetry run coverage report + + - name: Report coverage percentage + run: | + COVERAGE_FILE="coverage.xml" + if [ ! -f "$COVERAGE_FILE" ]; then + echo "ERROR: Coverage file not found at $COVERAGE_FILE" + exit 1 + fi + + COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "$COVERAGE_FILE") + TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "$COVERAGE_FILE") + + # Calculate percentage using Python for precision + PERCENTAGE=$(python3 -c "covered=${COVERED}; total=${TOTAL}; print(round((covered/total)*100, 2))") + + echo "๐Ÿ“Š Combined Coverage: ${PERCENTAGE}%" diff --git a/tests/e2e/test_complex_types.py b/tests/e2e/test_complex_types.py index 212ddf916..d075a5670 100644 --- a/tests/e2e/test_complex_types.py +++ b/tests/e2e/test_complex_types.py @@ -1,6 +1,7 @@ import pytest from numpy import ndarray from typing import Sequence +from uuid import uuid4 from tests.e2e.test_driver import PySQLPytestTestCase @@ -10,12 +11,15 @@ class TestComplexTypes(PySQLPytestTestCase): def table_fixture(self, connection_details): self.arguments = connection_details.copy() """A pytest fixture that creates a table with a complex type, inserts a record, yields, and then drops the table""" + + table_name = f"pysql_test_complex_types_table_{str(uuid4()).replace('-', '_')}" + self.table_name = table_name with self.cursor() as cursor: # Create the table cursor.execute( - """ - CREATE TABLE IF NOT EXISTS pysql_test_complex_types_table ( + f""" + CREATE TABLE IF NOT EXISTS {table_name} ( array_col ARRAY, map_col MAP, struct_col STRUCT, @@ -27,8 +31,8 @@ def table_fixture(self, connection_details): ) # Insert a record cursor.execute( - """ - INSERT INTO pysql_test_complex_types_table + f""" + INSERT INTO {table_name} VALUES ( ARRAY('a', 'b', 'c'), MAP('a', 1, 'b', 2, 'c', 3), @@ -40,10 +44,10 @@ def table_fixture(self, connection_details): """ ) try: - yield + yield table_name finally: # Clean up the table after the test - cursor.execute("DELETE FROM pysql_test_complex_types_table") + cursor.execute(f"DROP TABLE IF EXISTS {table_name}") @pytest.mark.parametrize( "field,expected_type", @@ -61,7 +65,7 @@ def test_read_complex_types_as_arrow(self, field, expected_type, table_fixture): with self.cursor() as cursor: result = cursor.execute( - "SELECT * FROM pysql_test_complex_types_table LIMIT 1" + f"SELECT * FROM {table_fixture} LIMIT 1" ).fetchone() assert isinstance(result[field], expected_type) @@ -83,7 +87,7 @@ def test_read_complex_types_as_string(self, field, table_fixture): extra_params={"_use_arrow_native_complex_types": False} ) as cursor: result = cursor.execute( - "SELECT * FROM pysql_test_complex_types_table LIMIT 1" + f"SELECT * FROM {table_fixture} LIMIT 1" ).fetchone() assert isinstance(result[field], str) diff --git a/tests/e2e/test_parameterized_queries.py b/tests/e2e/test_parameterized_queries.py index 79def9b72..9dba2ff5c 100644 --- a/tests/e2e/test_parameterized_queries.py +++ b/tests/e2e/test_parameterized_queries.py @@ -4,6 +4,7 @@ from enum import Enum from typing import Dict, List, Type, Union from unittest.mock import patch +from uuid import uuid4 import time import numpy as np @@ -130,9 +131,13 @@ def inline_table(self, connection_details): Note that this fixture doesn't clean itself up. So the table will remain in the schema for use by subsequent test runs. """ + + # Generate unique table name to avoid conflicts in parallel execution + table_name = f"pysql_e2e_inline_param_test_table_{str(uuid4()).replace('-', '_')}" + self.inline_table_name = table_name - query = """ - CREATE TABLE IF NOT EXISTS pysql_e2e_inline_param_test_table ( + query = f""" + CREATE TABLE IF NOT EXISTS {table_name} ( null_col INT, int_col INT, bigint_col BIGINT, @@ -179,9 +184,10 @@ def _inline_roundtrip(self, params: dict, paramstyle: ParamStyle, target_column) :paramstyle: This is a no-op but is included to make the test-code easier to read. """ - INSERT_QUERY = f"INSERT INTO pysql_e2e_inline_param_test_table (`{target_column}`) VALUES (%(p)s)" - SELECT_QUERY = f"SELECT {target_column} `col` FROM pysql_e2e_inline_param_test_table LIMIT 1" - DELETE_QUERY = "DELETE FROM pysql_e2e_inline_param_test_table" + table_name = self.inline_table_name + INSERT_QUERY = f"INSERT INTO {table_name} (`{target_column}`) VALUES (%(p)s)" + SELECT_QUERY = f"SELECT {target_column} `col` FROM {table_name} LIMIT 1" + DELETE_QUERY = f"DELETE FROM {table_name}" with self.connection(extra_params={"use_inline_params": True}) as conn: with conn.cursor() as cursor: diff --git a/tests/e2e/test_variant_types.py b/tests/e2e/test_variant_types.py index b5dc1f421..351f2ed61 100644 --- a/tests/e2e/test_variant_types.py +++ b/tests/e2e/test_variant_types.py @@ -1,6 +1,7 @@ import pytest from datetime import datetime import json +from uuid import uuid4 try: import pyarrow @@ -19,14 +20,14 @@ class TestVariantTypes(PySQLPytestTestCase): def variant_table(self, connection_details): """A pytest fixture that creates a test table and cleans up after tests""" self.arguments = connection_details.copy() - table_name = "pysql_test_variant_types_table" + table_name = f"pysql_test_variant_types_table_{str(uuid4()).replace('-', '_')}" with self.cursor() as cursor: try: # Create the table with variant columns cursor.execute( - """ - CREATE TABLE IF NOT EXISTS pysql_test_variant_types_table ( + f""" + CREATE TABLE IF NOT EXISTS {table_name} ( id INTEGER, variant_col VARIANT, regular_string_col STRING @@ -36,8 +37,8 @@ def variant_table(self, connection_details): # Insert test records with different variant values cursor.execute( - """ - INSERT INTO pysql_test_variant_types_table + f""" + INSERT INTO {table_name} VALUES (1, PARSE_JSON('{"name": "John", "age": 30}'), 'regular string'), (2, PARSE_JSON('[1, 2, 3, 4]'), 'another string') From 1417f6b6b6c271590ef22150bee947363c49e1a0 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 13:25:26 +0530 Subject: [PATCH 02/21] Modified parallel code coverage workflow to fail when e2e tests fail --- .github/workflows/coverage-check-dynamic-e2e-parallel.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage-check-dynamic-e2e-parallel.yml b/.github/workflows/coverage-check-dynamic-e2e-parallel.yml index 61e0ea8ee..761d70e48 100644 --- a/.github/workflows/coverage-check-dynamic-e2e-parallel.yml +++ b/.github/workflows/coverage-check-dynamic-e2e-parallel.yml @@ -1,4 +1,4 @@ -name: Code Coverage (Dynamic E2E Tests - SEA & Thrift) +name: Parallel Code Coverage permissions: contents: read @@ -92,7 +92,7 @@ jobs: poetry run pytest "${{ matrix.test_file }}" $TEST_FILTER \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ -v - continue-on-error: true + continue-on-error: false - name: Upload coverage artifact uses: actions/upload-artifact@v4 From bf24771bfb073335017ae195f5c210c3210ee555 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 13:34:06 +0530 Subject: [PATCH 03/21] Fixed parallel coverage check pytest command --- ...namic-e2e-parallel.yml => coverage-check-parallel.yml} | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) rename .github/workflows/{coverage-check-dynamic-e2e-parallel.yml => coverage-check-parallel.yml} (95%) diff --git a/.github/workflows/coverage-check-dynamic-e2e-parallel.yml b/.github/workflows/coverage-check-parallel.yml similarity index 95% rename from .github/workflows/coverage-check-dynamic-e2e-parallel.yml rename to .github/workflows/coverage-check-parallel.yml index 761d70e48..52103ffe7 100644 --- a/.github/workflows/coverage-check-dynamic-e2e-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -81,15 +81,17 @@ jobs: # Set test filter based on mode if [ "${{ matrix.mode }}" = "sea" ]; then - TEST_FILTER="-k 'extra_params1 or extra_params2'" + TEST_FILTER="-k" + TEST_EXPRESSION="extra_params1 or extra_params2" else - TEST_FILTER="-k 'extra_params0 or not extra_params'" + TEST_FILTER="-k" + TEST_EXPRESSION="extra_params0 or not extra_params" fi TEST_NAME=$(basename "${{ matrix.test_file }}" .py) COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" - poetry run pytest "${{ matrix.test_file }}" $TEST_FILTER \ + poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ -v continue-on-error: false From 4bbc653ff4ddf9be9178d21f3f1c87134a302719 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 14:12:33 +0530 Subject: [PATCH 04/21] Modified e2e tests to support parallel execution --- tests/e2e/test_parameterized_queries.py | 42 +++++++++++++++---------- tests/e2e/test_variant_types.py | 2 +- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/e2e/test_parameterized_queries.py b/tests/e2e/test_parameterized_queries.py index 9dba2ff5c..6fda5136b 100644 --- a/tests/e2e/test_parameterized_queries.py +++ b/tests/e2e/test_parameterized_queries.py @@ -119,23 +119,8 @@ class TestParameterizedQueries(PySQLPytestTestCase): def _get_inline_table_column(self, value): return self.inline_type_map[Primitive(value)] - @pytest.fixture(scope="class") - def inline_table(self, connection_details): - self.arguments = connection_details.copy() - """This table is necessary to verify that a parameter sent with INLINE - approach can actually write to its analogous data type. - - For example, a Python Decimal(), when rendered inline, should be able - to read/write into a DECIMAL column in Databricks - - Note that this fixture doesn't clean itself up. So the table will remain - in the schema for use by subsequent test runs. - """ - - # Generate unique table name to avoid conflicts in parallel execution - table_name = f"pysql_e2e_inline_param_test_table_{str(uuid4()).replace('-', '_')}" - self.inline_table_name = table_name - + def _create_inline_table(self, table_name): + """Create the inline test table with all necessary columns""" query = f""" CREATE TABLE IF NOT EXISTS {table_name} ( null_col INT, @@ -160,6 +145,24 @@ def inline_table(self, connection_details): with conn.cursor() as cursor: cursor.execute(query) + @pytest.fixture(scope="class") + def inline_table(self, connection_details): + self.arguments = connection_details.copy() + """This table is necessary to verify that a parameter sent with INLINE + approach can actually write to its analogous data type. + + For example, a Python Decimal(), when rendered inline, should be able + to read/write into a DECIMAL column in Databricks + + Note that this fixture doesn't clean itself up. So the table will remain + in the schema for use by subsequent test runs. + """ + + # Generate unique table name to avoid conflicts in parallel execution + table_name = f"pysql_e2e_inline_param_test_table_{str(uuid4()).replace('-', '_')}" + self.inline_table_name = table_name + self._create_inline_table(table_name) + @contextmanager def patch_server_supports_native_params(self, supports_native_params: bool = True): """Applies a patch so we can test the connector's behaviour under different SPARK_CLI_SERVICE_PROTOCOL_VERSION conditions.""" @@ -184,6 +187,11 @@ def _inline_roundtrip(self, params: dict, paramstyle: ParamStyle, target_column) :paramstyle: This is a no-op but is included to make the test-code easier to read. """ + if not hasattr(self, 'inline_table_name'): + table_name = f"pysql_e2e_inline_param_test_table_{str(uuid4()).replace('-', '_')}" + self.inline_table_name = table_name + self._create_inline_table(table_name) + table_name = self.inline_table_name INSERT_QUERY = f"INSERT INTO {table_name} (`{target_column}`) VALUES (%(p)s)" SELECT_QUERY = f"SELECT {target_column} `col` FROM {table_name} LIMIT 1" diff --git a/tests/e2e/test_variant_types.py b/tests/e2e/test_variant_types.py index 351f2ed61..14be3aa3d 100644 --- a/tests/e2e/test_variant_types.py +++ b/tests/e2e/test_variant_types.py @@ -40,7 +40,7 @@ def variant_table(self, connection_details): f""" INSERT INTO {table_name} VALUES - (1, PARSE_JSON('{"name": "John", "age": 30}'), 'regular string'), + (1, PARSE_JSON('{{\"name\": \"John\", \"age\": 30}}'), 'regular string'), (2, PARSE_JSON('[1, 2, 3, 4]'), 'another string') """ ) From 7ef1033184e46a34383d8162199d4fa530514a83 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 14:19:34 +0530 Subject: [PATCH 05/21] Added fallbacks for exit code 5 where we find no test for SEA --- .github/workflows/coverage-check-parallel.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 52103ffe7..07305e30c 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -93,16 +93,17 @@ jobs: poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ - -v - continue-on-error: false + -v || [ $? -eq 5 ] - name: Upload coverage artifact uses: actions/upload-artifact@v4 + if: always() with: name: coverage-$(basename "${{ matrix.test_file }}" .py)-${{ matrix.mode }} path: | .coverage coverage-*-${{ matrix.mode }}.xml + if-no-files-found: warn merge-coverage: runs-on: ubuntu-latest @@ -158,10 +159,10 @@ jobs: fi done - # Combine all coverage data - poetry run coverage combine .coverage.* - poetry run coverage xml - poetry run coverage report + # Combine all coverage data (ignore if no files found) + poetry run coverage combine .coverage.* 2>/dev/null || true + poetry run coverage xml 2>/dev/null || echo '' > coverage.xml + poetry run coverage report 2>/dev/null || true - name: Report coverage percentage run: | From d21f214a229c0264b171d4329460ce9194995ccb Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 14:22:28 +0530 Subject: [PATCH 06/21] Fixed coverage artifact for parallel test workflow --- .github/workflows/coverage-check-parallel.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 07305e30c..6ce5aea80 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -90,6 +90,7 @@ jobs: TEST_NAME=$(basename "${{ matrix.test_file }}" .py) COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" + echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ @@ -99,7 +100,7 @@ jobs: uses: actions/upload-artifact@v4 if: always() with: - name: coverage-$(basename "${{ matrix.test_file }}" .py)-${{ matrix.mode }} + name: coverage-${{ env.TEST_NAME }}-${{ matrix.mode }} path: | .coverage coverage-*-${{ matrix.mode }}.xml From 9cb8999c68d49ad005b1778b0189423029637256 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 15:30:57 +0530 Subject: [PATCH 07/21] Debugging coverage check merge --- .github/workflows/coverage-check-parallel.yml | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 6ce5aea80..78678ece0 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -95,6 +95,11 @@ jobs: poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ -v || [ $? -eq 5 ] + + # Ensure .coverage file exists for merging (even if empty) + if [ ! -f ".coverage" ]; then + touch .coverage + fi - name: Upload coverage artifact uses: actions/upload-artifact@v4 @@ -153,13 +158,24 @@ jobs: fi # Copy all coverage files with unique names + echo "๐Ÿ“ Checking for coverage files in artifacts..." for artifact_dir in coverage_files/*/; do - if [ -f "$artifact_dir/.coverage" ]; then - artifact_name=$(basename "$artifact_dir") - cp "$artifact_dir/.coverage" ".coverage.$artifact_name" + if [ -d "$artifact_dir" ]; then + echo "Artifact: $(basename "$artifact_dir")" + ls -la "$artifact_dir" || echo " (empty or inaccessible)" + if [ -f "$artifact_dir/.coverage" ]; then + artifact_name=$(basename "$artifact_dir") + cp "$artifact_dir/.coverage" ".coverage.$artifact_name" + echo " โœ… Copied .coverage file" + else + echo " โš ๏ธ No .coverage file found" + fi fi done + echo "Available .coverage files for merging:" + ls -la .coverage.* 2>/dev/null || echo "No .coverage.* files found" + # Combine all coverage data (ignore if no files found) poetry run coverage combine .coverage.* 2>/dev/null || true poetry run coverage xml 2>/dev/null || echo '' > coverage.xml From 59e83abd65da2aaf6280249969a99d37cd47abe0 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 18:18:04 +0530 Subject: [PATCH 08/21] Improved coverage report merge and removed the test_driver test for faster testing --- .github/workflows/coverage-check-parallel.yml | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 78678ece0..b569df3a4 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -21,8 +21,8 @@ jobs: - name: Discover test files id: discover run: | - # Find all test files in e2e directory and create JSON array - TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') + # Find all test files in e2e directory and create JSON array (excluding test_driver.py for now) + TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | grep -v test_driver.py | sort | jq -R -s -c 'split("\n")[:-1]') echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT echo "Discovered test files: $TEST_FILES" @@ -90,16 +90,25 @@ jobs: TEST_NAME=$(basename "${{ matrix.test_file }}" .py) COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" + COVERAGE_DATA=".coverage-${TEST_NAME}-${{ matrix.mode }}" echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ - --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term \ + --cov=src --cov-append --cov-report=xml:$COVERAGE_FILE --cov-report=term \ -v || [ $? -eq 5 ] # Ensure .coverage file exists for merging (even if empty) - if [ ! -f ".coverage" ]; then - touch .coverage + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + echo "โœ… Saved coverage data as $COVERAGE_DATA" + else + echo "โš ๏ธ No .coverage generated, creating empty file" + touch "$COVERAGE_DATA" fi + + # Debug: Show what files we have for upload + echo "๐Ÿ“ Files available for upload:" + ls -la .coverage* 2>/dev/null || echo "No coverage files found" - name: Upload coverage artifact uses: actions/upload-artifact@v4 @@ -107,7 +116,7 @@ jobs: with: name: coverage-${{ env.TEST_NAME }}-${{ matrix.mode }} path: | - .coverage + .coverage-* coverage-*-${{ matrix.mode }}.xml if-no-files-found: warn @@ -163,23 +172,21 @@ jobs: if [ -d "$artifact_dir" ]; then echo "Artifact: $(basename "$artifact_dir")" ls -la "$artifact_dir" || echo " (empty or inaccessible)" - if [ -f "$artifact_dir/.coverage" ]; then - artifact_name=$(basename "$artifact_dir") - cp "$artifact_dir/.coverage" ".coverage.$artifact_name" - echo " โœ… Copied .coverage file" - else - echo " โš ๏ธ No .coverage file found" - fi + for cov_file in "$artifact_dir"/.coverage-*; do + if [ -f "$cov_file" ]; then + cp "$cov_file" . + echo " โœ… Copied $(basename "$cov_file")" + fi + done fi done - + echo "Available .coverage files for merging:" - ls -la .coverage.* 2>/dev/null || echo "No .coverage.* files found" - - # Combine all coverage data (ignore if no files found) - poetry run coverage combine .coverage.* 2>/dev/null || true - poetry run coverage xml 2>/dev/null || echo '' > coverage.xml - poetry run coverage report 2>/dev/null || true + ls -la .coverage-* 2>/dev/null || echo "No .coverage-* files found" + + poetry run coverage combine .coverage-* || true + poetry run coverage xml || echo '' > coverage.xml + poetry run coverage report || true - name: Report coverage percentage run: | From 271ecac0acde08c55c0428160c00a5168435ed52 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 18:59:00 +0530 Subject: [PATCH 09/21] Debug commit for coverage merge --- .github/workflows/coverage-check-parallel.yml | 95 +++++++++++++++---- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index b569df3a4..cc056d2b9 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -79,7 +79,6 @@ jobs: run: | echo "Running ${{ matrix.mode }} tests for ${{ matrix.test_file }}" - # Set test filter based on mode if [ "${{ matrix.mode }}" = "sea" ]; then TEST_FILTER="-k" TEST_EXPRESSION="extra_params1 or extra_params2" @@ -93,12 +92,23 @@ jobs: COVERAGE_DATA=".coverage-${TEST_NAME}-${{ matrix.mode }}" echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV + # Clean any previous coverage data to avoid conflicts + rm -f .coverage* + + echo "๐Ÿงช Running pytest with coverage..." poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ - --cov=src --cov-append --cov-report=xml:$COVERAGE_FILE --cov-report=term \ - -v || [ $? -eq 5 ] + --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v || [ $? -eq 5 ] + + echo "๐Ÿ” DEBUG: Post-test file analysis..." + echo "Current directory contents:" + ls -la + + echo "Coverage-related files:" + ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" - # Ensure .coverage file exists for merging (even if empty) if [ -f ".coverage" ]; then + COVERAGE_SIZE=$(stat -c%s .coverage 2>/dev/null || stat -f%z .coverage) + echo "โœ… .coverage file found (${COVERAGE_SIZE} bytes)" mv .coverage "$COVERAGE_DATA" echo "โœ… Saved coverage data as $COVERAGE_DATA" else @@ -106,9 +116,17 @@ jobs: touch "$COVERAGE_DATA" fi - # Debug: Show what files we have for upload - echo "๐Ÿ“ Files available for upload:" - ls -la .coverage* 2>/dev/null || echo "No coverage files found" + if [ -f "$COVERAGE_FILE" ]; then + XML_SIZE=$(stat -c%s "$COVERAGE_FILE" 2>/dev/null || stat -f%z "$COVERAGE_FILE") + echo "โœ… XML coverage file found: $COVERAGE_FILE (${XML_SIZE} bytes)" + echo "XML preview:" + head -3 "$COVERAGE_FILE" 2>/dev/null || echo "Cannot read XML file" + else + echo "โŒ No XML coverage file generated: $COVERAGE_FILE" + fi + + echo "๐Ÿ“ Final files available for upload:" + ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" - name: Upload coverage artifact uses: actions/upload-artifact@v4 @@ -161,32 +179,78 @@ jobs: - name: Merge coverage run: | - # Install xmllint if not available + echo "๐Ÿ”ง Installing xmllint..." if ! command -v xmllint &> /dev/null; then sudo apt-get update && sudo apt-get install -y libxml2-utils fi - # Copy all coverage files with unique names + echo "๐Ÿ“ DEBUG: Checking downloaded artifacts structure..." + find coverage_files -type f -name "*" | head -20 + echo "Total files found: $(find coverage_files -type f | wc -l)" + echo "๐Ÿ“ Checking for coverage files in artifacts..." + COVERAGE_FILES_FOUND=0 for artifact_dir in coverage_files/*/; do if [ -d "$artifact_dir" ]; then - echo "Artifact: $(basename "$artifact_dir")" + echo "๐Ÿ” Artifact: $(basename "$artifact_dir")" + echo " Contents:" ls -la "$artifact_dir" || echo " (empty or inaccessible)" + + # Copy .coverage files for cov_file in "$artifact_dir"/.coverage-*; do if [ -f "$cov_file" ]; then cp "$cov_file" . - echo " โœ… Copied $(basename "$cov_file")" + COVERAGE_FILES_FOUND=$((COVERAGE_FILES_FOUND + 1)) + echo " โœ… Copied $(basename "$cov_file") ($(stat -c%s "$cov_file" 2>/dev/null || stat -f%z "$cov_file") bytes)" + fi + done + + # Copy XML files for debugging + for xml_file in "$artifact_dir"/coverage-*.xml; do + if [ -f "$xml_file" ]; then + cp "$xml_file" . + echo " ๐Ÿ“„ Copied $(basename "$xml_file") ($(stat -c%s "$xml_file" 2>/dev/null || stat -f%z "$xml_file") bytes)" fi done fi done + echo "๐Ÿ“Š SUMMARY: Found $COVERAGE_FILES_FOUND .coverage files" echo "Available .coverage files for merging:" - ls -la .coverage-* 2>/dev/null || echo "No .coverage-* files found" + ls -la .coverage-* 2>/dev/null || echo "โŒ No .coverage-* files found" + + echo "Available XML files:" + ls -la coverage-*.xml 2>/dev/null || echo "โŒ No XML files found" - poetry run coverage combine .coverage-* || true - poetry run coverage xml || echo '' > coverage.xml - poetry run coverage report || true + if [ $COVERAGE_FILES_FOUND -gt 0 ]; then + echo "๐Ÿ”„ Combining coverage data..." + poetry run coverage combine .coverage-* || { + echo "โŒ Coverage combine failed, checking individual files:" + for f in .coverage-*; do + if [ -f "$f" ]; then + echo " File: $f ($(stat -c%s "$f" 2>/dev/null || stat -f%z "$f") bytes)" + file "$f" 2>/dev/null || echo " Cannot determine file type" + fi + done + echo "โš ๏ธ Using fallback approach..." + touch .coverage + } + + echo "๐Ÿ“Š Generating XML report..." + poetry run coverage xml || { + echo "โŒ XML generation failed, using fallback" + echo '' > coverage.xml + } + + echo "๐Ÿ“‹ Generating text report..." + poetry run coverage report || echo "โš ๏ธ Text report failed" + else + echo "โš ๏ธ No coverage data files found, creating empty report" + echo '' > coverage.xml + fi + + echo "๐Ÿ“„ Final coverage.xml preview:" + head -5 coverage.xml 2>/dev/null || echo "Cannot read coverage.xml" - name: Report coverage percentage run: | @@ -199,7 +263,6 @@ jobs: COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "$COVERAGE_FILE") TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "$COVERAGE_FILE") - # Calculate percentage using Python for precision PERCENTAGE=$(python3 -c "covered=${COVERED}; total=${TOTAL}; print(round((covered/total)*100, 2))") echo "๐Ÿ“Š Combined Coverage: ${PERCENTAGE}%" From b6ac8cb336b7fe13d3dcd5a887c3760d213a1248 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 19:12:13 +0530 Subject: [PATCH 10/21] Debugging coverage merge 2 --- .github/workflows/coverage-check-parallel.yml | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index cc056d2b9..9e7e13938 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -21,8 +21,8 @@ jobs: - name: Discover test files id: discover run: | - # Find all test files in e2e directory and create JSON array (excluding test_driver.py for now) - TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | grep -v test_driver.py | sort | jq -R -s -c 'split("\n")[:-1]') + # Find all test files in e2e directory and create JSON array (excluding test_driver.py and test_parameterized_queries.py for now) + TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | grep -v -E "(test_driver\.py|test_parameterized_queries\.py)" | sort | jq -R -s -c 'split("\n")[:-1]') echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT echo "Discovered test files: $TEST_FILES" @@ -112,8 +112,18 @@ jobs: mv .coverage "$COVERAGE_DATA" echo "โœ… Saved coverage data as $COVERAGE_DATA" else - echo "โš ๏ธ No .coverage generated, creating empty file" - touch "$COVERAGE_DATA" + echo "โš ๏ธ No .coverage generated, creating minimal coverage file" + # Create a minimal but valid coverage file using coverage.py + poetry run coverage erase + poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + echo "โœ… Created minimal coverage file as $COVERAGE_DATA" + else + # Fallback: create empty file (will be handled gracefully in merge) + touch "$COVERAGE_DATA" + echo "โš ๏ธ Created empty placeholder as $COVERAGE_DATA" + fi fi if [ -f "$COVERAGE_FILE" ]; then @@ -127,6 +137,22 @@ jobs: echo "๐Ÿ“ Final files available for upload:" ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" + + echo "๐Ÿ” Specifically checking for files to upload:" + echo " .coverage-* files:" + ls -la .coverage-* 2>/dev/null || echo " None found" + echo " coverage-*-${{ matrix.mode }}.xml files:" + ls -la coverage-*-${{ matrix.mode }}.xml 2>/dev/null || echo " None found" + + echo "๐Ÿ” CRITICAL DEBUG: Checking exact upload patterns:" + echo " Pattern '.coverage-*' matches:" + find . -maxdepth 1 -name ".coverage-*" -type f 2>/dev/null || echo " No matches" + echo " Pattern 'coverage-*-${{ matrix.mode }}.xml' matches:" + find . -maxdepth 1 -name "coverage-*-${{ matrix.mode }}.xml" -type f 2>/dev/null || echo " No matches" + + echo "๐Ÿ” Working directory: $(pwd)" + echo "๐Ÿ” All files in current directory:" + ls -la - name: Upload coverage artifact uses: actions/upload-artifact@v4 From 1c2f238fb5fc8c279afdd53170c9219c5ce31879 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 19:17:37 +0530 Subject: [PATCH 11/21] Debugging coverage merge 3 --- .github/workflows/coverage-check-parallel.yml | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 9e7e13938..9a6455a75 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -89,7 +89,7 @@ jobs: TEST_NAME=$(basename "${{ matrix.test_file }}" .py) COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" - COVERAGE_DATA=".coverage-${TEST_NAME}-${{ matrix.mode }}" + COVERAGE_DATA="coverage-data-${TEST_NAME}-${{ matrix.mode }}" echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV # Clean any previous coverage data to avoid conflicts @@ -139,14 +139,14 @@ jobs: ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" echo "๐Ÿ” Specifically checking for files to upload:" - echo " .coverage-* files:" - ls -la .coverage-* 2>/dev/null || echo " None found" + echo " coverage-data-* files:" + ls -la coverage-data-* 2>/dev/null || echo " None found" echo " coverage-*-${{ matrix.mode }}.xml files:" ls -la coverage-*-${{ matrix.mode }}.xml 2>/dev/null || echo " None found" echo "๐Ÿ” CRITICAL DEBUG: Checking exact upload patterns:" - echo " Pattern '.coverage-*' matches:" - find . -maxdepth 1 -name ".coverage-*" -type f 2>/dev/null || echo " No matches" + echo " Pattern 'coverage-data-*' matches:" + find . -maxdepth 1 -name "coverage-data-*" -type f 2>/dev/null || echo " No matches" echo " Pattern 'coverage-*-${{ matrix.mode }}.xml' matches:" find . -maxdepth 1 -name "coverage-*-${{ matrix.mode }}.xml" -type f 2>/dev/null || echo " No matches" @@ -160,7 +160,7 @@ jobs: with: name: coverage-${{ env.TEST_NAME }}-${{ matrix.mode }} path: | - .coverage-* + coverage-data-* coverage-*-${{ matrix.mode }}.xml if-no-files-found: warn @@ -222,8 +222,8 @@ jobs: echo " Contents:" ls -la "$artifact_dir" || echo " (empty or inaccessible)" - # Copy .coverage files - for cov_file in "$artifact_dir"/.coverage-*; do + # Copy coverage data files + for cov_file in "$artifact_dir"/coverage-data-*; do if [ -f "$cov_file" ]; then cp "$cov_file" . COVERAGE_FILES_FOUND=$((COVERAGE_FILES_FOUND + 1)) @@ -241,18 +241,29 @@ jobs: fi done - echo "๐Ÿ“Š SUMMARY: Found $COVERAGE_FILES_FOUND .coverage files" - echo "Available .coverage files for merging:" - ls -la .coverage-* 2>/dev/null || echo "โŒ No .coverage-* files found" + echo "๐Ÿ“Š SUMMARY: Found $COVERAGE_FILES_FOUND coverage data files" + echo "Available coverage data files for merging:" + ls -la coverage-data-* 2>/dev/null || echo "โŒ No coverage-data-* files found" echo "Available XML files:" ls -la coverage-*.xml 2>/dev/null || echo "โŒ No XML files found" if [ $COVERAGE_FILES_FOUND -gt 0 ]; then echo "๐Ÿ”„ Combining coverage data..." - poetry run coverage combine .coverage-* || { + + # Rename coverage-data-* files to .coverage format for combining + for f in coverage-data-*; do + if [ -f "$f" ]; then + # Extract the suffix and create .coverage.suffix format + suffix=$(echo "$f" | sed 's/coverage-data-/.coverage./') + mv "$f" "$suffix" + echo " ๐Ÿ“ Renamed $f to $suffix" + fi + done + + poetry run coverage combine .coverage.* || { echo "โŒ Coverage combine failed, checking individual files:" - for f in .coverage-*; do + for f in .coverage.*; do if [ -f "$f" ]; then echo " File: $f ($(stat -c%s "$f" 2>/dev/null || stat -f%z "$f") bytes)" file "$f" 2>/dev/null || echo " Cannot determine file type" From 3657fbd78281abf398ad04bdd9fcc9a43761617c Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 19:28:19 +0530 Subject: [PATCH 12/21] Removed unnecessary debug statements from the parallel code coverage workflow --- .github/workflows/coverage-check-parallel.yml | 128 +++--------------- 1 file changed, 21 insertions(+), 107 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 9a6455a75..f8eebde00 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -21,8 +21,8 @@ jobs: - name: Discover test files id: discover run: | - # Find all test files in e2e directory and create JSON array (excluding test_driver.py and test_parameterized_queries.py for now) - TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | grep -v -E "(test_driver\.py|test_parameterized_queries\.py)" | sort | jq -R -s -c 'split("\n")[:-1]') + # Find all test files in e2e directory + TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT echo "Discovered test files: $TEST_FILES" @@ -95,64 +95,25 @@ jobs: # Clean any previous coverage data to avoid conflicts rm -f .coverage* - echo "๐Ÿงช Running pytest with coverage..." + echo "Running pytest with coverage..." poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v || [ $? -eq 5 ] - echo "๐Ÿ” DEBUG: Post-test file analysis..." - echo "Current directory contents:" - ls -la - - echo "Coverage-related files:" - ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" - + # Save coverage data with unique name if [ -f ".coverage" ]; then - COVERAGE_SIZE=$(stat -c%s .coverage 2>/dev/null || stat -f%z .coverage) - echo "โœ… .coverage file found (${COVERAGE_SIZE} bytes)" mv .coverage "$COVERAGE_DATA" - echo "โœ… Saved coverage data as $COVERAGE_DATA" + echo "Coverage data saved as $COVERAGE_DATA" else - echo "โš ๏ธ No .coverage generated, creating minimal coverage file" - # Create a minimal but valid coverage file using coverage.py + # Create minimal coverage file for cases where no tests run poetry run coverage erase poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true if [ -f ".coverage" ]; then mv .coverage "$COVERAGE_DATA" - echo "โœ… Created minimal coverage file as $COVERAGE_DATA" else - # Fallback: create empty file (will be handled gracefully in merge) touch "$COVERAGE_DATA" - echo "โš ๏ธ Created empty placeholder as $COVERAGE_DATA" fi + echo "Created minimal coverage file as $COVERAGE_DATA" fi - - if [ -f "$COVERAGE_FILE" ]; then - XML_SIZE=$(stat -c%s "$COVERAGE_FILE" 2>/dev/null || stat -f%z "$COVERAGE_FILE") - echo "โœ… XML coverage file found: $COVERAGE_FILE (${XML_SIZE} bytes)" - echo "XML preview:" - head -3 "$COVERAGE_FILE" 2>/dev/null || echo "Cannot read XML file" - else - echo "โŒ No XML coverage file generated: $COVERAGE_FILE" - fi - - echo "๐Ÿ“ Final files available for upload:" - ls -la .coverage* coverage-* 2>/dev/null || echo "No coverage files found" - - echo "๐Ÿ” Specifically checking for files to upload:" - echo " coverage-data-* files:" - ls -la coverage-data-* 2>/dev/null || echo " None found" - echo " coverage-*-${{ matrix.mode }}.xml files:" - ls -la coverage-*-${{ matrix.mode }}.xml 2>/dev/null || echo " None found" - - echo "๐Ÿ” CRITICAL DEBUG: Checking exact upload patterns:" - echo " Pattern 'coverage-data-*' matches:" - find . -maxdepth 1 -name "coverage-data-*" -type f 2>/dev/null || echo " No matches" - echo " Pattern 'coverage-*-${{ matrix.mode }}.xml' matches:" - find . -maxdepth 1 -name "coverage-*-${{ matrix.mode }}.xml" -type f 2>/dev/null || echo " No matches" - - echo "๐Ÿ” Working directory: $(pwd)" - echo "๐Ÿ” All files in current directory:" - ls -la - name: Upload coverage artifact uses: actions/upload-artifact@v4 @@ -205,101 +166,54 @@ jobs: - name: Merge coverage run: | - echo "๐Ÿ”ง Installing xmllint..." + # Install xmllint if not available if ! command -v xmllint &> /dev/null; then sudo apt-get update && sudo apt-get install -y libxml2-utils fi - echo "๐Ÿ“ DEBUG: Checking downloaded artifacts structure..." - find coverage_files -type f -name "*" | head -20 - echo "Total files found: $(find coverage_files -type f | wc -l)" - - echo "๐Ÿ“ Checking for coverage files in artifacts..." + # Copy coverage data files from artifacts COVERAGE_FILES_FOUND=0 for artifact_dir in coverage_files/*/; do if [ -d "$artifact_dir" ]; then - echo "๐Ÿ” Artifact: $(basename "$artifact_dir")" - echo " Contents:" - ls -la "$artifact_dir" || echo " (empty or inaccessible)" - - # Copy coverage data files for cov_file in "$artifact_dir"/coverage-data-*; do if [ -f "$cov_file" ]; then cp "$cov_file" . COVERAGE_FILES_FOUND=$((COVERAGE_FILES_FOUND + 1)) - echo " โœ… Copied $(basename "$cov_file") ($(stat -c%s "$cov_file" 2>/dev/null || stat -f%z "$cov_file") bytes)" - fi - done - - # Copy XML files for debugging - for xml_file in "$artifact_dir"/coverage-*.xml; do - if [ -f "$xml_file" ]; then - cp "$xml_file" . - echo " ๐Ÿ“„ Copied $(basename "$xml_file") ($(stat -c%s "$xml_file" 2>/dev/null || stat -f%z "$xml_file") bytes)" fi done fi done - echo "๐Ÿ“Š SUMMARY: Found $COVERAGE_FILES_FOUND coverage data files" - echo "Available coverage data files for merging:" - ls -la coverage-data-* 2>/dev/null || echo "โŒ No coverage-data-* files found" - - echo "Available XML files:" - ls -la coverage-*.xml 2>/dev/null || echo "โŒ No XML files found" + echo "Found $COVERAGE_FILES_FOUND coverage data files" if [ $COVERAGE_FILES_FOUND -gt 0 ]; then - echo "๐Ÿ”„ Combining coverage data..." + echo "Combining coverage data..." - # Rename coverage-data-* files to .coverage format for combining for f in coverage-data-*; do if [ -f "$f" ]; then - # Extract the suffix and create .coverage.suffix format suffix=$(echo "$f" | sed 's/coverage-data-/.coverage./') mv "$f" "$suffix" - echo " ๐Ÿ“ Renamed $f to $suffix" fi done - poetry run coverage combine .coverage.* || { - echo "โŒ Coverage combine failed, checking individual files:" - for f in .coverage.*; do - if [ -f "$f" ]; then - echo " File: $f ($(stat -c%s "$f" 2>/dev/null || stat -f%z "$f") bytes)" - file "$f" 2>/dev/null || echo " Cannot determine file type" - fi - done - echo "โš ๏ธ Using fallback approach..." - touch .coverage - } - - echo "๐Ÿ“Š Generating XML report..." - poetry run coverage xml || { - echo "โŒ XML generation failed, using fallback" - echo '' > coverage.xml - } - - echo "๐Ÿ“‹ Generating text report..." - poetry run coverage report || echo "โš ๏ธ Text report failed" + # Combine coverage files and generate reports + poetry run coverage combine .coverage.* 2>/dev/null || true + poetry run coverage xml 2>/dev/null || echo '' > coverage.xml + poetry run coverage report 2>/dev/null || true else - echo "โš ๏ธ No coverage data files found, creating empty report" + echo "No coverage data files found, creating empty report" echo '' > coverage.xml fi - - echo "๐Ÿ“„ Final coverage.xml preview:" - head -5 coverage.xml 2>/dev/null || echo "Cannot read coverage.xml" - name: Report coverage percentage run: | - COVERAGE_FILE="coverage.xml" - if [ ! -f "$COVERAGE_FILE" ]; then - echo "ERROR: Coverage file not found at $COVERAGE_FILE" + if [ ! -f "coverage.xml" ]; then + echo "ERROR: Coverage file not found" exit 1 fi - COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "$COVERAGE_FILE") - TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "$COVERAGE_FILE") - + COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "coverage.xml") + TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "coverage.xml") PERCENTAGE=$(python3 -c "covered=${COVERED}; total=${TOTAL}; print(round((covered/total)*100, 2))") - echo "๐Ÿ“Š Combined Coverage: ${PERCENTAGE}%" + echo "Combined Coverage: ${PERCENTAGE}%" From 2b4e2573c2e82823ab9fb744771c3eb33c633d59 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 21:50:24 +0530 Subject: [PATCH 13/21] Added unit test and common e2e tests --- .github/workflows/coverage-check-parallel.yml | 180 +++++++++++++++++- 1 file changed, 175 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index f8eebde00..560b2c469 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -22,9 +22,19 @@ jobs: id: discover run: | # Find all test files in e2e directory - TEST_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') - echo "test-files=$TEST_FILES" >> $GITHUB_OUTPUT - echo "Discovered test files: $TEST_FILES" + E2E_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') + echo "e2e-test-files=$E2E_FILES" >> $GITHUB_OUTPUT + echo "Discovered E2E test files: $E2E_FILES" + + # Find all test files in unit directory + UNIT_FILES=$(find tests/unit -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') + echo "unit-test-files=$UNIT_FILES" >> $GITHUB_OUTPUT + echo "Discovered unit test files: $UNIT_FILES" + + # Find all test files in common directory + COMMON_FILES=$(find tests/e2e/common -name "*.py" -type f | grep -v __init__ | sort | jq -R -s -c 'split("\n")[:-1]') + echo "common-test-files=$COMMON_FILES" >> $GITHUB_OUTPUT + echo "Discovered common test files: $COMMON_FILES" e2e-tests: runs-on: ubuntu-latest @@ -32,7 +42,7 @@ jobs: needs: discover-tests strategy: matrix: - test_file: ${{ fromJson(needs.discover-tests.outputs.test-files) }} + test_file: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files) }} mode: ["thrift", "sea"] env: DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} @@ -125,9 +135,169 @@ jobs: coverage-*-${{ matrix.mode }}.xml if-no-files-found: warn + unit-tests: + runs-on: ubuntu-latest + needs: discover-tests + strategy: + matrix: + test_file: ${{ fromJson(needs.discover-tests.outputs.unit-test-files) }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction --all-extras + + - name: Run unit tests with coverage + run: | + TEST_NAME=$(basename "${{ matrix.test_file }}" .py) + COVERAGE_FILE="coverage-${TEST_NAME}-unit.xml" + COVERAGE_DATA="coverage-data-${TEST_NAME}-unit" + echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV + + # Clean any previous coverage data to avoid conflicts + rm -f .coverage* + + echo "Running unit tests with coverage..." + poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v + + # Save coverage data with unique name + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + echo "Coverage data saved as $COVERAGE_DATA" + else + # Create minimal coverage file for cases where no tests run + poetry run coverage erase + poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + else + touch "$COVERAGE_DATA" + fi + echo "Created minimal coverage file as $COVERAGE_DATA" + fi + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-${{ env.TEST_NAME }}-unit + path: | + coverage-data-* + coverage-*-unit.xml + if-no-files-found: warn + + common-tests: + runs-on: ubuntu-latest + needs: discover-tests + strategy: + matrix: + test_file: ${{ fromJson(needs.discover-tests.outputs.common-test-files) }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + + - name: Install library + run: poetry install --no-interaction --all-extras + + - name: Run common tests with coverage + run: | + TEST_NAME=$(basename "${{ matrix.test_file }}" .py) + COVERAGE_FILE="coverage-${TEST_NAME}-common.xml" + COVERAGE_DATA="coverage-data-${TEST_NAME}-common" + echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV + + # Clean any previous coverage data to avoid conflicts + rm -f .coverage* + + echo "Running common tests with coverage..." + poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v + + # Save coverage data with unique name + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + echo "Coverage data saved as $COVERAGE_DATA" + else + # Create minimal coverage file for cases where no tests run + poetry run coverage erase + poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true + if [ -f ".coverage" ]; then + mv .coverage "$COVERAGE_DATA" + else + touch "$COVERAGE_DATA" + fi + echo "Created minimal coverage file as $COVERAGE_DATA" + fi + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-${{ env.TEST_NAME }}-common + path: | + coverage-data-* + coverage-*-common.xml + if-no-files-found: warn + merge-coverage: runs-on: ubuntu-latest - needs: [e2e-tests] + needs: [e2e-tests, unit-tests, common-tests] steps: - name: Check out repository uses: actions/checkout@v4 From 19407ab9dc7a05f1498d84b0a5705f3102a61fe5 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 22:04:20 +0530 Subject: [PATCH 14/21] Added null checks for coverage workflow --- .github/workflows/coverage-check-parallel.yml | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 560b2c469..ea12b425d 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -22,24 +22,40 @@ jobs: id: discover run: | # Find all test files in e2e directory - E2E_FILES=$(find tests/e2e -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') - echo "e2e-test-files=$E2E_FILES" >> $GITHUB_OUTPUT - echo "Discovered E2E test files: $E2E_FILES" + E2E_FILES=$(find tests/e2e -name "test_*.py" -type f | sort) + if [ -n "$E2E_FILES" ]; then + E2E_JSON=$(echo "$E2E_FILES" | jq -R -s -c 'split("\n")[:-1]') + else + E2E_JSON="[]" + fi + echo "e2e-test-files=$E2E_JSON" >> $GITHUB_OUTPUT + echo "Discovered E2E test files: $E2E_JSON" # Find all test files in unit directory - UNIT_FILES=$(find tests/unit -name "test_*.py" -type f | sort | jq -R -s -c 'split("\n")[:-1]') - echo "unit-test-files=$UNIT_FILES" >> $GITHUB_OUTPUT - echo "Discovered unit test files: $UNIT_FILES" + UNIT_FILES=$(find tests/unit -name "test_*.py" -type f | sort) + if [ -n "$UNIT_FILES" ]; then + UNIT_JSON=$(echo "$UNIT_FILES" | jq -R -s -c 'split("\n")[:-1]') + else + UNIT_JSON="[]" + fi + echo "unit-test-files=$UNIT_JSON" >> $GITHUB_OUTPUT + echo "Discovered unit test files: $UNIT_JSON" # Find all test files in common directory - COMMON_FILES=$(find tests/e2e/common -name "*.py" -type f | grep -v __init__ | sort | jq -R -s -c 'split("\n")[:-1]') - echo "common-test-files=$COMMON_FILES" >> $GITHUB_OUTPUT - echo "Discovered common test files: $COMMON_FILES" + COMMON_FILES=$(find tests/e2e/common -name "*.py" -type f | grep -v __init__ | sort) + if [ -n "$COMMON_FILES" ]; then + COMMON_JSON=$(echo "$COMMON_FILES" | jq -R -s -c 'split("\n")[:-1]') + else + COMMON_JSON="[]" + fi + echo "common-test-files=$COMMON_JSON" >> $GITHUB_OUTPUT + echo "Discovered common test files: $COMMON_JSON" e2e-tests: runs-on: ubuntu-latest environment: azure-prod needs: discover-tests + if: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files)[0] != null }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files) }} @@ -138,6 +154,7 @@ jobs: unit-tests: runs-on: ubuntu-latest needs: discover-tests + if: ${{ fromJson(needs.discover-tests.outputs.unit-test-files)[0] != null }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.unit-test-files) }} @@ -218,6 +235,7 @@ jobs: common-tests: runs-on: ubuntu-latest needs: discover-tests + if: ${{ fromJson(needs.discover-tests.outputs.common-test-files)[0] != null }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.common-test-files) }} @@ -298,6 +316,7 @@ jobs: merge-coverage: runs-on: ubuntu-latest needs: [e2e-tests, unit-tests, common-tests] + if: always() steps: - name: Check out repository uses: actions/checkout@v4 From 6df96bedb1089b93a24dbeffd9b58127d207cc7a Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 22:12:17 +0530 Subject: [PATCH 15/21] Improved the null check for test list --- .github/workflows/coverage-check-parallel.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index ea12b425d..705f4c9cd 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -55,7 +55,7 @@ jobs: runs-on: ubuntu-latest environment: azure-prod needs: discover-tests - if: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files)[0] != null }} + if: ${{ needs.discover-tests.outputs.e2e-test-files != '[]' }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files) }} @@ -154,7 +154,7 @@ jobs: unit-tests: runs-on: ubuntu-latest needs: discover-tests - if: ${{ fromJson(needs.discover-tests.outputs.unit-test-files)[0] != null }} + if: ${{ needs.discover-tests.outputs.unit-test-files != '[]' }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.unit-test-files) }} @@ -235,7 +235,7 @@ jobs: common-tests: runs-on: ubuntu-latest needs: discover-tests - if: ${{ fromJson(needs.discover-tests.outputs.common-test-files)[0] != null }} + if: ${{ needs.discover-tests.outputs.common-test-files != '[]' }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.common-test-files) }} From 602809b8abb0dd967c717e7ef3bacf7ebc54e7fa Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 22:22:32 +0530 Subject: [PATCH 16/21] Improved the visibility for test list --- .github/workflows/coverage-check-parallel.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 705f4c9cd..72447b9c4 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -9,7 +9,9 @@ jobs: discover-tests: runs-on: ubuntu-latest outputs: - test-files: ${{ steps.discover.outputs.test-files }} + e2e-test-files: ${{ steps.discover.outputs.e2e-test-files }} + unit-test-files: ${{ steps.discover.outputs.unit-test-files }} + common-test-files: ${{ steps.discover.outputs.common-test-files }} steps: - name: Check out repository uses: actions/checkout@v4 From b25ed879e761d8924dceffadf25cd7e2dd06364b Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Fri, 3 Oct 2025 22:48:03 +0530 Subject: [PATCH 17/21] Added check for exit code 5 --- .github/workflows/coverage-check-parallel.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml index 72447b9c4..3bd2948a0 100644 --- a/.github/workflows/coverage-check-parallel.yml +++ b/.github/workflows/coverage-check-parallel.yml @@ -236,11 +236,18 @@ jobs: common-tests: runs-on: ubuntu-latest + environment: azure-prod needs: discover-tests if: ${{ needs.discover-tests.outputs.common-test-files != '[]' }} strategy: matrix: test_file: ${{ fromJson(needs.discover-tests.outputs.common-test-files) }} + env: + DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} + DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }} + DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} + DATABRICKS_CATALOG: peco + DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }} steps: - name: Check out repository uses: actions/checkout@v4 @@ -287,7 +294,7 @@ jobs: rm -f .coverage* echo "Running common tests with coverage..." - poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v + poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v || [ $? -eq 5 ] # Save coverage data with unique name if [ -f ".coverage" ]; then From 45ef85aec3eb2611f0ecbd23b6844a0d29aa57b5 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Thu, 9 Oct 2025 15:25:15 +0530 Subject: [PATCH 18/21] Updated the workflowfor coverage check to use pytst -xdist to run the tests parallely --- .github/workflows/code-coverage.yml | 136 ++++++ .github/workflows/coverage-check-parallel.yml | 417 ------------------ pyproject.toml | 1 + 3 files changed, 137 insertions(+), 417 deletions(-) create mode 100644 .github/workflows/code-coverage.yml delete mode 100644 .github/workflows/coverage-check-parallel.yml diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 000000000..e85a8e887 --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,136 @@ +name: Code Coverage + +permissions: + contents: read + +on: [pull_request, workflow_dispatch] + +jobs: + test-with-coverage: + runs-on: ubuntu-latest + environment: azure-prod + env: + DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} + DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }} + DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} + DATABRICKS_CATALOG: peco + DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }} + steps: + #---------------------------------------------- + # check-out repo and set-up python + #---------------------------------------------- + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + #---------------------------------------------- + # ----- install & configure poetry ----- + #---------------------------------------------- + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + #---------------------------------------------- + # load cached venv if cache exists + #---------------------------------------------- + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} + #---------------------------------------------- + # install dependencies if cache does not exist + #---------------------------------------------- + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + #---------------------------------------------- + # install your root project, if required + #---------------------------------------------- + - name: Install library + run: poetry install --no-interaction --all-extras + #---------------------------------------------- + # run all tests in parallel with xdist + #---------------------------------------------- + - name: Run all tests with coverage using pytest-xdist + continue-on-error: true + run: | + poetry run pytest tests/unit tests/e2e \ + -n auto \ + --cov=src \ + --cov-report=xml \ + --cov-report=term \ + -v + + #---------------------------------------------- + # check for coverage override + #---------------------------------------------- + - name: Check for coverage override + id: override + run: | + OVERRIDE_COMMENT=$(echo "${{ github.event.pull_request.body }}" | grep -E "SKIP_COVERAGE_CHECK\s*=" || echo "") + if [ -n "$OVERRIDE_COMMENT" ]; then + echo "override=true" >> $GITHUB_OUTPUT + REASON=$(echo "$OVERRIDE_COMMENT" | sed -E 's/.*SKIP_COVERAGE_CHECK\s*=\s*(.+)/\1/') + echo "reason=$REASON" >> $GITHUB_OUTPUT + echo "Coverage override found in PR description: $REASON" + else + echo "override=false" >> $GITHUB_OUTPUT + echo "No coverage override found" + fi + #---------------------------------------------- + # check coverage percentage + #---------------------------------------------- + - name: Check coverage percentage + if: steps.override.outputs.override == 'false' + run: | + COVERAGE_FILE="coverage.xml" + if [ ! -f "$COVERAGE_FILE" ]; then + echo "ERROR: Coverage file not found at $COVERAGE_FILE" + exit 1 + fi + + # Install xmllint if not available + if ! command -v xmllint &> /dev/null; then + sudo apt-get update && sudo apt-get install -y libxml2-utils + fi + + COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "$COVERAGE_FILE") + TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "$COVERAGE_FILE") + PERCENTAGE=$(python3 -c "covered=${COVERED}; total=${TOTAL}; print(round((covered/total)*100, 2))") + + echo "Branch Coverage: $PERCENTAGE%" + echo "Required Coverage: 85%" + + # Use Python to compare the coverage with 85 + python3 -c "import sys; sys.exit(0 if float('$PERCENTAGE') >= 85 else 1)" + if [ $? -eq 1 ]; then + echo "ERROR: Coverage is $PERCENTAGE%, which is less than the required 85%" + exit 1 + else + echo "SUCCESS: Coverage is $PERCENTAGE%, which meets the required 85%" + fi + + #---------------------------------------------- + # coverage enforcement summary + #---------------------------------------------- + - name: Coverage enforcement summary + run: | + if [ "${{ steps.override.outputs.override }}" == "true" ]; then + echo "โš ๏ธ Coverage checks bypassed: ${{ steps.override.outputs.reason }}" + echo "Please ensure this override is justified and temporary" + else + echo "โœ… Coverage checks enforced - minimum 85% required" + fi + diff --git a/.github/workflows/coverage-check-parallel.yml b/.github/workflows/coverage-check-parallel.yml deleted file mode 100644 index 3bd2948a0..000000000 --- a/.github/workflows/coverage-check-parallel.yml +++ /dev/null @@ -1,417 +0,0 @@ -name: Parallel Code Coverage - -permissions: - contents: read - -on: [pull_request, workflow_dispatch] - -jobs: - discover-tests: - runs-on: ubuntu-latest - outputs: - e2e-test-files: ${{ steps.discover.outputs.e2e-test-files }} - unit-test-files: ${{ steps.discover.outputs.unit-test-files }} - common-test-files: ${{ steps.discover.outputs.common-test-files }} - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref || github.ref_name }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - - - name: Discover test files - id: discover - run: | - # Find all test files in e2e directory - E2E_FILES=$(find tests/e2e -name "test_*.py" -type f | sort) - if [ -n "$E2E_FILES" ]; then - E2E_JSON=$(echo "$E2E_FILES" | jq -R -s -c 'split("\n")[:-1]') - else - E2E_JSON="[]" - fi - echo "e2e-test-files=$E2E_JSON" >> $GITHUB_OUTPUT - echo "Discovered E2E test files: $E2E_JSON" - - # Find all test files in unit directory - UNIT_FILES=$(find tests/unit -name "test_*.py" -type f | sort) - if [ -n "$UNIT_FILES" ]; then - UNIT_JSON=$(echo "$UNIT_FILES" | jq -R -s -c 'split("\n")[:-1]') - else - UNIT_JSON="[]" - fi - echo "unit-test-files=$UNIT_JSON" >> $GITHUB_OUTPUT - echo "Discovered unit test files: $UNIT_JSON" - - # Find all test files in common directory - COMMON_FILES=$(find tests/e2e/common -name "*.py" -type f | grep -v __init__ | sort) - if [ -n "$COMMON_FILES" ]; then - COMMON_JSON=$(echo "$COMMON_FILES" | jq -R -s -c 'split("\n")[:-1]') - else - COMMON_JSON="[]" - fi - echo "common-test-files=$COMMON_JSON" >> $GITHUB_OUTPUT - echo "Discovered common test files: $COMMON_JSON" - - e2e-tests: - runs-on: ubuntu-latest - environment: azure-prod - needs: discover-tests - if: ${{ needs.discover-tests.outputs.e2e-test-files != '[]' }} - strategy: - matrix: - test_file: ${{ fromJson(needs.discover-tests.outputs.e2e-test-files) }} - mode: ["thrift", "sea"] - env: - DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} - DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }} - DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} - DATABRICKS_CATALOG: peco - DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }} - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref || github.ref_name }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction --all-extras - - - name: Run ${{ matrix.mode }} tests for ${{ matrix.test_file }} - run: | - echo "Running ${{ matrix.mode }} tests for ${{ matrix.test_file }}" - - if [ "${{ matrix.mode }}" = "sea" ]; then - TEST_FILTER="-k" - TEST_EXPRESSION="extra_params1 or extra_params2" - else - TEST_FILTER="-k" - TEST_EXPRESSION="extra_params0 or not extra_params" - fi - - TEST_NAME=$(basename "${{ matrix.test_file }}" .py) - COVERAGE_FILE="coverage-${TEST_NAME}-${{ matrix.mode }}.xml" - COVERAGE_DATA="coverage-data-${TEST_NAME}-${{ matrix.mode }}" - echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV - - # Clean any previous coverage data to avoid conflicts - rm -f .coverage* - - echo "Running pytest with coverage..." - poetry run pytest "${{ matrix.test_file }}" "$TEST_FILTER" "$TEST_EXPRESSION" \ - --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v || [ $? -eq 5 ] - - # Save coverage data with unique name - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - echo "Coverage data saved as $COVERAGE_DATA" - else - # Create minimal coverage file for cases where no tests run - poetry run coverage erase - poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - else - touch "$COVERAGE_DATA" - fi - echo "Created minimal coverage file as $COVERAGE_DATA" - fi - - - name: Upload coverage artifact - uses: actions/upload-artifact@v4 - if: always() - with: - name: coverage-${{ env.TEST_NAME }}-${{ matrix.mode }} - path: | - coverage-data-* - coverage-*-${{ matrix.mode }}.xml - if-no-files-found: warn - - unit-tests: - runs-on: ubuntu-latest - needs: discover-tests - if: ${{ needs.discover-tests.outputs.unit-test-files != '[]' }} - strategy: - matrix: - test_file: ${{ fromJson(needs.discover-tests.outputs.unit-test-files) }} - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref || github.ref_name }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction --all-extras - - - name: Run unit tests with coverage - run: | - TEST_NAME=$(basename "${{ matrix.test_file }}" .py) - COVERAGE_FILE="coverage-${TEST_NAME}-unit.xml" - COVERAGE_DATA="coverage-data-${TEST_NAME}-unit" - echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV - - # Clean any previous coverage data to avoid conflicts - rm -f .coverage* - - echo "Running unit tests with coverage..." - poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v - - # Save coverage data with unique name - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - echo "Coverage data saved as $COVERAGE_DATA" - else - # Create minimal coverage file for cases where no tests run - poetry run coverage erase - poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - else - touch "$COVERAGE_DATA" - fi - echo "Created minimal coverage file as $COVERAGE_DATA" - fi - - - name: Upload coverage artifact - uses: actions/upload-artifact@v4 - if: always() - with: - name: coverage-${{ env.TEST_NAME }}-unit - path: | - coverage-data-* - coverage-*-unit.xml - if-no-files-found: warn - - common-tests: - runs-on: ubuntu-latest - environment: azure-prod - needs: discover-tests - if: ${{ needs.discover-tests.outputs.common-test-files != '[]' }} - strategy: - matrix: - test_file: ${{ fromJson(needs.discover-tests.outputs.common-test-files) }} - env: - DATABRICKS_SERVER_HOSTNAME: ${{ secrets.DATABRICKS_HOST }} - DATABRICKS_HTTP_PATH: ${{ secrets.TEST_PECO_WAREHOUSE_HTTP_PATH }} - DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }} - DATABRICKS_CATALOG: peco - DATABRICKS_USER: ${{ secrets.TEST_PECO_SP_ID }} - steps: - - name: Check out repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.ref || github.ref_name }} - repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction --all-extras - - - name: Run common tests with coverage - run: | - TEST_NAME=$(basename "${{ matrix.test_file }}" .py) - COVERAGE_FILE="coverage-${TEST_NAME}-common.xml" - COVERAGE_DATA="coverage-data-${TEST_NAME}-common" - echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV - - # Clean any previous coverage data to avoid conflicts - rm -f .coverage* - - echo "Running common tests with coverage..." - poetry run pytest "${{ matrix.test_file }}" --cov=src --cov-report=xml:$COVERAGE_FILE --cov-report=term -v || [ $? -eq 5 ] - - # Save coverage data with unique name - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - echo "Coverage data saved as $COVERAGE_DATA" - else - # Create minimal coverage file for cases where no tests run - poetry run coverage erase - poetry run coverage run --source=src -m pytest --version > /dev/null 2>&1 || true - if [ -f ".coverage" ]; then - mv .coverage "$COVERAGE_DATA" - else - touch "$COVERAGE_DATA" - fi - echo "Created minimal coverage file as $COVERAGE_DATA" - fi - - - name: Upload coverage artifact - uses: actions/upload-artifact@v4 - if: always() - with: - name: coverage-${{ env.TEST_NAME }}-common - path: | - coverage-data-* - coverage-*-common.xml - if-no-files-found: warn - - merge-coverage: - runs-on: ubuntu-latest - needs: [e2e-tests, unit-tests, common-tests] - if: always() - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: "3.10" - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ github.event.repository.name }}-${{ hashFiles('**/poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction --no-root - - - name: Install library - run: poetry install --no-interaction --all-extras - - - name: Download all coverage artifacts - uses: actions/download-artifact@v4 - with: - path: coverage_files - - - name: Merge coverage - run: | - # Install xmllint if not available - if ! command -v xmllint &> /dev/null; then - sudo apt-get update && sudo apt-get install -y libxml2-utils - fi - - # Copy coverage data files from artifacts - COVERAGE_FILES_FOUND=0 - for artifact_dir in coverage_files/*/; do - if [ -d "$artifact_dir" ]; then - for cov_file in "$artifact_dir"/coverage-data-*; do - if [ -f "$cov_file" ]; then - cp "$cov_file" . - COVERAGE_FILES_FOUND=$((COVERAGE_FILES_FOUND + 1)) - fi - done - fi - done - - echo "Found $COVERAGE_FILES_FOUND coverage data files" - - if [ $COVERAGE_FILES_FOUND -gt 0 ]; then - echo "Combining coverage data..." - - for f in coverage-data-*; do - if [ -f "$f" ]; then - suffix=$(echo "$f" | sed 's/coverage-data-/.coverage./') - mv "$f" "$suffix" - fi - done - - # Combine coverage files and generate reports - poetry run coverage combine .coverage.* 2>/dev/null || true - poetry run coverage xml 2>/dev/null || echo '' > coverage.xml - poetry run coverage report 2>/dev/null || true - else - echo "No coverage data files found, creating empty report" - echo '' > coverage.xml - fi - - - name: Report coverage percentage - run: | - if [ ! -f "coverage.xml" ]; then - echo "ERROR: Coverage file not found" - exit 1 - fi - - COVERED=$(xmllint --xpath "string(//coverage/@lines-covered)" "coverage.xml") - TOTAL=$(xmllint --xpath "string(//coverage/@lines-valid)" "coverage.xml") - PERCENTAGE=$(python3 -c "covered=${COVERED}; total=${TOTAL}; print(round((covered/total)*100, 2))") - - echo "Combined Coverage: ${PERCENTAGE}%" diff --git a/pyproject.toml b/pyproject.toml index a1f43bc70..4e6af7d1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ pylint = ">=2.12.0" black = "^22.3.0" pytest-dotenv = "^0.5.2" pytest-cov = "^4.0.0" +pytest-xdist = "^3.0.0" numpy = [ { version = ">=1.16.6", python = ">=3.8,<3.11" }, { version = ">=1.23.4", python = ">=3.11" }, From 0e1033adb58e7defa5964c5a734eb1e05fb00625 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Thu, 9 Oct 2025 15:26:37 +0530 Subject: [PATCH 19/21] Enforced the e2e tests should pass --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e85a8e887..8f491220f 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -64,7 +64,7 @@ jobs: # run all tests in parallel with xdist #---------------------------------------------- - name: Run all tests with coverage using pytest-xdist - continue-on-error: true + continue-on-error: false run: | poetry run pytest tests/unit tests/e2e \ -n auto \ From dac7c557fa59390259c2c59c2b3e7fc923471e18 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Thu, 9 Oct 2025 15:27:08 +0530 Subject: [PATCH 20/21] Changed name for workflow job --- .github/workflows/code-coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 8f491220f..d9954d051 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -61,9 +61,9 @@ jobs: - name: Install library run: poetry install --no-interaction --all-extras #---------------------------------------------- - # run all tests in parallel with xdist + # run all tests with coverage #---------------------------------------------- - - name: Run all tests with coverage using pytest-xdist + - name: Run all tests with coverage continue-on-error: false run: | poetry run pytest tests/unit tests/e2e \ From bf0a2454c6a736e1eed3d9426d4cece2afee4ae8 Mon Sep 17 00:00:00 2001 From: Madhavendra Rathore Date: Thu, 9 Oct 2025 15:31:52 +0530 Subject: [PATCH 21/21] Updated poetry --- poetry.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5fd216330..1a8074c2a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -70,7 +70,7 @@ description = "Foreign Function Interface for Python calling C code." optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and platform_python_implementation != \"PyPy\"" +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -475,7 +475,7 @@ description = "cryptography is a package which provides cryptographic recipes an optional = true python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.10\" and extra == \"true\"" +markers = "python_version < \"3.10\"" files = [ {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, @@ -526,7 +526,7 @@ description = "cryptography is a package which provides cryptographic recipes an optional = true python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["main"] -markers = "python_version >= \"3.10\" and extra == \"true\"" +markers = "python_version >= \"3.10\"" files = [ {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, @@ -587,7 +587,7 @@ description = "Decorators for Humans" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and sys_platform != \"win32\"" +markers = "sys_platform != \"win32\"" files = [ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, @@ -637,6 +637,21 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "gssapi" version = "1.9.0" @@ -644,7 +659,7 @@ description = "Python GSSAPI Wrapper" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and sys_platform != \"win32\"" +markers = "sys_platform != \"win32\"" files = [ {file = "gssapi-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:261e00ac426d840055ddb2199f4989db7e3ce70fa18b1538f53e392b4823e8f1"}, {file = "gssapi-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:14a1ae12fdf1e4c8889206195ba1843de09fe82587fa113112887cd5894587c6"}, @@ -725,7 +740,7 @@ description = "Kerberos API bindings for Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and sys_platform != \"win32\"" +markers = "sys_platform != \"win32\"" files = [ {file = "krb5-0.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cbdcd2c4514af5ca32d189bc31f30fee2ab297dcbff74a53bd82f92ad1f6e0ef"}, {file = "krb5-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40ad837d563865946cffd65a588f24876da2809aa5ce4412de49442d7cf11d50"}, @@ -1340,7 +1355,7 @@ description = "C parser in Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and platform_python_implementation != \"PyPy\"" +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1422,7 +1437,6 @@ description = "Windows Negotiate Authentication Client and Server" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\"" files = [ {file = "pyspnego-0.11.2-py3-none-any.whl", hash = "sha256:74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4"}, {file = "pyspnego-0.11.2.tar.gz", hash = "sha256:994388d308fb06e4498365ce78d222bf4f3570b6df4ec95738431f61510c971b"}, @@ -1496,6 +1510,50 @@ files = [ pytest = ">=5.0.0" python-dotenv = ">=0.9.1" +[[package]] +name = "pytest-xdist" +version = "3.6.1" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.10\"" +files = [ + {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, + {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1567,7 +1625,6 @@ description = "A Kerberos authentication handler for python-requests" optional = true python-versions = ">=3.6" groups = ["main"] -markers = "extra == \"true\"" files = [ {file = "requests_kerberos-0.15.0-py2.py3-none-any.whl", hash = "sha256:ba9b0980b8489c93bfb13854fd118834e576d6700bfea3745cb2e62278cd16a6"}, {file = "requests_kerberos-0.15.0.tar.gz", hash = "sha256:437512e424413d8113181d696e56694ffa4259eb9a5fc4e803926963864eaf4e"}, @@ -1597,7 +1654,7 @@ description = "SSPI API bindings for Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"true\" and sys_platform == \"win32\" and python_version < \"3.10\"" +markers = "python_version < \"3.10\" and sys_platform == \"win32\"" files = [ {file = "sspilib-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:34f566ba8b332c91594e21a71200de2d4ce55ca5a205541d4128ed23e3c98777"}, {file = "sspilib-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b11e4f030de5c5de0f29bcf41a6e87c9fd90cb3b0f64e446a6e1d1aef4d08f5"}, @@ -1644,7 +1701,7 @@ description = "SSPI API bindings for Python" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"true\" and sys_platform == \"win32\" and python_version >= \"3.10\"" +markers = "python_version >= \"3.10\" and sys_platform == \"win32\"" files = [ {file = "sspilib-0.3.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c45860bdc4793af572d365434020ff5a1ef78c42a2fc2c7a7d8e44eacaf475b6"}, {file = "sspilib-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:62cc4de547503dec13b81a6af82b398e9ef53ea82c3535418d7d069c7a05d5cd"}, @@ -1797,9 +1854,8 @@ zstd = ["zstandard (>=0.18.0)"] [extras] pyarrow = ["pyarrow", "pyarrow"] -true = ["requests-kerberos"] [metadata] lock-version = "2.1" python-versions = "^3.8.0" -content-hash = "ddc7354d47a940fa40b4d34c43a1c42488b01258d09d771d58d64a0dfaf0b955" +content-hash = "0a3f611ef8747376f018c1df0a1ea7873368851873cc4bd3a4d51bba0bba847c"