Skip to content

Commit 249d7b9

Browse files
committed
fixes tests
1 parent 6195a26 commit 249d7b9

File tree

2 files changed

+68
-42
lines changed

2 files changed

+68
-42
lines changed

services/web/server/src/simcore_service_webserver/login/handlers_change.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,6 @@ class ResetPasswordBody(InputSchema):
4949
email: str
5050

5151

52-
def _get_request_context(request: web.Request) -> dict[str, str]:
53-
return {
54-
"request.remote": f"{request.remote}",
55-
"request.method": f"{request.method}",
56-
"request.path": f"{request.path}",
57-
}
58-
59-
6052
@routes.post(f"/{API_VTAG}/auth/reset-password", name="initiate_reset_password")
6153
@global_rate_limit_route(number_of_requests=10, interval_seconds=HOUR)
6254
async def initiate_reset_password(request: web.Request):
@@ -80,27 +72,50 @@ async def initiate_reset_password(request: web.Request):
8072

8173
request_body = await parse_request_body_as(ResetPasswordBody, request)
8274

75+
_error_msg_prefix = "Password reset initiated"
76+
77+
def _get_error_context(
78+
user=None,
79+
) -> dict[str, str]:
80+
ctx = {
81+
"user_email": request_body.email,
82+
"product_name": product.name,
83+
"request.remote": f"{request.remote}",
84+
"request.method": f"{request.method}",
85+
"request.path": f"{request.path}",
86+
}
87+
88+
if user:
89+
ctx.update(
90+
{
91+
"user_email": request_body.email,
92+
"user_id": user["id"],
93+
"user_status": user["status"],
94+
"user_role": user["role"],
95+
}
96+
)
97+
return ctx
98+
8399
# NOTE: Always same response: never want to confirm or deny the existence of an account
84100
# with a given email or username.
85101
initiated_response = flash_response(
86102
MSG_EMAIL_SENT.format(email=request_body.email), "INFO"
87103
)
104+
88105
# CHECK user exists
89106
user = await db.get_user({"email": request_body.email})
90107
if not user:
91108
_logger.warning(
92109
**create_troubleshotting_log_kwargs(
93-
"Password reset initiated for non-existent email. Ignoring request.",
110+
"{_error_msg_prefix} for non-existent email. Ignoring request.",
94111
error=Exception("No user found with this email"),
95-
error_context={
96-
"user_email": request_body.email,
97-
"product_name": product.name,
98-
**_get_request_context(request),
99-
},
112+
error_context=_get_error_context(),
100113
)
101114
)
102115
return initiated_response
103116

117+
assert user["email"] == request_body.email # nosec
118+
104119
# CHECK user state
105120
try:
106121
validate_user_status(user=dict(user), support_email=product.support_email)
@@ -109,20 +124,14 @@ async def initiate_reset_password(request: web.Request):
109124
# do not want to forward but rather log due to the special rules in this entrypoint
110125
_logger.warning(
111126
**create_troubleshotting_log_kwargs(
112-
"Password reset initiated for invalid user. Ignoring request.",
127+
f"{_error_msg_prefix} for invalid user. Ignoring request.",
113128
error=err,
114-
error_context={
115-
"user_id": user["id"],
116-
"user": user,
117-
"product_name": product.name,
118-
**_get_request_context(request),
119-
},
129+
error_context=_get_error_context(user),
120130
)
121131
)
122132
return initiated_response
123133

124134
assert user["status"] == ACTIVE # nosec
125-
assert user["email"] == request_body.email # nosec
126135
assert isinstance(user["id"], int) # nosec
127136

