diagnostics: Simplify getting translated description in results

Tests:

- Unit tests pass.

- Run full diagnostics tests and see that results and app name are translated
when language preference is not English.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
Sunil Mohan Adapa 2024-01-18 22:01:57 -08:00
parent 27284fe888
commit 5f08752058
No known key found for this signature in database
GPG Key ID: 43EA1CFF0AA7C5F2
10 changed files with 84 additions and 110 deletions

View File

@ -12,8 +12,7 @@ from plinth import app
from plinth.modules.apache.components import (Uwsgi, Webserver, check_url,
diagnose_url,
diagnose_url_on_all)
from plinth.modules.diagnostics.check import (DiagnosticCheck, Result,
translate, translate_checks)
from plinth.modules.diagnostics.check import DiagnosticCheck, Result
def test_webserver_init():
@ -249,16 +248,16 @@ def test_diagnose_url(get_addresses, check):
}
parameters = {key: args[key] for key in ['url', 'kind']}
check.return_value = True
result = translate(diagnose_url(**args))
result = diagnose_url(**args)
assert result == DiagnosticCheck(
'apache-url-kind-https://localhost/test-4',
'Access URL https://localhost/test on tcp4', Result.PASSED, parameters)
'Access URL {url} on tcp{kind}', Result.PASSED, parameters)
check.return_value = False
result = translate(diagnose_url(**args))
result = diagnose_url(**args)
assert result == DiagnosticCheck(
'apache-url-kind-https://localhost/test-4',
'Access URL https://localhost/test on tcp4', Result.FAILED, parameters)
'Access URL {url} on tcp{kind}', Result.FAILED, parameters)
del args['kind']
args['url'] = 'https://{host}/test'
@ -284,14 +283,14 @@ def test_diagnose_url(get_addresses, check):
'kind': '6'
},
]
results = translate_checks(diagnose_url_on_all(**args))
results = diagnose_url_on_all(**args)
assert results == [
DiagnosticCheck('apache-url-kind-https://test-host-1/test-4',
'Access URL https://test-host-1/test on tcp4',
Result.PASSED, parameters[0]),
'Access URL {url} on tcp{kind}', Result.PASSED,
parameters[0]),
DiagnosticCheck('apache-url-kind-https://test-host-2/test-6',
'Access URL https://test-host-2/test on tcp6',
Result.PASSED, parameters[1]),
'Access URL {url} on tcp{kind}', Result.PASSED,
parameters[1]),
]

View File

