Skip to content

Commit 8093b42

Browse files
authored
♻️ Maintenance: refactors guest user and save-state logic to improve flaky tests (ITISFoundation#2897)
1 parent f2039b3 commit 8093b42

File tree

18 files changed

+404
-241
lines changed

18 files changed

+404
-241
lines changed

packages/models-library/src/models_library/projects.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from pydantic import BaseModel, EmailStr, Extra, Field, HttpUrl, constr, validator
1111

1212
from .basic_regex import DATE_RE, UUID_RE
13-
from .projects_access import AccessRights, GroupID
13+
from .projects_access import AccessRights, GroupIDStr
1414
from .projects_nodes import Node
1515
from .projects_nodes_io import NodeIDStr
1616
from .projects_state import ProjectState
@@ -121,7 +121,7 @@ class Project(BaseProjectModel):
121121
examples=["2018-07-01T11:13:43Z"],
122122
alias="lastChangeDate",
123123
)
124-
access_rights: Dict[GroupID, AccessRights] = Field(
124+
access_rights: Dict[GroupIDStr, AccessRights] = Field(
125125
...,
126126
description="object containing the GroupID as key and read/write/execution permissions as value",
127127
alias="accessRights",

packages/models-library/src/models_library/projects_access.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from pydantic import BaseModel, Extra, Field, constr
88
from pydantic.types import PositiveInt
99

10-
GroupID = constr(regex=r"^\S+$")
10+
GroupIDStr = constr(regex=r"^\S+$")
1111

1212

1313
class AccessEnum(str, Enum):

packages/postgres-database/src/simcore_postgres_database/models/users.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,24 @@
44
- Users they have a role within the framework that provides
55
them different access levels to it
66
"""
7-
import itertools
87
from enum import Enum
8+
from functools import total_ordering
99

1010
import sqlalchemy as sa
1111
from sqlalchemy.sql import func
1212

1313
from .base import metadata
1414

15+
_USER_ROLE_TO_LEVEL = {
16+
"ANONYMOUS": 0,
17+
"GUEST": 10,
18+
"USER": 20,
19+
"TESTER": 30,
20+
"ADMIN": 100,
21+
}
1522

23+
24+
@total_ordering
1625
class UserRole(Enum):
1726
"""SORTED enumeration of user roles
1827
@@ -36,11 +45,14 @@ class UserRole(Enum):
3645
TESTER = "TESTER"
3746
ADMIN = "ADMIN"
3847

39-
@classmethod
40-
def super_users(cls):
41-
return list(itertools.takewhile(lambda e: e != cls.USER, cls))
48+
@property
49+
def privilege_level(self) -> int:
50+
return _USER_ROLE_TO_LEVEL[self.name]
4251

43-
# TODO: add comparison https://portingguide.readthedocs.io/en/latest/comparisons.html
52+
def __lt__(self, other) -> bool:
53+
if self.__class__ is other.__class__:
54+
return self.privilege_level < other.privilege_level
55+
return NotImplemented
4456

4557

4658
class UserStatus(Enum):
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from simcore_postgres_database.models.users import _USER_ROLE_TO_LEVEL, UserRole
2+
3+
4+
def test_user_role_to_level_map_in_sync():
5+
# If fails, then update _USER_ROLE_TO_LEVEL map
6+
assert set(_USER_ROLE_TO_LEVEL.keys()) == set(UserRole.__members__.keys())
7+
8+
9+
def test_user_role_comparison():
10+
11+
assert UserRole.ANONYMOUS < UserRole.ADMIN
12+
assert UserRole.GUEST < UserRole.ADMIN
13+
assert UserRole.USER < UserRole.ADMIN
14+
assert UserRole.TESTER < UserRole.ADMIN
15+
assert UserRole.ADMIN == UserRole.ADMIN
16+
17+
assert UserRole.ANONYMOUS < UserRole.TESTER
18+
assert UserRole.GUEST < UserRole.TESTER
19+
assert UserRole.USER < UserRole.TESTER
20+
assert UserRole.TESTER == UserRole.TESTER
21+
assert UserRole.ADMIN > UserRole.TESTER
22+
23+
assert UserRole.ANONYMOUS < UserRole.USER
24+
assert UserRole.GUEST < UserRole.USER
25+
assert UserRole.USER == UserRole.USER
26+
assert UserRole.TESTER > UserRole.USER
27+
assert UserRole.ADMIN > UserRole.USER
28+
29+
assert UserRole.ANONYMOUS < UserRole.GUEST
30+
assert UserRole.GUEST == UserRole.GUEST
31+
assert UserRole.USER > UserRole.GUEST
32+
assert UserRole.TESTER > UserRole.GUEST
33+
assert UserRole.ADMIN > UserRole.GUEST
34+
35+
assert UserRole.ANONYMOUS == UserRole.ANONYMOUS
36+
assert UserRole.GUEST > UserRole.ANONYMOUS
37+
assert UserRole.USER > UserRole.ANONYMOUS
38+
assert UserRole.TESTER > UserRole.ANONYMOUS
39+
assert UserRole.ADMIN > UserRole.ANONYMOUS
40+
41+
# < and >
42+
assert UserRole.TESTER < UserRole.ADMIN
43+
assert UserRole.ADMIN > UserRole.TESTER
44+
45+
# >=, == and <=
46+
assert UserRole.TESTER <= UserRole.ADMIN
47+
assert UserRole.ADMIN >= UserRole.TESTER
48+
49+
assert UserRole.ADMIN <= UserRole.ADMIN
50+
assert UserRole.ADMIN == UserRole.ADMIN

packages/pytest-simcore/src/pytest_simcore/helpers/utils_login.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import Any, Dict
2+
from typing import TypedDict
33

44
from aiohttp import web
55
from aiohttp.test_utils import TestClient
@@ -12,9 +12,22 @@
1212

1313
from .utils_assert import assert_status
1414

15-
# WARNING: UserDict is already in https://docs.python.org/3/library/collections.html#collections.UserDict
16-
# TODO: move this to future simcore_service_webserver.users_models.py
17-
AUserDict = Dict[str, Any]
15+
16+
# WARNING: DO NOT use UserDict is already in https://docs.python.org/3/library/collections.html#collections.UserDictclass UserRowDict(TypedDict):
17+
# NOTE: this is modified dict version of packages/postgres-database/src/simcore_postgres_database/models/users.py for testing purposes
18+
class _UserInfoDictRequired(TypedDict, total=True):
19+
id: int
20+
name: str
21+
email: str
22+
raw_password: str
23+
status: UserStatus
24+
role: UserRole
25+
26+
27+
class UserInfoDict(_UserInfoDictRequired, total=False):
28+
created_ip: int
29+
password_hash: str
30+
1831

1932
TEST_MARKS = re.compile(r"TEST (\w+):(.*)")
2033

@@ -37,7 +50,7 @@ def parse_link(text):
3750
return URL(link).path
3851

3952

40-
async def create_user(db: AsyncpgStorage, data=None) -> AUserDict:
53+
async def create_user(db: AsyncpgStorage, data=None) -> UserInfoDict:
4154
data = data or {}
4255
password = get_random_string(10)
4356
params = {
@@ -56,7 +69,7 @@ async def create_user(db: AsyncpgStorage, data=None) -> AUserDict:
5669

5770
async def log_client_in(
5871
client: TestClient, user_data=None, *, enable_check=True
59-
) -> AUserDict:
72+
) -> UserInfoDict:
6073
# creates user directly in db
6174
db: AsyncpgStorage = get_plugin_storage(client.app)
6275
cfg: LoginOptions = get_plugin_options(client.app)
@@ -99,7 +112,7 @@ def __init__(self, client, params=None, *, check_if_succeeds=True):
99112
self.client = client
100113
self.enable_check = check_if_succeeds
101114

102-
async def __aenter__(self) -> AUserDict:
115+
async def __aenter__(self) -> UserInfoDict:
103116
self.user = await log_client_in(
104117
self.client, self.params, enable_check=self.enable_check
105118
)

services/web/server/src/simcore_service_webserver/catalog_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import asyncio
55
import logging
66
import urllib.parse
7-
from typing import Any, Dict, List, Optional
7+
from typing import Any, Dict, List, Mapping, Optional
88

99
from aiohttp import ClientSession, ClientTimeout, web
1010
from aiohttp.client_exceptions import (
@@ -60,7 +60,7 @@ async def make_request_and_envelope_response(
6060
app: web.Application,
6161
method: str,
6262
url: URL,
63-
headers: Optional[Dict[str, str]] = None,
63+
headers: Optional[Mapping[str, str]] = None,
6464
data: Optional[bytes] = None,
6565
) -> web.Response:
6666
"""

0 commit comments

Comments
 (0)