forked from erp-dev/erp
218 lines
7.6 KiB
Python
218 lines
7.6 KiB
Python
"""
|
|
企业微信用户绑定 API 测试
|
|
"""
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.test import TestCase, override_settings
|
|
from rest_framework.test import APIClient
|
|
|
|
from basic_info.models import Employee, Merchant, MerchantTypeEnum
|
|
|
|
|
|
@override_settings(AGENT_ACCESS_KEY='test-key-123')
|
|
class WecomBindingAPITestCase(TestCase):
|
|
"""测试企业微信用户绑定接口"""
|
|
|
|
def setUp(self):
|
|
self.client = APIClient()
|
|
self.url = '/api/v2/wecom/binduser/'
|
|
self.auth_header = 'test-key-123'
|
|
|
|
# 创建商户
|
|
self.merchant = Merchant.objects.create(
|
|
name='测试商户',
|
|
type=MerchantTypeEnum.STORE,
|
|
)
|
|
|
|
# 创建用户
|
|
self.user = User.objects.create_user(
|
|
username='testuser',
|
|
password='testpass123',
|
|
)
|
|
|
|
# 创建员工并关联用户
|
|
self.employee = Employee.objects.create(
|
|
merchant=self.merchant,
|
|
name='测试员工',
|
|
sys_user=self.user,
|
|
)
|
|
|
|
def _post(self, data, auth=None):
|
|
"""辅助方法:发送 POST 请求"""
|
|
headers = {'HTTP_AUTHORIZATION': auth or self.auth_header}
|
|
return self.client.post(self.url, data, format='json', **headers)
|
|
|
|
# ==================== 认证测试 ====================
|
|
|
|
def test_missing_authorization_header(self):
|
|
"""缺少 Authorization 头应返回 401"""
|
|
resp = self.client.post(self.url, {}, format='json')
|
|
self.assertEqual(resp.status_code, 401)
|
|
|
|
def test_invalid_authorization_key(self):
|
|
"""错误的 AGENT_ACCESS_KEY 应返回 401"""
|
|
resp = self._post(
|
|
{'wecom_user_id': 'wx123', 'username': 'testuser', 'password': 'testpass123'},
|
|
auth='wrong-key',
|
|
)
|
|
self.assertEqual(resp.status_code, 401)
|
|
|
|
# ==================== 参数验证测试 ====================
|
|
|
|
def test_missing_required_fields(self):
|
|
"""缺少必填字段应返回 400"""
|
|
resp = self._post({})
|
|
self.assertEqual(resp.status_code, 400)
|
|
data = resp.json()
|
|
self.assertIn('wecom_user_id', data)
|
|
self.assertIn('username', data)
|
|
self.assertIn('password', data)
|
|
|
|
def test_missing_wecom_user_id(self):
|
|
"""缺少 wecom_user_id 应返回 400"""
|
|
resp = self._post({'username': 'testuser', 'password': 'testpass123'})
|
|
self.assertEqual(resp.status_code, 400)
|
|
self.assertIn('wecom_user_id', resp.json())
|
|
|
|
# ==================== 用户凭据验证测试 ====================
|
|
|
|
def test_wrong_password(self):
|
|
"""密码错误应返回 401"""
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx123',
|
|
'username': 'testuser',
|
|
'password': 'wrongpass',
|
|
})
|
|
self.assertEqual(resp.status_code, 401)
|
|
self.assertEqual(resp.json()['error'], '用户名或密码错误')
|
|
|
|
def test_nonexistent_username(self):
|
|
"""不存在的用户名应返回 401"""
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx123',
|
|
'username': 'nouser',
|
|
'password': 'testpass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 401)
|
|
|
|
def test_inactive_user(self):
|
|
"""被禁用的用户应返回 403"""
|
|
self.user.is_active = False
|
|
self.user.save()
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx123',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
})
|
|
# Django authenticate() returns None for inactive users by default
|
|
# so it will be 401 (用户名或密码错误)
|
|
self.assertIn(resp.status_code, [401, 403])
|
|
|
|
def test_user_without_employee(self):
|
|
"""用户未关联员工应返回 404"""
|
|
user2 = User.objects.create_user(username='noemployee', password='pass123')
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx123',
|
|
'username': 'noemployee',
|
|
'password': 'pass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 404)
|
|
self.assertEqual(resp.json()['error'], '该用户未关联任何员工记录')
|
|
|
|
# ==================== 绑定成功测试 ====================
|
|
|
|
def test_binding_success(self):
|
|
"""正常绑定应返回 200"""
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_user_001',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 200)
|
|
data = resp.json()
|
|
self.assertEqual(data['message'], '绑定成功')
|
|
self.assertEqual(data['employee_id'], self.employee.id)
|
|
self.assertEqual(data['employee_name'], '测试员工')
|
|
self.assertEqual(data['wecom_user_id'], 'wx_user_001')
|
|
|
|
# 验证数据库
|
|
self.employee.refresh_from_db()
|
|
self.assertEqual(self.employee.wecom_user_id, 'wx_user_001')
|
|
|
|
def test_binding_idempotent(self):
|
|
"""重复绑定相同 wecom_user_id 应幂等返回 200"""
|
|
self.employee.wecom_user_id = 'wx_user_001'
|
|
self.employee.save()
|
|
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_user_001',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertEqual(resp.json()['message'], '绑定成功')
|
|
|
|
# ==================== 冲突测试 ====================
|
|
|
|
def test_wecom_user_id_already_bound_to_other_employee(self):
|
|
"""wecom_user_id 已绑定到其他员工应返回 409"""
|
|
other_employee = Employee.objects.create(
|
|
merchant=self.merchant,
|
|
name='其他员工',
|
|
wecom_user_id='wx_user_001',
|
|
)
|
|
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_user_001',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 409)
|
|
self.assertIn('该企业微信用户已绑定到其他员工', resp.json()['error'])
|
|
|
|
def test_employee_already_has_different_wecom_user_id_without_force(self):
|
|
"""员工已有不同 wecom_user_id 且未传 force_update 应返回 409"""
|
|
self.employee.wecom_user_id = 'wx_old_user'
|
|
self.employee.save()
|
|
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_new_user',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
})
|
|
self.assertEqual(resp.status_code, 409)
|
|
data = resp.json()
|
|
self.assertEqual(data['error'], '该员工已绑定其他企业微信用户')
|
|
self.assertEqual(data['current_wecom_user_id'], 'wx_old_user')
|
|
self.assertIn('hint', data)
|
|
|
|
def test_employee_already_has_different_wecom_user_id_with_force(self):
|
|
"""员工已有不同 wecom_user_id 但传了 force_update=true 应覆盖成功"""
|
|
self.employee.wecom_user_id = 'wx_old_user'
|
|
self.employee.save()
|
|
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_new_user',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
'force_update': True,
|
|
})
|
|
self.assertEqual(resp.status_code, 200)
|
|
self.assertEqual(resp.json()['wecom_user_id'], 'wx_new_user')
|
|
|
|
self.employee.refresh_from_db()
|
|
self.assertEqual(self.employee.wecom_user_id, 'wx_new_user')
|
|
|
|
def test_force_update_false_explicitly(self):
|
|
"""显式传 force_update=false 应拒绝覆盖"""
|
|
self.employee.wecom_user_id = 'wx_old_user'
|
|
self.employee.save()
|
|
|
|
resp = self._post({
|
|
'wecom_user_id': 'wx_new_user',
|
|
'username': 'testuser',
|
|
'password': 'testpass123',
|
|
'force_update': False,
|
|
})
|
|
self.assertEqual(resp.status_code, 409)
|