Skip to content

Commit

Permalink
Smoke test for cou plan (#179)
Browse files Browse the repository at this point in the history
* Smoke test for cou plan

check the stdout for the following scenarios:

* plan with backup
* plan without backup

* Use absolute path instead of relative for snap file

* - add log about cou executable path

* - use pathlib instead of os.
- use the full snap path to not use the python package when using
  the snap.

* - cou wrapper to run commands
- not remove the cou python package on tearDown.

* - add error log message if subprocess fail.

* Explicitly pass the model name

- Using juju switch it’s not possible because it uses JUJU_MODEL
and python libjuju doesn't support this env var.
- Running without explicitly passing the model can make cou run in
  a different model that it’s not on the recently deployed by zaza.

* - remove comment to skip test.

* - apply suggestions

* - added custom exception for install commands
- snap_installed logic inside configure_executable_path

* - remove get_or_create_libjuju_thread and clean_up_libjuju_thread
- use COU_DATA to create local share folder.

---------

Co-authored-by: TQ <[email protected]>
  • Loading branch information
gabrielcocenza and agileshaw authored Dec 6, 2023
1 parent c216634 commit 8692508
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ jobs:
with:
name: SNAP_FILE
- name: Run func tests
run: TEST_SNAP=charmed-openstack-upgrader.snap tox -e func
run: TEST_SNAP=$GITHUB_WORKSPACE/charmed-openstack-upgrader.snap tox -e func
156 changes: 156 additions & 0 deletions tests/functional/tests/smoke.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import logging
import os
import unittest
from pathlib import Path
from subprocess import CalledProcessError, CompletedProcess, check_call, run

import zaza

from cou.utils import COU_DATA

log = logging.getLogger(__name__)


class FuncSmokeException(Exception):
"""Default Func Smoke exception."""


class SmokeTest(unittest.TestCase):
"""COU smoke functional tests."""

@classmethod
def setUpClass(cls) -> None:
cls.create_local_share_folder()
cls.model_name = zaza.model.get_juju_model()
cls.configure_executable_path()

@classmethod
def tearDownClass(cls) -> None:
cls.remove_snap_package()

def create_local_share_folder() -> None:
"""Create the .local/share/ folder if does not exist."""
COU_DATA.mkdir(parents=True, exist_ok=True)

@classmethod
def configure_executable_path(cls) -> None:
cls.snap_installed = False
cou_snap = os.environ.get("TEST_SNAP")
if cou_snap:
cls.install_snap_package(cou_snap)
cls.exc_path = "/snap/bin/cou"
cls.snap_installed = True
else:
# functest already installs cou as python package
log.warning("using cou as python package")
cls.exc_path = os.getenv("TEST_PYTHON_PACKAGE") + "/bin/cou"

log.info("Using cou path: %s", cls.exc_path)

@classmethod
def install_snap_package(cls, cou_snap: str) -> None:
"""Install cou snap package.
:param cou_snap: Path to the cou snap.
:type cou_snap: str
"""
log.info("Installing %s", cou_snap)
assert Path(cou_snap).is_file(), f"{cou_snap} is not file"

# install the snap
cls.snap_install_commands(
["sudo", "snap", "install", "--dangerous", cou_snap],
"Cannot install the cou snap. Please check your permission",
)

# connect interfaces
interfaces_to_connect = [
"juju-client-observe",
"dot-local-share-cou",
"ssh-public-keys",
]
for interface in interfaces_to_connect:
cls.snap_install_commands(
[
"sudo",
"snap",
"connect",
f"charmed-openstack-upgrader:{interface}",
"snapd",
],
f"Cannot connect the interface: {interface}",
)

# make the cou alias
cls.snap_install_commands(
["sudo", "snap", "alias", "charmed-openstack-upgrader.cou", "cou"],
"Cannot create the cou alias",
)

# check that the executable path exists
assert Path("/snap/bin/cou").exists(), "Cannot find the cou executable snap path."
cls.exc_path = "/snap/bin/cou"

def snap_install_commands(cmd: list[str], custom_err_msg: str):
"""Commands to run and install the cou snap.
:param cmd: The command to be executed.
:type cmd: list[str]
:param custom_err_msg: Custom error message if the command fails.
:type custom_err_msg: str
:raises FuncSmokeException: When the command fails.
"""
try:
check_call(cmd)
except CalledProcessError as err:
raise FuncSmokeException(custom_err_msg) from err

@classmethod
def remove_snap_package(cls) -> None:
"""Remove cou package."""
if cls.snap_installed:
log.info("Removing snap package cou")
check_call(["sudo", "snap", "remove", "charmed-openstack-upgrader", "--purge"])

def cou(self, cmd: list[str]) -> CompletedProcess:
"""Run cou commands.
:param cmd: Command to run.
:type cmd: list[str]
:return: Response of the command.
:rtype: CompletedProcess
"""
return run([self.exc_path] + cmd, capture_output=True, text=True)

def test_plan_default(self) -> None:
"""Test plan with backup."""
result = self.cou(["plan", "--model", self.model_name]).stdout
expected_plan = (
"Upgrade cloud from 'ussuri' to 'victoria'\n"
"\tVerify that all OpenStack applications are in idle state\n"
"\tBackup mysql databases\n"
"\tControl Plane principal(s) upgrade plan\n"
"\t\tUpgrade plan for 'designate-bind' to victoria\n"
"\t\t\tUpgrade software packages of 'designate-bind' "
"from the current APT repositories\n"
"\t\t\tUpgrade 'designate-bind' to the new channel: 'victoria/stable'\n"
"\t\t\tWait 300s for app designate-bind to reach the idle state.\n"
"\t\t\tCheck if the workload of 'designate-bind' has been upgraded\n"
)
self.assertIn(expected_plan, result)

def test_plan_no_backup(self) -> None:
"""Test plan with no backup."""
result = self.cou(["plan", "--model", self.model_name, "--no-backup"]).stdout
expected_plan = (
"Upgrade cloud from 'ussuri' to 'victoria'\n"
"\tVerify that all OpenStack applications are in idle state\n"
"\tControl Plane principal(s) upgrade plan\n"
"\t\tUpgrade plan for 'designate-bind' to victoria\n"
"\t\t\tUpgrade software packages of 'designate-bind' "
"from the current APT repositories\n"
"\t\t\tUpgrade 'designate-bind' to the new channel: 'victoria/stable'\n"
"\t\t\tWait 300s for app designate-bind to reach the idle state.\n"
"\t\t\tCheck if the workload of 'designate-bind' has been upgraded\n"
)
self.assertIn(expected_plan, result)
1 change: 1 addition & 0 deletions tests/functional/tests/tests.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
tests:
- tests.functional.tests.model.COUModelTest
- tests.functional.tests.smoke.SmokeTest
- openstack:
- tests.functional.tests.backup.BackupTest
gate_bundles:
Expand Down
7 changes: 5 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ skip_missing_interpreters = True

[testenv]
basepython = python3
setenv = PYTHONPATH={toxinidir}
passenv = USER
setenv =
PYTHONPATH={toxinidir}
TEST_PYTHON_PACKAGE={envdir}

[testenv:dev-environment]
envdir = {toxinidir}/.venv
Expand Down Expand Up @@ -58,6 +59,7 @@ deps = .[functests]
passenv =
TEST_*
OS_*
USER
commands =
functest-run-suite --smoke {posargs:--keep-faulty-model}

Expand All @@ -67,5 +69,6 @@ deps = .[functests]
passenv =
TEST_*
OS_*
USER
commands =
functest-run-suite {posargs:--keep-faulty-model}

0 comments on commit 8692508

Please sign in to comment.