Skip to content

Commit

Permalink
test: add LocalDataSourceIdentityInfoInitializer unittest
Browse files Browse the repository at this point in the history
  • Loading branch information
narasux committed Sep 19, 2023
1 parent d163ee7 commit 0539648
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 195 deletions.
40 changes: 27 additions & 13 deletions src/bk-user/bkuser/apps/data_source/initializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
specific language governing permissions and limitations under the License.
"""
import datetime
from typing import List

from django.utils import timezone

Expand Down Expand Up @@ -44,16 +45,35 @@ class LocalDataSourceIdentityInfoInitializer:

def __init__(self, data_source: DataSource):
self.data_source = data_source
if not data_source.is_local:
return

self.plugin_cfg = LocalDataSourcePluginConfig(**data_source.plugin_config)
self.password_provider = PasswordProvider(self.plugin_cfg)

def initialize(self) -> None:
if self._can_skip_initialize():
def sync(self) -> None:
"""检查指定数据源的所有用户,对没有账密信息的,做初始化,适用于批量同步(导入)的情况"""
if self._can_skip():
return

exists_info_user_ids = LocalDataSourceIdentityInfo.objects.filter(
data_source=self.data_source,
).values_list("user_id", flat=True)
# NOTE:已经存在的账密信息,不会按照最新规则重新生成!不然用户密码就失效了!
waiting_init_users = DataSourceUser.objects.filter(
data_source=self.data_source,
).exclude(id__in=exists_info_user_ids)

self._init_users_identity_info(waiting_init_users)

def initialize(self, user: DataSourceUser) -> None:
"""初始化用户身份信息,适用于单个用户创建的情况"""
if self._can_skip():
return

self._init_users_identity_info()
self._init_users_identity_info([user])

def _can_skip_initialize(self):
def _can_skip(self):
"""预先判断能否直接跳过"""

# 不是本地数据源的,不需要初始化
Expand All @@ -66,14 +86,8 @@ def _can_skip_initialize(self):

return False

def _init_users_identity_info(self):
exists_infos = LocalDataSourceIdentityInfo.objects.filter(data_source=self.data_source)
exists_info_user_ids = exists_infos.objects.values_list("user_id", flat=True)
# NOTE:已经存在的账密信息,不会按照最新规则重新生成!
waiting_init_users = DataSourceUser.objects.filter(
data_source=self.data_source,
).exclude(id__in=exists_info_user_ids)

def _init_users_identity_info(self, users: List[DataSourceUser]):
"""初始化用户身份信息"""
time_now = timezone.now()
expired_at = self._get_password_expired_at(time_now)

Expand All @@ -88,7 +102,7 @@ def _init_users_identity_info(self):
created_at=time_now,
updated_at=time_now,
)
for user in waiting_init_users
for user in users
]
LocalDataSourceIdentityInfo.objects.bulk_create(waiting_create_infos, batch_size=self.BATCH_SIZE)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
# Generated by Django 3.2.20 on 2023-09-12 03:18
# Generated by Django 3.2.20 on 2023-09-19 09:45

import blue_krill.models.fields
from django.db import migrations
Expand All @@ -24,6 +14,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='localdatasourceidentityinfo',
name='password',
field=blue_krill.models.fields.EncryptField(blank=True, default='', max_length=255, null=True),
field=blue_krill.models.fields.EncryptField(blank=True, default='', max_length=255, null=True, verbose_name='用户密码'),
),
]
4 changes: 2 additions & 2 deletions src/bk-user/bkuser/apps/data_source/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ class LocalDataSourceIdentityInfo(TimestampedModel):
"""

user = models.OneToOneField(DataSourceUser, on_delete=models.CASCADE)
password = EncryptField("用户密码", null=True, blank=True, default="", max_length=255)
password = EncryptField(verbose_name="用户密码", null=True, blank=True, default="", max_length=255)
password_updated_at = models.DateTimeField("密码最后更新时间", null=True, blank=True)
password_expired_at = models.DateTimeField("密码过期时间", null=True, blank=True)

# data_source_id/username为冗余字段,便于认证时快速匹配
# data_source / username 为冗余字段,便于认证时快速匹配
data_source = models.ForeignKey(DataSource, on_delete=models.DO_NOTHING, db_constraint=False)
username = models.CharField("用户名", max_length=128)

Expand Down
4 changes: 2 additions & 2 deletions src/bk-user/bkuser/apps/sync/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@


