From 1e95db0bdacd8656578cbf44c91e12ecf250f539 Mon Sep 17 00:00:00 2001 From: chunyu <12914@example.com> Date: Tue, 15 Sep 2026 15:20:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(C-07)=EF=BC=9A=E6=90=9C=E7=B4=A2=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E6=94=B6=E5=8F=A3+=E7=BB=93=E6=9E=9C=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E6=AD=BB=E9=93=BE=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit q超长截断100字符、page/page_size健壮解析、types白名单;文章/工具/课程/接口结果URL对齐前端现行路由(/post、/utility、/course-learn、/open-api-detail)。 --- search/tests/__init__.py | 0 search/tests/test_search_c07.py | 90 +++++++++++++++++++++++++++++++++ search/views.py | 53 +++++++++++++++---- 3 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 search/tests/__init__.py create mode 100644 search/tests/test_search_c07.py diff --git a/search/tests/__init__.py b/search/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/search/tests/test_search_c07.py b/search/tests/test_search_c07.py new file mode 100644 index 0000000..8a36e27 --- /dev/null +++ b/search/tests/test_search_c07.py @@ -0,0 +1,90 @@ +"""C-07 全站统一搜索回归:多模块聚合/类型筛选/分页/异常输入健壮性/结果跳转死链。""" +from django.test import TestCase +from rest_framework.test import APIClient + +from article.models import Article +from tool.models import Tool +from learn.models import Course +from apidirectory.models import ApiItem +from user.models import FUser + +KW = 'c07searchkey' + + +class UnifiedSearchTest(TestCase): + def setUp(self): + self.client = APIClient() + self.u = FUser.objects.create_user(username='c07u', password='x12345678') + self.art = Article.objects.create( + title=f'{KW}文章', content='x' * 500, author=self.u, status='published') + self.tool = Tool.objects.create( + name=f'{KW}工具', description='desc', url_path='/utility/c07-tool') + self.course = Course.objects.create( + title=f'{KW}课程', description='desc', author=self.u, status='published') + self.api = ApiItem.objects.create( + name=f'{KW}接口', description='desc', url_path='/api/c07', + method='GET', is_enabled=True) + + def _get(self, **params): + r = self.client.get('/search/', params) + self.assertEqual(r.status_code, 200) + body = r.json() + self.assertEqual(body.get('code'), 10000) + return body['data'] + + def test_multi_module_hit(self): + data = self._get(q=KW) + titles = [x['title'] for x in data['results']] + self.assertIn(f'{KW}文章', titles) + self.assertIn(f'{KW}工具', titles) + self.assertIn(f'{KW}课程', titles) + self.assertIn(f'{KW}接口', titles) + self.assertGreaterEqual(data['total'], 4) + + def test_type_filter_article(self): + data = self._get(q=KW, type='article') + self.assertTrue(data['results']) + self.assertTrue(all(x['type'] == '文章' for x in data['results'])) + + def test_type_filter_tool(self): + data = self._get(q=KW, type='tool') + self.assertTrue(data['results']) + self.assertTrue(all(x['type'] == '工具' for x in data['results'])) + + def test_result_urls_are_live_routes(self): + data = self._get(q=KW) + by_type = {x['type']: x for x in data['results']} + self.assertTrue(by_type['文章']['url'].startswith('/post/')) + self.assertEqual(by_type['工具']['url'], '/utility/c07-tool') + self.assertTrue(by_type['课程']['url'].startswith('/course-learn?id=')) + self.assertTrue(by_type['API']['url'].startswith('/open-api-detail/')) + + def test_pagination(self): + data = self._get(q=KW, page=1, page_size=2) + self.assertEqual(len(data['results']), 2) + data2 = self._get(q=KW, page=2, page_size=2) + self.assertTrue(data2['results']) + + def test_empty_q_graceful(self): + data = self._get(q='') + self.assertEqual(data['results'], []) + self.assertEqual(data['total'], 0) + + def test_long_q_truncated_no_500(self): + data = self._get(q='x' * 5000) + self.assertIn('results', data) + + def test_special_chars_no_500(self): + for bad in ['%_%', "a'b\"c", '