Skip to content

Commit

Permalink
eat: integration tests bumping resources
Browse files Browse the repository at this point in the history
#133

Summary of changes:
- Use lightkube for deletion and testing.
- Verify remove test when juju/python-libjuju#877 is resolved.
  • Loading branch information
Ivan Chvets committed Jun 14, 2023
1 parent 924c7c3 commit 0bfbe30
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 40 deletions.
8 changes: 8 additions & 0 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from lightkube import ApiError
from lightkube.generic_resource import load_in_cluster_generic_resources
from lightkube.models.core_v1 import ServicePort
from lightkube.resources.core_v1 import ConfigMap
from ops.charm import CharmBase
from ops.framework import EventBase, StoredState
from ops.main import main
Expand Down Expand Up @@ -406,6 +407,13 @@ def _on_remove(self, _):
self.configmap_resource_handler.lightkube_client,
configmap_resources_manifests,
)
# remove ConfigMap deployed by workload
self.configmap_resource_handler.lightkube_client.delete(
ConfigMap,
name="a33bd623.machinelearning.seldon.io",
namespace=self._namespace,
grace_period=0,
)
except ApiError as error:
# do not log/report when resources were not found
if error.status.code != 404:
Expand Down
69 changes: 29 additions & 40 deletions tests/integration/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from lightkube.generic_resource import create_namespaced_resource
from lightkube.resources.apiextensions_v1 import CustomResourceDefinition
from lightkube.resources.apps_v1 import Deployment
from lightkube.resources.core_v1 import ConfigMap, Namespace, Service
from lightkube.resources.core_v1 import ConfigMap, Namespace, Pod, Service
from pytest_operator.plugin import OpsTest

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -110,6 +110,24 @@ def assert_available(client, resource_class, resource_name, namespace):

assert state == "Available", f"Waited too long for {resource_class_kind}/{resource_name}!"

@tenacity.retry(
wait=tenacity.wait_exponential(multiplier=2, min=1, max=10),
stop=tenacity.stop_after_attempt(60),
reraise=True,
)
def assert_deleted(client, resource_class, resource_name, namespace):
"""Test for deleted resource. Retries multiple times to allow deployment to be deleted."""
logger.info(f"Waiting for {resource_class}/{resource_name} to be deleted.")
deleted = False
try:
dep = client.get(resource_class, resource_name, namespace=namespace)
except ApiError as error:
logger.info(f"Not found {resource_class}/{resource_name}. Status {error.status.code} ")
if error.status.code == 404:
deleted = True

assert deleted, f"Waited too long for {resource_class}/{resource_name} to be deleted!"


async def fetch_url(url):
"""Fetch provided URL and return JSON."""
Expand Down Expand Up @@ -245,25 +263,6 @@ async def test_seldon_alert_rules(ops_test: OpsTest):
)


@tenacity.retry(
wait=tenacity.wait_exponential(multiplier=2, min=1, max=10),
stop=tenacity.stop_after_attempt(60),
reraise=True,
)
def assert_deleted(client, resource_class, resource_name, namespace):
"""Test for deleted resource. Retries multiple times to allow deployment to be deleted."""
logger.info(f"Waiting for {resource_class}/{resource_name} to be deleted.")
deleted = False
try:
dep = client.get(resource_class, resource_name, namespace=namespace)
except ApiError as error:
logger.info(f"Not found {resource_class}/{resource_name}. Status {error.status.code} ")
if error.status.code == 404:
deleted = True

assert deleted, f"Waited too long for {resource_class}/{resource_name} to be deleted!"


@pytest.mark.asyncio
async def test_seldon_deployment(ops_test: OpsTest):
"""Test Seldon Deployment scenario."""
Expand Down Expand Up @@ -496,34 +495,24 @@ async def test_seldon_predictor_server(ops_test: OpsTest, server_config, url, re
)


@tenacity.retry(
wait=tenacity.wait_exponential(multiplier=2, min=1, max=10),
stop=tenacity.stop_after_attempt(60),
reraise=True,
)
async def assert_application_removed(ops_test: OpsTest):
"""Remove application and verify it is removed."""
logger.info(f"Removing application {APP_NAME} from model {ops_test.model_name}")
# TO-DO: use this: await ops_test.run("juju", "remove-application", f"{APP_NAME}")
subprocess.check_output(
["juju", "remove-application", "-m", f"{ops_test.model_name}", f"{APP_NAME}"]
)
assert APP_NAME not in ops_test.model.applications, f"Waited too long for {APP_NAME} removal!"


@pytest.mark.abort_on_fail
@pytest.mark.asyncio
async def test_remove_with_resources_present(ops_test: OpsTest):
def test_remove_with_resources_present(ops_test: OpsTest):
"""Test remove with all resources deployed.
Verify that all deployed resources that need to be removed are removed.
"""
lightkube_client = Client()

# remove deployed charm and verify that it is removed
await assert_application_removed(ops_test)
# TO-DO: use this: await ops_test.run("juju", "remove-application", f"{APP_NAME}")
subprocess.check_output(
f"juju remove-application -m {ops_test.model_name} {APP_NAME}",
shell=True,
stderr=subprocess.STDOUT,
)
assert_deleted(lightkube_client, Pod, "seldon-controller-manager-0", ops_test.model_name)

# verify that all resources that were deployed are removed
lightkube_client = Client()

# verify all CRDs in namespace are removed
crd_list = lightkube_client.list(
CustomResourceDefinition,
Expand Down

0 comments on commit 0bfbe30

Please sign in to comment.