Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Flatpak CLI support and CRUD case #17013

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
195 changes: 195 additions & 0 deletions tests/foreman/cli/test_flatpak.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
"""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({'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']})
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({'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)


@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)
Loading