Skip to content

Commit

Permalink
feat(api-tags): normalize whitespaces around tags and check string le…
Browse files Browse the repository at this point in the history
…ngth
  • Loading branch information
laurent-laporte-pro committed Feb 19, 2024
1 parent 54d6c24 commit b7c063a
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 2 deletions.
15 changes: 13 additions & 2 deletions antarest/study/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from datetime import datetime, timedelta
from pathlib import Path

from pydantic import BaseModel
from pydantic import BaseModel, validator
from sqlalchemy import ( # type: ignore
Boolean,
Column,
Expand Down Expand Up @@ -351,7 +351,18 @@ class StudyMetadataPatchDTO(BaseModel):
scenario: t.Optional[str] = None
status: t.Optional[str] = None
doc: t.Optional[str] = None
tags: t.List[str] = []
tags: t.Sequence[str] = ()

@validator("tags", each_item=True)
def _normalize_tags(cls, v: str) -> str:
"""Remove leading and trailing whitespaces, and replace consecutive whitespaces by a single one."""
tag = " ".join(v.split())
if not tag:
raise ValueError("Tag cannot be empty")
elif len(tag) > 40:
raise ValueError(f"Tag is too long: {tag!r}")
else:
return tag


class StudySimSettingsDTO(BaseModel):
Expand Down
95 changes: 95 additions & 0 deletions tests/integration/studies_blueprint/test_update_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from starlette.testclient import TestClient


class TestupdateStudyMetadata:
"""
Test the study tags update through the `update_study_metadata` API endpoint.
"""

def test_update_tags(
self,
client: TestClient,
user_access_token: str,
study_id: str,
) -> None:
"""
This test verifies that we can update the tags of a study.
It also tests the tags normalization.
"""

# Classic usage: set some tags to a study
study_tags = ["Tag1", "Tag2"]
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 200, res.json()
actual = res.json()
assert set(actual["tags"]) == set(study_tags)

# Update the tags with already existing tags (case-insensitive):
# - "Tag1" is preserved, but with the same case as the existing one.
# - "Tag2" is replaced by "Tag3".
study_tags = ["tag1", "Tag3"]
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 200, res.json()
actual = res.json()
assert set(actual["tags"]) != set(study_tags) # not the same case
assert set(tag.upper() for tag in actual["tags"]) == {"TAG1", "TAG3"}

# String normalization: whitespaces are stripped and
# consecutive whitespaces are replaced by a single one.
study_tags = [" \xa0Foo \t Bar \n ", " \t Baz\xa0\xa0"]
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 200, res.json()
actual = res.json()
assert set(actual["tags"]) == {"Foo Bar", "Baz"}

# We can have symbols in the tags
study_tags = ["Foo-Bar", ":Baz%"]
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 200, res.json()
actual = res.json()
assert set(actual["tags"]) == {"Foo-Bar", ":Baz%"}

def test_update_tags__invalid_tags(
self,
client: TestClient,
user_access_token: str,
study_id: str,
) -> None:
# We cannot have empty tags
study_tags = [""]
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 422, res.json()
description = res.json()["description"]
assert "Tag cannot be empty" in description

# We cannot have tags longer than 40 characters
study_tags = ["very long tags, very long tags, very long tags"]
assert len(study_tags[0]) > 40
res = client.put(
f"/v1/studies/{study_id}",
headers={"Authorization": f"Bearer {user_access_token}"},
json={"tags": study_tags},
)
assert res.status_code == 422, res.json()
description = res.json()["description"]
assert "Tag is too long" in description

0 comments on commit b7c063a

Please sign in to comment.