test(backend): convert existing app suites to unittest

This commit is contained in:
2026-04-30 12:41:54 +03:30
parent 204225dd16
commit 8774a4d4dc
16 changed files with 1785 additions and 1780 deletions

View File

@@ -1,200 +1,78 @@
import json
from collections import defaultdict
import pytest
from django.conf import settings
from django.test import TestCase
from apps.notifications.services import store as services
from apps.notifications.services import RedisNotificationStore
from apps.notifications.tests.fakes import FakeRedis
class FakePipeline:
def __init__(self, client):
self.client = client
self.operations = []
class RedisNotificationStoreTests(TestCase):
def setUp(self):
self.fake_redis = FakeRedis()
self.original_redis_client = services.redis_client
services.redis_client = self.fake_redis
def __getattr__(self, name):
def wrapper(*args, **kwargs):
self.operations.append((name, args, kwargs))
return self
def tearDown(self):
services.redis_client = self.original_redis_client
return wrapper
def test_add_publishes_notification_and_unread_count(self):
with self.settings(NOTIFICATIONS_ENABLED=True):
notification = RedisNotificationStore.add(
"user-1",
{
"title": "Build finished",
"message": "Your deploy completed.",
"level": "success",
},
)
def execute(self):
results = []
for name, args, kwargs in self.operations:
results.append(getattr(self.client, name)(*args, **kwargs))
self.operations.clear()
return results
self.assertEqual(notification["title"], "Build finished")
self.assertEqual(notification["message"], "Your deploy completed.")
self.assertEqual(notification["level"], "success")
self.assertEqual(len(self.fake_redis.published), 2)
class FakePubSub:
def __init__(self):
self.channels = []
self.messages = []
self.closed = False
def subscribe(self, channel):
self.channels.append(channel)
def unsubscribe(self, channel):
if channel in self.channels:
self.channels.remove(channel)
def get_message(self, timeout=1.0):
if self.messages:
return self.messages.pop(0)
return None
def close(self):
self.closed = True
class FakeRedis:
def __init__(self):
self.sorted_sets = defaultdict(dict)
self.hashes = defaultdict(dict)
self.sets = defaultdict(set)
self.published = []
self.pubsub_instance = FakePubSub()
def pipeline(self):
return FakePipeline(self)
def zadd(self, key, mapping):
self.sorted_sets[key].update(mapping)
return len(mapping)
def hset(self, key, field, value):
self.hashes[key][field] = value
return 1
def sadd(self, key, *members):
before = len(self.sets[key])
self.sets[key].update(members)
return len(self.sets[key]) - before
def zrevrange(self, key, start, stop):
items = sorted(
self.sorted_sets[key].items(),
key=lambda item: (item[1], item[0]),
reverse=True,
channel, payload = self.fake_redis.published[0]
self.assertEqual(
channel,
f"{settings.NOTIFICATION_REDIS_CHANNEL_PREFIX}:user-1",
)
if stop == -1:
return [member for member, _ in items[start:]]
return [member for member, _ in items[start : stop + 1]]
self.assertEqual(payload["event"], "notification")
self.assertEqual(payload["data"]["notification"]["id"], notification["id"])
self.assertEqual(payload["data"]["unread_count"], 1)
def hget(self, key, field):
return self.hashes[key].get(field)
def test_mark_seen_and_mark_all_seen_publish_sync_events(self):
with self.settings(NOTIFICATIONS_ENABLED=True):
first = RedisNotificationStore.add("user-2", {"title": "First"})
RedisNotificationStore.add("user-2", {"title": "Second"})
self.fake_redis.published.clear()
def zrem(self, key, *members):
removed = 0
for member in members:
if member in self.sorted_sets[key]:
del self.sorted_sets[key][member]
removed += 1
return removed
payload = RedisNotificationStore.mark_seen("user-2", first["id"])
def hdel(self, key, *fields):
removed = 0
for field in fields:
if field in self.hashes[key]:
del self.hashes[key][field]
removed += 1
return removed
self.assertEqual(payload["notification_id"], first["id"])
self.assertFalse(payload["deleted"])
self.assertTrue(payload["notification"]["is_seen"])
self.assertEqual(self.fake_redis.published[0][1]["event"], "notification_seen")
def smembers(self, key):
return set(self.sets[key])
self.fake_redis.published.clear()
updated = RedisNotificationStore.mark_all_seen("user-2")
def srem(self, key, member):
if member in self.sets[key]:
self.sets[key].remove(member)
return 1
return 0
self.assertEqual(updated, 2)
self.assertEqual(self.fake_redis.published[0][1]["event"], "notification_mark_all_read")
self.assertEqual(self.fake_redis.published[1][1]["event"], "unread_count")
self.assertEqual(self.fake_redis.published[1][1]["data"]["unread_count"], 0)
def zrangebyscore(self, key, min_score, max_score):
lower = float("-inf") if min_score == "-inf" else float(min_score)
upper = float(max_score)
return [
member
for member, score in self.sorted_sets[key].items()
if lower <= score <= upper
]
def test_list_returns_total_count_and_filtered_notifications(self):
RedisNotificationStore.add("user-3", {"title": "General", "type": "general"})
RedisNotificationStore.add("user-3", {"title": "Billing", "type": "billing"})
RedisNotificationStore.add("user-3", {"title": "General 2", "type": "general"})
def zcard(self, key):
return len(self.sorted_sets[key])
notifications, total_count = RedisNotificationStore.list(
"user-3",
limit=1,
offset=0,
type_filter="general",
)
def publish(self, channel, message):
self.published.append((channel, json.loads(message)))
return 1
def pubsub(self, ignore_subscribe_messages=True):
return self.pubsub_instance
@pytest.fixture()
def fake_redis(monkeypatch):
redis = FakeRedis()
monkeypatch.setattr(services, "redis_client", redis)
return redis
def test_add_publishes_notification_and_unread_count(fake_redis, settings):
settings.NOTIFICATIONS_ENABLED = True
notification = RedisNotificationStore.add(
"user-1",
{
"title": "Build finished",
"message": "Your deploy completed.",
"level": "success",
},
)
assert notification["title"] == "Build finished"
assert notification["message"] == "Your deploy completed."
assert notification["level"] == "success"
assert len(fake_redis.published) == 2
channel, payload = fake_redis.published[0]
assert channel == f"{settings.NOTIFICATION_REDIS_CHANNEL_PREFIX}:user-1"
assert payload["event"] == "notification"
assert payload["data"]["notification"]["id"] == notification["id"]
assert payload["data"]["unread_count"] == 1
def test_mark_seen_and_mark_all_seen_publish_sync_events(fake_redis, settings):
settings.NOTIFICATIONS_ENABLED = True
first = RedisNotificationStore.add("user-2", {"title": "First"})
second = RedisNotificationStore.add("user-2", {"title": "Second"})
fake_redis.published.clear()
payload = RedisNotificationStore.mark_seen("user-2", first["id"])
assert payload["notification_id"] == first["id"]
assert payload["deleted"] is False
assert payload["notification"]["is_seen"] is True
assert fake_redis.published[0][1]["event"] == "notification_seen"
fake_redis.published.clear()
updated = RedisNotificationStore.mark_all_seen("user-2")
assert updated == 2
assert fake_redis.published[0][1]["event"] == "notification_mark_all_read"
assert fake_redis.published[1][1]["event"] == "unread_count"
assert fake_redis.published[1][1]["data"]["unread_count"] == 0
def test_list_returns_total_count_and_filtered_notifications(fake_redis):
RedisNotificationStore.add("user-3", {"title": "General", "type": "general"})
RedisNotificationStore.add("user-3", {"title": "Billing", "type": "billing"})
RedisNotificationStore.add("user-3", {"title": "General 2", "type": "general"})
notifications, total_count = RedisNotificationStore.list(
"user-3",
limit=1,
offset=0,
type_filter="general",
)
assert total_count == 2
assert len(notifications) == 1
assert notifications[0]["type"] == "general"
self.assertEqual(total_count, 2)
self.assertEqual(len(notifications), 1)
self.assertEqual(notifications[0]["type"], "general")