From f261d17d62f7fd435879d001506095a9dee5f504 Mon Sep 17 00:00:00 2001 From: Mike Alfare <13974384+mikealfare@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:20:51 -0400 Subject: [PATCH 1/5] Remove `freezegun` as a test dependency since it is not used (#875) * remove `freezegun` as a test dependency since it is not used --- .changes/unreleased/Under the Hood-20240719-133151.yaml | 6 ++++++ dev-requirements.txt | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changes/unreleased/Under the Hood-20240719-133151.yaml diff --git a/.changes/unreleased/Under the Hood-20240719-133151.yaml b/.changes/unreleased/Under the Hood-20240719-133151.yaml new file mode 100644 index 000000000..b67ac6cea --- /dev/null +++ b/.changes/unreleased/Under the Hood-20240719-133151.yaml @@ -0,0 +1,6 @@ +kind: Under the Hood +body: Remove `freezegun` as a testing dependency; this package is no longer used +time: 2024-07-19T13:31:51.503575-04:00 +custom: + Author: mikealfare + Issue: "1136" diff --git a/dev-requirements.txt b/dev-requirements.txt index d7e570f92..c82ea37ca 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -12,7 +12,6 @@ pre-commit~=3.5.0;python_version <"3.9" # test ddtrace==2.3.0 -freezegun~=1.4 pytest~=7.4 pytest-csv~=3.0 pytest-dotenv~=0.5.2 From a1f33db1806a24993df071859497f918d2c6767e Mon Sep 17 00:00:00 2001 From: Mila Page <67295367+VersusFacit@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:21:25 -0700 Subject: [PATCH 2/5] Adap 821/unit tests infer wrong datatype for None values in fixtures (#885) * Add test to confirm upstream handling * Add changelog. * Add another test. * standardize names to reflect python objects. * revert dev requirements. * Add the macro for the row checking. * Test for user facing exception thrown in base adapter with new redshift macor. * revert the dev requirements --------- Co-authored-by: Mila Page Co-authored-by: Mike Alfare <13974384+mikealfare@users.noreply.github.com> --- .../unreleased/Fixes-20240625-170324.yaml | 7 ++ .../redshift/macros/adapters/unit_testing.sql | 11 +++ .../adapter/unit_testing/fixtures.py | 73 +++++++++++++++++++ .../adapter/unit_testing/test_unit_testing.py | 64 ++++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 .changes/unreleased/Fixes-20240625-170324.yaml create mode 100644 dbt/include/redshift/macros/adapters/unit_testing.sql create mode 100644 tests/functional/adapter/unit_testing/fixtures.py diff --git a/.changes/unreleased/Fixes-20240625-170324.yaml b/.changes/unreleased/Fixes-20240625-170324.yaml new file mode 100644 index 000000000..316a92b95 --- /dev/null +++ b/.changes/unreleased/Fixes-20240625-170324.yaml @@ -0,0 +1,7 @@ +kind: Fixes +body: 'Handle unit test fixtures where typing goes wrong from first value in column + being Null. ' +time: 2024-06-25T17:03:24.73937-07:00 +custom: + Author: versusfacit + Issue: "821" diff --git a/dbt/include/redshift/macros/adapters/unit_testing.sql b/dbt/include/redshift/macros/adapters/unit_testing.sql new file mode 100644 index 000000000..5463f4e2b --- /dev/null +++ b/dbt/include/redshift/macros/adapters/unit_testing.sql @@ -0,0 +1,11 @@ +{%- macro redshift__validate_fixture_rows(rows, row_number) -%} + {%- if rows is not none and rows|length > 0 -%} + {%- set row = rows[0] -%} + {%- for key, value in row.items() -%} + {%- if value is none -%} + {%- set fixture_name = "expected output" if model.resource_type == 'unit_test' else ("'" ~ model.name ~ "'") -%} + {{ exceptions.raise_compiler_error("Unit test fixture " ~ fixture_name ~ " in " ~ model.name ~ " does not have any row free of null values, which may cause type mismatch errors during unit test execution.") }} + {%- endif -%} + {%- endfor -%} + {%- endif -%} +{%- endmacro -%} diff --git a/tests/functional/adapter/unit_testing/fixtures.py b/tests/functional/adapter/unit_testing/fixtures.py new file mode 100644 index 000000000..36212dff3 --- /dev/null +++ b/tests/functional/adapter/unit_testing/fixtures.py @@ -0,0 +1,73 @@ +model_none_value_base = """ +{{ config(materialized="table") }} + +select 1 as id, 'a' as col1 +""" + +model_none_value_model = """ +{{config(materialized="table")}} + +select * from {{ ref('none_value_base') }} +""" + + +test_none_column_value_doesnt_throw_error_csv = """ +unit_tests: + - name: test_simple + + model: none_value_model + given: + - input: ref('none_value_base') + format: csv + rows: | + id,col1 + ,d + ,e + 6,f + + expect: + format: csv + rows: | + id,col1 + ,d + ,e + 6,f +""" + +test_none_column_value_doesnt_throw_error_dct = """ +unit_tests: + - name: test_simple + + model: none_value_model + given: + - input: ref('none_value_base') + rows: + - { "id": , "col1": "d"} + - { "id": , "col1": "e"} + - { "id": 6, "col1": "f"} + + expect: + rows: + - {id: , "col1": "d"} + - {id: , "col1": "e"} + - {id: 6, "col1": "f"} +""" + +test_none_column_value_will_throw_error = """ +unit_tests: + - name: test_simple + + model: none_value_model + given: + - input: ref('none_value_base') + rows: + - { "id": , "col1": "d"} + - { "id": , "col1": "e"} + - { "id": 6, "col1": } + + expect: + rows: + - {id: , "col1": "d"} + - {id: , "col1": "e"} + - {id: 6, "col1": } +""" diff --git a/tests/functional/adapter/unit_testing/test_unit_testing.py b/tests/functional/adapter/unit_testing/test_unit_testing.py index 4d89c4b08..27ed54cb6 100644 --- a/tests/functional/adapter/unit_testing/test_unit_testing.py +++ b/tests/functional/adapter/unit_testing/test_unit_testing.py @@ -1,7 +1,21 @@ import pytest + +from dbt.artifacts.schemas.results import RunStatus +from dbt.tests.fixtures.project import write_project_files +from dbt.tests.util import run_dbt + from dbt.tests.adapter.unit_testing.test_types import BaseUnitTestingTypes from dbt.tests.adapter.unit_testing.test_case_insensitivity import BaseUnitTestCaseInsensivity from dbt.tests.adapter.unit_testing.test_invalid_input import BaseUnitTestInvalidInput +from tests.functional.adapter.unit_testing.fixtures import ( + model_none_value_base, + model_none_value_model, + test_none_column_value_doesnt_throw_error_csv, + test_none_column_value_doesnt_throw_error_dct, + test_none_column_value_will_throw_error, +) + +from dbt_common.exceptions import CompilationError class TestRedshiftUnitTestingTypes(BaseUnitTestingTypes): @@ -34,6 +48,56 @@ def data_types(self): ] +class RedshiftUnitTestingNone: + def test_nones_handled_dict(self, project): + run_dbt(["build"]) + + +class TestRedshiftUnitTestCsvNone(RedshiftUnitTestingNone): + @pytest.fixture(scope="class") + def models(self): + return { + "none_value_base.sql": model_none_value_base, + "none_value_model.sql": model_none_value_model, + "__properties.yml": test_none_column_value_doesnt_throw_error_csv, + } + + +class TestRedshiftUnitTestDictNone(RedshiftUnitTestingNone): + @pytest.fixture(scope="class") + def models(self): + return { + "none_value_base.sql": model_none_value_base, + "none_value_model.sql": model_none_value_model, + "__properties.yml": test_none_column_value_doesnt_throw_error_dct, + } + + +class TestRedshiftUnitTestingTooManyNonesFails: + @pytest.fixture(scope="class") + def models(self): + return { + "__properties.yml": test_none_column_value_will_throw_error, + "none_value_base.sql": model_none_value_base, + "none_value_model.sql": model_none_value_model, + } + + def test_invalid_input(self, project): + """This is a user-facing exception, so we can't pytest.raise(CompilationError)""" + + def _find_first_error(items): + return next((item for item in items if item.status == RunStatus.Error), None) + + run_result = run_dbt(["build"], expect_pass=False) + first_item = _find_first_error(run_result) + + assert first_item is not None + assert ( + "does not have any row free of null values, which may cause type mismatch errors during unit test execution" + in str(first_item.message) + ) + + class TestRedshiftUnitTestCaseInsensitivity(BaseUnitTestCaseInsensivity): pass From 5c6c2bbae197a021c779a5c3a6a5d237c93cb867 Mon Sep 17 00:00:00 2001 From: Mila Page <67295367+VersusFacit@users.noreply.github.com> Date: Thu, 25 Jul 2024 06:09:23 -0700 Subject: [PATCH 3/5] Add support for 3.12 in workflow files and configs. (#886) Co-authored-by: Mila Page --- .github/workflows/integration.yml | 4 +++- .github/workflows/main.yml | 4 ++-- .pre-commit-config.yaml | 1 + setup.py | 1 + tox.ini | 6 +++--- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index b05fcb00d..5a320e258 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -76,6 +76,8 @@ jobs: python-version: "3.10" - os: ubuntu-22.04 python-version: "3.11" + - os: ubuntu-22.04 + python-version: "3.12" env: TOXENV: integration-redshift @@ -201,7 +203,7 @@ jobs: fail-fast: false max-parallel: 1 matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] env: TOXENV: integration-redshift diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e21d453fe..5acb4f7b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,7 +70,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] env: TOXENV: "unit" @@ -174,7 +174,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-12, windows-2022] - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] steps: - name: Set up Python ${{ matrix.python-version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ae249943d..a46d0f050 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,6 +27,7 @@ repos: - --target-version=py39 - --target-version=py310 - --target-version=py311 + - --target-version=py312 - repo: https://github.com/pycqa/flake8 rev: 7.0.0 diff --git a/setup.py b/setup.py index 036ac30fb..712da3870 100644 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ def _plugin_version() -> str: "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], python_requires=">=3.8", ) diff --git a/tox.ini b/tox.ini index 462bc8f07..fafa867a3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] skipsdist = True -envlist = py38,py39,py310,py311 +envlist = py38,py39,py310,py311,py312 -[testenv:{unit,py38,py39,py310,py311,py}] +[testenv:{unit,py38,py39,py310,py311,py312,py}] description = unit testing skip_install = true passenv = @@ -13,7 +13,7 @@ deps = -rdev-requirements.txt -e. -[testenv:{integration,py38,py39,py310,py311,py}-{redshift}] +[testenv:{integration,py38,py39,py310,py311,py312,py}-{redshift}] description = adapter plugin integration testing skip_install = true passenv = From b18b5556a64524c452df9ef10874763ff82dcdf8 Mon Sep 17 00:00:00 2001 From: Mike Alfare <13974384+mikealfare@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:42:08 -0400 Subject: [PATCH 4/5] make dependabot less aggressive (#878) --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ae2be43aa..746dcae22 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,13 +5,25 @@ updates: schedule: interval: "daily" rebase-strategy: "disabled" + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-patch - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" rebase-strategy: "disabled" + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-patch - package-ecosystem: "docker" directory: "/docker" schedule: interval: "weekly" rebase-strategy: "disabled" + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-patch From 38fd49a2c8abacae285c3eb4102a11444cd9fd9a Mon Sep 17 00:00:00 2001 From: Gerda Shank Date: Wed, 31 Jul 2024 21:54:08 -0400 Subject: [PATCH 5/5] Integration workflow update to support all-in-one adapter testing (#889) --- .github/scripts/update_dbt_core_branch.sh | 20 ----- .../scripts/update_dev_dependency_branches.sh | 21 +++++ .github/workflows/integration.yml | 80 ++++++++++++++----- dev-requirements.txt | 2 +- 4 files changed, 84 insertions(+), 39 deletions(-) delete mode 100755 .github/scripts/update_dbt_core_branch.sh create mode 100755 .github/scripts/update_dev_dependency_branches.sh diff --git a/.github/scripts/update_dbt_core_branch.sh b/.github/scripts/update_dbt_core_branch.sh deleted file mode 100755 index d28a40c35..000000000 --- a/.github/scripts/update_dbt_core_branch.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e -set -e - -git_branch=$1 -target_req_file="dev-requirements.txt" -core_req_sed_pattern="s|dbt-core.git.*#egg=dbt-core|dbt-core.git@${git_branch}#egg=dbt-core|g" -postgres_req_sed_pattern="s|dbt-core.git.*#egg=dbt-postgres|dbt-core.git@${git_branch}#egg=dbt-postgres|g" -tests_req_sed_pattern="s|dbt-core.git.*#egg=dbt-tests|dbt-core.git@${git_branch}#egg=dbt-tests|g" -if [[ "$OSTYPE" == darwin* ]]; then - # mac ships with a different version of sed that requires a delimiter arg - sed -i "" "$core_req_sed_pattern" $target_req_file - sed -i "" "$postgres_req_sed_pattern" $target_req_file - sed -i "" "$tests_req_sed_pattern" $target_req_file -else - sed -i "$core_req_sed_pattern" $target_req_file - sed -i "$postgres_req_sed_pattern" $target_req_file - sed -i "$tests_req_sed_pattern" $target_req_file -fi -core_version=$(curl "https://raw.githubusercontent.com/dbt-labs/dbt-core/${git_branch}/core/dbt/version.py" | grep "__version__ = *"|cut -d'=' -f2) -bumpversion --allow-dirty --new-version "$core_version" major diff --git a/.github/scripts/update_dev_dependency_branches.sh b/.github/scripts/update_dev_dependency_branches.sh new file mode 100755 index 000000000..022df6a8a --- /dev/null +++ b/.github/scripts/update_dev_dependency_branches.sh @@ -0,0 +1,21 @@ +#!/bin/bash -e +set -e + + +dbt_adapters_branch=$1 +dbt_core_branch=$2 +dbt_common_branch=$3 +target_req_file="dev-requirements.txt" +core_req_sed_pattern="s|dbt-core.git.*#egg=dbt-core|dbt-core.git@${dbt_core_branch}#egg=dbt-core|g" +adapters_req_sed_pattern="s|dbt-adapters.git|dbt-adapters.git@${dbt_adapters_branch}|g" +common_req_sed_pattern="s|dbt-common.git|dbt-common.git@${dbt_common_branch}|g" +if [[ "$OSTYPE" == darwin* ]]; then + # mac ships with a different version of sed that requires a delimiter arg + sed -i "" "$adapters_req_sed_pattern" $target_req_file + sed -i "" "$core_req_sed_pattern" $target_req_file + sed -i "" "$common_req_sed_pattern" $target_req_file +else + sed -i "$adapters_req_sed_pattern" $target_req_file + sed -i "$core_req_sed_pattern" $target_req_file + sed -i "$common_req_sed_pattern" $target_req_file +fi diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 5a320e258..4d6bbd8d9 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -20,6 +20,8 @@ name: Adapter Integration Tests +run-name: "${{ (contains(github.event_name, 'workflow_') && inputs.name) || github.event_name }}: ${{ (contains(github.event_name, 'workflow_') && inputs.adapter_branch) || github.ref_name }} by @${{ github.actor }}" + on: # pushes to release branches push: @@ -34,10 +36,31 @@ on: # manual trigger workflow_dispatch: inputs: - dbt-core-branch: - description: "branch of dbt-core to use in dev-requirements.txt" + name: + description: "Name to associate with run (example: 'dbt-adapters-242')" + required: false + type: string + default: "Adapter Integration Tests" + adapter_branch: + description: "The branch of this adapter repository to use" + type: string + required: false + default: "main" + dbt_adapters_branch: + description: "The branch of dbt-adapters to use" + type: string required: false + default: "main" + dbt_core_branch: + description: "The branch of dbt-core to use" type: string + required: false + default: "main" + dbt_common_branch: + description: "The branch of dbt-common to use" + type: string + required: false + default: "main" # explicitly turn off permissions for `GITHUB_TOKEN` permissions: read-all @@ -90,13 +113,20 @@ jobs: DD_SERVICE: ${{ github.event.repository.name }} steps: - - name: Check out the repository - if: github.event_name != 'pull_request_target' + - name: Check out the repository (push) + if: github.event_name == 'push' + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Check out the repository (workflow_dispatch) + if: github.event_name == 'workflow_dispatch' uses: actions/checkout@v4 with: persist-credentials: false + ref: ${{ inputs.adapter_branch }} - # explicity checkout the branch for the PR, + # explicitly checkout the branch for the PR, # this is necessary for the `pull_request_target` event - name: Check out the repository (PR) if: github.event_name == 'pull_request_target' @@ -110,6 +140,15 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Update Adapters and Core branches (update dev_requirements.txt) + if: github.event_name == 'workflow_dispatch' + run: | + ./.github/scripts/update_dev_dependency_branches.sh \ + ${{ inputs.dbt_adapters_branch }} \ + ${{ inputs.dbt_core_branch }} \ + ${{ inputs.dbt_common_branch }} + cat dev-requirements.txt + - name: Install python dependencies run: | python -m pip install --user --upgrade pip @@ -117,12 +156,6 @@ jobs: python -m pip --version tox --version - - name: Update dev_requirements.txt - if: inputs.dbt-core-branch != '' - run: | - pip install bumpversion - ./.github/scripts/update_dbt_core_branch.sh ${{ inputs.dbt-core-branch }} - - name: Create AWS IAM profiles run: | aws configure --profile $AWS_USER_PROFILE set aws_access_key_id $AWS_USER_ACCESS_KEY_ID @@ -217,13 +250,20 @@ jobs: DD_SERVICE: ${{ github.event.repository.name }} steps: - - name: Check out the repository - if: github.event_name != 'pull_request_target' + - name: Check out the repository (push) + if: github.event_name == 'push' uses: actions/checkout@v3 with: persist-credentials: false - # explicity checkout the branch for the PR, + - name: Check out the repository (workflow_dispatch) + if: github.event_name == 'workflow_dispatch' + uses: actions/checkout@v4 + with: + persist-credentials: false + ref: ${{ inputs.adapter_branch }} + + # explicitly checkout the branch for the PR, # this is necessary for the `pull_request_target` event - name: Check out the repository (PR) if: github.event_name == 'pull_request_target' @@ -244,11 +284,15 @@ jobs: python -m pip --version tox --version - - name: Update dev_requirements.txt - if: inputs.dbt-core-branch != '' + - name: Update Adapters and Core branches (update dev_requirements.txt) + if: github.event_name == 'workflow_dispatch' run: | - pip install bumpversion - ./.github/scripts/update_dbt_core_branch.sh ${{ inputs.dbt-core-branch }} + ./.github/scripts/update_dev_dependency_branches.sh \ + ${{ inputs.dbt_adapters_branch }} \ + ${{ inputs.dbt_core_branch }} \ + ${{ inputs.dbt_common_branch }} + cat dev-requirements.txt + - name: Run tox (redshift) env: diff --git a/dev-requirements.txt b/dev-requirements.txt index c82ea37ca..52c26c936 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,8 +1,8 @@ # install latest changes in dbt-core + dbt-postgres +git+https://github.com/dbt-labs/dbt-core.git#egg=dbt-core&subdirectory=core git+https://github.com/dbt-labs/dbt-adapters.git git+https://github.com/dbt-labs/dbt-adapters.git#subdirectory=dbt-tests-adapter git+https://github.com/dbt-labs/dbt-common.git -git+https://github.com/dbt-labs/dbt-core.git#subdirectory=core git+https://github.com/dbt-labs/dbt-postgres.git # dev