Skip to content

Commit

Permalink
Merge pull request #57 from truenas/apps-ci-unit-tests
Browse files Browse the repository at this point in the history
NAS-131884 / 25.04 / Add unit tests for apps ci package
  • Loading branch information
sonicaj authored Oct 19, 2024
2 parents 5002d51 + 50c8a9f commit 4c85322
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ jobs:
PYTHONPATH=$(pwd) pytest apps_validation/pytest/unit/
PYTHONPATH=$(pwd) pytest catalog_reader/pytest/unit/
PYTHONPATH=$(pwd) pytest apps_schema/pytest/unit/
PYTHONPATH=$(pwd) pytest apps_ci/pytest/unit/
23 changes: 23 additions & 0 deletions apps_ci/pytest/unit/test_get_apps_to_publish.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import collections

import pytest

from apps_ci.scripts.catalog_update import get_apps_to_publish


@pytest.mark.parametrize('isdir,', [
[True, True, True],
[True, False, False],
[False, False, False]
])
def test_get_apps_to_publish(mocker, isdir):
mocker.patch('os.listdir', side_effect=[
['community'],
['app1', 'app2']
])
mocker.patch('os.path.isdir', side_effect=isdir)
mocker.patch('apps_ci.scripts.catalog_update.version_has_been_bumped', return_value=True)
mocker.patch('apps_ci.scripts.catalog_update.get_app_version', return_value='1.0.1')

result = get_apps_to_publish('/path/to/catalog')
assert isinstance(result, collections.defaultdict)
55 changes: 55 additions & 0 deletions apps_ci/pytest/unit/test_get_changed_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import collections
import os

import pytest

from apps_ci.git import get_changed_apps
from apps_exceptions import CatalogDoesNotExist


@pytest.mark.parametrize('path, base_branch, path_exists, is_train_valid, should_work', [
(
'/valid/path/to/catalog',
'master',
True,
True,
True
),
(
'/valid/path/to/catalog',
'master',
True,
False,
True
),
(
'/invalid/path/to/catalog',
'master',
False,
False,
False
)
])
def test_get_changed_apps(mocker, path, base_branch, path_exists, is_train_valid, should_work):
mocker.patch('os.path.exists', return_value=path_exists)
mock_subprocess_run = mocker.patch('subprocess.run')
mock_subprocess_run.return_value.stdout = b'''
ix-dev/community/actual-budget/1.1.9/values.yaml
ix-dev/community/another-app/1.0.0/metadata.yaml
ix-dev/community/another-app/1.0.0/upgrade_info.json
'''
mock_get_ci_development_directory = mocker.patch('catalog_reader.dev_directory.get_ci_development_directory')
mock_get_ci_development_directory.return_value = '/mock/ci/development'
mocker.patch('apps_ci.git.is_train_valid', return_value=is_train_valid)
if should_work:
result = get_changed_apps(path, base_branch)

os.path.exists.assert_called_once_with(path)
mock_subprocess_run.assert_called_once_with(
['git', '-C', path, '--no-pager', 'diff', '--name-only', base_branch],
capture_output=True, check=True,
)
assert isinstance(result, collections.defaultdict)
else:
with pytest.raises(CatalogDoesNotExist):
get_changed_apps(path, base_branch)
97 changes: 97 additions & 0 deletions apps_ci/pytest/unit/test_is_main_dep.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import pathlib
import textwrap

import pytest

from apps_ci.images_info import is_main_dep
from apps_exceptions import AppDoesNotExist, ValidationErrors


@pytest.mark.parametrize('yaml_data, dep_name, is_dir, is_file, should_work', [
(
textwrap.dedent(
'''
images:
image:
repository: ABC
tag: some_tag
db_image:
repository: ABC
tag: some_tag
'''
),
'ABC',
True,
True,
True
),
(
textwrap.dedent(
'''
images:
image:
repository: ABC
tag: some_tag
db_image:
repository: ABC
tag: some_tag
'''
),
'ABC',
False,
False,
False
),
(
textwrap.dedent(
'''
images:
image:
repository: some_repo
tag: some_tag
db_image:
repository: some_repo
tag: some_tag
'''
),
'ABC',
True,
True,
False
),
(
textwrap.dedent(
'''
images:
image:
repository: ABC
tag: some_tag
db_image:
repository: ABC
tag: some_tag
'''
),
'ABC',
True,
False,
False
),
])
def test_is_main_dep(mocker, yaml_data, dep_name, is_dir, is_file, should_work):
mock_file = mocker.mock_open(read_data=yaml_data)
mocker.patch('builtins.open', mock_file)
mocker.patch('pathlib.Path.is_dir', return_value=is_dir)
mocker.patch('pathlib.Path.is_file', return_value=is_file)
if should_work:
result = is_main_dep(pathlib.Path('/valid/path'), dep_name)
assert result is True
elif dep_name not in yaml_data:
result = is_main_dep(pathlib.Path('/valid/path'), dep_name)
assert result is False
else:
with pytest.raises((AppDoesNotExist, ValidationErrors)):
is_main_dep(pathlib.Path('/valid/path'), dep_name)
56 changes: 56 additions & 0 deletions apps_ci/pytest/unit/test_publish_updated_apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import collections

import pytest

from apps_ci.scripts.catalog_update import publish_updated_apps


