From 8cbdd67e8b090bc236d4bcc6270eeb64c86c343a Mon Sep 17 00:00:00 2001 From: Jacob Callahan Date: Tue, 22 Nov 2022 18:59:19 -0500 Subject: [PATCH] Add basic tests for dependencies These check some basic functionality for out top-level dependencies. They are not meant to be exhaustive, but rather to catch any obvious changes in behavior. I also added a helper script for robottelo's config files. The initial helper allows a user to symlink their configs from another directory. We should expand on this script later for config migration/etc --- .github/workflows/pull_request.yml | 3 + requirements.txt | 1 - scripts/config_helpers.py | 40 +++++++ tests/robottelo/conftest.py | 6 ++ tests/robottelo/test_dependencies.py | 150 +++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 scripts/config_helpers.py create mode 100644 tests/robottelo/test_dependencies.py diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index fd18f7826f7..4203bb64d21 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -56,6 +56,9 @@ jobs: pytest --collect-only --setup-plan --disable-pytest-warnings -n 2 -m pre_upgrade tests/upgrades/ pytest --collect-only --setup-plan --disable-pytest-warnings -n 2 -m post_upgrade tests/upgrades/ + - name: Run Robottelo's Tests + run: pytest -sv tests/robottelo/ + - name: Make Docs run: | make test-docstrings diff --git a/requirements.txt b/requirements.txt index daddd626fbf..f7241f41620 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ fauxfactory==3.1.0 jinja2==3.1.2 manifester==0.0.11 navmazing==1.1.6 -pexpect==4.8.0 productmd==1.33 pyotp==2.7.0 python-box==6.1.0 diff --git a/scripts/config_helpers.py b/scripts/config_helpers.py new file mode 100644 index 00000000000..d1a41007a09 --- /dev/null +++ b/scripts/config_helpers.py @@ -0,0 +1,40 @@ +"""A series of commands to help with robottelo configuration""" +from pathlib import Path + +import click +from logzero import logger + + +@click.group() +def config(): + """Manage robottelo configuration""" + pass + + +@config.command("symlink") +@click.option( + "--from", + "from_", + type=click.Path(exists=True, file_okay=False), + help="The path to the existing config directory", +) +def symlink(from_): + """Symlink the config directory to the specified path""" + from_ = Path(from_) + # iterate through all template files in the conf directory + for template in Path("conf/").glob("*.template"): + # check if non-template file exists + if not (real_name := Path(f"conf/{template.stem}")).exists(): + # if not, symlink to the file in the from_ directory + link_path = from_ / real_name.name + if not link_path.exists(): + logger.error(f"Could not find {link_path}") + continue + logger.warning(f"Symlinking {real_name} to {from_ / real_name}") + real_name.symlink_to(from_ / real_name.name) + else: + logger.info(f"Skipping {real_name} because it already exists") + + +if __name__ == "__main__": + config() diff --git a/tests/robottelo/conftest.py b/tests/robottelo/conftest.py index 5c5298d5cff..c093c969d12 100644 --- a/tests/robottelo/conftest.py +++ b/tests/robottelo/conftest.py @@ -7,6 +7,12 @@ from fauxfactory import gen_string +@pytest.fixture(scope='session', autouse=True) +def align_to_satellite(): + """Override align_to_satellite used in functional tests""" + pass + + @pytest.fixture(scope='function') def dummy_test(request): """This should be indirectly parametrized to provide dynamic dummy_tests to exec_test""" diff --git a/tests/robottelo/test_dependencies.py b/tests/robottelo/test_dependencies.py new file mode 100644 index 00000000000..71dbee35466 --- /dev/null +++ b/tests/robottelo/test_dependencies.py @@ -0,0 +1,150 @@ +"""Test important behavior in robottelo's direct dependencies""" + + +def test_cryptography(): + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import padding + from cryptography.hazmat.primitives.asymmetric import rsa + + fake_key = rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=default_backend() + ).private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + private_key = serialization.load_pem_private_key( + fake_key, password=None, backend=default_backend() + ) + assert private_key.key_size == 2048 + signature = private_key.sign(b"test", padding.PKCS1v15(), hashes.SHA256()) + assert len(signature) == 256 + + +def test_deepdiff(): + from deepdiff import DeepDiff + + assert DeepDiff({'a': 1}, {'a': 2}) + + +def test_dynaconf(): + from robottelo.config import settings + + assert settings + + +def test_fauxfactory(): + import fauxfactory + + meth_args = { + 'gen_alpha': {'length': 10}, + 'gen_alphanumeric': {'length': 20}, + 'gen_cjk': {'length': 30}, + 'gen_html': {'length': 40}, + 'gen_integer': {'min_value': 1, 'max_value': 10}, + 'gen_ipaddr': {}, + 'gen_string': {'str_type': 'alphanumeric', 'length': 50}, + 'gen_url': {}, + } + for meth, args in meth_args.items(): + result = getattr(fauxfactory, meth)(**args) + assert result + if 'length' in args and meth != 'gen_html': + assert len(result) == args['length'] + + +def test_jinja2(): + import jinja2 + + template = jinja2.Template("Hello {{ name }}!") + assert template.render(name="John Doe") == "Hello John Doe!" + + +def test_navmazing(): + from navmazing import NavigationTriesExceeded + + assert NavigationTriesExceeded + + +def test_productmd(): + from productmd.common import parse_nvra + + assert parse_nvra('foo-1.0-1.x86_64.rpm') == { + 'arch': 'x86_64', + 'epoch': 0, + 'name': 'foo', + 'release': '1', + 'version': '1.0', + } + + +def test_pyotp(): + import pyotp + + fake_secret = 'JBSWY3DPEHPK3PXP' + totp = pyotp.TOTP(fake_secret) + assert totp.now() + + +def test_python_box(): + from box import Box + + assert Box({'a': 1}).a == 1 + + +def test_pyyaml(): + import yaml + + assert yaml.safe_load('a: 1') == {'a': 1} + assert yaml.safe_dump({'a': 1}).strip() == 'a: 1' + + +def test_requests(): + import requests + + assert requests.get('https://www.redhat.com').status_code == 200 + from requests.exceptions import HTTPError + + assert HTTPError + + +def test_tenacity(): + from tenacity import retry + from tenacity import stop_after_attempt + from tenacity import wait_fixed + + @retry(stop=stop_after_attempt(3), wait=wait_fixed(1)) + def test(): + raise Exception('test') + + try: + test() + except Exception: + pass + + +def test_testimony(): + import testimony + + test_cases = testimony.get_testcases(['tests/foreman/api/test_activationkey.py']) + assert test_cases + + +def test_wait_for(): + from wait_for import wait_for + + assert wait_for(lambda: True, num_sec=1, delay=1) + + +def test_wrapanapi(): + from wrapanapi.systems.google import GoogleCloudSystem + + assert GoogleCloudSystem + from wrapanapi.systems.virtualcenter import VMWareSystem + + assert VMWareSystem + from wrapanapi.entities.vm import VmState + + assert VmState