# SPDX-License-Identifier: AGPL-3.0-or-later """ Test module for App, base class for all applications. """ import collections from unittest.mock import patch import pytest from plinth.app import App, Component, FollowerComponent, Info, LeaderComponent class AppTest(App): """Sample App for testing.""" app_id = 'test-app' class LeaderTest(FollowerComponent): """Test class for using LeaderComponent in tests.""" is_leader = True def diagnose(self): """Return diagnostic results.""" return [('test-result-' + self.component_id, 'success')] @pytest.fixture(name='app_with_components') def fixture_app_with_components(): """Setup an app with some components.""" app = AppTest() app.add(FollowerComponent('test-follower-1')) app.add(FollowerComponent('test-follower-2')) app.add(LeaderTest('test-leader-1')) app.add(LeaderTest('test-leader-2')) return app @pytest.fixture(name='empty_apps', autouse=True) def fixture_empty_apps(): """Remove all apps from global list before starting a test.""" App._all_apps = collections.OrderedDict() def test_app_instantiation(): """Test that App is instantiated properly.""" app = AppTest() assert isinstance(app.components, collections.OrderedDict) assert not app.components assert app.app_id == 'test-app' assert app._all_apps['test-app'] == app assert len(app._all_apps) == 1 def test_app_get(): """Test that an app can be correctly retrieved.""" app = AppTest() assert App.get(app.app_id) == app def test_app_list(): """Test listing all apps.""" app = AppTest() assert list(App.list()) == [app] def test_app_add(): """Test adding a components to an App.""" app = AppTest() component = Component('test-component') return_value = app.add(component) assert len(app.components) == 1 assert app.components['test-component'] == component assert return_value == app def test_app_remove(app_with_components): """Test removing a component from an App.""" app = app_with_components component = app.components['test-leader-1'] assert app.remove('test-leader-1') == component assert 'test-leader-1' not in app.components def test_get_component(app_with_components): """Test retrieving a component from an App.""" app = app_with_components component = app.components['test-leader-1'] assert app.get_component('test-leader-1') == component with pytest.raises(KeyError): app.get_component('x-invalid-component') def test_get_components_of_type(app_with_components): """Test retrieving list of components of a given type.""" app = app_with_components components = app.get_components_of_type(FollowerComponent) follower_components = [ app.components['test-follower-1'], app.components['test-follower-2'], app.components['test-leader-1'], app.components['test-leader-2'], ] assert list(components) == follower_components components = app.get_components_of_type(LeaderTest) leader_components = [ app.components['test-leader-1'], app.components['test-leader-2'], ] assert list(components) == leader_components def test_app_enable(app_with_components): """Test that enabling an app enables components.""" app_with_components.disable() app_with_components.enable() for component in app_with_components.components.values(): assert component.is_enabled() def test_app_disable(app_with_components): """Test that disabling an app disables components.""" app_with_components.enable() app_with_components.disable() for component in app_with_components.components.values(): assert not component.is_enabled() def test_app_is_enabled(app_with_components): """Test checking for app enabled.""" app = app_with_components app.disable() # Disabling the components disables that app assert not app.is_enabled() # Enabling followers will not enable the app app.components['test-follower-1'].enable() assert not app.is_enabled() app.components['test-follower-2'].enable() assert not app.is_enabled() # Enabling both leaders will enable the app app.components['test-leader-1'].enable() assert not app.is_enabled() app.components['test-leader-2'].enable() assert app.is_enabled() # Disabling followers has no effect app.components['test-follower-1'].disable() assert app.is_enabled() def test_app_is_enabled_with_no_leader_components(): """When there are not leader components, app.is_enabled() returns True.""" app = AppTest() assert app.is_enabled() def test_app_set_enabled(app_with_components): """Test that setting enabled effects only followers.""" app = app_with_components app.disable() app.set_enabled(True) assert app.components['test-follower-1'].is_enabled() assert not app.components['test-leader-1'].is_enabled() app.enable() app.set_enabled(False) assert not app.components['test-follower-1'].is_enabled() assert app.components['test-leader-1'].is_enabled() def test_app_diagnose(app_with_components): """Test running diagnostics on an app.""" results = app_with_components.diagnose() assert results == [('test-result-test-leader-1', 'success'), ('test-result-test-leader-2', 'success')] def test_app_has_diagnostics(app_with_components): """Test checking if app has diagnostics implemented.""" app = app_with_components # App with components that has diagnostics assert app.has_diagnostics() # App with components that don't have diagnostics app.remove('test-leader-1') app.remove('test-leader-2') assert not app.has_diagnostics() # App with app-level diagnostics with patch.object(AppTest, 'diagnose', return_value=[('test1', 'passed')]): assert app.has_diagnostics() def test_component_initialization(): """Test that component is initialized properly.""" with pytest.raises(ValueError): Component(None) component = Component('test-component') assert component.component_id == 'test-component' assert not component.is_leader def test_component_diagnose(): """Test running diagnostics on component.""" component = Component('test-component') assert component.diagnose() == [] def test_component_has_diagnostics(): """Test checking if component has diagnostics implemented.""" component = LeaderTest('test-leader-1') assert component.has_diagnostics() component = FollowerComponent('test-follower-1') assert not component.has_diagnostics() def test_follower_component_initialization(): """Test that follower component is initialized properly.""" component = FollowerComponent('test-follower-1') assert not component.is_enabled() component = FollowerComponent('test-follower-2', False) assert not component.is_enabled() component = FollowerComponent('test-follower-3', True) assert component.is_enabled() def test_follower_component_set_enabled(): """Test setting internal enabled state a follower component.""" component = FollowerComponent('test-follower-1', False) component.set_enabled(True) assert component.is_enabled() component.set_enabled(False) assert not component.is_enabled() def test_follower_component_enable(): """Test enabling a follower component.""" component = FollowerComponent('test-follower-1', False) component.enable() assert component.is_enabled() def test_follower_component_disable(): """Test disabling a follower component.""" component = FollowerComponent('test-follower-1', True) component.disable() assert not component.is_enabled() def test_leader_component_initialization(): """Test that leader component is initialized properly.""" component = LeaderComponent('test-leader-1') assert component.is_leader def test_leader_component_is_enabled(): """Test getting enabled state is not implemented in leader component.""" component = LeaderComponent('test-leader-1') with pytest.raises(NotImplementedError): assert component.is_enabled() def test_info_initialization_without_args(): """Test initializing the Info component without arguments.""" info = Info('test-app', 3) assert info.component_id == 'test-app-info' assert info.app_id == 'test-app' assert info.version == 3 assert not info.is_essential assert info.depends == [] assert info.name is None assert info.icon is None assert info.icon_filename is None assert info.short_description is None assert info.description is None assert info.manual_page is None assert info.clients is None def test_info_initialization_with_args(): """Test initializing the Info component with arguments.""" info = Info('test-app', 3, is_essential=True, depends=['test-app-2'], name='Test App', icon='fa-test', icon_filename='test-icon', short_description='For Test', description='Test description', manual_page='Test', clients=['test']) assert info.is_essential assert info.depends == ['test-app-2'] assert info.name == 'Test App' assert info.icon == 'fa-test' assert info.icon_filename == 'test-icon' assert info.short_description == 'For Test' assert info.description == 'Test description' assert info.manual_page == 'Test' assert info.clients == ['test']