diff --git a/rockcraft.yaml b/rockcraft.yaml index 67473fe..d63cf4f 100644 --- a/rockcraft.yaml +++ b/rockcraft.yaml @@ -16,10 +16,25 @@ services: override: replace startup: enabled +package-repositories: + - type: apt + url: https://deb.nodesource.com/node_20.x + components: [main] + suites: [focal] + key-id: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 + - type: apt + url: https://dl.yarnpkg.com/debian/ + components: [main] + suites: [stable] + key-id: 72ECF46A56B4AD39C907BBB71646B01B86E50310 + parts: vault: plugin: go + go-buildtags: + - vault + - ui source: https://github.com/hashicorp/vault.git source-tag: v1.15.6 source-type: git @@ -28,7 +43,11 @@ parts: - bin/vault build-snaps: - go/1.21/stable + build-packages: + - nodejs + - yarn override-build: | + make static-dist craftctl default strip -s $CRAFT_PART_INSTALL/bin/* diff --git a/tests/pyproject.toml b/tests/pyproject.toml index 90c9442..ee28151 100644 --- a/tests/pyproject.toml +++ b/tests/pyproject.toml @@ -1,51 +1,38 @@ +# Testing tools configuration [tool.coverage.run] branch = true [tool.coverage.report] show_missing = true -[tool.black] -line-length = 99 -target-version = ["py38"] +[tool.pytest.ini_options] +minversion = "6.0" +log_cli_level = "INFO" -[tool.isort] -profile = "black" +# Linting tools configuration +[tool.ruff] +line-length = 99 -[tool.flake8] -max-line-length = 99 -max-doc-length = 99 +[tool.ruff.lint] +select = ["E", "W", "F", "C", "N", "D", "I001"] +extend-ignore = [ + "D203", + "D204", + "D213", + "D215", + "D400", + "D404", + "D406", + "D407", + "D408", + "D409", + "D413", +] +ignore = ["E501", "D107"] + +[tool.ruff.lint.mccabe] max-complexity = 10 -exclude = [".git", "__pycache__", ".tox", "build", "dist", "*.egg_info", "venv"] -select = ["E", "W", "F", "C", "N", "R", "D", "H"] -per-file-ignores = ["tests/*:D100,D101,D102,D103,D107"] -docstring-convention = "google" -copyright-check = "True" -copyright-author = "Canonical Ltd." -copyright-regexp = "Copyright\\s\\d{4}([-,]\\d{4})*\\s+%(author)s" -[tool.mypy] -pretty = true -python_version = 3.8 -follow_imports = "normal" -warn_redundant_casts = true -warn_unused_ignores = true -warn_unused_configs = true -show_traceback = true -show_error_codes = true -namespace_packages = true -explicit_package_bases = true -check_untyped_defs = true -allow_redefinition = true +[tool.codespell] +skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage" -# Ignore libraries that do not have type hint nor stubs -[[tool.mypy.overrides]] -module = ["flatten_json.*", "git.*"] -ignore_missing_imports = true - -[[tool.mypy.overrides]] -module = ["charms.*"] -follow_imports = "silent" - -[tool.pytest.ini_options] -minversion = "6.0" -log_cli_level = "INFO" diff --git a/tests/requirements.txt b/tests/requirements.txt index 440fb85..f8d7dbb 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,2 +1,5 @@ hvac requests +ruff +pyright +pytest diff --git a/tests/test_integration.py b/tests/test_integration.py index 06915a4..4207f60 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -7,14 +7,16 @@ import logging import subprocess import time -import unittest + +import pytest +import requests from vault import Vault logger = logging.getLogger(__name__) -def wait_for_vault_to_be_available(timeout: int = 30): +def wait_for_vault_to_be_available(timeout: int = 30) -> None: """Wait for Vault to be available.""" initial_time = time.time() vault = Vault("http://localhost:8200") @@ -22,34 +24,43 @@ def wait_for_vault_to_be_available(timeout: int = 30): try: if vault.is_api_available(): logger.info("Vault API is available") - return True + return except Exception: pass time.sleep(1) raise TimeoutError("Vault is not available after {} seconds".format(timeout)) -class TestVaultRock(unittest.TestCase): - """Integration tests to validate that the Vault ROCK works as expected.""" +@pytest.fixture(scope="module") +def run_container(): + """Start a Vault container.""" + subprocess.check_call( + "docker run -d -p 8200:8200 vault-rock:test", + shell=True, + ) + + +def test_given_vault_container_running_when_ui_is_enabled_then_ui_is_available(run_container): + """Validate that UI is available.""" + wait_for_vault_to_be_available() + response = requests.get("http://localhost:8200/ui/vault/init") - def setUp(self): - """Starts a Vault container.""" - subprocess.check_call( - "docker run -d -p 8200:8200 vault-rock:test ", - shell=True, - ) + assert response.status_code == 200 + assert "Vault UI is not available in this binary." not in response.text # This is the message when UI is disabled # noqa: E501 + assert "vault/config/environment" in response.text # This is a common element in the UI - def test_given_vault_container_running_when_initialize_then_properly_responds_to_commands( - self, - ): - """Runs basic CLI commands to initialize and unseal Vault.""" - vault = Vault("http://localhost:8200") - wait_for_vault_to_be_available() +def test_given_vault_container_running_when_initialize_then_properly_responds_to_commands( + run_container +): + """Runs basic CLI commands to initialize and unseal Vault.""" + vault = Vault("http://localhost:8200") + + wait_for_vault_to_be_available() - root_token, unseal_keys = vault.initialize() + _, unseal_keys = vault.initialize() - vault.unseal(unseal_keys) + vault.unseal(unseal_keys) - self.assertEqual(vault.is_initialized(), True) - self.assertEqual(vault.is_sealed(), False) + assert vault.is_initialized() + assert not vault.is_sealed() diff --git a/tests/tox.ini b/tests/tox.ini index df1af55..dd0e389 100644 --- a/tests/tox.ini +++ b/tests/tox.ini @@ -9,55 +9,29 @@ envlist = integration, lint, fmt, static [testenv] deps = - pytest - pytest-operator + -r{toxinidir}/requirements.txt setenv = PYTHONPATH = {toxinidir} PYTHONBREAKPOINT=ipdb.set_trace [testenv:fmt] description = Apply coding style standards to code -deps = - black - isort commands = - isort {toxinidir} - black {toxinidir} + ruff check --fix {[vars]all_path} [testenv:lint] description = Check code against coding style standards -deps = - black - flake8 - flake8-docstrings - flake8-copyright - flake8-builtins - pyproject-flake8 - pep8-naming - isort commands = - pflake8 {toxinidir} - isort --check-only --diff {toxinidir} - black --check --diff {toxinidir} + ruff check {toxinidir} [testenv:static] description = Run static analysis checks -deps = - -r{toxinidir}/requirements.txt - mypy - types-PyYAML - pytest - types-setuptools - types-toml commands = - mypy {toxinidir} {posargs} + pyright {toxinidir} setenv = PYTHONPATH = "" [testenv:integration] description = Run integration tests -deps = - pytest - -r{toxinidir}/requirements.txt commands = - pytest -v --tb native --log-cli-level=INFO -s {posargs} {toxinidir} \ No newline at end of file + pytest -v --tb native --log-cli-level=INFO -s {posargs} {toxinidir} diff --git a/tests/vault.py b/tests/vault.py index 5cfe6ee..3b78597 100644 --- a/tests/vault.py +++ b/tests/vault.py @@ -35,11 +35,11 @@ def initialize( return initialize_response["root_token"], initialize_response["keys"] def is_initialized(self) -> bool: - """Returns whether Vault is initialized.""" + """Return whether Vault is initialized.""" return self._client.sys.is_initialized() def is_sealed(self) -> bool: - """Returns whether Vault is sealed.""" + """Return whether Vault is sealed.""" return self._client.sys.is_sealed() def unseal(self, unseal_keys: List[str]) -> None: @@ -49,7 +49,7 @@ def unseal(self, unseal_keys: List[str]) -> None: logger.info("Vault is unsealed") def is_api_available(self) -> bool: - """Returns whether Vault is available.""" + """Return whether Vault is available.""" self._client.sys.read_health_status() try: self._client.sys.read_health_status() @@ -58,5 +58,5 @@ def is_api_available(self) -> bool: return True def set_token(self, token: str) -> None: - """Sets the Vault token for authentication.""" + """Set the Vault token for authentication.""" self._client.token = token