Skip to content

Commit

Permalink
remove PUT project - fixing unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
matusdrobuliak66 committed Oct 25, 2024
1 parent 9607181 commit b1d5ee3
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,6 @@ class ProjectReplace(InputSchema):
)


class ProjectUpdate(InputSchema):
name: ShortTruncatedStr = FieldNotRequired()
description: LongTruncatedStr = FieldNotRequired()
thumbnail: HttpUrlWithCustomMinLength = FieldNotRequired()
workbench: NodesDict = FieldNotRequired()
access_rights: dict[GroupIDStr, AccessRights] = FieldNotRequired()
tags: list[int] = FieldNotRequired()
classifiers: list[ClassifierID] = FieldNotRequired()
ui: StudyUI | None = None
quality: dict[str, Any] = FieldNotRequired()


class ProjectPatch(InputSchema):
name: ShortTruncatedStr = FieldNotRequired()
description: LongTruncatedStr = FieldNotRequired()
Expand All @@ -143,6 +131,10 @@ class ProjectPatch(InputSchema):
ui: StudyUI | None = FieldNotRequired()
quality: dict[str, Any] = FieldNotRequired()

_empty_is_none = validator("thumbnail", allow_reuse=True, pre=True)(
empty_str_to_none_pre_validator
)


__all__: tuple[str, ...] = (
"EmptyModel",
Expand All @@ -151,6 +143,5 @@ class ProjectPatch(InputSchema):
"ProjectGet",
"ProjectListItem",
"ProjectReplace",
"ProjectUpdate",
"TaskProjectGet",
)
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async def _wrapper(request: web.Request) -> web.StreamResponse:
FolderAccessForbiddenError,
WorkspaceAccessForbiddenError,
) as exc:
raise web.HTTPUnauthorized(reason=f"{exc}") from exc
raise web.HTTPForbidden(reason=f"{exc}") from exc

return _wrapper

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
# pylint: disable=unused-argument
# pylint: disable=unused-variable

