tests: Merge actions related test files

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2024-03-10 11:54:07 -07:00 committed by James Valleroy
parent a14578c50d
commit 157abb023a
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 172 additions and 177 deletions

View File

@ -10,13 +10,16 @@ description of the expectations.
import json
import os
import subprocess
import typing
from unittest.mock import Mock, call, patch
import pytest
from plinth import cfg
from plinth import actions, cfg
from plinth.actions import privileged
actions_name = 'actions'
@pytest.fixture(name='popen')
def fixture_popen():
@ -140,3 +143,171 @@ def test_privileged_method_exceptions(get_module_name, popen):
wrapped_func = privileged(func_with_exception)
with pytest.raises(TypeError, match='type error'):
wrapped_func()
@patch('importlib.import_module')
@patch('plinth.module_loader.get_module_import_path')
@patch('os.getuid')
def test_call_syntax_checks(getuid, get_module_import_path, import_module):
"""Test that calling a method results in proper syntax checks."""
privileged_call = actions._privileged_call
# Module name validation
getuid.return_value = 0
with pytest.raises(SyntaxError, match='Invalid module name'):
privileged_call('foo.bar', 'x-action', {})
# Module import test
get_module_import_path.return_value = 'plinth.modules.test_module'
import_module.side_effect = ModuleNotFoundError
with pytest.raises(SyntaxError, match='Specified module not found'):
privileged_call('test_module', 'x-action', {})
import_module.assert_has_calls(
[call('plinth.modules.test_module.privileged')])
# Finding action in a module
module = type('', (), {})
import_module.side_effect = None
import_module.return_value = module
with pytest.raises(SyntaxError, match='Specified action not found'):
privileged_call('test_module', 'x-action', {})
# Checking if action is privileged
def unprivileged_func():
pass
setattr(module, 'func', unprivileged_func)
with pytest.raises(SyntaxError,
match='Specified action is not privileged action'):
privileged_call('test-module', 'func', {})
# Argument validation
@actions.privileged
def func():
return 'foo'
setattr(module, 'func', func)
with pytest.raises(SyntaxError, match='Invalid arguments format'):
privileged_call('test-module', 'func', {})
# Successful call
return_value = privileged_call('test-module', 'func', {
'args': [],
'kwargs': {}
})
assert return_value == {'result': 'success', 'return': 'foo'}
# Exception call
@actions.privileged
def exception_func():
raise RuntimeError('foo exception')
setattr(module, 'func', exception_func)
return_value = privileged_call('test-module', 'func', {
'args': [],
'kwargs': {}
})
assert return_value['result'] == 'exception'
assert return_value['exception']['module'] == 'builtins'
assert return_value['exception']['name'] == 'RuntimeError'
assert return_value['exception']['args'] == ('foo exception', )
assert isinstance(return_value['exception']['traceback'], list)
for line in return_value['exception']['traceback']:
assert isinstance(line, str)
def test_assert_valid_arguments():
"""Test that checking valid arguments works."""
assert_valid = actions._privileged_assert_valid_arguments
values = [
None, [], 10, {}, {
'args': []
}, {
'kwargs': {}
}, {
'args': {},
'kwargs': {}
}, {
'args': [],
'kwargs': []
}
]
for value in values:
with pytest.raises(SyntaxError, match='Invalid arguments format'):
assert_valid(lambda: None, value)
def func(a: int, b: str, c: int = 3, d: str = 'foo'):
pass
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {'args': [1, 2, 3], 'kwargs': {'c': 3, 'd': 4}})
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {'args': [1, 2, 3, 4, 5], 'kwargs': {}})
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {
'args': [],
'kwargs': {
'a': 1,
'b': '2',
'c': 3,
'd': '4',
'e': 5
}
})
with pytest.raises(SyntaxError, match='Argument not provided: b'):
assert_valid(func, {'args': [1], 'kwargs': {}})
with pytest.raises(SyntaxError, match='Unknown argument: e'):
assert_valid(func, {'args': [1, '2'], 'kwargs': {'e': 5}})
with pytest.raises(SyntaxError, match='Duplicate argument: c'):
assert_valid(func, {'args': [1, '2', 3], 'kwargs': {'c': 4}})
with pytest.raises(TypeError, match='Expected type str for arg #1'):
assert_valid(func, {'args': [1, 2], 'kwargs': {}})
with pytest.raises(TypeError, match='Expected type int for arg c'):
assert_valid(func, {'args': [1, '2'], 'kwargs': {'c': '3'}})
def test_assert_valid_type():
"""Test that type validation works as expected."""
assert_valid = actions._privileged_assert_valid_type
assert_valid(None, None, typing.Any)
# Invalid values for int, str, float and Optional
values = [[1, bool], ['foo', int], [1, str], [1, float],
[1, typing.Optional[str]], [1, str | None],
[1.1, typing.Union[int, str]], [1.1, int | str], [1, list],
[1, dict], [[1], list[str]], [{
'a': 'b'
}, dict[int, str]], [{
1: 2
}, dict[int, str]]]
for value in values:
with pytest.raises(TypeError):
assert_valid('arg', *value)
# Valid values
assert_valid('arg', True, bool)
assert_valid('arg', 1, int)
assert_valid('arg', '1', str)
assert_valid('arg', 1.1, float)
assert_valid('arg', None, typing.Optional[int])
assert_valid('arg', 1, typing.Optional[int])
assert_valid('arg', None, int | None)
assert_valid('arg', 1, int | None)
assert_valid('arg', 1, typing.Union[int, str])
assert_valid('arg', '1', typing.Union[int, str])
assert_valid('arg', 1, int | str)
assert_valid('arg', '1', int | str)
assert_valid('arg', [], list[int])
assert_valid('arg', ['foo'], list[str])
assert_valid('arg', {}, dict[int, str])
assert_valid('arg', {1: 'foo'}, dict[int, str])

