From 773dd9959e5684902e84cc4751d47ccf321a4f22 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 7 Mar 2023 19:51:20 -0400 Subject: [PATCH] Integration tests for NG UI charm Change-Id: I3c8958d54aeed84faf1ed2194bc818c1691cf755 Signed-off-by: Daniel Arndt --- .../osm-ng-ui/tests/integration/test_charm.py | 155 ++++++++++++++++++ installers/charm/osm-ng-ui/tox.ini | 16 +- 2 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 installers/charm/osm-ng-ui/tests/integration/test_charm.py diff --git a/installers/charm/osm-ng-ui/tests/integration/test_charm.py b/installers/charm/osm-ng-ui/tests/integration/test_charm.py new file mode 100644 index 00000000..b9aa9101 --- /dev/null +++ b/installers/charm/osm-ng-ui/tests/integration/test_charm.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Copyright 2023 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: legal@canonical.com +# +# To get in touch with the maintainers, please contact: +# osm-charmers@lists.launchpad.net +# +# Learn more about testing at: https://juju.is/docs/sdk/testing + +import asyncio +import logging +import shlex +from pathlib import Path + +import pytest +import yaml +from pytest_operator.plugin import OpsTest + +logger = logging.getLogger(__name__) + +METADATA = yaml.safe_load(Path("./metadata.yaml").read_text()) +NG_UI_APP = METADATA["name"] + +# Required charms (needed by NG UI) +NBI_CHARM = "osm-nbi" +NBI_APP = "nbi" +KAFKA_CHARM = "kafka-k8s" +KAFKA_APP = "kafka" +MONGO_DB_CHARM = "mongodb-k8s" +MONGO_DB_APP = "mongodb" +PROMETHEUS_CHARM = "osm-prometheus" +PROMETHEUS_APP = "prometheus" +KEYSTONE_CHARM = "osm-keystone" +KEYSTONE_APP = "keystone" +MYSQL_CHARM = "charmed-osm-mariadb-k8s" +MYSQL_APP = "mysql" +ZOOKEEPER_CHARM = "zookeeper-k8s" +ZOOKEEPER_APP = "zookeeper" + +INGRESS_CHARM = "nginx-ingress-integrator" +INGRESS_APP = "ingress" + +ALL_APPS = [ + NBI_APP, + NG_UI_APP, + KAFKA_APP, + MONGO_DB_APP, + PROMETHEUS_APP, + KEYSTONE_APP, + MYSQL_APP, + ZOOKEEPER_APP, +] + + +@pytest.mark.abort_on_fail +async def test_ng_ui_is_deployed(ops_test: OpsTest): + ng_ui_charm = await ops_test.build_charm(".") + ng_ui_resources = {"ng-ui-image": METADATA["resources"]["ng-ui-image"]["upstream-source"]} + keystone_deploy_cmd = f"juju deploy -m {ops_test.model_full_name} {KEYSTONE_CHARM} {KEYSTONE_APP} --resource keystone-image=opensourcemano/keystone:testing-daily" + + await asyncio.gather( + ops_test.model.deploy( + ng_ui_charm, resources=ng_ui_resources, application_name=NG_UI_APP, series="focal" + ), + ops_test.model.deploy(NBI_CHARM, application_name=NBI_APP, channel="beta"), + ops_test.model.deploy(KAFKA_CHARM, application_name=KAFKA_APP, channel="stable"), + ops_test.model.deploy( + MONGO_DB_CHARM, application_name=MONGO_DB_APP, channel="latest/stable" + ), + ops_test.model.deploy( + PROMETHEUS_CHARM, application_name=PROMETHEUS_APP, channel="latest/edge" + ), + ops_test.model.deploy(ZOOKEEPER_CHARM, application_name=ZOOKEEPER_APP, channel="stable"), + ops_test.model.deploy(MYSQL_CHARM, application_name=MYSQL_APP, channel="stable"), + # Keystone is deployed separately because the juju python library has a bug where resources + # are not properly deployed. See https://github.com/juju/python-libjuju/issues/766 + ops_test.run(*shlex.split(keystone_deploy_cmd), check=True), + ) + + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS, timeout=300) + logger.info("Adding relations for other components") + await asyncio.gather( + ops_test.model.relate(MYSQL_APP, KEYSTONE_APP), + ops_test.model.relate(KAFKA_APP, ZOOKEEPER_APP), + ops_test.model.relate(KEYSTONE_APP, NBI_APP), + ops_test.model.relate(KAFKA_APP, NBI_APP), + ops_test.model.relate(MONGO_DB_APP, NBI_APP), + ops_test.model.relate(PROMETHEUS_APP, NBI_APP), + ) + + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS, timeout=300) + + assert ops_test.model.applications[NG_UI_APP].status == "blocked" + unit = ops_test.model.applications[NG_UI_APP].units[0] + assert unit.workload_status_message == "need nbi relation" + + logger.info("Adding relations") + await ops_test.model.relate(NG_UI_APP, NBI_APP) + + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS, status="active", timeout=300) + + +@pytest.mark.abort_on_fail +async def test_ng_ui_scales_up(ops_test: OpsTest): + logger.info("Scaling up osm-ng-ui") + expected_units = 3 + assert len(ops_test.model.applications[NG_UI_APP].units) == 1 + await ops_test.model.applications[NG_UI_APP].scale(expected_units) + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle( + apps=[NG_UI_APP], status="active", wait_for_exact_units=expected_units + ) + + +@pytest.mark.abort_on_fail +async def test_ng_ui_blocks_without_relation(ops_test: OpsTest): + await asyncio.gather(ops_test.model.applications[NBI_APP].remove_relation(NBI_APP, NG_UI_APP)) + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=[NG_UI_APP]) + assert ops_test.model.applications[NG_UI_APP].status == "blocked" + for unit in ops_test.model.applications[NG_UI_APP].units: + assert unit.workload_status_message == "need nbi relation" + await ops_test.model.relate(NG_UI_APP, NBI_APP) + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS, status="active") + + +@pytest.mark.abort_on_fail +async def test_ng_ui_integration_ingress(ops_test: OpsTest): + await asyncio.gather( + ops_test.model.deploy(INGRESS_CHARM, application_name=INGRESS_APP, channel="beta"), + ) + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS + [INGRESS_APP]) + + await ops_test.model.relate(NG_UI_APP, INGRESS_APP) + async with ops_test.fast_forward(): + await ops_test.model.wait_for_idle(apps=ALL_APPS + [INGRESS_APP], status="active") diff --git a/installers/charm/osm-ng-ui/tox.ini b/installers/charm/osm-ng-ui/tox.ini index 13c97358..94974def 100644 --- a/installers/charm/osm-ng-ui/tox.ini +++ b/installers/charm/osm-ng-ui/tox.ini @@ -21,13 +21,13 @@ [tox] skipsdist=True skip_missing_interpreters = True -envlist = lint, unit +envlist = lint, unit, integration [vars] -src_path = {toxinidir}/src/ -tst_path = {toxinidir}/tests/ +src_path = {toxinidir}/src +tst_path = {toxinidir}/tests lib_path = {toxinidir}/lib/charms/osm_ng_ui -all_path = {[vars]src_path} {[vars]tst_path} +all_path = {[vars]src_path} {[vars]tst_path} [testenv] setenv = @@ -63,7 +63,7 @@ deps = commands = # uncomment the following line if this charm owns a lib codespell {[vars]lib_path} - codespell {toxinidir}/. --skip {toxinidir}/.git --skip {toxinidir}/.tox \ + 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 # pflake8 wrapper supports config from pyproject.toml @@ -80,16 +80,16 @@ deps = -r{toxinidir}/requirements.txt commands = coverage run --source={[vars]src_path},{[vars]lib_path} \ - -m pytest --ignore={[vars]tst_path}integration -v --tb native -s {posargs} + -m pytest {[vars]tst_path}/unit -v --tb native -s {posargs} coverage report coverage xml [testenv:integration] description = Run integration tests deps = + juju<3.0.0 pytest - juju pytest-operator -r{toxinidir}/requirements.txt commands = - pytest -v --tb native --ignore={[vars]tst_path}unit --log-cli-level=INFO -s {posargs} + pytest -v --tb native {[vars]tst_path}/integration --log-cli-level=INFO -s {posargs} --cloud microk8s -- 2.25.1