@receiver(post_sync_data_source)
def initialize_local_data_source_identity_info(sender, data_source: DataSource, **kwargs):
def sync_local_data_source_identity_infos(sender, data_source: DataSource, **kwargs):
"""在完成数据源同步后,需要对本地数据源的用户账密信息做初始化"""
LocalDataSourceIdentityInfoInitializer(data_source).initialize()
LocalDataSourceIdentityInfoInitializer(data_source).sync()


@receiver(post_sync_data_source)
Expand Down
4 changes: 4 additions & 0 deletions src/bk-user/bkuser/biz/data_source_organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from django.db import transaction
from pydantic import BaseModel

from bkuser.apps.data_source.initializers import LocalDataSourceIdentityInfoInitializer
from bkuser.apps.data_source.models import (
DataSource,
DataSourceDepartment,
Expand Down Expand Up @@ -82,6 +83,9 @@ def create_user(
data_source=data_source, code=gen_code(base_user_info.username), **base_user_info.model_dump()
)

# 为本地数据源用户初始化账密信息
LocalDataSourceIdentityInfoInitializer(data_source).initialize(user)

# 批量创建数据源用户-部门关系
department_user_relation_objs = [
DataSourceDepartmentUserRelation(department_id=dept_id, user_id=user.id)
Expand Down
4 changes: 4 additions & 0 deletions src/bk-user/bkuser/biz/tenant.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.utils.translation import gettext_lazy as _
from pydantic import BaseModel

from bkuser.apps.data_source.initializers import LocalDataSourceIdentityInfoInitializer
from bkuser.apps.data_source.models import DataSourceDepartmentRelation, DataSourceUser
from bkuser.apps.tenant.models import Tenant, TenantDepartment, TenantManager, TenantUser
from bkuser.biz.data_source import (
Expand Down Expand Up @@ -290,6 +291,9 @@ def create_with_managers(
if tenant_manager_objs:
TenantManager.objects.bulk_create(tenant_manager_objs)

# 批量为租户管理员创建账密信息
LocalDataSourceIdentityInfoInitializer(data_source).sync()

return tenant_info.id

@staticmethod
Expand Down
10 changes: 10 additions & 0 deletions src/bk-user/tests/apps/data_source/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
46 changes: 46 additions & 0 deletions src/bk-user/tests/apps/data_source/test_initializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
"""
TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
import pytest
from bkuser.apps.data_source.initializers import LocalDataSourceIdentityInfoInitializer
from bkuser.apps.data_source.models import DataSourceUser, LocalDataSourceIdentityInfo

pytestmark = pytest.mark.django_db


class TestLocalDataSourceIdentityInfoInitializer:
"""测试本地数据源账密初始化"""

def test_sync(self, full_local_data_source):
"""批量同步的情况"""
LocalDataSourceIdentityInfoInitializer(full_local_data_source).sync()
assert (
LocalDataSourceIdentityInfo.objects.filter(data_source=full_local_data_source).count()
== DataSourceUser.objects.filter(data_source=full_local_data_source).count()
)

def test_initialize(self, full_local_data_source):
"""单个初始化的情况"""
user = DataSourceUser.objects.filter(data_source=full_local_data_source).first()
LocalDataSourceIdentityInfoInitializer(full_local_data_source).initialize(user)
assert LocalDataSourceIdentityInfo.objects.filter(data_source=full_local_data_source).count() == 1

def test_skip_not_local_data_source(self, full_general_data_source):
"""不是本地数据源的,同步不会生效"""
LocalDataSourceIdentityInfoInitializer(full_general_data_source).sync()
assert not LocalDataSourceIdentityInfo.objects.filter(data_source=full_general_data_source).exists()

def test_skip_not_account_password_login_data_source(self, full_local_data_source):
"""没有启用账密登录的,同步不会生效"""
full_local_data_source.plugin_config["enable_account_password_login"] = False
full_local_data_source.save()

LocalDataSourceIdentityInfoInitializer(full_local_data_source).sync()
assert not LocalDataSourceIdentityInfo.objects.filter(data_source=full_local_data_source).exists()
Binary file added src/bk-user/tests/assets/fake_users.xlsx
Binary file not shown.
4 changes: 4 additions & 0 deletions src/bk-user/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
from bkuser.auth.models import User

from tests.fixtures.data_source import ( # noqa: F401
bare_general_data_source,
bare_local_data_source,
full_general_data_source,
full_local_data_source,
general_ds_plugin,
general_ds_plugin_config,
local_ds_plugin,
local_ds_plugin_config,
)
Expand Down
Loading

0 comments on commit 0539648

Please sign in to comment.