Skip to content

Commit 4b530bf

Browse files
authored
fix: 增加本地增强服务创建&更新时 name 校验,禁止与现有的远程增强服务 id 相同 (#2771)
1 parent 056d05d commit 4b530bf

3 files changed

Lines changed: 95 additions & 0 deletions

File tree

apiserver/paasng/locale/en/LC_MESSAGES/django.po

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2330,6 +2330,10 @@ msgstr ""
23302330
"letters, numbers, hyphens (-) or underscores (_), must start with a letter "
23312331
"and end with a letter or number."
23322332

2333+
#: paasng/plat_mgt/infras/services/serializers/services.py:151
2334+
msgid "{} 不符合规范: 禁止存在相同的增强服务 ID"
2335+
msgstr "{} dose not meet requirements: Duplicate Enhanced Service IDs are prohibited"
2336+
23332337
#: paasng/plat_admin/admin42/utils/__init__.py:35
23342338
#, python-brace-format
23352339
msgid "由于: {reason}, 该功能暂不支持"

apiserver/paasng/paasng/plat_mgt/infras/services/serializers/services.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from paasng.accessories.servicehub.constants import ServiceType
2626
from paasng.accessories.servicehub.local.manager import LocalServiceObj
27+
from paasng.accessories.servicehub.manager import mixed_service_mgr
2728
from paasng.accessories.servicehub.remote.manager import RemoteServiceObj
2829
from paasng.utils.i18n import to_translated_field
2930

@@ -145,6 +146,13 @@ def validate_name(self, name: str) -> str:
145146
).format(name)
146147
)
147148

149+
# 创建 S-Mart 应用时,使用 service_name 来指定增强服务, 故禁止本地增强服务和远程增强服务重名
150+
service_id_ctx = getattr(self.context.get("service"), "uuid")
151+
for svc in mixed_service_mgr.list():
152+
# 更新时,允许和自己重名
153+
if svc.name == name and svc.uuid != service_id_ctx:
154+
raise ValidationError(_("{} 不符合规范: 禁止存在相同的增强服务 ID").format(name))
155+
148156
return name
149157

150158

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# -*- coding: utf-8 -*-
2+
# TencentBlueKing is pleased to support the open source community by making
3+
# 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available.
4+
# Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5+
# Licensed under the MIT License (the "License"); you may not use this file except
6+
# in compliance with the License. You may obtain a copy of the License at
7+
#
8+
# http://opensource.org/licenses/MIT
9+
#
10+
# Unless required by applicable law or agreed to in writing, software distributed under
11+
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12+
# either express or implied. See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# We undertake not to change the open source license (MIT license) applicable
16+
# to the current version of the project delivered to anyone in the future.
17+
from dataclasses import dataclass
18+
from unittest import mock
19+
20+
import pytest
21+
from rest_framework.exceptions import ValidationError
22+
23+
from paasng.accessories.servicehub.services import ServiceObj
24+
from paasng.plat_mgt.infras.services.serializers.services import ServiceCreateSLZ
25+
26+
27+
@dataclass
28+
class StubServiceObj(ServiceObj):
29+
"""用于测试的简单 ServiceObj 存根"""
30+
31+
32+
def _make_stub_service(uuid: str, name: str) -> StubServiceObj:
33+
"""创建一个用于测试的 ServiceObj 存根对象"""
34+
return StubServiceObj(uuid=uuid, name=name, logo="", is_visible=True)
35+
36+
37+
class TestServiceCreateSLZValidateNameDuplication:
38+
"""测试 ServiceCreateSLZ.validate_name 中禁止增强服务重名的逻辑"""
39+
40+
@pytest.fixture()
41+
def current_service(self) -> StubServiceObj:
42+
"""当前正在创建/更新的服务对象(放入 serializer context)"""
43+
return _make_stub_service(uuid="aaaa-1111", name="my-svc")
44+
45+
@pytest.fixture()
46+
def existing_services(self) -> list:
47+
"""模拟 mixed_service_mgr.list() 返回的已有服务列表"""
48+
return [
49+
_make_stub_service(uuid="bbbb-2222", name="mysql"),
50+
_make_stub_service(uuid="cccc-3333", name="redis"),
51+
]
52+
53+
@pytest.fixture()
54+
def _mock_list(self, existing_services):
55+
"""Mock mixed_service_mgr.list() 返回预设的已有服务列表"""
56+
with mock.patch("paasng.plat_mgt.infras.services.serializers.services.mixed_service_mgr") as m:
57+
m.list.return_value = existing_services
58+
yield m
59+
60+
def _run_validate_name(self, current_service: StubServiceObj, name: str) -> str:
61+
"""构造 serializer 实例并调用 validate_name"""
62+
slz = ServiceCreateSLZ(context={"service": current_service})
63+
return slz.validate_name(name)
64+
65+
@pytest.mark.usefixtures("_mock_list")
66+
def test_name_no_conflict(self, current_service):
67+
"""名称与已有服务均不冲突时,校验通过并返回原名称"""
68+
result = self._run_validate_name(current_service, "new-svc")
69+
assert result == "new-svc"
70+
71+
@pytest.mark.usefixtures("_mock_list")
72+
def test_name_conflicts_with_existing_service(self, current_service):
73+
"""名称与另一个已有服务重名时,应抛出 ValidationError"""
74+
with pytest.raises(ValidationError, match="禁止存在相同的增强服务"):
75+
self._run_validate_name(current_service, "mysql")
76+
77+
@pytest.mark.usefixtures("_mock_list")
78+
def test_update_allows_same_name_as_self(self, existing_services):
79+
"""更新时,允许与自身重名(UUID 相同)"""
80+
# 使用已有服务列表中的第一个服务作为当前服务(模拟更新场景)
81+
self_service = existing_services[0]
82+
result = self._run_validate_name(self_service, self_service.name)
83+
assert result == self_service.name

0 commit comments

Comments
 (0)