128137
# CHECK access to product
@@ -131,14 +140,9 @@ async def initiate_reset_password(request: web.Request):
131140
):
132141
_logger.warning(
133142
**create_troubleshotting_log_kwargs(
134-
"Password reset initiated for a user with NO access to this product. Ignoring request.",
143+
f"{_error_msg_prefix} for a user with NO access to this product. Ignoring request.",
135144
error=Exception("User cannot access this product"),
136-
error_context={
137-
"user_id": user["id"],
138-
"user": user,
139-
"product_name": product.name,
140-
**_get_request_context(request),
141-
},
145+
error_context=_get_error_context(user),
142146
)
143147
)
144148
return initiated_response
@@ -169,11 +173,7 @@ async def initiate_reset_password(request: web.Request):
169173
**create_troubleshotting_log_kwargs(
170174
"Unable to send email",
171175
error=err,
172-
error_context={
173-
"product_name": product.name,
174-
"user_id": user["id"],
175-
**_get_request_context(request),
176-
},
176+
error_context=_get_error_context(user),
177177
)
178178
)
179179
raise web.HTTPServiceUnavailable(reason=MSG_CANT_SEND_MAIL) from err

services/web/server/tests/unit/with_dbs/03/login/test_login_reset_password.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,16 @@ async def test_unknown_email(
138138

139139
# email is not sent
140140
out, _ = capsys.readouterr()
141-
assert not parse_test_marks(out)
141+
assert not parse_test_marks(out), "Expected no email to be sent"
142142

143143
# Check logger warning
144+
logged_warnings = [
145+
record.message for record in caplog.records if record.levelname == "WARNING"
146+
]
147+
144148
assert any(
145-
record.levelname == "WARNING"
146-
and record.message.startswith("Password reset initiated")
147-
for record in caplog.records
148-
)
149+
message.startswith("Password reset initiated") for message in logged_warnings
150+
), f"Missing warning in {logged_warnings}"
149151

150152

151153
@pytest.mark.parametrize(
@@ -158,6 +160,7 @@ async def test_unknown_email(
158160
async def test_blocked_user(
159161
client: TestClient,
160162
capsys: pytest.CaptureFixture,
163+
caplog: pytest.LogCaptureFixture,
161164
user_status: UserStatus,
162165
expected_msg: str,
163166
):
@@ -175,12 +178,24 @@ async def test_blocked_user(
175178
assert response.url.path == reset_url.path
176179
await assert_status(response, status.HTTP_200_OK, MSG_EMAIL_SENT.format(**user))
177180

181+
# email is not sent
178182
out, _ = capsys.readouterr()
183+
assert not parse_test_marks(out), "Expected no email to be sent"
184+
179185
# expected_msg contains {support_email} at the end of the string
180-
assert expected_msg[:-20] in parse_test_marks(out)["reason"]
186+
logged_warnings = [
187+
record.message for record in caplog.records if record.levelname == "WARNING"
188+
]
189+
190+
assert any(
191+
message.startswith("Password reset initiated") and expected_msg[:50] in message
192+
for message in logged_warnings
193+
), f"Missing warning in {logged_warnings}"
181194

182195

183-
async def test_inactive_user(client: TestClient, capsys: pytest.CaptureFixture):
196+
async def test_inactive_user(
197+
client: TestClient, capsys: pytest.CaptureFixture, caplog: pytest.LogCaptureFixture
198+
):
184199
assert client.app
185200
reset_url = client.app.router["initiate_reset_password"].url_for()
186201

@@ -197,8 +212,19 @@ async def test_inactive_user(client: TestClient, capsys: pytest.CaptureFixture):
197212
assert response.url.path == reset_url.path
198213
await assert_status(response, status.HTTP_200_OK, MSG_EMAIL_SENT.format(**user))
199214

215+
# email is not sent
200216
out, _ = capsys.readouterr()
201-
assert parse_test_marks(out)["reason"] == MSG_ACTIVATION_REQUIRED
217+
assert not parse_test_marks(out), "Expected no email to be sent"
218+
219+
logged_warnings = [
220+
record.message for record in caplog.records if record.levelname == "WARNING"
221+
]
222+
223+
assert any(
224+
message.startswith("Password reset initiated")
225+
and MSG_ACTIVATION_REQUIRED[:20] in message
226+
for message in logged_warnings
227+
), f"Missing warning in {logged_warnings}"
202228

203229

204230
async def test_too_often(

0 commit comments

Comments
 (0)