新增ToolUsageRecord使用日志(tool+created_at索引);/tool/top/总榜按累计排序、周榜按近7天聚合(无日志回退总榜,兼容period旧参);/tool/recent/登录去重倒序;seed新增AI图片放大/代码运行两个工具。
93 lines
4.2 KiB
Python
93 lines
4.2 KiB
Python
"""C-02 工具热榜聚合用例:总榜/周榜窗口/匿名归因/recent 权限/兼容参数。"""
|
|
from datetime import timedelta
|
|
|
|
from django.test import TestCase
|
|
from django.utils import timezone
|
|
from rest_framework.test import APIClient
|
|
|
|
from tool.models import Tool, ToolUsageRecord
|
|
from user.models import FUser
|
|
|
|
|
|
class ToolTopTest(TestCase):
|
|
def setUp(self):
|
|
self.client = APIClient()
|
|
self.a = Tool.objects.create(name='A', url_path='/utility/a-tool', usage_count=10)
|
|
self.b = Tool.objects.create(name='B', url_path='/utility/b-tool', usage_count=5)
|
|
self.c = Tool.objects.create(name='C', url_path='/utility/c-tool', usage_count=1)
|
|
self.u = FUser.objects.create_user(username='c02u', password='x12345678')
|
|
|
|
def test_total_rank_order(self):
|
|
r = self.client.get('/tool/top/', {'range': 'all', 'limit': 3})
|
|
self.assertEqual(r.status_code, 200)
|
|
data = r.json()['data']
|
|
self.assertEqual([x['id'] for x in data], [self.a.id, self.b.id, self.c.id])
|
|
self.assertEqual([x['rank'] for x in data], [1, 2, 3])
|
|
for x in data:
|
|
self.assertIn('usage_count', x)
|
|
self.assertIn('weekly_count', x)
|
|
|
|
def test_period_alias_total(self):
|
|
r = self.client.get('/tool/top/', {'period': 'total', 'limit': 3})
|
|
self.assertEqual(r.status_code, 200)
|
|
self.assertEqual([x['rank'] for x in r.json()['data']], [1, 2, 3])
|
|
|
|
def test_weekly_window_aggregation(self):
|
|
now = timezone.now()
|
|
for _ in range(3):
|
|
ToolUsageRecord.objects.create(tool=self.c, user=self.u)
|
|
old = ToolUsageRecord.objects.create(tool=self.a, user=self.u)
|
|
old.created_at = now - timedelta(days=8)
|
|
old.save(update_fields=['created_at'])
|
|
r = self.client.get('/tool/top/', {'range': 'week', 'limit': 3})
|
|
self.assertEqual(r.status_code, 200)
|
|
data = r.json()['data']
|
|
# C 近7天3次应排第一
|
|
self.assertEqual(data[0]['id'], self.c.id)
|
|
self.assertEqual(data[0]['weekly_count'], 3)
|
|
|
|
def test_weekly_boundary_7days(self):
|
|
now = timezone.now()
|
|
edge = ToolUsageRecord.objects.create(tool=self.b)
|
|
edge.created_at = now - timedelta(days=7) + timedelta(seconds=60)
|
|
edge.save(update_fields=['created_at'])
|
|
out = ToolUsageRecord.objects.create(tool=self.b)
|
|
out.created_at = now - timedelta(days=7, seconds=60)
|
|
out.save(update_fields=['created_at'])
|
|
r = self.client.get('/tool/top/', {'range': 'week', 'limit': 10})
|
|
data = {x['id']: x['weekly_count'] for x in r.json()['data']}
|
|
self.assertEqual(data[self.b.id], 1)
|
|
|
|
def test_weekly_empty_fallback_to_total(self):
|
|
r = self.client.get('/tool/top/', {'range': 'week', 'limit': 3})
|
|
self.assertEqual(r.status_code, 200)
|
|
self.assertEqual([x['id'] for x in r.json()['data']], [self.a.id, self.b.id, self.c.id])
|
|
|
|
def test_increment_writes_record_anonymous(self):
|
|
r = self.client.post(f'/tool/usage/{self.a.id}/increment/')
|
|
self.assertEqual(r.status_code, 200)
|
|
self.assertEqual(ToolUsageRecord.objects.filter(tool=self.a).count(), 1)
|
|
self.a.refresh_from_db()
|
|
self.assertEqual(self.a.usage_count, 11)
|
|
|
|
def test_increment_writes_record_login(self):
|
|
self.client.force_authenticate(user=self.u)
|
|
r = self.client.post(f'/tool/usage/{self.b.id}/increment/')
|
|
self.assertEqual(r.status_code, 200)
|
|
rec = ToolUsageRecord.objects.filter(tool=self.b).order_by('-id').first()
|
|
self.assertEqual(rec.user_id, self.u.id)
|
|
|
|
def test_recent_requires_login(self):
|
|
r = self.client.get('/tool/recent/')
|
|
self.assertIn(r.status_code, (401, 403))
|
|
|
|
def test_recent_dedup_order(self):
|
|
ToolUsageRecord.objects.create(tool=self.a, user=self.u)
|
|
ToolUsageRecord.objects.create(tool=self.b, user=self.u)
|
|
ToolUsageRecord.objects.create(tool=self.a, user=self.u)
|
|
self.client.force_authenticate(user=self.u)
|
|
r = self.client.get('/tool/recent/', {'limit': 10})
|
|
self.assertEqual(r.status_code, 200)
|
|
ids = [x['id'] for x in r.json()['data']]
|
|
self.assertEqual(ids, [self.a.id, self.b.id])
|