From 94da1b8ce7f45fc805965cc0aace1db9f0e85738 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 12:18:36 +0000 Subject: [PATCH 1/6] Use matrix --- .github/workflows/ci.yaml | 105 +++++--------------------------------- 1 file changed, 12 insertions(+), 93 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 15d8b4374..e6032b4e9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,8 +27,18 @@ jobs: - name: Run tests run: tox -e unit - integration-test-microk8s-charm: - name: Charm integration tests (microk8s) + integration-test: + strategy: + fail-fast: false + matrix: + tox-environments: + - integration-charm + - integration-database-relation + - integration-osm-mysql + - integration-replication +# - integration-self-healing + - integration-tls + name: ${{ matrix.tox-environments }} needs: - lint - unit-test @@ -44,94 +54,3 @@ jobs: bootstrap-options: "--agent-version 2.9.29" - name: Run charm integration tests run: tox -e integration-charm - - integration-test-database-relation: - name: Integration tests for database relation - needs: - - lint - - unit-test - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup operator environment - uses: charmed-kubernetes/actions-operator@main - with: - provider: microk8s - # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed - bootstrap-options: "--agent-version 2.9.29" - - name: Run integration database tests - run: tox -e integration-database-relation - - integration-test-microk8s-osm-mysql: - name: Integration osm-msyql relation tests (microk8s) - needs: - - lint - - unit-test - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup operator environment - uses: charmed-kubernetes/actions-operator@main - with: - provider: microk8s - # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed - bootstrap-options: "--agent-version 2.9.29" - - name: Run osm-mysql relation integration tests - run: tox -e integration-osm-mysql - - integration-test-microk8s-replication: - name: Integration replication tests (microk8s) - needs: - - lint - - unit-test - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup operator environment - uses: charmed-kubernetes/actions-operator@main - with: - provider: microk8s - # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed - bootstrap-options: "--agent-version 2.9.29" - - name: Run replication integration tests - run: tox -e integration-replication - -# TODO: re-enable when stable (currently flaky) -# integration-test-microk8s-self-healing: -# name: Integration self healing tests (microk8s) -# needs: -# - lint -# - unit-test -# runs-on: ubuntu-latest -# steps: -# - name: Checkout -# uses: actions/checkout@v3 -# - name: Setup operator environment -# uses: charmed-kubernetes/actions-operator@main -# with: -# provider: microk8s -# microk8s-group: microk8s -# # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed -# bootstrap-options: "--agent-version 2.9.29" -# - name: Run self healing integration tests -# run: tox -e integration-self-healing - - integration-test-tls: - needs: - - lint - - unit-test - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup operator environment - uses: charmed-kubernetes/actions-operator@main - with: - provider: microk8s - # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed - bootstrap-options: "--agent-version 2.9.29" - - name: Integration tls relation tests - run: tox -e integration-tls From faf4c1ab65dd8cbe27da9252ff720d516938f20a Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 13:22:09 +0000 Subject: [PATCH 2/6] Cache `charmcraft pack` container, skip unstable tests except on schedule Ported from: https://github.com/canonical/mysql-operator/pull/78 https://github.com/canonical/mysql-operator/pull/88 https://github.com/canonical/mysql-operator/pull/87 https://github.com/canonical/mysql-operator/pull/100 --- .github/workflows/ci.yaml | 48 +++++++++-- CONTRIBUTING.md | 16 ++-- pyproject.toml | 9 +-- tests/integration/__init__.py | 0 tests/integration/conftest.py | 28 +++++++ tests/integration/helpers.py | 3 +- .../integration/high_availability/__init__.py | 0 .../integration/high_availability/conftest.py | 3 +- .../high_availability_helpers.py | 2 +- .../high_availability/test_replication.py | 9 +-- .../high_availability/test_self_healing.py | 17 ++-- tests/integration/relations/__init__.py | 0 tests/integration/relations/test_database.py | 5 +- tests/integration/relations/test_osm_mysql.py | 5 +- tests/integration/test_charm.py | 11 +-- tests/integration/test_tls.py | 8 +- tox.ini | 79 ++++++++++++------- 17 files changed, 150 insertions(+), 93 deletions(-) create mode 100644 tests/integration/__init__.py create mode 100644 tests/integration/conftest.py create mode 100644 tests/integration/high_availability/__init__.py create mode 100644 tests/integration/relations/__init__.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e6032b4e9..39d29cf78 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,8 +1,13 @@ -name: integration and other tests +# Copyright 2022 Canonical Ltd. +# See LICENSE file for licensing details. +name: Tests on: - workflow_call: pull_request: + schedule: + - cron: '53 0 * * *' # Daily at 00:53 UTC + # Triggered on push to branch "main" by .github/workflows/release.yaml + workflow_call: jobs: lint: @@ -11,10 +16,11 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Install dependencies + - name: Install tox + # TODO: Consider replacing with custom image on self-hosted runner OR pinning version run: python3 -m pip install tox - name: Run linters - run: tox -e lint + run: tox run -e lint unit-test: name: Unit tests @@ -22,10 +28,15 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Install dependencies - run: python -m pip install tox + - name: Install tox + # TODO: Consider replacing with custom image on self-hosted runner OR pinning version + run: python3 -m pip install tox - name: Run tests - run: tox -e unit + run: tox run -e unit + + build: + name: Build charms + uses: canonical/data-platform-workflows/.github/workflows/build_charms_with_cache.yaml@v1 integration-test: strategy: @@ -36,17 +47,19 @@ jobs: - integration-database-relation - integration-osm-mysql - integration-replication -# - integration-self-healing + - integration-self-healing - integration-tls name: ${{ matrix.tox-environments }} needs: - lint - unit-test + - build runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Setup operator environment + # TODO: Replace with custom image on self-hosted runner uses: charmed-kubernetes/actions-operator@main with: provider: microk8s @@ -54,3 +67,22 @@ jobs: bootstrap-options: "--agent-version 2.9.29" - name: Run charm integration tests run: tox -e integration-charm + - name: Download packed charm(s) + uses: actions/download-artifact@v3 + with: + name: ${{ needs.build.outputs.artifact-name }} + - name: Select tests + id: select-tests + run: | + if [ "${{ github.event_name }}" == "schedule" ] + then + echo Running unstable and stable tests + echo "mark_expression=" >> $GITHUB_OUTPUT + else + echo Skipping unstable tests + echo "mark_expression=not unstable" >> $GITHUB_OUTPUT + fi + - name: Run integration tests + run: tox run -e ${{ matrix.tox-environments }} -- -m '${{ steps.select-tests.outputs.mark_expression }}' + env: + CI_PACKED_CHARMS: ${{ needs.build.outputs.charms }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 68dfccac0..60de3ff95 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,21 +21,21 @@ this operator. ## Developing -You can use the environments created by `tox` for development: +You can create an environment for development with `tox`: ```shell -tox --notest -e unit -source .tox/unit/bin/activate +tox devenv -e integration +source venv/bin/activate ``` ### Testing ```shell -tox -e fmt # update your code according to linting rules -tox -e lint # code style -tox -e unit # unit tests -tox -e integration-* # integration tests -tox # runs 'lint' and 'unit' environments +tox run -e format # update your code according to linting rules +tox run -e lint # code style +tox run -e unit # unit tests +tox run -e integration-* # integration tests +tox # runs 'lint' and 'unit' environments ``` ## Build charm diff --git a/pyproject.toml b/pyproject.toml index e89bc6870..04cbf8bad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,14 +12,7 @@ show_missing = true minversion = "6.0" log_cli_level = "INFO" asyncio_mode = "auto" -markers = [ - "charm_tests", - "database_tests", - "osm_mysql_tests", - "replication_tests", - "self_healing_tests", - "tls_tests", -] +markers = ["unstable"] # Formatting tools configuration [tool.black] diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 000000000..a5a9e3655 --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# Copyright 2022 Canonical Ltd. +# See LICENSE file for licensing details. + +import json +import os +from pathlib import Path + +import pytest +from pytest_operator.plugin import OpsTest + + +@pytest.fixture +def ops_test(ops_test: OpsTest) -> OpsTest: + if os.environ.get("CI") == "true": + # Running in GitHub Actions; skip build step + # (GitHub Actions uses a separate, cached build step. See .github/workflows/ci.yaml) + packed_charms = json.loads(os.environ["CI_PACKED_CHARMS"]) + + async def build_charm(charm_path, bases_index: int = None) -> Path: + for charm in packed_charms: + if Path(charm_path) == Path(charm["directory_path"]): + if bases_index is None or bases_index == charm["bases_index"]: + return charm["file_path"] + raise ValueError(f"Unable to find .charm file for {bases_index=} at {charm_path=}") + + ops_test.build_charm = build_charm + return ops_test diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 4bcfdd753..ec7f8cf29 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -20,7 +20,8 @@ from tenacity import retry, stop_after_attempt, wait_fixed from constants import SERVER_CONFIG_USERNAME -from tests.integration.connector import MySQLConnector + +from .connector import MySQLConnector def generate_random_string(length: int) -> str: diff --git a/tests/integration/high_availability/__init__.py b/tests/integration/high_availability/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/high_availability/conftest.py b/tests/integration/high_availability/conftest.py index 448bc1ddb..ce73b2157 100644 --- a/tests/integration/high_availability/conftest.py +++ b/tests/integration/high_availability/conftest.py @@ -8,7 +8,8 @@ from pytest_operator.plugin import OpsTest from constants import CONTAINER_NAME, MYSQLD_SERVICE -from tests.integration.high_availability.high_availability_helpers import ( + +from .high_availability_helpers import ( deploy_chaos_mesh, destroy_chaos_mesh, get_application_name, diff --git a/tests/integration/high_availability/high_availability_helpers.py b/tests/integration/high_availability/high_availability_helpers.py index db81948e7..e7d5a1ecf 100644 --- a/tests/integration/high_availability/high_availability_helpers.py +++ b/tests/integration/high_availability/high_availability_helpers.py @@ -24,7 +24,7 @@ wait_fixed, ) -from tests.integration.helpers import ( +from ..helpers import ( execute_queries_on_unit, generate_random_string, get_cluster_status, diff --git a/tests/integration/high_availability/test_replication.py b/tests/integration/high_availability/test_replication.py index f625899a2..4f68da2b2 100644 --- a/tests/integration/high_availability/test_replication.py +++ b/tests/integration/high_availability/test_replication.py @@ -11,14 +11,14 @@ from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed -from tests.integration.helpers import ( +from ..helpers import ( execute_queries_on_unit, get_primary_unit, get_server_config_credentials, get_unit_address, scale_application, ) -from tests.integration.high_availability.high_availability_helpers import ( +from .high_availability_helpers import ( clean_up_database_and_table, deploy_and_scale_mysql, ensure_all_units_continuous_writes_incrementing, @@ -32,14 +32,12 @@ TIMEOUT = 15 * 60 -@pytest.mark.replication_tests async def test_build_and_deploy(ops_test: OpsTest) -> None: """Simple test to ensure that the mysql and application charms get deployed.""" await high_availability_test_setup(ops_test) @pytest.mark.abort_on_fail -@pytest.mark.replication_tests async def test_check_consistency(ops_test: OpsTest, continuous_writes) -> None: """Test to write to primary, and read the same data back from replicas.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) @@ -55,7 +53,6 @@ async def test_check_consistency(ops_test: OpsTest, continuous_writes) -> None: @pytest.mark.abort_on_fail -@pytest.mark.replication_tests async def test_no_replication_across_clusters(ops_test: OpsTest, continuous_writes) -> None: """Test to ensure that writes to one cluster do not replicate to another cluster.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) @@ -112,7 +109,6 @@ async def test_no_replication_across_clusters(ops_test: OpsTest, continuous_writ @pytest.mark.abort_on_fail -@pytest.mark.replication_tests async def test_scaling_without_data_loss(ops_test: OpsTest) -> None: """Test to ensure that data is preserved when a unit is scaled up and then down. @@ -193,7 +189,6 @@ async def test_scaling_without_data_loss(ops_test: OpsTest) -> None: # TODO: move test immediately after "test_build_and_deploy" once the following issue is resolved # https://github.com/canonical/mysql-k8s-operator/issues/102 @pytest.mark.abort_on_fail -@pytest.mark.replication_tests async def test_kill_primary_check_reelection(ops_test: OpsTest, continuous_writes) -> None: """Test to kill the primary under load and ensure re-election of primary.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) diff --git a/tests/integration/high_availability/test_self_healing.py b/tests/integration/high_availability/test_self_healing.py index 8979764e8..a4ccc592d 100644 --- a/tests/integration/high_availability/test_self_healing.py +++ b/tests/integration/high_availability/test_self_healing.py @@ -11,13 +11,13 @@ from pytest_operator.plugin import OpsTest from tenacity import Retrying, stop_after_delay, wait_fixed -from tests.integration.helpers import ( +from ..helpers import ( get_cluster_status, get_primary_unit, get_process_pid, scale_application, ) -from tests.integration.high_availability.high_availability_helpers import ( +from .high_availability_helpers import ( clean_up_database_and_table, ensure_all_units_continuous_writes_incrementing, ensure_n_online_mysql_members, @@ -39,14 +39,13 @@ TIMEOUT = 30 * 60 -@pytest.mark.self_healing_tests async def test_build_and_deploy(ops_test: OpsTest) -> None: """Simple test to ensure that the mysql and application charms get deployed.""" await high_availability_test_setup(ops_test) @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_kill_db_process(ops_test: OpsTest, continuous_writes) -> None: """Test to send a SIGKILL to the primary db process and ensure that the cluster self heals.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) @@ -104,7 +103,7 @@ async def test_kill_db_process(ops_test: OpsTest, continuous_writes) -> None: @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_freeze_db_process(ops_test: OpsTest, continuous_writes) -> None: """Test to send a SIGSTOP to the primary db process and ensure that the cluster self heals.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) @@ -206,7 +205,7 @@ async def test_freeze_db_process(ops_test: OpsTest, continuous_writes) -> None: @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_graceful_crash_of_primary(ops_test: OpsTest, continuous_writes) -> None: """Test to send SIGTERM to primary instance and then verify recovery.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) @@ -264,7 +263,7 @@ async def test_graceful_crash_of_primary(ops_test: OpsTest, continuous_writes) - @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_network_cut_affecting_an_instance( ops_test: OpsTest, continuous_writes, chaos_mesh ) -> None: @@ -323,7 +322,7 @@ async def test_network_cut_affecting_an_instance( @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_graceful_full_cluster_crash_test( ops_test: OpsTest, continuous_writes, restart_policy ) -> None: @@ -405,7 +404,7 @@ async def test_graceful_full_cluster_crash_test( @pytest.mark.abort_on_fail -@pytest.mark.self_healing_tests +@pytest.mark.unstable async def test_single_unit_pod_delete(ops_test: OpsTest) -> None: """Delete the pod in a single unit deployment and write data to new pod.""" mysql_application_name, _ = await high_availability_test_setup(ops_test) diff --git a/tests/integration/relations/__init__.py b/tests/integration/relations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/relations/test_database.py b/tests/integration/relations/test_database.py index 61cb368a7..1bec2bd9a 100644 --- a/tests/integration/relations/test_database.py +++ b/tests/integration/relations/test_database.py @@ -10,7 +10,7 @@ import yaml from pytest_operator.plugin import OpsTest -from tests.integration.helpers import is_relation_broken, is_relation_joined +from ..helpers import is_relation_broken, is_relation_joined logger = logging.getLogger(__name__) @@ -30,7 +30,6 @@ @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -@pytest.mark.database_tests async def test_build_and_deploy(ops_test: OpsTest): """Build the charm and deploy 3 units to ensure a cluster is formed.""" # Build and deploy charm from local source folder @@ -87,7 +86,6 @@ async def test_build_and_deploy(ops_test: OpsTest): @pytest.mark.abort_on_fail -@pytest.mark.database_tests async def test_relation_creation(ops_test: OpsTest): """Relate charms and wait for the expected changes in status.""" await ops_test.model.relate(APPLICATION_APP_NAME, f"{DATABASE_APP_NAME}:{ENDPOINT}") @@ -101,7 +99,6 @@ async def test_relation_creation(ops_test: OpsTest): @pytest.mark.abort_on_fail -@pytest.mark.database_tests async def test_relation_broken(ops_test: OpsTest): """Remove relation and wait for the expected changes in status.""" await ops_test.model.applications[DATABASE_APP_NAME].remove_relation( diff --git a/tests/integration/relations/test_osm_mysql.py b/tests/integration/relations/test_osm_mysql.py index a35196f01..d9ee145e4 100644 --- a/tests/integration/relations/test_osm_mysql.py +++ b/tests/integration/relations/test_osm_mysql.py @@ -6,12 +6,11 @@ import logging from pathlib import Path -import pytest import yaml from pytest_operator.plugin import OpsTest from tenacity import AsyncRetrying, RetryError, stop_after_attempt, wait_fixed -from tests.integration.helpers import ( +from ..helpers import ( execute_queries_on_unit, get_server_config_credentials, get_unit_address, @@ -26,7 +25,6 @@ # TODO: deploy and relate osm-grafana once it can be use with MySQL Group Replication -@pytest.mark.osm_mysql_tests async def test_deploy_and_relate_osm_bundle(ops_test: OpsTest) -> None: """Test the deployment and relation with osm bundle with mysql replacing mariadb.""" async with ops_test.fast_forward(): @@ -139,7 +137,6 @@ async def test_deploy_and_relate_osm_bundle(ops_test: OpsTest) -> None: ) -@pytest.mark.osm_mysql_tests async def test_osm_pol_operations(ops_test: OpsTest) -> None: """Test the existence of databases and tables created by osm-pol's migrations.""" show_databases_sql = [ diff --git a/tests/integration/test_charm.py b/tests/integration/test_charm.py index bebbe5f94..eb79d60ec 100644 --- a/tests/integration/test_charm.py +++ b/tests/integration/test_charm.py @@ -11,7 +11,9 @@ from tenacity import AsyncRetrying, RetryError, stop_after_delay, wait_fixed from constants import CLUSTER_ADMIN_USERNAME, PASSWORD_LENGTH, ROOT_USERNAME -from tests.integration.helpers import ( +from utils import generate_random_password + +from .helpers import ( execute_queries_on_unit, fetch_credentials, generate_random_string, @@ -22,7 +24,6 @@ rotate_credentials, scale_application, ) -from utils import generate_random_password logger = logging.getLogger(__name__) @@ -34,7 +35,6 @@ @pytest.mark.skip_if_deployed @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_build_and_deploy(ops_test: OpsTest) -> None: """Build the mysql charm and deploy it.""" async with ops_test.fast_forward(): @@ -81,7 +81,6 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_consistent_data_replication_across_cluster(ops_test: OpsTest) -> None: """Confirm that data is replicated from the primary node to all the replicas.""" # Insert values into a table on the primary unit @@ -134,7 +133,6 @@ async def test_consistent_data_replication_across_cluster(ops_test: OpsTest) -> @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_scale_up_and_down(ops_test: OpsTest) -> None: """Confirm that a new primary is elected when the current primary is torn down.""" async with ops_test.fast_forward(): @@ -187,7 +185,6 @@ async def test_scale_up_and_down(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_password_rotation(ops_test: OpsTest): """Rotate password and confirm changes.""" random_unit = ops_test.model.applications[APP_NAME].units[-1] @@ -221,7 +218,6 @@ async def test_password_rotation(ops_test: OpsTest): @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_password_rotation_silent(ops_test: OpsTest): """Rotate password and confirm changes.""" random_unit = ops_test.model.applications[APP_NAME].units[-1] @@ -250,7 +246,6 @@ async def test_password_rotation_silent(ops_test: OpsTest): @pytest.mark.abort_on_fail -@pytest.mark.charm_tests async def test_password_rotation_root_user_implicit(ops_test: OpsTest): """Rotate password and confirm changes.""" random_unit = ops_test.model.applications[APP_NAME].units[-1] diff --git a/tests/integration/test_tls.py b/tests/integration/test_tls.py index 3d8d91e0e..fea65f1d3 100644 --- a/tests/integration/test_tls.py +++ b/tests/integration/test_tls.py @@ -9,7 +9,8 @@ from pytest_operator.plugin import OpsTest from constants import CLUSTER_ADMIN_USERNAME, TLS_SSL_CERT_FILE -from tests.integration.helpers import ( + +from .helpers import ( app_name, fetch_credentials, get_process_pid, @@ -29,7 +30,6 @@ @pytest.mark.abort_on_fail -@pytest.mark.tls_tests async def test_build_and_deploy(ops_test: OpsTest) -> None: """Build the charm and deploy 3 units to ensure a cluster is formed.""" if app := await app_name(ops_test): @@ -61,7 +61,6 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.tls_tests async def test_connection_before_tls(ops_test: OpsTest) -> None: """Ensure connections (with and without ssl) are possible before relating with TLS operator.""" app = await app_name(ops_test) @@ -91,7 +90,6 @@ async def test_connection_before_tls(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.tls_tests async def test_enable_tls(ops_test: OpsTest) -> None: """Test for encryption enablement when relation to TLS charm.""" app = await app_name(ops_test) @@ -134,7 +132,6 @@ async def test_enable_tls(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.tls_tests async def test_rotate_tls_key(ops_test: OpsTest) -> None: """Verify rotating tls private keys restarts cluster with new certificates. @@ -195,7 +192,6 @@ async def test_rotate_tls_key(ops_test: OpsTest) -> None: @pytest.mark.abort_on_fail -@pytest.mark.tls_tests async def test_disable_tls(ops_test: OpsTest) -> None: # Remove the relation app = await app_name(ops_test) diff --git a/tox.ini b/tox.ini index 0e8ef5fe4..cd5fd3933 100644 --- a/tox.ini +++ b/tox.ini @@ -2,27 +2,27 @@ # See LICENSE file for licensing details. [tox] -skipsdist=True +no_package = True skip_missing_interpreters = True -envlist = lint, unit +env_list = lint, unit [vars] -src_path = {toxinidir}/src/ -tst_path = {toxinidir}/tests/ -;lib_path = {toxinidir}/lib/charms/operator_name_with_underscores -all_path = {[vars]src_path} {[vars]tst_path} +src_path = {tox_root}/src +tests_path = {tox_root}/tests +;lib_path = {tox_root}/lib/charms/operator_name_with_underscores +all_path = {[vars]src_path} {[vars]tests_path} [testenv] -setenv = - PYTHONPATH = {toxinidir}:{toxinidir}/lib:{[vars]src_path}:{[vars]tst_path}:{[vars]tst_path}/integration +set_env = + PYTHONPATH = {tox_root}/lib:{[vars]src_path} PYTHONBREAKPOINT=ipdb.set_trace PY_COLORS=1 -passenv = +pass_env = PYTHONPATH CHARM_BUILD_DIR MODEL_SETTINGS -[testenv:fmt] +[testenv:format] description = Apply coding style standards to code deps = black @@ -48,10 +48,10 @@ allowlist_externals = /bin/bash commands = # uncomment the following line if this charm owns a lib # codespell {[vars]lib_path} - codespell {toxinidir} --skip {toxinidir}/.git --skip {toxinidir}/.tox \ - --skip {toxinidir}/build --skip {toxinidir}/lib --skip {toxinidir}/venv \ - --skip {toxinidir}/.mypy_cache --skip {toxinidir}/icon.svg \ - --skip {toxinidir}/.kube --skip {toxinidir}/.config + codespell {tox_root} --skip {tox_root}/.git --skip {tox_root}/.tox \ + --skip {tox_root}/build --skip {tox_root}/lib --skip {tox_root}/venv \ + --skip {tox_root}/.mypy_cache --skip {tox_root}/icon.svg \ + --skip {tox_root}/.kube --skip {tox_root}/.config # pflake8 wrapper supports config from pyproject.toml pflake8 {[vars]all_path} isort --check-only --diff {[vars]all_path} @@ -63,7 +63,7 @@ description = Run unit tests deps = pytest coverage[toml] - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = coverage run --source={[vars]src_path} \ -m pytest --ignore={[vars]tst_path}integration -v --tb native -s {posargs} @@ -71,54 +71,74 @@ commands = [testenv:integration-charm] description = Run charm integration tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 lightkube mysql-connector-python pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "charm_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/test_charm.py [testenv:integration-database-relation] description = Run database relation tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 lightkube mysql-connector-python pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "database_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/relations/test_database.py [testenv:integration-osm-mysql] description = Run integration tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 lightkube mysql-connector-python pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "osm_mysql_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/relations/test_osm_mysql.py [testenv:integration-replication] description = Run replication integration tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 lightkube mysql-connector-python pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "replication_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/high_availability/test_replication.py [testenv:integration-self-healing] description = Run self healing integration tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 kubernetes @@ -126,19 +146,22 @@ deps = mysql-connector-python pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "self_healing_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/high_availability/test_self_healing.py [testenv:integration-tls] description = Run TLS tests +pass_env = + {[testenv]pass_env} + CI + CI_PACKED_CHARMS deps = juju==2.9.38.1 lightkube mysql-connector-python - pdbpp pytest pytest-operator - -r{toxinidir}/requirements.txt + -r {tox_root}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} -m "tls_tests" + pytest -v --tb native --log-cli-level=INFO -s {posargs} {[vars]tests_path}/integration/test_tls.py From ca5085c318a18f11e083754747de5a532e21cd34 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 13:29:54 +0000 Subject: [PATCH 3/6] Fix indentation --- .github/workflows/ci.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 39d29cf78..6347f6ea4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,10 +4,10 @@ name: Tests on: pull_request: - schedule: - - cron: '53 0 * * *' # Daily at 00:53 UTC - # Triggered on push to branch "main" by .github/workflows/release.yaml - workflow_call: + schedule: + - cron: '53 0 * * *' # Daily at 00:53 UTC + # Triggered on push to branch "main" by .github/workflows/release.yaml + workflow_call: jobs: lint: From 6cf5974a48e4acb78cb5e747076000442caad27d Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 13:51:44 +0000 Subject: [PATCH 4/6] Remove extra step --- .github/workflows/ci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6347f6ea4..f16aecde8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -65,8 +65,6 @@ jobs: provider: microk8s # This is needed until https://bugs.launchpad.net/juju/+bug/1977582 is fixed bootstrap-options: "--agent-version 2.9.29" - - name: Run charm integration tests - run: tox -e integration-charm - name: Download packed charm(s) uses: actions/download-artifact@v3 with: From d2c503995da6801cda7f18143c42e3c649796e69 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 13:55:38 +0000 Subject: [PATCH 5/6] Update unit tox environment --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index cd5fd3933..9283841c3 100644 --- a/tox.ini +++ b/tox.ini @@ -66,7 +66,7 @@ deps = -r {tox_root}/requirements.txt commands = coverage run --source={[vars]src_path} \ - -m pytest --ignore={[vars]tst_path}integration -v --tb native -s {posargs} + -m pytest -v --tb native -s {posargs} {[vars]tests_path}/unit coverage report [testenv:integration-charm] From 64f7b65cf5f90df7af6f11954e94852ce883e822 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 15 Feb 2023 15:36:51 +0000 Subject: [PATCH 6/6] Fix lint --- tests/integration/__init__.py | 2 ++ tests/integration/high_availability/__init__.py | 2 ++ tests/integration/relations/__init__.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index e69de29bb..db3bfe1a6 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. diff --git a/tests/integration/high_availability/__init__.py b/tests/integration/high_availability/__init__.py index e69de29bb..db3bfe1a6 100644 --- a/tests/integration/high_availability/__init__.py +++ b/tests/integration/high_availability/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details. diff --git a/tests/integration/relations/__init__.py b/tests/integration/relations/__init__.py index e69de29bb..db3bfe1a6 100644 --- a/tests/integration/relations/__init__.py +++ b/tests/integration/relations/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2023 Canonical Ltd. +# See LICENSE file for licensing details.