From 832e22ee00f2681720071cea21eb73afc21c5b92 Mon Sep 17 00:00:00 2001 From: Vladimir Sedmik Date: Thu, 28 Nov 2024 19:24:33 +0100 Subject: [PATCH 1/5] Add Flatpak CLI support and CRUD case --- .github/CODEOWNERS | 1 + robottelo/cli/flatpak_remote.py | 55 ++++++++++++ robottelo/constants/__init__.py | 18 ++++ tests/foreman/cli/test_flatpak.py | 144 ++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 robottelo/cli/flatpak_remote.py create mode 100644 tests/foreman/cli/test_flatpak.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 03127d591db..239ab0cf1d2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -52,6 +52,7 @@ tests/foreman/cli/test_contentview.py @SatelliteQE/team-phoenix tests/foreman/cli/test_contentviewfilter.py @SatelliteQE/team-phoenix tests/foreman/cli/test_docker.py @SatelliteQE/team-phoenix tests/foreman/cli/test_errata.py @SatelliteQE/team-phoenix +tests/foreman/cli/test_flatpak.py @SatelliteQE/team-phoenix tests/foreman/cli/test_host.py @SatelliteQE/team-phoenix tests/foreman/cli/test_hostcollection.py @SatelliteQE/team-phoenix tests/foreman/cli/test_http_proxy.py @SatelliteQE/team-phoenix diff --git a/robottelo/cli/flatpak_remote.py b/robottelo/cli/flatpak_remote.py new file mode 100644 index 00000000000..d44b6701664 --- /dev/null +++ b/robottelo/cli/flatpak_remote.py @@ -0,0 +1,55 @@ +""" +Usage:: + + hammer flatpak-remote [OPTIONS] SUBCOMMAND [ARG] ... + +Parameters:: + + SUBCOMMAND Subcommand + [ARG] ... Subcommand arguments + +Subcommands:: + + create Create a flatpak remote + delete Delete a flatpak remote + info Show a flatpak remote + list List flatpak remotes + remote-repository View and manage flatpak remote repositories + scan Scan a flatpak remote + update Update a flatpak remote + +""" + +from robottelo.cli.base import Base + + +class FlatpakRemote(Base): + """ + Manipulates Flatpak remotes and repositories + """ + + command_base = 'flatpak-remote' + + @classmethod + def scan(cls, options=None, output_format=None): + """Scan a flatpak remote""" + cls.command_sub = 'scan' + return cls.execute(cls._construct_command(options), output_format=output_format) + + @classmethod + def repository_info(cls, options=None, output_format='csv'): + """Show a flatpak remote repository""" + cls.command_sub = 'remote-repository info' + return cls.execute(cls._construct_command(options), output_format=output_format) + + @classmethod + def repository_list(cls, options=None, output_format='csv'): + """List flatpak remote repositories""" + cls.command_sub = 'remote-repository list' + return cls.execute(cls._construct_command(options), output_format=output_format) + + @classmethod + def repository_mirror(cls, options=None, output_format=None): + """Mirror a flatpak remote repository""" + cls.command_sub = 'remote-repository mirror' + return cls.execute(cls._construct_command(options), output_format=output_format) diff --git a/robottelo/constants/__init__.py b/robottelo/constants/__init__.py index 8a0637f4c70..62630a565da 100644 --- a/robottelo/constants/__init__.py +++ b/robottelo/constants/__init__.py @@ -746,6 +746,18 @@ } LABELLED_REPOS = [BOOTABLE_REPO, FLATPAK_REPO] CONTAINER_MANIFEST_LABELS = {'annotations', 'labels', 'is_bootable', 'is_flatpak'} + +FLATPAK_REMOTES = { + 'Fedora': { + 'url': 'https://registry.fedoraproject.org', + 'index_url': 'https://registry.fedoraproject.org/index/static?label:org.flatpak.ref:exists=1&tag=latest', + }, + 'RedHat': { + 'url': 'https://flatpaks.redhat.io', + 'index_url': 'https://flatpaks.redhat.io/rhel/index/static?label:org.flatpak.ref:exists=1&tag=latest', + }, +} + CONTAINER_CLIENTS = ['docker', 'podman'] CUSTOM_LOCAL_FOLDER = '/var/lib/pulp/imports/myrepo/' CUSTOM_LOCAL_FILE = '/var/lib/pulp/imports/myrepo/test.txt' @@ -1140,6 +1152,12 @@ 'destroy_alternate_content_sources', 'view_alternate_content_sources', ], + 'Katello::FlatpakRemote': [ + 'view_flatpak_remotes', + 'create_flatpak_remotes', + 'edit_flatpak_remotes', + 'destroy_flatpak_remotes', + ], 'KeyPair': ["view_keypairs", "destroy_keypairs"], 'Location': [ 'view_locations', diff --git a/tests/foreman/cli/test_flatpak.py b/tests/foreman/cli/test_flatpak.py new file mode 100644 index 00000000000..8a4247105bf --- /dev/null +++ b/tests/foreman/cli/test_flatpak.py @@ -0,0 +1,144 @@ +"""Capsule-Content related tests being run through CLI. + +:Requirement: Repository + +:CaseAutomation: Automated + +:CaseComponent: Repositories + +:team: Phoenix-content + +:CaseImportance: High + +""" + +import pytest + +from robottelo.constants import FLATPAK_REMOTES +from robottelo.exceptions import CLIReturnCodeError +from robottelo.utils.datafactory import gen_string + + +@pytest.fixture +def function_role(target_sat): + """An empty Role, no permissions""" + role = target_sat.api.Role().create() + yield role + role.delete() + + +@pytest.fixture +def function_user(target_sat, function_role, function_org): + """Non-admin user with an empty role assigned.""" + password = gen_string('alphanumeric') + user = target_sat.api.User( + login=gen_string('alpha'), + password=password, + role=[function_role], + organization=[function_org], + ).create() + user.password = password + yield user + user.delete() + + +def test_CRUD_and_sync_flatpak_remote_with_permissions( + target_sat, function_user, function_role, function_org +): + """Verify that Flatpak remote can be created, read, updated, scanned and deleted + only with appropriate permissions. + + :id: 3a8df09f-49bf-498f-8d71-7c0c3b4c505d + + :setup: + 1. Non-admin user with an empty role (no permissions yet) assigned. + + :steps: + Ensure that Flatpak remote can be + 1. listed only with proper permissions. + 2. created only with proper permissions. + 3. updated and scanned only with proper permissions. + 4. deleted only with proper permissions. + + :expectedresults: + 1. Every action succeeds only with the proper permission. + 2. The required permission is mentioned in the error message correctly. + + """ + emsg = 'Missing one of the required permissions: {}' + usr, pwd = function_user.login, function_user.password + + # 1. Ensure that remotes can be listed only with proper permissions. + p = 'view_flatpak_remotes' + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).list() + assert emsg.format(p) in str(e) + + target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) + res = ( + target_sat.cli.FlatpakRemote() + .with_user(usr, pwd) + .list({'organization-id': function_org.id}) + ) + assert len(res) == 0, f'Expected no remotes yet in the {function_org.name} org, but got {res}' + + # 2. Ensure that remotes can be created only with proper permissions. + p = 'create_flatpak_remotes' + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).create( + { + 'organization-id': function_org.id, + 'url': FLATPAK_REMOTES['Fedora']['url'], + 'name': gen_string('alpha'), + } + ) + assert emsg.format(p) in str(e) + + target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) + remote = ( + target_sat.cli.FlatpakRemote() + .with_user(usr, pwd) + .create( + { + 'organization-id': function_org.id, + 'url': FLATPAK_REMOTES['Fedora']['url'], + 'name': gen_string('alpha'), + } + ) + ) + res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + assert res == remote, 'Read values differ from the created ones' + + # 3. Ensure that remotes can be updated and scanned only with proper permissions. + p = 'edit_flatpak_remotes' + desc = gen_string('alpha') + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).update( + {'name': remote['name'], 'description': desc} + ) + assert emsg.format(p) in str(e) + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan({'name': remote['name']}) + assert emsg.format(p) in str(e) + + target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).update( + {'name': remote['name'], 'description': desc} + ) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan({'name': remote['name']}) + res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + assert res['description'] == desc, 'Description was not updated' + assert 'http' in res['registry-url'], 'Scan of flatpak remote failed' + + # 4. Ensure that remotes can be deleted only with proper permissions. + p = 'destroy_flatpak_remotes' + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).delete({'name': remote['name']}) + assert emsg.format(p) in str(e) + + target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) + res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).delete({'name': remote['name']}) + assert 'Flatpak Remote deleted' in res + with pytest.raises(CLIReturnCodeError) as e: + target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + assert 'Error: flatpak_remote not found' in str(e) From 7fff81f54e6a5d8582c6dddf031c1cf245f5c14c Mon Sep 17 00:00:00 2001 From: Vladimir Sedmik Date: Fri, 29 Nov 2024 13:38:23 +0100 Subject: [PATCH 2/5] Add a case to validate the remote scan --- tests/foreman/cli/test_flatpak.py | 40 ++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/foreman/cli/test_flatpak.py b/tests/foreman/cli/test_flatpak.py index 8a4247105bf..b11fb6630cf 100644 --- a/tests/foreman/cli/test_flatpak.py +++ b/tests/foreman/cli/test_flatpak.py @@ -1,4 +1,4 @@ -"""Capsule-Content related tests being run through CLI. +"""Flatpak related tests being run through CLI. :Requirement: Repository @@ -13,6 +13,7 @@ """ import pytest +import requests from robottelo.constants import FLATPAK_REMOTES from robottelo.exceptions import CLIReturnCodeError @@ -142,3 +143,40 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( with pytest.raises(CLIReturnCodeError) as e: target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) assert 'Error: flatpak_remote not found' in str(e) + + +def test_scan(target_sat, function_org, function_product): + """Verify flatpak remote scan detects all repos available in the remote index. + + :id: 3dff23f3-f415-4fb2-a41c-7cdcae617bb0 + + :steps: + 1. Create a flatpak remote and scan it. + 2. Read the remote index via its API. + 3. Compare the scanned repos match the repos in the remote index. + + :expectedresults: + 1. Repos scanned by flatpak remote match the repos available in the remote index. + + """ + remote = FLATPAK_REMOTES['Fedora'] + + # 1. Create a flatpak remote and scan it. + fr = target_sat.cli.FlatpakRemote().create( + { + 'organization-id': function_org.id, + 'url': remote['url'], + 'name': gen_string('alpha'), + } + ) + target_sat.cli.FlatpakRemote().scan({'id': fr['id']}) + + scanned_repos = target_sat.cli.FlatpakRemote().repository_list({'flatpak-remote-id': fr['id']}) + scanned_repo_names = [item['name'] for item in scanned_repos] + + # 2. Read the remote index via its API. + rq = requests.get(remote['index_url']).json() + index_repo_names = [item['Name'] for item in rq['Results']] + + # 3. Compare the scanned repos match the repos in the remote index. + assert sorted(scanned_repo_names) == sorted(index_repo_names) From 9326b197136760b3ad492bf85d38f4f22fcfc52e Mon Sep 17 00:00:00 2001 From: Vladimir Sedmik Date: Wed, 4 Dec 2024 09:23:15 +0100 Subject: [PATCH 3/5] Use more descriptive test name --- tests/foreman/cli/test_flatpak.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/foreman/cli/test_flatpak.py b/tests/foreman/cli/test_flatpak.py index b11fb6630cf..c38f84031f3 100644 --- a/tests/foreman/cli/test_flatpak.py +++ b/tests/foreman/cli/test_flatpak.py @@ -145,7 +145,7 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( assert 'Error: flatpak_remote not found' in str(e) -def test_scan(target_sat, function_org, function_product): +def test_scan_flatpak_remote(target_sat, function_org, function_product): """Verify flatpak remote scan detects all repos available in the remote index. :id: 3dff23f3-f415-4fb2-a41c-7cdcae617bb0 From ab64bf12193da89f0b56380f9b69263ad0ea0b35 Mon Sep 17 00:00:00 2001 From: Vladimir Sedmik Date: Thu, 5 Dec 2024 17:49:34 +0100 Subject: [PATCH 4/5] Extend the scan case with authenticated remote --- robottelo/constants/__init__.py | 4 ++- tests/foreman/cli/test_flatpak.py | 41 ++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/robottelo/constants/__init__.py b/robottelo/constants/__init__.py index 62630a565da..57fc0114ba0 100644 --- a/robottelo/constants/__init__.py +++ b/robottelo/constants/__init__.py @@ -751,10 +751,12 @@ 'Fedora': { 'url': 'https://registry.fedoraproject.org', 'index_url': 'https://registry.fedoraproject.org/index/static?label:org.flatpak.ref:exists=1&tag=latest', + 'authenticated': False, }, 'RedHat': { - 'url': 'https://flatpaks.redhat.io', + 'url': 'https://flatpaks.redhat.io/rhel/', 'index_url': 'https://flatpaks.redhat.io/rhel/index/static?label:org.flatpak.ref:exists=1&tag=latest', + 'authenticated': True, }, } diff --git a/tests/foreman/cli/test_flatpak.py b/tests/foreman/cli/test_flatpak.py index c38f84031f3..917daa00d84 100644 --- a/tests/foreman/cli/test_flatpak.py +++ b/tests/foreman/cli/test_flatpak.py @@ -15,6 +15,7 @@ import pytest import requests +from robottelo.config import settings from robottelo.constants import FLATPAK_REMOTES from robottelo.exceptions import CLIReturnCodeError from robottelo.utils.datafactory import gen_string @@ -107,7 +108,11 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( } ) ) - res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + res = ( + target_sat.cli.FlatpakRemote() + .with_user(usr, pwd) + .info({'organization-id': function_org.id, 'name': remote['name']}) + ) assert res == remote, 'Read values differ from the created ones' # 3. Ensure that remotes can be updated and scanned only with proper permissions. @@ -115,7 +120,7 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( desc = gen_string('alpha') with pytest.raises(CLIReturnCodeError) as e: target_sat.cli.FlatpakRemote().with_user(usr, pwd).update( - {'name': remote['name'], 'description': desc} + {'organization-id': function_org.id, 'name': remote['name'], 'description': desc} ) assert emsg.format(p) in str(e) with pytest.raises(CLIReturnCodeError) as e: @@ -124,10 +129,14 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) target_sat.cli.FlatpakRemote().with_user(usr, pwd).update( - {'name': remote['name'], 'description': desc} + {'organization-id': function_org.id, 'name': remote['name'], 'description': desc} ) target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan({'name': remote['name']}) - res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + res = ( + target_sat.cli.FlatpakRemote() + .with_user(usr, pwd) + .info({'organization-id': function_org.id, 'name': remote['name']}) + ) assert res['description'] == desc, 'Description was not updated' assert 'http' in res['registry-url'], 'Scan of flatpak remote failed' @@ -145,11 +154,14 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( assert 'Error: flatpak_remote not found' in str(e) -def test_scan_flatpak_remote(target_sat, function_org, function_product): +@pytest.mark.parametrize('remote', FLATPAK_REMOTES.values(), ids=FLATPAK_REMOTES) +def test_scan_flatpak_remote(target_sat, function_org, function_product, remote): """Verify flatpak remote scan detects all repos available in the remote index. :id: 3dff23f3-f415-4fb2-a41c-7cdcae617bb0 + :parametrized: yes + :steps: 1. Create a flatpak remote and scan it. 2. Read the remote index via its API. @@ -159,16 +171,17 @@ def test_scan_flatpak_remote(target_sat, function_org, function_product): 1. Repos scanned by flatpak remote match the repos available in the remote index. """ - remote = FLATPAK_REMOTES['Fedora'] - # 1. Create a flatpak remote and scan it. - fr = target_sat.cli.FlatpakRemote().create( - { - 'organization-id': function_org.id, - 'url': remote['url'], - 'name': gen_string('alpha'), - } - ) + create_opts = { + 'organization-id': function_org.id, + 'url': remote['url'], + 'name': gen_string('alpha'), + } + if remote['authenticated']: + create_opts['username'] = settings.container_repo.registries.redhat.username + create_opts['token'] = settings.container_repo.registries.redhat.password + + fr = target_sat.cli.FlatpakRemote().create(create_opts) target_sat.cli.FlatpakRemote().scan({'id': fr['id']}) scanned_repos = target_sat.cli.FlatpakRemote().repository_list({'flatpak-remote-id': fr['id']}) From 493948a0b6818d4097b681dde879447c344e4ca7 Mon Sep 17 00:00:00 2001 From: Vladimir Sedmik Date: Mon, 9 Dec 2024 17:57:14 +0100 Subject: [PATCH 5/5] Update the CRUD case with organization scoping --- tests/foreman/cli/test_flatpak.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/foreman/cli/test_flatpak.py b/tests/foreman/cli/test_flatpak.py index 917daa00d84..116c7cf7c65 100644 --- a/tests/foreman/cli/test_flatpak.py +++ b/tests/foreman/cli/test_flatpak.py @@ -124,14 +124,18 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( ) assert emsg.format(p) in str(e) with pytest.raises(CLIReturnCodeError) as e: - target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan({'name': remote['name']}) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan( + {'organization-id': function_org.id, 'name': remote['name']} + ) assert emsg.format(p) in str(e) target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) target_sat.cli.FlatpakRemote().with_user(usr, pwd).update( {'organization-id': function_org.id, 'name': remote['name'], 'description': desc} ) - target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan({'name': remote['name']}) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).scan( + {'organization-id': function_org.id, 'name': remote['name']} + ) res = ( target_sat.cli.FlatpakRemote() .with_user(usr, pwd) @@ -143,14 +147,22 @@ def test_CRUD_and_sync_flatpak_remote_with_permissions( # 4. Ensure that remotes can be deleted only with proper permissions. p = 'destroy_flatpak_remotes' with pytest.raises(CLIReturnCodeError) as e: - target_sat.cli.FlatpakRemote().with_user(usr, pwd).delete({'name': remote['name']}) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).delete( + {'organization-id': function_org.id, 'name': remote['name']} + ) assert emsg.format(p) in str(e) target_sat.api_factory.create_role_permissions(function_role, {'Katello::FlatpakRemote': [p]}) - res = target_sat.cli.FlatpakRemote().with_user(usr, pwd).delete({'name': remote['name']}) + res = ( + target_sat.cli.FlatpakRemote() + .with_user(usr, pwd) + .delete({'organization-id': function_org.id, 'name': remote['name']}) + ) assert 'Flatpak Remote deleted' in res with pytest.raises(CLIReturnCodeError) as e: - target_sat.cli.FlatpakRemote().with_user(usr, pwd).info({'name': remote['name']}) + target_sat.cli.FlatpakRemote().with_user(usr, pwd).info( + {'organization-id': function_org.id, 'name': remote['name']} + ) assert 'Error: flatpak_remote not found' in str(e)