Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relaxed nautilus schema #1004

Merged
merged 4 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dispatcher/backend/src/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@

# OFFLINERS
ZIMIT_USE_RELAXED_SCHEMA = bool(os.getenv("ZIMIT_USE_RELAXED_SCHEMA"))
NAUTILUS_USE_RELAXED_SCHEMA = bool(os.getenv("NAUTILUS_USE_RELAXED_SCHEMA"))
7 changes: 6 additions & 1 deletion dispatcher/backend/src/common/schemas/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
KolibriFlagsSchema,
MWOfflinerFlagsSchema,
NautilusFlagsSchema,
NautilusFlagsSchemaRelaxed,
OpenedxFlagsSchema,
PhetFlagsSchema,
SotokiFlagsSchema,
Expand Down Expand Up @@ -84,7 +85,11 @@ def get_offliner_schema(offliner):
Offliner.gutenberg: GutenbergFlagsSchema,
Offliner.phet: PhetFlagsSchema,
Offliner.sotoki: SotokiFlagsSchema,
Offliner.nautilus: NautilusFlagsSchema,
Offliner.nautilus: (
NautilusFlagsSchemaRelaxed
if constants.NAUTILUS_USE_RELAXED_SCHEMA
else NautilusFlagsSchema
),
Offliner.ted: TedFlagsSchema,
Offliner.openedx: OpenedxFlagsSchema,
Offliner.zimit: (
Expand Down
6 changes: 5 additions & 1 deletion dispatcher/backend/src/common/schemas/offliners/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from common.schemas.offliners.ifixit import IFixitFlagsSchema
from common.schemas.offliners.kolibri import KolibriFlagsSchema
from common.schemas.offliners.mwoffliner import MWOfflinerFlagsSchema
from common.schemas.offliners.nautilus import NautilusFlagsSchema
from common.schemas.offliners.nautilus import (
NautilusFlagsSchema,
NautilusFlagsSchemaRelaxed,
)
from common.schemas.offliners.openedx import OpenedxFlagsSchema
from common.schemas.offliners.sotoki import SotokiFlagsSchema
from common.schemas.offliners.ted import TedFlagsSchema
Expand All @@ -19,6 +22,7 @@
"KolibriFlagsSchema",
"MWOfflinerFlagsSchema",
"NautilusFlagsSchema",
"NautilusFlagsSchemaRelaxed",
"OpenedxFlagsSchema",
"SotokiFlagsSchema",
"TedFlagsSchema",
Expand Down
16 changes: 16 additions & 0 deletions dispatcher/backend/src/common/schemas/offliners/nautilus.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,19 @@ class Meta:
falsy=[False],
metadata={"label": "Debug", "description": "Enable verbose output"},
)


class NautilusFlagsSchemaRelaxed(NautilusFlagsSchema):
"""A Nautils flags schema with relaxed constraints on validation

For now, only zim_file name is not checked anymore.
Typically used for nautilus.kiwix.org
"""

zim_file = String(
metadata={
"label": "ZIM filename",
"description": "ZIM file name (based on --name if not provided).",
},
data_key="zim-file",
)
3 changes: 1 addition & 2 deletions dispatcher/backend/src/common/schemas/offliners/zimit.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,8 +564,7 @@ class ZimitFlagsSchemaRelaxed(ZimitFlagsSchema):
zim_file = String(
metadata={
"label": "ZIM filename",
"description": "ZIM file name (based on --name if not provided). "
"Make sure to end with _{period}.zim",
"description": "ZIM file name (based on --name if not provided).",
},
data_key="zim-file",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from collections import namedtuple
from typing import List

import pytest
from utils_for_tests import update_dict

from common import constants


class TestNautilus:
mod = namedtuple("Modification", ["key_path", "new_value"])

@pytest.mark.parametrize(
"modifications, relaxed_schema, succeeds",
[
(
[mod(key_path="name", new_value="nautilus_test_good_name_not_relaxed")],
False,
True,
),
(
[mod(key_path="name", new_value="nautilus_test_good_name_relaxed")],
True,
True,
),
(
[
mod(
key_path="name", new_value="nautilus_test_bad_name_not_relaxed"
),
mod(key_path="config.flags.zim-file", new_value="bad_name"),
],
False,
False,
),
(
[
mod(key_path="name", new_value="nautilus_test_bad_name_relaxed"),
mod(key_path="config.flags.zim-file", new_value="bad_name"),
],
True,
True,
),
],
)
def test_create_nautilus_schedule_generic(
self,
client,
access_token,
garbage_collector,
modifications: List[mod],
relaxed_schema: bool,
succeeds: bool,
):
constants.NAUTILUS_USE_RELAXED_SCHEMA = relaxed_schema
schedule = {
"name": "nautilus_test_ok",
"category": "other",
"enabled": False,
"tags": [],
"language": {"code": "fr", "name_en": "French", "name_native": "Français"},
"config": {
"task_name": "nautilus",
"warehouse_path": "/other",
"image": {"name": "openzim/nautilus", "tag": "1.0.0"},
"monitor": False,
"platform": None,
"flags": {
"name": "acme",
"collection": "https://www.acme.com",
"zim-file": "acme_en_all_{period}.zim",
},
"resources": {"cpu": 3, "memory": 1024, "disk": 0},
},
"periodicity": "quarterly",
}
for modification in modifications:
update_dict(schedule, modification.key_path, modification.new_value)
url = "/schedules/"
response = client.post(
url, json=schedule, headers={"Authorization": access_token}
)
response_data = response.get_json()
if "_id" in response_data:
garbage_collector.add_schedule_id(response_data["_id"])
if succeeds:
assert response.status_code == 201
else:
assert response.status_code == 400
assert "error_description" in response_data
assert "zim-file" in response_data["error_description"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,11 @@
from typing import List

import pytest
from utils_for_tests import update_dict

from common import constants


def update_dict(dict: dict, key_path: str, new_value: any):
"""Update a nested key value in a dictionary

E.g if key_path is 'key1.subkey2', then dict['key1']['subkey2'] will be set"""

# Split the key path into individual keys
keys = key_path.split(".")

# Initialize a reference to the nested dictionary
current_dict = dict

# Navigate through the nested structure
for key in keys[:-1]:
current_dict = current_dict[key]

# Update the value using the last key
current_dict[keys[-1]] = new_value


class TestZimit:
mod = namedtuple("Modification", ["key_path", "new_value"])

Expand Down
19 changes: 19 additions & 0 deletions dispatcher/backend/src/tests/utils_for_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,22 @@ def patch_dict(data, patch):
# If the key is not present in the original dictionary, set it with the
# patch value
data[key] = patch_value


def update_dict(dict: dict, key_path: str, new_value: any):
"""Update a nested key value in a dictionary

E.g if key_path is 'key1.subkey2', then dict['key1']['subkey2'] will be set"""

# Split the key path into individual keys
keys = key_path.split(".")

# Initialize a reference to the nested dictionary
current_dict = dict

# Navigate through the nested structure
for key in keys[:-1]:
current_dict = current_dict[key]

# Update the value using the last key
current_dict[keys[-1]] = new_value