From bbb2ed302d1919728ad223f5e24c3b659fd0ac7d Mon Sep 17 00:00:00 2001 From: Adam Dyess Date: Fri, 22 Sep 2023 08:44:54 -0500 Subject: [PATCH] Upgrade tests to juju 3.1 (#211) * Upgrade tests to juju 3.1 * Update test_etcd.py use model destroy_unit() * Stop listening on 127.0.0.1:4001 with http (#212) * Stop listening on 127.0.0.1:4001 with http * Ensure the restore action uses the secure endpoint as well * linting * Update config.yaml Co-authored-by: Kevin W Monroe --------- Co-authored-by: Kevin W Monroe --------- Co-authored-by: Kevin W Monroe --- .github/workflows/vsphere-integration.yaml | 5 +- actions/restore.py | 8 +- config.yaml | 6 + lib/etcd_databag.py | 8 +- lib/etcdctl.py | 26 ++-- templates/check_etcd-alarms.cron | 2 +- templates/etcd2.conf | 4 +- templates/etcd3.conf | 4 +- tests/integration/conftest.py | 2 +- tests/integration/test_etcd.py | 172 ++++++++++----------- tests/{ => unit}/conftest.py | 1 - tests/unit/lib/test_etcd_databag.py | 2 + tox.ini | 2 - 13 files changed, 119 insertions(+), 123 deletions(-) rename tests/{ => unit}/conftest.py (99%) diff --git a/.github/workflows/vsphere-integration.yaml b/.github/workflows/vsphere-integration.yaml index 7e3a686..6bcab4b 100644 --- a/.github/workflows/vsphere-integration.yaml +++ b/.github/workflows/vsphere-integration.yaml @@ -18,12 +18,13 @@ jobs: uses: charmed-kubernetes/actions-operator@main with: provider: vsphere + juju-channel: 3.1/stable credentials-yaml: ${{ secrets.CREDENTIALS_YAML }} clouds-yaml: ${{ secrets.CLOUDS_YAML }} bootstrap-constraints: "arch=amd64 cores=2 mem=4G" - bootstrap-options: "${{ secrets.FOCAL_BOOTSTRAP_OPTIONS }} --model-default datastore=vsanDatastore --model-default primary-network=VLAN_2763" + bootstrap-options: "${{ secrets.JAMMY_BOOTSTRAP_OPTIONS }} --model-default datastore=vsanDatastore --model-default primary-network=VLAN_2763" - name: Run test - run: tox -e integration + run: tox -e integration -- --basetemp=/home/ubuntu/pytest - name: Setup Debug Artifact Collection if: ${{ failure() }} run: mkdir tmp diff --git a/actions/restore.py b/actions/restore.py index f865fe2..6ab6bad 100755 --- a/actions/restore.py +++ b/actions/restore.py @@ -3,7 +3,7 @@ from charms import layer from charmhelpers.core.templating import render from charmhelpers.core import hookenv -from charmhelpers.core.hookenv import function_fail +from charmhelpers.core.hookenv import action_fail from charmhelpers.core.hookenv import action_get from charmhelpers.core.hookenv import action_set from charmhelpers.core.hookenv import config @@ -56,10 +56,10 @@ def preflight_check(): """Check preconditions for data restoration""" if not is_leader(): - function_fail("This action can only be run on the leader unit") + action_fail("This action can only be run on the leader unit") sys.exit(0) if not SNAPSHOT_ARCHIVE: - function_fail({"result.failed": "Missing snapshot. See: README.md"}) + action_fail("Missing snapshot. See: README.md") sys.exit(0) @@ -112,7 +112,7 @@ def restore_v3_backup(): # Use the insecure 4001 port we have open in our deployment environ = dict(os.environ, ETCDCTL_API="3") cmd = ( - "/snap/bin/etcdctl --endpoints=http://localhost:4001 snapshot " + "/snap/bin/etcdctl --endpoints=https://127.0.0.1:2379 snapshot " "restore /root/tmp/restore-v3/db --skip-hash-check " "--data-dir='/root/tmp/restore-v3/etcd' " "--initial-cluster='{}' --initial-cluster-token='{}' " diff --git a/config.yaml b/config.yaml index 1f28fe4..dec0c7c 100644 --- a/config.yaml +++ b/config.yaml @@ -30,6 +30,12 @@ options: description: | The service binds to all network interfaces if true. The service binds only to the first found bind address of each relation if false + bind_with_insecure_http: + type: boolean + default: false + description: | + The service binds to localhost:4001 with http if true. This exposes an insecure + endpoint for the service and is not recommended in production environments. tls_cipher_suites: type: string default: "" diff --git a/lib/etcd_databag.py b/lib/etcd_databag.py index f8d0d90..a6a8aa3 100644 --- a/lib/etcd_databag.py +++ b/lib/etcd_databag.py @@ -38,12 +38,16 @@ def __init__(self): self.db = unitdata.kv() self.build_uri = build_uri self.cluster_bind_address = self.get_bind_address("cluster") - self.db_bind_address = self.get_bind_address("db") self.port = config("port") + self.listen_client_urls = [ + build_uri("https", self.get_bind_address("db"), self.port) + ] + if config("bind_with_insecure_http"): + self.listen_client_urls.insert(0, build_uri("http", "127.0.0.1", 4001)) + self.advertise_urls = [build_uri("https", get_ingress_address("db"), self.port)] self.management_port = config("management_port") # Live polled properties self.cluster_address = get_ingress_address("cluster") - self.db_address = get_ingress_address("db") self.unit_name = os.getenv("JUJU_UNIT_NAME").replace("/", "") # Pull the TLS certificate paths from layer data diff --git a/lib/etcdctl.py b/lib/etcdctl.py index 1cb2fa8..ebf5115 100644 --- a/lib/etcdctl.py +++ b/lib/etcdctl.py @@ -3,6 +3,7 @@ from subprocess import CalledProcessError from subprocess import check_output from subprocess import STDOUT +from typing import Optional import os from etcd_lib import build_uri @@ -66,7 +67,7 @@ def unregister(self, unit_id, leader_address=None): """ return self.run(["member", "remove", unit_id], endpoints=leader_address, api=2) - def member_list(self, leader_address=False): + def member_list(self, leader_address=None): """Returns the output from `etcdctl member list` as a python dict organized by unit_name, containing all the data-points in the resulting response.""" @@ -122,7 +123,7 @@ def cluster_health(self, output_only=False): organized by topical information with detailed unit output""" health = {} try: - out = self.run("cluster-health", endpoints=False, api=2) + out = self.run("cluster-health", endpoints=None, api=2) if output_only: return out health_output = out.strip("\n").split("\n") @@ -134,7 +135,7 @@ def cluster_health(self, output_only=False): health["units"] = [] return health - def run(self, arguments, endpoints=None, api=3): + def run(self, arguments, endpoints: Optional[str] = None, api=3): """Wrapper to subprocess calling output. This is a convenience method to clean up the calls to subprocess and append TLS data""" env = {} @@ -149,20 +150,18 @@ def run(self, arguments, endpoints=None, api=3): env["ETCDCTL_CACERT"] = ca_path env["ETCDCTL_CERT"] = crt_path env["ETCDCTL_KEY"] = key_path - if endpoints is None: - endpoints = "http://127.0.0.1:4001" elif api == 2: env["ETCDCTL_API"] = "2" env["ETCDCTL_CA_FILE"] = ca_path env["ETCDCTL_CERT_FILE"] = crt_path env["ETCDCTL_KEY_FILE"] = key_path - if endpoints is None: - endpoints = ":4001" - else: raise NotImplementedError("etcd api version {} not supported".format(api)) + if not endpoints: + endpoints = "https://127.0.0.1:2379" + if isinstance(arguments, str): command.extend(arguments.split()) elif isinstance(arguments, list) or isinstance(arguments, tuple): @@ -172,12 +171,11 @@ def run(self, arguments, endpoints=None, api=3): "arguments not correct type; must be string, list or tuple" ) - if endpoints is not False: - if api == 3: - command.extend(["--endpoints", endpoints]) - elif api == 2: - command.insert(1, "--endpoint") - command.insert(2, endpoints) + if api == 3: + command.extend(["--endpoints", endpoints]) + elif api == 2: + command.insert(1, "--endpoint") + command.insert(2, endpoints) try: return check_output(command, env=env, stderr=STDOUT).decode("utf-8") diff --git a/templates/check_etcd-alarms.cron b/templates/check_etcd-alarms.cron index 16c3e3b..b7ae7f0 100644 --- a/templates/check_etcd-alarms.cron +++ b/templates/check_etcd-alarms.cron @@ -1,2 +1,2 @@ # check_etcd_alarms -* * * * * root [ -x /snap/bin/etcdctl ] && ETCDCTL_API=3 /snap/bin/etcdctl --endpoints=127.0.0.1:4001 alarm list 2>&1| tee /var/lib/nagios/etcd-alarm-list.txt > /dev/null +* * * * * root [ -x /snap/bin/etcdctl ] && ETCDCTL_API=3 ETCDCTL_KEY=/var/snap/etcd/common/client.key ETCDCTL_CERT=/var/snap/etcd/common/client.crt ETCDCTL_CACERT=/var/snap/etcd/common/ca.crt /snap/bin/etcdctl --endpoints=https://127.0.0.1:2379 alarm list 2>&1| tee /var/lib/nagios/etcd-alarm-list.txt > /dev/null \ No newline at end of file diff --git a/templates/etcd2.conf b/templates/etcd2.conf index c3bd063..61fee6a 100644 --- a/templates/etcd2.conf +++ b/templates/etcd2.conf @@ -1,8 +1,8 @@ # This file is rendered by Juju, manual edits will not be persisted ETCD_DATA_DIR={{ etcd_data_dir }}/{{ unit_name }}.etcd ETCD_NAME={{ unit_name }} -ETCD_ADVERTISE_CLIENT_URLS="{{ build_uri('https', db_address, port) }}" -ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:4001,{{ build_uri('https', db_bind_address, port) }}" +ETCD_ADVERTISE_CLIENT_URLS="{{ advertise_urls | join(',') }}" +ETCD_LISTEN_CLIENT_URLS="{{ listen_client_urls | join(',') }}" ETCD_LISTEN_PEER_URLS="{{ build_uri('https', cluster_bind_address, management_port) }}" ETCD_INITIAL_ADVERTISE_PEER_URLS="{{ build_uri('https', cluster_address, management_port) }}" {% if cluster %} diff --git a/templates/etcd3.conf b/templates/etcd3.conf index 20552fa..50cf84a 100644 --- a/templates/etcd3.conf +++ b/templates/etcd3.conf @@ -31,7 +31,7 @@ quota-backend-bytes: 0 listen-peer-urls: {{ build_uri('https', cluster_bind_address, management_port) }} # List of comma separated URLs to listen on for client traffic. -listen-client-urls: http://127.0.0.1:4001,{{ build_uri('https', db_bind_address, port) }} +listen-client-urls: {{ listen_client_urls | join(",") }} # Maximum number of snapshot files to retain (0 is unlimited). max-snapshots: 5 @@ -49,7 +49,7 @@ initial-advertise-peer-urls: {{ build_uri('https', cluster_address, management_p # List of this member's client URLs to advertise to the public. # The URLs needed to be a comma-separated list. -advertise-client-urls: {{ build_uri('https', db_address, port) }} +advertise-client-urls: {{ advertise_urls | join(",") }} # Discovery URL used to bootstrap the cluster. discovery: diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index c51d98b..a305d59 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -5,7 +5,7 @@ def pytest_addoption(parser): parser.addoption( "--series", type=str, - default="focal", + default="jammy", help="Set series for the machine units", ) diff --git a/tests/integration/test_etcd.py b/tests/integration/test_etcd.py index c981796..122bdac 100644 --- a/tests/integration/test_etcd.py +++ b/tests/integration/test_etcd.py @@ -1,21 +1,37 @@ from typing import List -import pytest from pytest_operator.plugin import OpsTest from juju.unit import Unit import logging import os +from pathlib import Path +import pytest log = logging.getLogger(__name__) -certs = [ +v2_env = [ + "ETCDCTL_API=2", "ETCDCTL_KEY_FILE=/var/snap/etcd/common/client.key", "ETCDCTL_CERT_FILE=/var/snap/etcd/common/client.crt", "ETCDCTL_CA_FILE=/var/snap/etcd/common/ca.crt", +] +v3_env = [ + "ETCDCTL_API=3", "ETCDCTL_KEY=/var/snap/etcd/common/client.key", "ETCDCTL_CERT=/var/snap/etcd/common/client.crt", "ETCDCTL_CACERT=/var/snap/etcd/common/ca.crt", ] +etcdctl_2 = f"{' '.join(v2_env)} /snap/bin/etcdctl --endpoint=https://127.0.0.1:2379" +etcdctl_3 = f"{' '.join(v3_env)} /snap/bin/etcdctl --endpoints=https://127.0.0.1:2379" + + +async def _unit_run(unit: Unit, jcmd: str, check: bool = True): + action = await unit.run(jcmd) + action = await action.wait() + if check: + assert action.status == "completed", f"Failed to run '{jcmd}'" + return action + @pytest.mark.abort_on_fail async def test_build_and_deploy(series: str, ops_test: OpsTest): @@ -26,17 +42,11 @@ async def test_build_and_deploy(series: str, ops_test: OpsTest): await ops_test.model.add_relation("easyrsa:client", "etcd:certificates") await ops_test.model.wait_for_idle(wait_for_active=True, timeout=60 * 60) - jcmd = "{} ETCDCTL_API=2 /snap/bin/etcd.etcdctl set juju rocks".format( - " ".join(certs) - ) - action = await ops_test.model.applications["etcd"].units[0].run(jcmd) - assert action.status == "completed" + jcmd = f"{etcdctl_2} set juju rocks" + await _unit_run(ops_test.model.applications["etcd"].units[0], jcmd) - nscmd = "{} ETCDCTL_API=2 /snap/bin/etcd.etcdctl set nested/data works".format( - " ".join(certs) - ) - action = await ops_test.model.applications["etcd"].units[0].run(nscmd) - assert action.status == "completed" + nscmd = f"{etcdctl_2} set nested/data works" + await _unit_run(ops_test.model.applications["etcd"].units[0], nscmd) async def _get_leader(units: List[Unit]) -> Unit: @@ -47,20 +57,19 @@ async def _get_leader(units: List[Unit]) -> Unit: async def test_leader_daemon_status(ops_test: OpsTest): leader = await _get_leader(ops_test.model.applications["etcd"].units) - action = await leader.run("systemctl is-active snap.etcd.etcd") - assert action.status == "completed" - assert "inactive" not in action.results["Stdout"] - assert "active" in action.results["Stdout"] + action = await _unit_run(leader, "systemctl is-active snap.etcd.etcd") + assert "inactive" not in action.results["stdout"] + assert "active" in action.results["stdout"] async def test_config_snapd_refresh(ops_test: OpsTest): leader = await _get_leader(ops_test.model.applications["etcd"].units) - action = await leader.run("snap get core refresh.timer") - assert len(action.results["Stdout"].strip()) == len("dayX") + action = await _unit_run(leader, "snap get core refresh.timer") + assert len(action.results["stdout"].strip()) == len("dayX") await ops_test.model.applications["etcd"].set_config({"snapd_refresh": "fri5"}) - action = await leader.run("snap get core refresh.timer") - assert len(action.results["Stdout"].strip()) == len("fri5") + action = await _unit_run(leader, "snap get core refresh.timer") + assert len(action.results["stdout"].strip()) == len("fri5") async def test_node_scale_up(ops_test: OpsTest): @@ -70,43 +79,39 @@ async def test_node_scale_up(ops_test: OpsTest): unit: Unit for unit in ops_test.model.applications["etcd"].units: - action = await unit.run("systemctl is-active snap.etcd.etcd") - assert action.status == "completed" - assert "inactive" not in action.results["Stdout"] - assert "active" in action.results["Stdout"] + action = await _unit_run(unit, "systemctl is-active snap.etcd.etcd") + assert "inactive" not in action.results["stdout"] + assert "active" in action.results["stdout"] async def test_cluster_health(ops_test: OpsTest): for unit in ops_test.model.applications["etcd"].units: - cmd = "{} ETCDCTL_API=2 /snap/bin/etcdctl cluster-health".format( - " ".join(certs) - ) - action = await unit.run(cmd) - assert action.status == "completed" - assert "unhealthy" not in action.results["Stdout"] - assert "unavailable" not in action.results["Stdout"] + cmd = f"{etcdctl_2} cluster-health" + action = await _unit_run(unit, cmd) + assert "unhealthy" not in action.results["stdout"] + assert "unavailable" not in action.results["stdout"] async def test_leader_knows_all_members(ops_test: OpsTest): leader = await _get_leader(ops_test.model.applications["etcd"].units) - cmd = "{} ETCDCTL_API=2 /snap/bin/etcdctl member list".format(" ".join(certs)) - action = await leader.run(cmd) - assert action.status == "completed" - members = action.results["Stdout"].strip().split("\n") + cmd = f"{etcdctl_2} member list" + action = await _unit_run(leader, cmd) + members = action.results["stdout"].strip().split("\n") assert "etcd cluster is unavailable" not in members assert len(members) == len(ops_test.model.applications["etcd"].units) async def test_node_scale_down(ops_test: OpsTest): + if len(ops_test.model.applications["etcd"].units) == 1: + return leader = await _get_leader(ops_test.model.applications["etcd"].units) - await leader.destroy() + await ops_test.model.destroy_unit(leader.name) await ops_test.model.wait_for_idle(wait_for_active=True, timeout=60 * 60) async def test_health_check(ops_test: OpsTest): action = await ops_test.model.applications["etcd"].units[0].run_action("health") await action.wait() - assert action.status == "completed" assert "cluster is healthy" in action.results["output"] @@ -115,7 +120,6 @@ async def test_snap_action(ops_test: OpsTest): await ops_test.model.applications["etcd"].units[0].run_action("snap-upgrade") ) await action.wait() - assert action.status == "completed" await validate_running_snap_daemon(ops_test) await validate_etcd_fixture_data(ops_test) @@ -128,27 +132,22 @@ async def test_snap_upgrade_to_three_oh(ops_test: OpsTest): async def validate_etcd_fixture_data(ops_test: OpsTest): - jcmd = "{} ETCDCTL_API=2 /snap/bin/etcd.etcdctl get juju".format(" ".join(certs)) - action = await ops_test.model.applications["etcd"].units[0].run(jcmd) - assert action.status == "completed" - assert "rocks" in action.results["Stdout"] + jcmd = f"{etcdctl_2} get juju" + action = await _unit_run(ops_test.model.applications["etcd"].units[0], jcmd) + assert "rocks" in action.results["stdout"] - nscmd = "{} ETCDCTL_API=2 /snap/bin/etcd.etcdctl get nested/data".format( - " ".join(certs) - ) - action = await ops_test.model.applications["etcd"].units[0].run(nscmd) - assert action.status == "completed" - assert "works" in action.results["Stdout"] + nscmd = f"{etcdctl_2} get nested/data" + action = await _unit_run(ops_test.model.applications["etcd"].units[0], nscmd) + assert "works" in action.results["stdout"] async def validate_running_snap_daemon(ops_test: OpsTest): cmd = "systemctl is-active snap.etcd.etcd" - action = await ops_test.model.applications["etcd"].units[0].run(cmd) - assert action.status == "completed" - assert "active" in action.results["Stdout"] + action = await _unit_run(ops_test.model.applications["etcd"].units[0], cmd) + assert "active" in action.results["stdout"] -async def test_snapshot_restore(ops_test: OpsTest): +async def test_snapshot_restore(ops_test: OpsTest, tmp_path: Path): # Make sure there is only 1 unit of etcd running for unit in ops_test.model.applications["etcd"].units: if len(ops_test.model.applications["etcd"].units) > 1: @@ -168,23 +167,22 @@ async def test_snapshot_restore(ops_test: OpsTest): log.info(action.status) log.info(action.results) assert action.status == "completed" - await leader.scp_from(action.results["snapshot"]["path"], ".") - filenames[dataset] = os.path.basename(action.results["snapshot"]["path"]) + await leader.scp_from(action.results["snapshot"]["path"], tmp_path) + filenames[dataset] = tmp_path / os.path.basename( + action.results["snapshot"]["path"] + ) await delete_data(ops_test) assert not await is_data_present(ops_test, "v2") assert not await is_data_present(ops_test, "v3") - # Below code is better but waiting for python-libjuju #654 fix, can't attach binary files yet due to the bug - # with open(filenames["v2"], mode='rb') as file: - # ops_test.model.applications["etcd"].attach_resource("snapshot", filenames["v2"], file) + with filenames["v2"].open(mode="rb") as file: + ops_test.model.applications["etcd"].attach_resource( + "snapshot", filenames["v2"], file + ) await ops_test.model.wait_for_idle(wait_for_active=True, timeout=60 * 60) - await ops_test.juju( - "attach-resource", "etcd", "snapshot={}".format(filenames["v2"]) - ) - leader = await _get_leader(ops_test.model.applications["etcd"].units) action = await leader.run_action("restore") await action.wait() @@ -196,16 +194,13 @@ async def test_snapshot_restore(ops_test: OpsTest): assert await is_data_present(ops_test, "v2") assert not await is_data_present(ops_test, "v3") - # Below code is better but waiting for python-libjuju #654 fix, can't attach binary files yet due to the bug - # with open(filenames["v3"], mode='rb') as file: - # ops_test.model.applications["etcd"].attach_resource("snapshot", filenames["v3"], file) + with filenames["v3"].open(mode="rb") as file: + ops_test.model.applications["etcd"].attach_resource( + "snapshot", filenames["v3"], file + ) await ops_test.model.wait_for_idle(wait_for_active=True, timeout=60 * 60) - await ops_test.juju( - "attach-resource", "etcd", "snapshot={}".format(filenames["v3"]) - ) - leader = await _get_leader(ops_test.model.applications["etcd"].units) action = await leader.run_action("restore") await action.wait() @@ -220,38 +215,32 @@ async def test_snapshot_restore(ops_test: OpsTest): async def load_data(ops_test: OpsTest): leader = await _get_leader(ops_test.model.applications["etcd"].units) - cmd = "{} ETCDCTL_API=2 /snap/bin/etcdctl set /etcd2key etcd2value".format( - " ".join(certs) - ) - await leader.run(cmd) - cmd = "{} ETCDCTL_API=3 /snap/bin/etcdctl --endpoints=http://localhost:4001 put etcd3key etcd3value".format( - " ".join(certs[3:]) - ) - await leader.run(cmd) + cmd = f"{etcdctl_2} set /etcd2key etcd2value" + await _unit_run(leader, cmd) + cmd = f"{etcdctl_3} put etcd3key etcd3value" + await _unit_run(leader, cmd) async def is_data_present(ops_test: OpsTest, version: str): leader = await _get_leader(ops_test.model.applications["etcd"].units) if version == "v2": - cmd = "{} ETCDCTL_API=2 /snap/bin/etcdctl ls".format(" ".join(certs)) - action = await leader.run(cmd) + cmd = f"{etcdctl_2} ls" + action = await _unit_run(leader, cmd) log.info(action.status) log.info(action.results) return ( - "etcd2key" in action.results["Stdout"] - if "Stdout" in action.results + "etcd2key" in action.results["stdout"] + if "stdout" in action.results else False ) elif version == "v3": - cmd = '{} ETCDCTL_API=3 /snap/bin/etcdctl --endpoints=http://localhost:4001 get "" --prefix --keys-only'.format( - " ".join(certs[3:]) - ) - action = await leader.run(cmd) + cmd = f'{etcdctl_3} get "" --prefix --keys-only' + action = await _unit_run(leader, cmd) log.info(action.status) log.info(action.results) return ( - "etcd3key" in action.results["Stdout"] - if "Stdout" in action.results + "etcd3key" in action.results["stdout"] + if "stdout" in action.results else False ) return False @@ -259,9 +248,8 @@ async def is_data_present(ops_test: OpsTest, version: str): async def delete_data(ops_test: OpsTest): leader = await _get_leader(ops_test.model.applications["etcd"].units) - cmd = "{} ETCDCTL_API=2 /snap/bin/etcdctl rm /etcd2key".format(" ".join(certs)) - await leader.run(cmd) - cmd = "{} ETCDCTL_API=3 /snap/bin/etcdctl --endpoints=http://localhost:4001 del etcd3key".format( - " ".join(certs[3:]) - ) - await leader.run(cmd) + cmd = f"{etcdctl_2} rm /etcd2key" + await _unit_run(leader, cmd) + + cmd = f"{etcdctl_3} del etcd3key" + await _unit_run(leader, cmd) diff --git a/tests/conftest.py b/tests/unit/conftest.py similarity index 99% rename from tests/conftest.py rename to tests/unit/conftest.py index c1a6d48..f25a605 100644 --- a/tests/conftest.py +++ b/tests/unit/conftest.py @@ -2,4 +2,3 @@ charms.unit_test.patch_reactive() charms.unit_test.patch_module("charms.leadership") - diff --git a/tests/unit/lib/test_etcd_databag.py b/tests/unit/lib/test_etcd_databag.py index 344a88f..7690f22 100644 --- a/tests/unit/lib/test_etcd_databag.py +++ b/tests/unit/lib/test_etcd_databag.py @@ -42,6 +42,7 @@ def test_render_etcd2( ): config.set("management_port", 1234) config.set("port", 5678) + config.set("bind_with_insecure_http", True) bag = etcd_databag.EtcdDatabag() template_env = Environment(loader=FileSystemLoader("templates")) config = template_env.get_template("etcd2.conf").render(bag.__dict__) @@ -62,6 +63,7 @@ def test_render_etcd3( ): config.set("management_port", 1234) config.set("port", 5678) + config.set("bind_with_insecure_http", True) bag = etcd_databag.EtcdDatabag() template_env = Environment(loader=FileSystemLoader("templates")) config = template_env.get_template("etcd3.conf").render(bag.__dict__) diff --git a/tox.ini b/tox.ini index 6ce3dde..1e821f9 100644 --- a/tox.ini +++ b/tox.ini @@ -31,10 +31,8 @@ commands = [testenv:integration] deps = - juju<3.0 pytest pytest-operator - charms.unit_test commands = pytest --tb native --show-capture=no --disable-pytest-warnings --log-cli-level=INFO -s {posargs} {toxinidir}/tests/integration [testenv:lint]