@ -21,7 +21,7 @@ from plinth.modules.apache.components import diagnose_url_on_all
from plinth.modules.backups.components import BackupRestore
from . import manifest
from .check import CheckJSONDecoder, CheckJSONEncoder, Result, translate_checks
from .check import CheckJSONDecoder, CheckJSONEncoder, Result
_description = [
_('The system diagnostic test will run a number of checks on your '
@ -338,14 +338,9 @@ def get_results():
results = json.loads(results, cls=CheckJSONDecoder)
results = {'results': results, 'progress_percentage': 100}
# Translate and format diagnostic check descriptions for each app
# Add a translated name for each app
for app_id in results['results']:
app = app_module.App.get(app_id)
app_name = app.info.name or app_id
results['results'][app_id]['name'] = app_name
if 'diagnosis' in results['results'][app_id]:
diagnosis = results['results'][app_id]['diagnosis']
results['results'][app_id]['diagnosis'] = translate_checks(
diagnosis)
results['results'][app_id]['name'] = app.info.name or app_id
return results

View File

@ -2,9 +2,9 @@
"""Diagnostic check data type."""
import dataclasses
import json
from dataclasses import dataclass, field
from enum import StrEnum
import json
from django.utils.translation import gettext
@ -28,21 +28,14 @@ class DiagnosticCheck:
result: Result = Result.NOT_DONE
parameters: dict = field(default_factory=dict)
@property
def translated_description(self):
"""Return translated string for description."""
description = gettext(self.description)
if self.parameters:
return SafeFormatter().vformat(description, [], self.parameters)
def translate(check: DiagnosticCheck) -> DiagnosticCheck:
"""Translate and format description using parameters."""
description = gettext(check.description)
if check.parameters:
description = SafeFormatter().vformat(description, [],
check.parameters)
return DiagnosticCheck(check.check_id, description, check.result,
check.parameters)
def translate_checks(checks: list[DiagnosticCheck]) -> list[DiagnosticCheck]:
"""Translate and format diagnostic checks."""
return [translate(check) for check in checks]
return description
class CheckJSONEncoder(json.JSONEncoder):

View File

@ -15,7 +15,7 @@
<tbody>
{% for result in results %}
<tr>
<td>{{ result.description }}</td>
<td>{{ result.translated_description }}</td>
<td class="diagnostics-result">
{% if result.result == 'passed' %}
<span class="badge badge-success">{% trans result.result %}</span>

View File

@ -2,12 +2,12 @@
"""Tests for diagnostic check data type."""
import json
import pytest
from plinth.modules.diagnostics.check import (DiagnosticCheck,
from plinth.modules.diagnostics.check import (CheckJSONDecoder,
CheckJSONEncoder,
CheckJSONDecoder, Result,
translate)
DiagnosticCheck, Result)
def test_result():
@ -29,6 +29,7 @@ def test_diagnostic_check():
check = DiagnosticCheck('some-check-id', 'sample check')
assert check.check_id == 'some-check-id'
assert check.description == 'sample check'
assert check.translated_description == 'sample check'
assert check.result == Result.NOT_DONE
assert not check.parameters
@ -43,24 +44,13 @@ def test_diagnostic_check():
def test_translate():
"""Test formatting the translated description."""
check = DiagnosticCheck('some-check-id', 'sample check', Result.PASSED)
translated = translate(check)
assert translated.check_id == 'some-check-id'
assert translated.description == 'sample check'
assert translated.result == Result.PASSED
assert not translated.parameters
check = DiagnosticCheck('some-check-id', 'sample check {key}',
Result.FAILED, {'key': 'value'})
translated = translate(check)
assert translated.description == 'sample check value'
assert translated.result == Result.FAILED
assert translated.parameters == {'key': 'value'}
assert check.translated_description == 'sample check value'
check = DiagnosticCheck('some-check-id', 'sample check {missing}',
Result.PASSED, {'key': 'value'})
translated = translate(check)
assert translated.description == 'sample check ?missing?'
assert check.translated_description == 'sample check ?missing?'
def test_json_encoder_decoder():

View File

@ -17,7 +17,7 @@ from plinth.app import App
from plinth.modules import diagnostics
from plinth.views import AppView
from .check import Result, translate_checks
from .check import Result
logger = logging.getLogger(__name__)
@ -83,8 +83,6 @@ def diagnose_app(request, app_id):
exception)
diagnosis_exception = str(exception)
# Translate and format diagnostic check descriptions
diagnosis = translate_checks(diagnosis)
show_rerun_setup = False
for check in diagnosis:
if check.result in [Result.FAILED, Result.WARNING]:

View File

@ -8,8 +8,7 @@ from unittest.mock import call, patch
import pytest
from plinth.app import App
from plinth.modules.diagnostics.check import (DiagnosticCheck, Result,
translate_checks)
from plinth.modules.diagnostics.check import DiagnosticCheck, Result
from plinth.modules.firewall.components import (Firewall,
FirewallLocalProtection)
@ -154,32 +153,32 @@ def test_diagnose(get_enabled_services, get_port_details):
get_port_details.side_effect = get_port_details_side_effect
firewall = Firewall('test-firewall-1', ports=['test-port1', 'test-port2'],
is_external=False)
results = translate_checks(firewall.diagnose())
results = firewall.diagnose()
assert results == [
DiagnosticCheck(
'firewall-port-internal-test-port1',
'Port test-port1 (1234/tcp, 1234/udp) available for internal '
'Port {name} ({details}) available for internal '
'networks', Result.PASSED, {
'name': 'test-port1',
'details': '1234/tcp, 1234/udp'
}),
DiagnosticCheck(
'firewall-port-external-unavailable-test-port1',
'Port test-port1 (1234/tcp, 1234/udp) unavailable for external '
'Port {name} ({details}) unavailable for external '
'networks', Result.PASSED, {
'name': 'test-port1',
'details': '1234/tcp, 1234/udp'
}),
DiagnosticCheck(
'firewall-port-internal-test-port2',
'Port test-port2 (2345/udp) available for internal networks',
'Port {name} ({details}) available for internal networks',
Result.FAILED, {
'name': 'test-port2',
'details': '2345/udp'
}),
DiagnosticCheck(
'firewall-port-external-unavailable-test-port2',
'Port test-port2 (2345/udp) unavailable for external networks',
'Port {name} ({details}) unavailable for external networks',
Result.FAILED, {
'name': 'test-port2',
'details': '2345/udp'
@ -188,32 +187,32 @@ def test_diagnose(get_enabled_services, get_port_details):
firewall = Firewall('test-firewall-1', ports=['test-port3', 'test-port4'],
is_external=True)
results = translate_checks(firewall.diagnose())
results = firewall.diagnose()
assert results == [
DiagnosticCheck(
'firewall-port-internal-test-port3',
'Port test-port3 (3456/tcp) available for internal networks',
'Port {name} ({details}) available for internal networks',
Result.PASSED, {
'name': 'test-port3',
'details': '3456/tcp'
}),
DiagnosticCheck(
'firewall-port-external-available-test-port3',
'Port test-port3 (3456/tcp) available for external networks',
'Port {name} ({details}) available for external networks',
Result.PASSED, {
'name': 'test-port3',
'details': '3456/tcp'
}),
DiagnosticCheck(
'firewall-port-internal-test-port4',
'Port test-port4 (4567/udp) available for internal networks',
'Port {name} ({details}) available for internal networks',
Result.FAILED, {
'name': 'test-port4',
'details': '4567/udp'
}),
DiagnosticCheck(
'firewall-port-external-available-test-port4',
'Port test-port4 (4567/udp) available for external networks',
'Port {name} ({details}) available for external networks',
Result.FAILED, {
'name': 'test-port4',
'details': '4567/udp'

View File

@ -9,8 +9,7 @@ import pytest
from plinth.app import App
from plinth.config import DropinConfigs
from plinth.modules.diagnostics.check import (DiagnosticCheck, Result,
translate_checks)
from plinth.modules.diagnostics.check import DiagnosticCheck, Result
pytestmark = pytest.mark.usefixtures('mock_privileged')
privileged_modules_to_mock = ['plinth.privileged.config']
@ -161,16 +160,15 @@ def test_dropin_config_diagnose_symlinks(dropin_configs, tmp_path):
"""Test diagnosing dropin configs for symlinks."""
with patch('plinth.config.DropinConfigs.ROOT', new=tmp_path):
# Nothing exists
results = translate_checks(dropin_configs.diagnose())
results = dropin_configs.diagnose()
assert results == [
DiagnosticCheck(
f'dropin-config-{tmp_path}/etc/test/path1',
f'Static configuration {tmp_path}/etc/test/path1 is setup '
'properly', Result.FAILED,
{'etc_path': f'{tmp_path}/etc/test/path1'}),
'Static configuration {etc_path} is setup properly',
Result.FAILED, {'etc_path': f'{tmp_path}/etc/test/path1'}),
DiagnosticCheck(
f'dropin-config-{tmp_path}/etc/path2',
f'Static configuration {tmp_path}/etc/path2 is setup properly',
'Static configuration {etc_path} is setup properly',
Result.FAILED, {'etc_path': f'{tmp_path}/etc/path2'}),
]

View File

@ -12,8 +12,7 @@ import pytest
from plinth.app import App, FollowerComponent, Info
from plinth.daemon import (Daemon, RelatedDaemon, app_is_running,
diagnose_netcat, diagnose_port_listening)
from plinth.modules.diagnostics.check import (DiagnosticCheck, Result,
translate, translate_checks)
from plinth.modules.diagnostics.check import DiagnosticCheck, Result
privileged_modules_to_mock = ['plinth.privileged.service']
@ -149,10 +148,10 @@ def test_diagnose(port_listening, service_is_running, daemon):
(345, 'udp')])
port_listening.side_effect = side_effect
service_is_running.return_value = True
results = translate_checks(daemon.diagnose())
results = daemon.diagnose()
assert results == [
DiagnosticCheck('daemon-running-test-unit',
'Service test-unit is running', Result.PASSED,
'Service {service_name} is running', Result.PASSED,
{'service_name': 'test-unit'}),
DiagnosticCheck('test-result-8273-tcp4', 'test-result-8273-tcp4',
Result.PASSED),
@ -215,34 +214,34 @@ def test_diagnose_port_listening(connections):
]
# Check that message is correct
results = translate(diagnose_port_listening(1234))
results = diagnose_port_listening(1234)
assert results == DiagnosticCheck('daemon-listening-tcp-1234',
'Listening on tcp port 1234',
'Listening on {kind} port {port}',
Result.PASSED, {
'kind': 'tcp',
'port': 1234
})
results = translate(diagnose_port_listening(1234, 'tcp', '0.0.0.0'))
results = diagnose_port_listening(1234, 'tcp', '0.0.0.0')
assert results == DiagnosticCheck(
'daemon-listening-address-tcp-1234-0.0.0.0',
'Listening on tcp port 0.0.0.0:1234', Result.PASSED, {
'Listening on {kind} port {listen_address}:{port}', Result.PASSED, {
'kind': 'tcp',
'port': 1234,
'listen_address': '0.0.0.0'
})
# Failed results
results = translate(diagnose_port_listening(4321))
results = diagnose_port_listening(4321)
assert results == DiagnosticCheck('daemon-listening-tcp-4321',
'Listening on tcp port 4321',
'Listening on {kind} port {port}',
Result.FAILED, {
'kind': 'tcp',
'port': 4321
})
results = translate(diagnose_port_listening(4321, 'tcp', '0.0.0.0'))
results = diagnose_port_listening(4321, 'tcp', '0.0.0.0')
assert results == DiagnosticCheck(
'daemon-listening-address-tcp-4321-0.0.0.0',
'Listening on tcp port 0.0.0.0:4321', Result.FAILED, {
'Listening on {kind} port {listen_address}:{port}', Result.FAILED, {
'kind': 'tcp',
'port': 4321,
'listen_address': '0.0.0.0'

View File

@ -10,8 +10,7 @@ import pytest
from plinth.app import App
from plinth.errors import MissingPackageError
from plinth.modules.diagnostics.check import (DiagnosticCheck, Result,
translate_checks)
from plinth.modules.diagnostics.check import DiagnosticCheck, Result
from plinth.package import Package, Packages, packages_installed
@ -239,33 +238,37 @@ def test_diagnose(cache):
Package('package4') | Package('package5'),
Package('package6') | Package('package7')
])
results = translate_checks(component.diagnose())
results = component.diagnose()
assert results == [
DiagnosticCheck('package-available-package1',
'Package package1 is not available for install',
Result.FAILED, {'package_expression': 'package1'}),
DiagnosticCheck('package-latest-package2',
'Package package2 is the latest version (2.0)',
Result.PASSED, {
'package_name': 'package2',
'latest_version': '2.0'
}),
DiagnosticCheck('package-latest-package3',
'Package package3 is the latest version (3.0)',
Result.WARNING, {
'package_name': 'package3',
'latest_version': '3.0'
}),
DiagnosticCheck(
'package-available-package1',
'Package {package_expression} is not available for install',
Result.FAILED, {'package_expression': 'package1'}),
DiagnosticCheck(
'package-latest-package2',
'Package {package_name} is the latest version ({latest_version})',
Result.PASSED, {
'package_name': 'package2',
'latest_version': '2.0'
}),
DiagnosticCheck(
'package-latest-package3',
'Package {package_name} is the latest version ({latest_version})',
Result.WARNING, {
'package_name': 'package3',
'latest_version': '3.0'
}),
DiagnosticCheck(
'package-available-package4 | package5',
'Package package4 | package5 is not available for install',
'Package {package_expression} is not available for install',
Result.FAILED, {'package_expression': 'package4 | package5'}),
DiagnosticCheck('package-latest-package7',
'Package package7 is the latest version (4.0)',
Result.PASSED, {
'package_name': 'package7',
'latest_version': '4.0'
}),
DiagnosticCheck(
'package-latest-package7',
'Package {package_name} is the latest version ({latest_version})',
Result.PASSED, {
'package_name': 'package7',
'latest_version': '4.0'
}),
]