Skip to content

Commit

Permalink
Add Flatpak CLI support and CRUD case (#17013)
Browse files Browse the repository at this point in the history
* Add Flatpak CLI support and CRUD case

* Add a case to validate the remote scan

* Use more descriptive test name

* Extend the scan case with authenticated remote

* Update the CRUD case with organization scoping
  • Loading branch information
vsedmik authored Dec 13, 2024
1 parent 8c12788 commit 649e4cc
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions robottelo/cli/flatpak_remote.py
Original file line number Diff line number Diff line change
@@ -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)
20 changes: 20 additions & 0 deletions robottelo/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,20 @@
}
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',
'authenticated': False,
},
'RedHat': {
'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,
},
}

CONTAINER_CLIENTS = ['docker', 'podman']
CUSTOM_LOCAL_FOLDER = '/var/lib/pulp/imports/myrepo/'
CUSTOM_LOCAL_FILE = '/var/lib/pulp/imports/myrepo/test.txt'
Expand Down Expand Up @@ -1140,6 +1154,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',
Expand Down
207 changes: 207 additions & 0 deletions tests/foreman/cli/test_flatpak.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
"""Flatpak related tests being run through CLI.
:Requirement: Repository
:CaseAutomation: Automated
:CaseComponent: Repositories
:team: Phoenix-content
:CaseImportance: High
"""

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


@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({'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.
p = 'edit_flatpak_remotes'
desc = gen_string('alpha')
with pytest.raises(CLIReturnCodeError) as e:
target_sat.cli.FlatpakRemote().with_user(usr, pwd).update(
{'organization-id': function_org.id, '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(
{'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(
{'organization-id': function_org.id, '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'

# 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(
{'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({'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(
{'organization-id': function_org.id, 'name': remote['name']}
)
assert 'Error: flatpak_remote not found' in str(e)


@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.
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.
"""
# 1. Create a flatpak remote and scan it.
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']})
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)

0 comments on commit 649e4cc

Please sign in to comment.