Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .devcontainer/test_application_qa.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import unittest
from io import BytesIO
from time import monotonic
from unittest.mock import Mock, patch
from zipfile import ZipFile

Expand All @@ -18,14 +19,13 @@
class ApplicationQATests(unittest.TestCase):
def test_eventual_completion(self) -> None:
probe = Mock(side_effect=[None, None, {"completed": True}])
with patch("application_qa.time.sleep") as sleep:
with patch("application_qa.time", monotonic=monotonic) as clock:
self.assertEqual(wait_for("import", probe), {"completed": True})
self.assertEqual(sleep.call_count, 2)
self.assertEqual(clock.sleep.call_count, 2)

def test_deadline(self) -> None:
with (
patch("application_qa.time.monotonic", side_effect=[0, 1, 181]),
patch("application_qa.time.sleep"),
patch("application_qa.time", monotonic=Mock(side_effect=[0, 1, 181])),
self.assertRaisesRegex(TimeoutError, "180s: notification"),
):
wait_for("notification", lambda: False)
Expand Down
10 changes: 5 additions & 5 deletions .devcontainer/test_doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import os
import unittest
from time import monotonic
from unittest.mock import MagicMock, patch

from django.db import DatabaseError
Expand All @@ -23,26 +24,25 @@ def test_database_startup_retry(self) -> None:
cache = MagicMock()
with (
patch("doctor.connection") as database,
patch("doctor.time.sleep") as sleep,
patch("doctor.time", monotonic=monotonic) as clock,
):
database.cursor.side_effect = [DatabaseError("starting"), MagicMock()]
wait_for_services(cache)
database.close.assert_called_once()
sleep.assert_called_once_with(1)
clock.sleep.assert_called_once_with(1)
cache.ping.assert_called_once()

def test_valkey_timeout(self) -> None:
cache = MagicMock()
cache.ping.side_effect = RedisConnectionError("private diagnostic")
with (
patch("doctor.connection"),
patch("doctor.time.monotonic", side_effect=[0, 61]),
patch("doctor.time.sleep") as sleep,
patch("doctor.time", monotonic=MagicMock(side_effect=[0, 61])) as clock,
self.assertRaisesRegex(SystemExit, "unavailable after 60 seconds") as error,
):
wait_for_services(cache)
self.assertNotIn("private diagnostic", str(error.exception))
sleep.assert_not_called()
clock.sleep.assert_not_called()


class BrowserTests(unittest.TestCase):
Expand Down
9 changes: 5 additions & 4 deletions .devcontainer/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from io import StringIO
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch
from time import monotonic
from unittest.mock import Mock, patch

from environment import Environment, configuration, initialize, main, project_name

Expand Down Expand Up @@ -408,10 +409,10 @@ def test_readiness_requires_every_service(self) -> None:
"output",
side_effect=[json.dumps(entries[:-1]), json.dumps(entries)],
),
patch("environment.time.sleep") as sleep,
patch("environment.time", monotonic=monotonic) as clock,
):
self.assertEqual(self.env.wait(), 0)
sleep.assert_called_once()
clock.sleep.assert_called_once()

