Skip to content

Commit

Permalink
project lock completely tested
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderegg committed Apr 5, 2022
1 parent 075b603 commit e9d2a1f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 10 deletions.
4 changes: 2 additions & 2 deletions packages/models-library/src/models_library/projects_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ class Config:

@validator("owner", pre=True, always=True)
@classmethod
def check_not_null(v, values):
def check_not_null(cls, v, values):
if values["value"] is True and v is None:
raise ValueError("value cannot be None when project is locked")
return v

@validator("status", always=True)
@classmethod
def check_status_compatible(v, values):
def check_status_compatible(cls, v, values):
if values["value"] is False and v not in ["CLOSED", "OPENED"]:
raise ValueError(
f"status is set to {v} and lock is set to {values['value']}!"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from contextlib import asynccontextmanager, suppress
from typing import Optional, Union

import aioredis.lock
import aioredis.exceptions
import aioredis.lock
from aiohttp import web
from models_library.projects import ProjectID
from models_library.projects_state import Owner, ProjectLocked, ProjectStatus
Expand Down Expand Up @@ -75,9 +75,9 @@ async def get_project_locked_state(
) -> Optional[ProjectLocked]:
"""returns the ProjectLocked object if the project is locked"""
if await is_project_locked(app, project_uuid):
redis_lock = get_redis_lock_manager_client(app).lock(
PROJECT_REDIS_LOCK_KEY.format(project_uuid)
)
redis_locks_client = get_redis_lock_manager_client(app)

if project_locked := redis_lock.local.token:
return ProjectLocked.parse_raw(project_locked)
if lock_value := await redis_locks_client.get(
PROJECT_REDIS_LOCK_KEY.format(project_uuid)
):
return ProjectLocked.parse_raw(lock_value)
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ async def _get_project_lock_state(
if not set_user_ids:
# no one has the project, so it is unlocked and closed.
log.debug("project [%s] is not in use", f"{project_uuid=}")
return ProjectLocked(value=False, status=ProjectStatus.CLOSED)
return ProjectLocked(value=False, status=ProjectStatus.CLOSED, owner=None)

log.debug(
"project [%s] might be used by the following users: [%s]",
Expand Down Expand Up @@ -840,7 +840,7 @@ async def add_project_states_for_user(
f"{project['uuid']=}",
)
# for templates: the project is never locked and never opened. also the running state is always unknown
lock_state = ProjectLocked(value=False, status=ProjectStatus.CLOSED)
lock_state = ProjectLocked(value=False, status=ProjectStatus.CLOSED, owner=None)
running_state = RunningState.UNKNOWN

if not is_template:
Expand Down
65 changes: 65 additions & 0 deletions services/web/server/tests/unit/with_dbs/02/test_project_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from simcore_service_webserver.projects.project_lock import (
PROJECT_REDIS_LOCK_KEY,
ProjectLockError,
get_project_locked_state,
is_project_locked,
lock_project,
)
from simcore_service_webserver.users_api import UserNameDict
Expand Down Expand Up @@ -130,3 +132,66 @@ async def test_raise_exception_while_locked_release_lock(
PROJECT_REDIS_LOCK_KEY.format(project_uuid)
)
assert not redis_value


async def test_is_project_locked(
client: TestClient,
user_id: UserID,
project_uuid: ProjectID,
faker: Faker,
):
assert client.app
assert await is_project_locked(client.app, project_uuid) == False
user_name: UserNameDict = {
"first_name": faker.first_name(),
"last_name": faker.last_name(),
}
async with lock_project(
app=client.app,
project_uuid=project_uuid,
status=ProjectStatus.EXPORTING,
user_id=user_id,
user_name=user_name,
):
assert await is_project_locked(client.app, project_uuid) == True


@pytest.mark.parametrize(
"lock_status",
[
ProjectStatus.CLOSING,
ProjectStatus.CLONING,
ProjectStatus.EXPORTING,
ProjectStatus.OPENING,
],
)
async def test_get_project_locked_state(
client: TestClient,
user_id: UserID,
project_uuid: ProjectID,
faker: Faker,
lock_status: ProjectStatus,
):
assert client.app
# no lock
assert await get_project_locked_state(client.app, project_uuid) == None

assert await is_project_locked(client.app, project_uuid) == False
user_name: UserNameDict = {
"first_name": faker.first_name(),
"last_name": faker.last_name(),
}
async with lock_project(
app=client.app,
project_uuid=project_uuid,
status=lock_status,
user_id=user_id,
user_name=user_name,
):
locked_state = await get_project_locked_state(client.app, project_uuid)
expected_locked_state = ProjectLocked(
value=bool(lock_status not in [ProjectStatus.CLOSED, ProjectStatus.OPENED]),
owner=Owner(user_id=user_id, **user_name),
status=lock_status,
)
assert locked_state == expected_locked_state

0 comments on commit e9d2a1f

Please sign in to comment.