mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-27 10:44:33 +00:00
app: Introduce API for managing setup state of the app
Useful for replacing setup_helper. This API should be considered EXPERIMENTAL and may change. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
929e7f6dba
commit
47cb5e027f
@ -4,6 +4,8 @@ Base class for all Freedombox applications.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import enum
|
||||||
|
import sys
|
||||||
|
|
||||||
from . import clients as clients_module
|
from . import clients as clients_module
|
||||||
|
|
||||||
@ -40,6 +42,12 @@ class App:
|
|||||||
|
|
||||||
_all_apps = collections.OrderedDict()
|
_all_apps = collections.OrderedDict()
|
||||||
|
|
||||||
|
class SetupState(enum.Enum):
|
||||||
|
"""Various states of app being setup."""
|
||||||
|
NEEDS_SETUP = 'needs-setup'
|
||||||
|
NEEDS_UPDATE = 'needs-update'
|
||||||
|
UP_TO_DATE = 'up-to-date'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Build the app by adding components.
|
"""Build the app by adding components.
|
||||||
|
|
||||||
@ -118,6 +126,51 @@ class App:
|
|||||||
for component in self.components.values():
|
for component in self.components.values():
|
||||||
component.setup(old_version=old_version)
|
component.setup(old_version=old_version)
|
||||||
|
|
||||||
|
def get_setup_state(self) -> SetupState:
|
||||||
|
"""Return whether the app is not setup or needs upgrade."""
|
||||||
|
current_version = self.get_setup_version()
|
||||||
|
if current_version and self.info.version <= current_version:
|
||||||
|
return self.SetupState.UP_TO_DATE
|
||||||
|
|
||||||
|
# If an app needs installing/updating but no setup method is available,
|
||||||
|
# then automatically set version.
|
||||||
|
#
|
||||||
|
# Minor violation of 'get' only discipline for convenience.
|
||||||
|
module = sys.modules[self.__module__]
|
||||||
|
if not hasattr(module, 'setup'):
|
||||||
|
self.set_setup_version(self.info.version)
|
||||||
|
return self.SetupState.UP_TO_DATE
|
||||||
|
|
||||||
|
if not current_version:
|
||||||
|
return self.SetupState.NEEDS_SETUP
|
||||||
|
|
||||||
|
return self.SetupState.NEEDS_UPDATE
|
||||||
|
|
||||||
|
def get_setup_version(self) -> int:
|
||||||
|
"""Return the setup version of the app."""
|
||||||
|
# XXX: Optimize version gets
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
try:
|
||||||
|
app_entry = models.Module.objects.get(pk=self.app_id)
|
||||||
|
return app_entry.setup_version
|
||||||
|
except models.Module.DoesNotExist:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def needs_setup(self) -> bool:
|
||||||
|
"""Return whether the app needs to be setup.
|
||||||
|
|
||||||
|
A simple shortcut for get_setup_state() == NEEDS_SETUP
|
||||||
|
"""
|
||||||
|
return self.get_setup_state() == self.SetupState.NEEDS_SETUP
|
||||||
|
|
||||||
|
def set_setup_version(self, version: int) -> None:
|
||||||
|
"""Set the app's setup version."""
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
models.Module.objects.update_or_create(
|
||||||
|
pk=self.app_id, defaults={'setup_version': version})
|
||||||
|
|
||||||
def enable(self):
|
def enable(self):
|
||||||
"""Enable all the components of the app."""
|
"""Enable all the components of the app."""
|
||||||
for component in self.components.values():
|
for component in self.components.values():
|
||||||
|
|||||||
@ -4,6 +4,7 @@ Test module for App, base class for all applications.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import sys
|
||||||
from unittest.mock import Mock, call, patch
|
from unittest.mock import Mock, call, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -18,6 +19,16 @@ class AppTest(App):
|
|||||||
app_id = 'test-app'
|
app_id = 'test-app'
|
||||||
|
|
||||||
|
|
||||||
|
class AppSetupTest(App):
|
||||||
|
"""Sample App for testing setup operations."""
|
||||||
|
app_id = 'test-app-setup'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
info = Info('test-app-setup', 3)
|
||||||
|
self.add(info)
|
||||||
|
|
||||||
|
|
||||||
class LeaderTest(FollowerComponent):
|
class LeaderTest(FollowerComponent):
|
||||||
"""Test class for using LeaderComponent in tests."""
|
"""Test class for using LeaderComponent in tests."""
|
||||||
is_leader = True
|
is_leader = True
|
||||||
@ -124,6 +135,52 @@ def test_app_setup(app_with_components):
|
|||||||
component.setup.assert_has_calls([call(old_version=2)])
|
component.setup.assert_has_calls([call(old_version=2)])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_setup_state():
|
||||||
|
"""Test retrieving the current setup state of the app."""
|
||||||
|
app = AppSetupTest()
|
||||||
|
app.info.version = 3
|
||||||
|
module = sys.modules[__name__]
|
||||||
|
|
||||||
|
app.set_setup_version(3)
|
||||||
|
assert app.get_setup_state() == App.SetupState.UP_TO_DATE
|
||||||
|
assert not app.needs_setup()
|
||||||
|
|
||||||
|
app.set_setup_version(0)
|
||||||
|
try:
|
||||||
|
delattr(module, 'setup')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
assert app.get_setup_state() == App.SetupState.UP_TO_DATE
|
||||||
|
assert not app.needs_setup()
|
||||||
|
assert app.get_setup_version() == 3
|
||||||
|
|
||||||
|
setattr(module, 'setup', True)
|
||||||
|
app.set_setup_version(0)
|
||||||
|
assert app.get_setup_state() == App.SetupState.NEEDS_SETUP
|
||||||
|
assert app.needs_setup()
|
||||||
|
|
||||||
|
app.set_setup_version(2)
|
||||||
|
assert app.get_setup_state() == App.SetupState.NEEDS_UPDATE
|
||||||
|
assert not app.needs_setup()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_get_set_setup_version():
|
||||||
|
"""Setting and getting the setup version of the app."""
|
||||||
|
app = AppSetupTest()
|
||||||
|
|
||||||
|
from plinth import models
|
||||||
|
try:
|
||||||
|
models.Module.objects.get(pk=app.app_id).delete()
|
||||||
|
except models.Module.DoesNotExist:
|
||||||
|
pass
|
||||||
|
assert app.get_setup_version() == 0
|
||||||
|
|
||||||
|
app.set_setup_version(5)
|
||||||
|
assert app.get_setup_version() == 5
|
||||||
|
|
||||||
|
|
||||||
def test_app_enable(app_with_components):
|
def test_app_enable(app_with_components):
|
||||||
"""Test that enabling an app enables components."""
|
"""Test that enabling an app enables components."""
|
||||||
app_with_components.disable()
|
app_with_components.disable()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user