@pytest.mark.parametrize('version, app_name, isdir, listdir_ver, should_work', [
(
'1.0.1',
'test_app',
[True, True, True],
['1.0.0', '1.0.1'],
True
),
(
'1.0.0',
'test_app',
[False],
['1.0.0'],
False
),
(
'1.0.1',
'test_app',
[True, True, True],
['1.0.0'],
True
),
])
def test_publish_updated_apps(mocker, capsys, version, app_name, isdir, listdir_ver, should_work):
to_publish_apps = collections.defaultdict(list)
to_publish_apps[version].append({'name': app_name, 'version': version})
mocker.patch('os.path.isdir', side_effect=isdir)
mocker.patch('os.makedirs')
mocker.patch('os.listdir', return_value=listdir_ver)
mocker.patch('os.path.exists', side_effect=[False, True])
mocker.patch('shutil.copy')
mocker.patch('shutil.copytree')
mocker.patch('shutil.move')
mocker.patch('shutil.rmtree')

mocker.patch('apps_ci.scripts.catalog_update.get_apps_to_publish', return_value=to_publish_apps)
mocker.patch('apps_ci.scripts.catalog_update.get_to_keep_versions', return_value=[version])

if should_work:
publish_updated_apps('/path/to/catalog')
expected_out = (
f'\x1b[92mOK\x1b[0m]\tPublished '
f'\'{app_name}\' having \'{version}\' version '
f'to \'{version}\' train successfully!'
)
assert expected_out in capsys.readouterr().out

else:
assert publish_updated_apps('/path/to/catalog') is None
75 changes: 75 additions & 0 deletions apps_ci/pytest/unit/test_rename_versioned_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pathlib

import pytest

from apps_ci.version_bump import rename_versioned_dir, bump_version
from apps_exceptions import AppDoesNotExist, ValidationErrors


@pytest.mark.parametrize('version, new_version, train_name, is_dir, should_work', [
(
'1.0.0',
'1.0.1',
'community',
[True, False, False],
True
),
(
'1.0',
'1.0.1',
'community',
[True, False, False],
False
),
(
'1.0.0',
'1.0.1',
'community',
[False, True, True],
False
),
(
'1.0.0',
'1.0.1',
'stable',
[True, True, True],
False
),
])
def test_rename_versioned_dir(mocker, version, new_version, train_name, is_dir, should_work):
mocker.patch('pathlib.Path.is_dir', side_effect=is_dir)
mocker.patch('pathlib.Path.rename', return_value=None)
if should_work:
result = rename_versioned_dir(version, new_version, train_name, pathlib.Path('/valid/path'))
assert result is None
else:
with pytest.raises((AppDoesNotExist, ValidationErrors)):
rename_versioned_dir(version, new_version, train_name, pathlib.Path('/valid/path'))


@pytest.mark.parametrize('version, bump, expected', [
(
'1.0.0',
'minor',
'1.1.0'
),
(
'1.0.0',
'major',
'2.0.0'
),
(
'1.0.0',
'patch',
'1.0.1'
)
])
def test_bump_version(version, bump, expected):
result = bump_version(version, bump)
assert result == expected


def test_bump_version_Fail():
with pytest.raises(ValueError):
bump_version('1.0', 'minor')
73 changes: 73 additions & 0 deletions apps_ci/pytest/unit/test_update_app_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import pytest

from apps_ci.scripts.bump_version import update_app_version
from apps_exceptions import AppDoesNotExist, ValidationErrors


@pytest.mark.parametrize('path, bump, dep, dep_version, yaml, expected_out', [
(
'/valid/path',
'minor',
'some_repo',
'1.0.2',
'''
version: 1.0.0
icon_url: https://www.chia.net/wp-content/uploads/2022/09/chia-logo.svg
sources:
- https://hub.docker.com/r/emby/embyserver
''',
'\x1b[92mOK\x1b[0m]\tUpdated app \'path\', '
'set app_version to \'1.0.2\' and bumped version from '
'\'1.0.0\' to \'1.1.0\'\n'
)
])
def test_update_app_version(mocker, capsys, path, bump, dep, dep_version, yaml, expected_out):
mocker.patch('os.path.exists', return_value=True)
mocker.patch('pathlib.Path.is_file', return_value=True)
mock_file = mocker.mock_open(read_data=yaml)
mocker.patch('builtins.open', mock_file)
mocker.patch('apps_ci.scripts.bump_version.is_main_dep', return_value=True)
mocker.patch('apps_ci.scripts.bump_version.rename_versioned_dir', return_value=None)
update_app_version(path, bump, dep, dep_version)
assert expected_out in capsys.readouterr().out


@pytest.mark.parametrize('path, bump, dep, dep_version, exists, is_file, yaml', [
(
'/valid/path',
'minor',
'some_repo',
'1.0.2',
False,
True,
'''
version: 1.0.0
icon_url: https://www.chia.net/wp-content/uploads/2022/09/chia-logo.svg
sources:
- https://hub.docker.com/r/emby/embyserver
'''
),
(
'/valid/path',
'minor',
'some_repo',
'1.0.2',
True,
False,
'''
version: 1.0.0
icon_url: https://www.chia.net/wp-content/uploads/2022/09/chia-logo.svg
sources:
- https://hub.docker.com/r/emby/embyserver
'''
),
])
def test_update_app_version_Errors(mocker, path, bump, dep, dep_version, exists, is_file, yaml):
mocker.patch('os.path.exists', return_value=exists)
mocker.patch('pathlib.Path.is_file', return_value=is_file)
mock_file = mocker.mock_open(read_data=yaml)
mocker.patch('builtins.open', mock_file)
mocker.patch('apps_ci.scripts.bump_version.is_main_dep', return_value=True)
mocker.patch('apps_ci.scripts.bump_version.rename_versioned_dir', return_value=None)
with pytest.raises((AppDoesNotExist, ValidationErrors)):
update_app_version(path, bump, dep, dep_version)
Loading

0 comments on commit 4c85322

Please sign in to comment.