View File

@ -1,176 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Test module for code that runs methods are privileged actions.
"""
import typing
from unittest.mock import call as mock_call
from unittest.mock import patch
import pytest
from plinth import actions
actions_name = 'actions'
@patch('importlib.import_module')
@patch('plinth.module_loader.get_module_import_path')
@patch('os.getuid')
def test_call_syntax_checks(getuid, get_module_import_path, import_module):
"""Test that calling a method results in proper syntax checks."""
call = actions._privileged_call
# Module name validation
getuid.return_value = 0
with pytest.raises(SyntaxError, match='Invalid module name'):
call('foo.bar', 'x-action', {})
# Module import test
get_module_import_path.return_value = 'plinth.modules.test_module'
import_module.side_effect = ModuleNotFoundError
with pytest.raises(SyntaxError, match='Specified module not found'):
call('test_module', 'x-action', {})
import_module.assert_has_calls(
[mock_call('plinth.modules.test_module.privileged')])
# Finding action in a module
module = type('', (), {})
import_module.side_effect = None
import_module.return_value = module
with pytest.raises(SyntaxError, match='Specified action not found'):
call('test_module', 'x-action', {})
# Checking if action is privileged
def unprivileged_func():
pass
setattr(module, 'func', unprivileged_func)
with pytest.raises(SyntaxError,
match='Specified action is not privileged action'):
call('test-module', 'func', {})
# Argument validation
@actions.privileged
def func():
return 'foo'
setattr(module, 'func', func)
with pytest.raises(SyntaxError, match='Invalid arguments format'):
call('test-module', 'func', {})
# Successful call
return_value = call('test-module', 'func', {'args': [], 'kwargs': {}})
assert return_value == {'result': 'success', 'return': 'foo'}
# Exception call
@actions.privileged
def exception_func():
raise RuntimeError('foo exception')
setattr(module, 'func', exception_func)
return_value = call('test-module', 'func', {'args': [], 'kwargs': {}})
assert return_value['result'] == 'exception'
assert return_value['exception']['module'] == 'builtins'
assert return_value['exception']['name'] == 'RuntimeError'
assert return_value['exception']['args'] == ('foo exception', )
assert isinstance(return_value['exception']['traceback'], list)
for line in return_value['exception']['traceback']:
assert isinstance(line, str)
def test_assert_valid_arguments():
"""Test that checking valid arguments works."""
assert_valid = actions._privileged_assert_valid_arguments
values = [
None, [], 10, {}, {
'args': []
}, {
'kwargs': {}
}, {
'args': {},
'kwargs': {}
}, {
'args': [],
'kwargs': []
}
]
for value in values:
with pytest.raises(SyntaxError, match='Invalid arguments format'):
assert_valid(lambda: None, value)
def func(a: int, b: str, c: int = 3, d: str = 'foo'):
pass
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {'args': [1, 2, 3], 'kwargs': {'c': 3, 'd': 4}})
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {'args': [1, 2, 3, 4, 5], 'kwargs': {}})
with pytest.raises(SyntaxError, match='Too many arguments'):
assert_valid(func, {
'args': [],
'kwargs': {
'a': 1,
'b': '2',
'c': 3,
'd': '4',
'e': 5
}
})
with pytest.raises(SyntaxError, match='Argument not provided: b'):
assert_valid(func, {'args': [1], 'kwargs': {}})
with pytest.raises(SyntaxError, match='Unknown argument: e'):
assert_valid(func, {'args': [1, '2'], 'kwargs': {'e': 5}})
with pytest.raises(SyntaxError, match='Duplicate argument: c'):
assert_valid(func, {'args': [1, '2', 3], 'kwargs': {'c': 4}})
with pytest.raises(TypeError, match='Expected type str for arg #1'):
assert_valid(func, {'args': [1, 2], 'kwargs': {}})
with pytest.raises(TypeError, match='Expected type int for arg c'):
assert_valid(func, {'args': [1, '2'], 'kwargs': {'c': '3'}})
def test_assert_valid_type():
"""Test that type validation works as expected."""
assert_valid = actions._privileged_assert_valid_type
assert_valid(None, None, typing.Any)
# Invalid values for int, str, float and Optional
values = [[1, bool], ['foo', int], [1, str], [1, float],
[1, typing.Optional[str]], [1, str | None],
[1.1, typing.Union[int, str]], [1.1, int | str], [1, list],
[1, dict], [[1], list[str]], [{
'a': 'b'
}, dict[int, str]], [{
1: 2
}, dict[int, str]]]
for value in values:
with pytest.raises(TypeError):
assert_valid('arg', *value)
# Valid values
assert_valid('arg', True, bool)
assert_valid('arg', 1, int)
assert_valid('arg', '1', str)
assert_valid('arg', 1.1, float)
assert_valid('arg', None, typing.Optional[int])
assert_valid('arg', 1, typing.Optional[int])
assert_valid('arg', None, int | None)
assert_valid('arg', 1, int | None)
assert_valid('arg', 1, typing.Union[int, str])
assert_valid('arg', '1', typing.Union[int, str])
assert_valid('arg', 1, int | str)
assert_valid('arg', '1', int | str)
assert_valid('arg', [], list[int])
assert_valid('arg', ['foo'], list[str])
assert_valid('arg', {}, dict[int, str])
assert_valid('arg', {1: 'foo'}, dict[int, str])