-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
## Issue No tests for relations that are not allowed for shards ## Solution add tests for checking unsupported relations ## extras create a dummy legacy application. This should NOT be used inside the legacy integration test suite as those tests should be done with production legacy charms
- Loading branch information
1 parent
dcb185a
commit a97970f
Showing
8 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Copyright 2023 Canonical Ltd. | ||
# See LICENSE file for licensing details. | ||
|
||
type: charm | ||
bases: | ||
- build-on: | ||
- name: "ubuntu" | ||
channel: "20.04" | ||
run-on: | ||
- name: "ubuntu" | ||
channel: "20.04" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Copyright 2023 Canonical Ltd. | ||
# See LICENSE file for licensing details. | ||
name: legacy-application | ||
description: | | ||
Dummy legacy application charm used in integration tests. | ||
summary: | | ||
Dummy legacy application charm meant only to be used in non-legacy integration tests. Legacy | ||
integration tests should use a production legacy application. | ||
series: | ||
- focal | ||
|
||
requires: | ||
obsolete: | ||
interface: mongodb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ops >= 1.4.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright 2023 Canonical Ltd. | ||
# See LICENSE file for licensing details. | ||
|
||
"""Application charm that connects to database charms. | ||
This charm is meant to be used only for testing | ||
of the libraries in this repository. | ||
""" | ||
|
||
import logging | ||
|
||
from ops.charm import CharmBase | ||
from ops.main import main | ||
from ops.model import ActiveStatus | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
# Extra roles that this application needs when interacting with the database. | ||
EXTRA_USER_ROLES = "admin" | ||
|
||
|
||
class ApplicationCharm(CharmBase): | ||
"""Application charm that connects to database charms.""" | ||
|
||
def __init__(self, *args): | ||
super().__init__(*args) | ||
|
||
# Default charm events. | ||
self.framework.observe(self.on.start, self._on_start) | ||
|
||
def _on_start(self, _) -> None: | ||
"""Only sets an Active status.""" | ||
self.unit.status = ActiveStatus() | ||
|
||
|
||
if __name__ == "__main__": | ||
main(ApplicationCharm) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright 2023 Canonical Ltd. | ||
# See LICENSE file for licensing details. | ||
|
||
import pytest | ||
from pytest_operator.plugin import OpsTest | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
async def legacy_charm(ops_test: OpsTest): | ||
"""Build an application charm that uses the legacy interface. | ||
Note: this should only be used outside of the legacy integration tests, as those tests should | ||
test a real legacy application. | ||
""" | ||
charm_path = "tests/integration/dummy_legacy_app" | ||
charm = await ops_test.build_charm(charm_path) | ||
return charm | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
async def application_charm(ops_test: OpsTest): | ||
"""Build the application charm.""" | ||
charm_path = "tests/integration/relation_tests/new_relations/application-charm" | ||
charm = await ops_test.build_charm(charm_path) | ||
return charm | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
async def database_charm(ops_test: OpsTest): | ||
"""Build the database charm.""" | ||
charm = await ops_test.build_charm(".") | ||
return charm |
140 changes: 140 additions & 0 deletions
140
tests/integration/sharding_tests/test_sharding_relations.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright 2023 Canonical Ltd. | ||
# See LICENSE file for licensing details. | ||
import pytest | ||
from juju.errors import JujuAPIError | ||
from pytest_operator.plugin import OpsTest | ||
|
||
SHARD_ONE_APP_NAME = "shard-one" | ||
CONFIG_SERVER_ONE_APP_NAME = "config-server-one" | ||
CONFIG_SERVER_TWO_APP_NAME = "config-server-two" | ||
APP_CHARM_NAME = "application" | ||
LEGACY_APP_CHARM_NAME = "legacy-application" | ||
|
||
CONFIG_SERVER_REL_NAME = "config-server" | ||
SHARD_REL_NAME = "sharding" | ||
DATABASE_REL_NAME = "first-database" | ||
LEGACY_RELATION_NAME = "obsolete" | ||
|
||
RELATION_LIMIT_MESSAGE = 'cannot add relation "shard-one:sharding config-server-two:config-server": establishing a new relation for shard-one:sharding would exceed its maximum relation limit of 1' | ||
# for now we have a large timeout due to the slow drainage of the `config.system.sessions` | ||
# collection. More info here: | ||
# https://stackoverflow.com/questions/77364840/mongodb-slow-chunk-migration-for-collection-config-system-sessions-with-remov | ||
TIMEOUT = 30 * 60 | ||
|
||
|
||
@pytest.mark.abort_on_fail | ||
async def test_build_and_deploy( | ||
ops_test: OpsTest, application_charm, legacy_charm, database_charm | ||
) -> None: | ||
"""Build and deploy a sharded cluster.""" | ||
await ops_test.model.deploy( | ||
database_charm, | ||
config={"role": "config-server"}, | ||
application_name=CONFIG_SERVER_ONE_APP_NAME, | ||
) | ||
await ops_test.model.deploy( | ||
database_charm, | ||
config={"role": "config-server"}, | ||
application_name=CONFIG_SERVER_TWO_APP_NAME, | ||
) | ||
await ops_test.model.deploy( | ||
database_charm, num_units=1, config={"role": "shard"}, application_name=SHARD_ONE_APP_NAME | ||
) | ||
await ops_test.model.deploy(application_charm, application_name=APP_CHARM_NAME) | ||
await ops_test.model.deploy(legacy_charm, application_name=LEGACY_APP_CHARM_NAME) | ||
|
||
await ops_test.model.wait_for_idle( | ||
apps=[ | ||
CONFIG_SERVER_ONE_APP_NAME, | ||
CONFIG_SERVER_TWO_APP_NAME, | ||
SHARD_ONE_APP_NAME, | ||
], | ||
idle_period=20, | ||
raise_on_blocked=False, | ||
timeout=TIMEOUT, | ||
) | ||
|
||
|
||
async def test_only_one_config_server_relation(ops_test: OpsTest) -> None: | ||
"""Verify that a shard can only be related to one config server.""" | ||
await ops_test.model.integrate( | ||
f"{SHARD_ONE_APP_NAME}:{SHARD_REL_NAME}", | ||
f"{CONFIG_SERVER_ONE_APP_NAME}:{CONFIG_SERVER_REL_NAME}", | ||
) | ||
|
||
with pytest.raises(JujuAPIError) as juju_error: | ||
await ops_test.model.integrate( | ||
f"{SHARD_ONE_APP_NAME}:{SHARD_REL_NAME}", | ||
f"{CONFIG_SERVER_TWO_APP_NAME}:{CONFIG_SERVER_REL_NAME}", | ||
) | ||
|
||
assert ( | ||
juju_error.value.args[0] == RELATION_LIMIT_MESSAGE | ||
), "Shard can relate to multiple config servers." | ||
|
||
|
||
async def test_cannot_use_db_relation(ops_test: OpsTest) -> None: | ||
"""Verify that a shard cannot use the DB relation.""" | ||
await ops_test.model.integrate( | ||
f"{APP_CHARM_NAME}:{DATABASE_REL_NAME}", | ||
SHARD_ONE_APP_NAME, | ||
) | ||
|
||
await ops_test.model.wait_for_idle( | ||
apps=[SHARD_ONE_APP_NAME], | ||
idle_period=20, | ||
raise_on_blocked=False, | ||
timeout=TIMEOUT, | ||
) | ||
|
||
shard_unit = ops_test.model.applications[SHARD_ONE_APP_NAME].units[0] | ||
assert ( | ||
shard_unit.workload_status_message == "Sharding roles do not support database interface." | ||
), "Shard cannot be related using the database relation" | ||
|
||
# clean up relation | ||
await ops_test.model.applications[SHARD_ONE_APP_NAME].remove_relation( | ||
f"{APP_CHARM_NAME}:{DATABASE_REL_NAME}", | ||
SHARD_ONE_APP_NAME, | ||
) | ||
|
||
await ops_test.model.wait_for_idle( | ||
apps=[SHARD_ONE_APP_NAME], | ||
idle_period=20, | ||
raise_on_blocked=False, | ||
timeout=TIMEOUT, | ||
) | ||
|
||
|
||
async def test_cannot_use_legacy_db_relation(ops_test: OpsTest) -> None: | ||
"""Verify that a shard cannot use the legcy DB relation.""" | ||
await ops_test.model.integrate( | ||
LEGACY_APP_CHARM_NAME, | ||
SHARD_ONE_APP_NAME, | ||
) | ||
|
||
await ops_test.model.wait_for_idle( | ||
apps=[SHARD_ONE_APP_NAME], | ||
idle_period=20, | ||
raise_on_blocked=False, | ||
timeout=TIMEOUT, | ||
) | ||
|
||
shard_unit = ops_test.model.applications[SHARD_ONE_APP_NAME].units[0] | ||
assert ( | ||
shard_unit.workload_status_message == "Sharding roles do not support obsolete interface." | ||
), "Shard cannot be related using the mongodb relation" | ||
|
||
# clean up relation | ||
await ops_test.model.applications[SHARD_ONE_APP_NAME].remove_relation( | ||
f"{SHARD_ONE_APP_NAME}:{LEGACY_RELATION_NAME}", | ||
f"{LEGACY_APP_CHARM_NAME}:{LEGACY_RELATION_NAME}", | ||
) | ||
|
||
await ops_test.model.wait_for_idle( | ||
apps=[SHARD_ONE_APP_NAME], | ||
idle_period=20, | ||
raise_on_blocked=False, | ||
timeout=TIMEOUT, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -192,6 +192,21 @@ deps = | |
commands = | ||
pytest -v --tb native --log-cli-level=INFO -s --durations=0 {posargs} {[vars]tests_path}/integration/sharding_tests/test_sharding.py | ||
|
||
[testenv:sharding-relation-integration] | ||
description = Run sharding integration tests | ||
pass_env = | ||
{[testenv]pass_env} | ||
CI | ||
deps = | ||
pytest | ||
juju==3.2.0.1 | ||
pytest-mock | ||
pytest-operator | ||
git+https://github.com/canonical/[email protected]\#subdirectory=python/pytest_plugins/pytest_operator_cache | ||
-r {tox_root}/requirements.txt | ||
commands = | ||
pytest -v --tb native --log-cli-level=INFO -s --durations=0 {posargs} {[vars]tests_path}/integration/sharding_tests/test_sharding_relations.py | ||
|
||
|
||
[testenv:integration] | ||
description = Run all integration tests | ||
|