def test_readiness_reports_exit_and_timeout(self) -> None:
with (
Expand All @@ -424,7 +425,7 @@ def test_readiness_reports_exit_and_timeout(self) -> None:
):
self.assertEqual(self.env.wait(), 1)
with (
patch("environment.time.monotonic", side_effect=[0, 1801]),
patch("environment.time", monotonic=Mock(side_effect=[0, 1801])),
redirect_stderr(StringIO()),
):
self.assertEqual(self.env.wait(), 1)
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ repos:
hooks:
- id: yamllint
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.17.2
rev: v0.17.3
hooks:
- id: ruff-check
args:
Expand All @@ -48,7 +48,7 @@ repos:
- id: doccmd
args: [--language, python, --no-pad-file, --command, ruff format]
additional_dependencies:
- ruff==0.17.2
- ruff==0.17.3
language: python
- repo: meta
hooks:
Expand Down
19 changes: 16 additions & 3 deletions weblate/accounts/tests/test_totp_enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ class TOTPEnrollmentTest(FixtureTestCase):
def setUp(self) -> None:
super().setUp()
self.timestamp = int(now().timestamp())
self.enterContext(mock.patch("time.time", return_value=self.timestamp))
self.enterContext(
mock.patch(
"django_otp.plugins.otp_totp.models.time",
time=mock.Mock(return_value=self.timestamp),
)
)
self.enterContext(
mock.patch("django_otp.oath.time", return_value=self.timestamp)
)
Expand Down Expand Up @@ -86,7 +91,10 @@ def test_replay_and_fresh_enrollment(self) -> None:
TOTPTokenForm(self.user, data={"otp_token": payload["token"]}).is_valid()
)
with (
mock.patch("time.time", return_value=self.timestamp + 30),
mock.patch(
"django_otp.plugins.otp_totp.models.time",
time=mock.Mock(return_value=self.timestamp + 30),
),
mock.patch("django_otp.oath.time", return_value=self.timestamp + 30),
mock.patch(
"django_otp.models.timezone.now",
Expand Down Expand Up @@ -333,7 +341,12 @@ def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_user("concurrent-totp", "totp@example.com")
self.timestamp = int(now().timestamp())
self.enterContext(mock.patch("time.time", return_value=self.timestamp))
self.enterContext(
mock.patch(
"django_otp.plugins.otp_totp.models.time",
time=mock.Mock(return_value=self.timestamp),
)
)
self.enterContext(
mock.patch("django_otp.oath.time", return_value=self.timestamp)
)
Expand Down
17 changes: 10 additions & 7 deletions weblate/accounts/tests/test_twofactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,10 @@ def add_totp(
timestamp = now().timestamp() - device.step
with (
mock.patch("django_otp.oath.time", return_value=timestamp),
mock.patch("time.time", return_value=timestamp),
mock.patch(
"django_otp.plugins.otp_totp.models.time",
time=mock.Mock(return_value=timestamp),
),
):
totp_response = f"{totp(device.bin_key):06d}"
response = self.post_with_callbacks(
Expand Down Expand Up @@ -801,12 +804,12 @@ def test_team_enforced_2fa(self) -> None:
def test_password_requires_recent_second_factor(self) -> None:
self.add_totp()

with mock.patch("weblate.accounts.views.time.time") as mocked_time:
mocked_time.return_value = 2_000_000_000
with mock.patch("weblate.accounts.utils.time") as clock:
clock.time.return_value = 2_000_000_000

stale_session = self.client.session
stale_session[SESSION_SECOND_FACTOR_TIMESTAMP] = int(
mocked_time.return_value
clock.time.return_value
) - (SECOND_FACTOR_VERIFY_SECONDS + 1)
stale_session.save()

Expand All @@ -824,12 +827,12 @@ def test_password_requires_recent_second_factor(self) -> None:
def test_password_allows_recent_second_factor(self) -> None:
self.add_totp()

with mock.patch("weblate.accounts.views.time.time") as mocked_time:
mocked_time.return_value = 2_000_000_000
with mock.patch("weblate.accounts.utils.time") as clock:
clock.time.return_value = 2_000_000_000

session = self.client.session
session[SESSION_SECOND_FACTOR_TIMESTAMP] = (
int(mocked_time.return_value) - SECOND_FACTOR_VERIFY_SECONDS
int(clock.time.return_value) - SECOND_FACTOR_VERIFY_SECONDS
)
session.save()

Expand Down
42 changes: 31 additions & 11 deletions weblate/accounts/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def get_request(self, data: dict[str, str] | None = None):
def test_authenticated_session_expiry_is_throttled(self) -> None:
request = self.get_request()

with mock.patch("weblate.accounts.utils.time.time", return_value=1000):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1000)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)

self.assertEqual(
Expand All @@ -122,11 +124,15 @@ def test_authenticated_session_expiry_is_throttled(self) -> None:
self.assertEqual(request.session.get_expiry_age(), 1200)

request.session.modified = False
with mock.patch("weblate.accounts.utils.time.time", return_value=1599):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1599)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertFalse(request.session.modified)

with mock.patch("weblate.accounts.utils.time.time", return_value=1600):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1600)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertTrue(request.session.modified)
self.assertEqual(request.session[SESSION_EXPIRY_REFRESHED], 1600)
Expand All @@ -138,15 +144,21 @@ def test_short_authenticated_session_expiry_refreshes_before_lifetime(self) -> N
self.assertEqual(get_session_expiry_refresh_seconds(1), 0)
self.assertLess(get_session_expiry_refresh_seconds(90), 90)

with mock.patch("weblate.accounts.utils.time.time", return_value=1000):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1000)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)