import random
import re
import uuid as uuidlib
from collections.abc import Awaitable, Callable, Iterator
from copy import deepcopy
from http import HTTPStatus
from math import ceil
from typing import Any
Expand All @@ -19,10 +17,7 @@
from aioresponses import aioresponses
from faker import Faker
from models_library.products import ProductName
from models_library.projects_nodes import Node
from models_library.projects_state import ProjectState
from models_library.services import ServiceKey
from models_library.utils.fastapi_encoders import jsonable_encoder
from pydantic import parse_obj_as
from pytest_simcore.helpers.assert_checks import assert_status
from pytest_simcore.helpers.webserver_login import UserInfoDict
Expand Down Expand Up @@ -187,7 +182,7 @@ async def _replace_project(
assert client.app

# PUT /v0/projects/{project_id}
url = client.app.router["replace_project"].url_for(
url = client.app.router["replace_project"].url_for( # <- MD: check this
project_id=project_update["uuid"]
)
assert str(url) == f"{API_PREFIX}/projects/{project_update['uuid']}"
Expand Down Expand Up @@ -656,141 +651,6 @@ async def test_new_template_from_project(
parse_obj_as(uuidlib.UUID, node_name)


# PUT --------
@pytest.mark.parametrize(
"user_role,expected,expected_change_access",
[
(
UserRole.ANONYMOUS,
status.HTTP_401_UNAUTHORIZED,
status.HTTP_401_UNAUTHORIZED,
),
(UserRole.GUEST, status.HTTP_200_OK, status.HTTP_403_FORBIDDEN),
(UserRole.USER, status.HTTP_200_OK, status.HTTP_200_OK),
(UserRole.TESTER, status.HTTP_200_OK, status.HTTP_200_OK),
],
)
async def test_replace_project(
client: TestClient,
logged_user: UserInfoDict,
user_project: ProjectDict,
expected,
expected_change_access,
all_group,
ensure_run_in_sequence_context_is_empty,
):
project_update = deepcopy(user_project)
project_update["description"] = "some updated from original project!!!"
await _replace_project(client, project_update, expected)

# replacing the owner access is not possible, it will keep the owner as well
project_update["accessRights"].update(
{str(all_group["gid"]): {"read": True, "write": True, "delete": True}}
)
await _replace_project(client, project_update, expected_change_access)


@pytest.mark.parametrize(
"user_role,expected",
[
(UserRole.ANONYMOUS, status.HTTP_401_UNAUTHORIZED),
(UserRole.GUEST, status.HTTP_200_OK),
(UserRole.USER, status.HTTP_200_OK),
(UserRole.TESTER, status.HTTP_200_OK),
],
)
async def test_replace_project_updated_inputs(
client: TestClient,
logged_user: UserInfoDict,
user_project: ProjectDict,
expected,
ensure_run_in_sequence_context_is_empty,
):
project_update = deepcopy(user_project)
#
# "inputAccess": {
# "Na": "ReadAndWrite", <--------
# "Kr": "ReadOnly",
# "BCL": "ReadAndWrite",
# "NBeats": "ReadOnly",
# "Ligand": "Invisible",
# "cAMKII": "Invisible"
# },
project_update["workbench"]["5739e377-17f7-4f09-a6ad-62659fb7fdec"]["inputs"][
"Na"
] = 55
await _replace_project(client, project_update, expected)


@pytest.mark.parametrize(
"user_role,expected",
[
(UserRole.ANONYMOUS, status.HTTP_401_UNAUTHORIZED),
(UserRole.GUEST, status.HTTP_200_OK),
(UserRole.USER, status.HTTP_200_OK),
(UserRole.TESTER, status.HTTP_200_OK),
],
)
async def test_replace_project_updated_readonly_inputs(
client: TestClient,
logged_user: UserInfoDict,
user_project: ProjectDict,
expected,
ensure_run_in_sequence_context_is_empty,
):
project_update = deepcopy(user_project)
project_update["workbench"]["5739e377-17f7-4f09-a6ad-62659fb7fdec"]["inputs"][
"Na"
] = 55
project_update["workbench"]["5739e377-17f7-4f09-a6ad-62659fb7fdec"]["inputs"][
"Kr"
] = 5
await _replace_project(client, project_update, expected)


@pytest.fixture
def random_minimal_node(faker: Faker) -> Callable[[], Node]:
def _creator() -> Node:
return Node(
key=ServiceKey(f"simcore/services/comp/{faker.pystr().lower()}"),
version=faker.numerify("#.#.#"),
label=faker.pystr(),
)

return _creator


@pytest.mark.parametrize(
"user_role,expected",
[
(UserRole.ANONYMOUS, status.HTTP_401_UNAUTHORIZED),
(UserRole.GUEST, status.HTTP_409_CONFLICT),
(UserRole.USER, status.HTTP_409_CONFLICT),
(UserRole.TESTER, status.HTTP_409_CONFLICT),
],
)
async def test_replace_project_adding_or_removing_nodes_raises_conflict(
client: TestClient,
logged_user: UserInfoDict,
user_project: ProjectDict,
expected,
ensure_run_in_sequence_context_is_empty,
faker: Faker,
random_minimal_node: Callable[[], Node],
):
# try adding a node should not work
project_update = deepcopy(user_project)
new_node = random_minimal_node()
project_update["workbench"][faker.uuid4()] = jsonable_encoder(new_node)
await _replace_project(client, project_update, expected)
# try removing a node should not work
project_update = deepcopy(user_project)
project_update["workbench"].pop(
random.choice(list(project_update["workbench"].keys())) # noqa: S311
)
await _replace_project(client, project_update, expected)


@pytest.fixture
def mock_director_v2_inactivity(
aioresponses_mocker: aioresponses, is_inactive: bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,18 @@ async def _replace_project(
) -> ProjectDict:
assert client.app

# PUT /v0/projects/{project_id}
url = client.app.router["replace_project"].url_for(
project_id=project_update["uuid"]
)
# PATCH /v0/projects/{project_id}
url = client.app.router["patch_project"].url_for(project_id=project_update["uuid"])
assert str(url) == f"{API_PREFIX}/projects/{project_update['uuid']}"
resp = await client.put(f"{url}", json=project_update)
resp = await client.patch(f"{url}", json=project_update)
data, error = await assert_status(resp, expected)
if not error:
assert_replaced(current_project=data, update_data=project_update)
url = client.app.router["get_project"].url_for(
project_id=project_update["uuid"]
)
resp = await client.get(f"{url}")
get_data, _ = await assert_status(resp, HTTPStatus.OK)
assert_replaced(current_project=get_data, update_data=project_update)
return data


Expand Down Expand Up @@ -307,10 +310,11 @@ async def test_share_project(
# user 2 can update the project if user 2 has write access
project_update = deepcopy(new_project)
project_update["name"] = "my super name"
project_update.pop("accessRights")
await _replace_project(
client,
project_update,
expected.ok if share_rights["write"] else expected.forbidden,
expected.no_content if share_rights["write"] else expected.forbidden,
)

# user 2 can delete projects if user 2 has delete access
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from models_library.projects import Project
from models_library.projects_nodes import Node
from models_library.services_resources import ServiceResourcesDict
from models_library.utils.json_serialization import json_dumps
from models_library.utils.json_serialization import json_dumps, json_loads
from pytest_mock import MockerFixture
from pytest_simcore.helpers.assert_checks import assert_status
from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict
Expand All @@ -34,6 +34,7 @@
meta_project_policy,
projects_redirection_middleware,
)
from simcore_service_webserver.projects.db import ProjectDBAPI
from simcore_service_webserver.projects.models import ProjectDict

REQUEST_MODEL_POLICY = {
Expand Down Expand Up @@ -144,13 +145,22 @@ async def test_iterators_workflow(
project_data.update({key: modifications[key] for key in ("workbench", "ui")})
project_data["ui"].setdefault("currentNodeId", project_uuid)

response = await client.put(
f"/v0/projects/{project_data['uuid']}",
json=project_data,
# response = await client.patch(
# f"/v0/projects/{project_data['uuid']}",
# json=project_data,
# )
# assert (
# response.status == status.HTTP_204_NO_CONTENT
# ), await response.text()

db: ProjectDBAPI = ProjectDBAPI.get_from_app_context(client.app)
project_data.pop("state")
await db.replace_project(
project_data,
logged_user["id"],
project_uuid=project_uuid,
product_name="osparc",
)
assert (
response.status == REPLACE_PROJECT_ON_MODIFIED.status_code
), await response.text()

# TODO: create iterations, so user could explore parametrizations?

Expand Down Expand Up @@ -260,11 +270,20 @@ async def _mock_catalog_get(*args, **kwarg):
assert node.inputs
node.inputs["linspace_stop"] = 4

response = await client.put(
f"/v0/projects/{project_uuid}",
data=json_dumps(new_project.dict(**REQUEST_MODEL_POLICY)),
# response = await client.patch(
# f"/v0/projects/{project_uuid}",
# data=json_dumps(new_project.dict(**REQUEST_MODEL_POLICY)),
# )
# assert response.status == status.HTTP_204_NO_CONTENT, await response.text()
# db: ProjectDBAPI = ProjectDBAPI.get_from_app_context(client.app)
_new_project_data = new_project.dict(**REQUEST_MODEL_POLICY)
_new_project_data.pop("state")
await db.replace_project(
json_loads(json_dumps(_new_project_data)),
logged_user["id"],
project_uuid=project_uuid,
product_name="osparc",
)
assert response.status == status.HTTP_200_OK, await response.text()

# RUN again them ---------------------------------------------------------------------------
response = await client.post(
Expand Down

0 comments on commit b1d5ee3

Please sign in to comment.