request.session.modified = False
with mock.patch("weblate.accounts.utils.time.time", return_value=1029):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1029)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertFalse(request.session.modified)

with mock.patch("weblate.accounts.utils.time.time", return_value=1030):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1030)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertTrue(request.session.modified)
self.assertEqual(request.session[SESSION_EXPIRY_REFRESHED], 1030)
Expand All @@ -159,15 +171,19 @@ def test_short_authenticated_session_expiry_refreshes_before_lifetime(self) -> N
def test_session_expiry_scope_changes(self) -> None:
request = self.get_request()

with mock.patch("weblate.accounts.utils.time.time", return_value=1000):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1000)
):
adjust_session_expiry(request=request, user=self.user)
self.assertEqual(
request.session[SESSION_EXPIRY_SCOPE], SESSION_EXPIRY_SCOPE_LOGIN
)
self.assertEqual(request.session.get_expiry_age(), 1000)

request.session.modified = False
with mock.patch("weblate.accounts.utils.time.time", return_value=1001):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1001)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertTrue(request.session.modified)
self.assertEqual(
Expand All @@ -182,7 +198,9 @@ def test_second_factor_session_promotes_to_authenticated(self) -> None:
request = self.get_request()
TOTPDevice.objects.create(user=self.user)

with mock.patch("weblate.accounts.utils.time.time", return_value=1000):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1000)
):
adjust_session_expiry(request=request, user=self.user)
self.assertEqual(
request.session[SESSION_EXPIRY_SCOPE], SESSION_EXPIRY_SCOPE_2FA
Expand All @@ -191,7 +209,9 @@ def test_second_factor_session_promotes_to_authenticated(self) -> None:

request.session[DEVICE_ID_SESSION_KEY] = "otp_totp.totpdevice/1"
request.session.modified = False
with mock.patch("weblate.accounts.utils.time.time", return_value=1001):
with mock.patch(
"weblate.accounts.utils.time", time=mock.Mock(return_value=1001)
):
adjust_session_expiry(request=request, user=self.user, is_login=False)
self.assertTrue(request.session.modified)
self.assertEqual(
Expand Down Expand Up @@ -228,7 +248,7 @@ def test_cleanup_social_auth(self) -> None:
)
with (
mock.patch("weblate.accounts.tasks.now", return_value=timestamp),
mock.patch("social_django.storage.time.time", return_value=1060),
mock.patch("social_django.storage.time", time=mock.Mock(return_value=1060)),
):
cleanup_social_auth()
self.assertEqual(
Expand Down
4 changes: 2 additions & 2 deletions weblate/addons/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -13453,8 +13453,8 @@ def test_broker_tls_handshake_enforces_deadline(self) -> None:

with (
patch(
"weblate.addons.fedora_messaging.time.monotonic",
side_effect=[0, 0, 8],
"weblate.addons.fedora_messaging.time",
monotonic=MagicMock(side_effect=[0, 0, 8]),
),
self.assertRaisesMessage(TimeoutError, "TLS handshake timed out"),
):
Expand Down
Loading
Loading