project initialization
Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
This commit is contained in:
322
backend/tests/integration/test_tenant_registration.py
Normal file
322
backend/tests/integration/test_tenant_registration.py
Normal file
@@ -0,0 +1,322 @@
|
||||
"""
|
||||
Integration test for tenant registration flow.
|
||||
This test MUST fail before implementation.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework import status
|
||||
import json
|
||||
|
||||
|
||||
class TenantRegistrationIntegrationTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
|
||||
# Super admin authentication header
|
||||
self.admin_auth = {'HTTP_AUTHORIZATION': 'Bearer super_admin_token'}
|
||||
|
||||
# Test tenant data
|
||||
self.tenant_data = {
|
||||
'name': 'Test Healthcare Sdn Bhd',
|
||||
'email': 'info@testhealthcare.com',
|
||||
'phone': '+60312345678',
|
||||
'address': {
|
||||
'street': '123 Medical Street',
|
||||
'city': 'Kuala Lumpur',
|
||||
'state': 'Wilayah Persekutuan',
|
||||
'postal_code': '50400',
|
||||
'country': 'Malaysia'
|
||||
},
|
||||
'business_type': 'HEALTHCARE',
|
||||
'subscription_plan': 'GROWTH',
|
||||
'pricing_model': 'SUBSCRIPTION',
|
||||
'admin_user': {
|
||||
'name': 'Dr. Sarah Johnson',
|
||||
'email': 'sarah.johnson@testhealthcare.com',
|
||||
'password': 'SecurePassword123!',
|
||||
'role': 'TENANT_ADMIN',
|
||||
'phone': '+60123456789'
|
||||
}
|
||||
}
|
||||
|
||||
def test_complete_tenant_registration_flow(self):
|
||||
"""Test complete tenant registration from creation to admin setup."""
|
||||
# Step 1: Create tenant (should fail before implementation)
|
||||
tenant_response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(self.tenant_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert tenant_response.status_code == status.HTTP_201_CREATED
|
||||
tenant_data = tenant_response.json()
|
||||
|
||||
# Verify tenant structure
|
||||
assert 'id' in tenant_data
|
||||
assert tenant_data['name'] == self.tenant_data['name']
|
||||
assert tenant_data['email'] == self.tenant_data['email']
|
||||
assert tenant_data['business_type'] == self.tenant_data['business_type']
|
||||
assert tenant_data['status'] == 'PENDING'
|
||||
|
||||
# Step 2: Verify tenant admin user was created
|
||||
# First, authenticate as super admin to get user list
|
||||
users_response = self.client.get(
|
||||
'/api/v1/users/',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert users_response.status_code == status.HTTP_200_OK
|
||||
users_data = users_response.json()
|
||||
|
||||
# Find the newly created admin user
|
||||
admin_user = None
|
||||
for user in users_data['users']:
|
||||
if user['email'] == self.tenant_data['admin_user']['email']:
|
||||
admin_user = user
|
||||
break
|
||||
|
||||
assert admin_user is not None
|
||||
assert admin_user['name'] == self.tenant_data['admin_user']['name']
|
||||
assert admin_user['role'] == 'TENANT_ADMIN'
|
||||
assert admin_user['tenant_id'] == tenant_data['id']
|
||||
|
||||
# Step 3: Verify subscription was created for tenant
|
||||
subscription_response = self.client.get(
|
||||
'/api/v1/subscriptions/',
|
||||
data={'tenant_id': tenant_data['id']},
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert subscription_response.status_code == status.HTTP_200_OK
|
||||
subscriptions_data = subscription_response.json()
|
||||
|
||||
assert len(subscriptions_data['subscriptions']) == 1
|
||||
subscription = subscriptions_data['subscriptions'][0]
|
||||
assert subscription['tenant_id'] == tenant_data['id']
|
||||
assert subscription['plan'] == self.tenant_data['subscription_plan']
|
||||
assert subscription['status'] == 'TRIAL'
|
||||
|
||||
# Step 4: Test tenant admin authentication
|
||||
# Login as tenant admin
|
||||
login_data = {
|
||||
'email': self.tenant_data['admin_user']['email'],
|
||||
'password': self.tenant_data['admin_user']['password']
|
||||
}
|
||||
|
||||
auth_response = self.client.post(
|
||||
'/api/v1/auth/login/',
|
||||
data=json.dumps(login_data),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
assert auth_response.status_code == status.HTTP_200_OK
|
||||
auth_data = auth_response.json()
|
||||
|
||||
assert 'access_token' in auth_data
|
||||
assert 'refresh_token' in auth_data
|
||||
assert 'user' in auth_data
|
||||
|
||||
# Verify user info in token
|
||||
user_info = auth_data['user']
|
||||
assert user_info['email'] == self.tenant_data['admin_user']['email']
|
||||
assert user_info['tenant_id'] == tenant_data['id']
|
||||
|
||||
# Step 5: Test tenant admin can access their tenant data
|
||||
tenant_admin_auth = {'HTTP_AUTHORIZATION': f'Bearer {auth_data["access_token"]}'}
|
||||
|
||||
tenant_own_response = self.client.get(
|
||||
'/api/v1/tenants/',
|
||||
**tenant_admin_auth
|
||||
)
|
||||
|
||||
assert tenant_own_response.status_code == status.HTTP_200_OK
|
||||
tenant_own_data = tenant_own_response.json()
|
||||
|
||||
# Should only see their own tenant
|
||||
assert len(tenant_own_data['tenants']) == 1
|
||||
assert tenant_own_data['tenants'][0]['id'] == tenant_data['id']
|
||||
|
||||
# Step 6: Test tenant isolation - cannot see other tenants
|
||||
# Create another tenant as super admin
|
||||
other_tenant_data = self.tenant_data.copy()
|
||||
other_tenant_data['name'] = 'Other Healthcare Sdn Bhd'
|
||||
other_tenant_data['email'] = 'info@otherhealthcare.com'
|
||||
other_tenant_data['admin_user']['email'] = 'admin@otherhealthcare.com'
|
||||
|
||||
other_tenant_response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(other_tenant_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert other_tenant_response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
# First tenant admin should still only see their own tenant
|
||||
tenant_still_own_response = self.client.get(
|
||||
'/api/v1/tenants/',
|
||||
**tenant_admin_auth
|
||||
)
|
||||
|
||||
assert tenant_still_own_response.status_code == status.HTTP_200_OK
|
||||
tenant_still_own_data = tenant_still_own_response.json()
|
||||
|
||||
# Should still only see their own tenant
|
||||
assert len(tenant_still_own_data['tenants']) == 1
|
||||
assert tenant_still_own_data['tenants'][0]['id'] == tenant_data['id']
|
||||
|
||||
def test_tenant_registration_invalid_business_type(self):
|
||||
"""Test tenant registration with invalid business type."""
|
||||
invalid_data = self.tenant_data.copy()
|
||||
invalid_data['business_type'] = 'INVALID_TYPE'
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(invalid_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_tenant_registration_missing_admin_user(self):
|
||||
"""Test tenant registration without admin user data."""
|
||||
invalid_data = self.tenant_data.copy()
|
||||
del invalid_data['admin_user']
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(invalid_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_tenant_registration_duplicate_email(self):
|
||||
"""Test tenant registration with duplicate email."""
|
||||
# Create first tenant
|
||||
first_response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(self.tenant_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert first_response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
# Try to create second tenant with same email
|
||||
second_response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(self.tenant_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert second_response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_tenant_registration_unauthorized(self):
|
||||
"""Test tenant registration without admin authentication."""
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(self.tenant_data),
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
def test_tenant_registration_weak_admin_password(self):
|
||||
"""Test tenant registration with weak admin password."""
|
||||
invalid_data = self.tenant_data.copy()
|
||||
invalid_data['admin_user']['password'] = '123'
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(invalid_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_tenant_registration_with_modules_configuration(self):
|
||||
"""Test tenant registration with specific modules configuration."""
|
||||
modules_data = self.tenant_data.copy()
|
||||
modules_data['modules'] = ['healthcare', 'appointments', 'billing']
|
||||
modules_data['modules_config'] = {
|
||||
'healthcare': {
|
||||
'features': ['patient_management', 'appointment_scheduling', 'medical_records'],
|
||||
'settings': {
|
||||
'enable_telemedicine': True,
|
||||
'appointment_reminders': True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(modules_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
if response.status_code == status.HTTP_201_CREATED:
|
||||
tenant_data = response.json()
|
||||
# Should have modules configuration
|
||||
assert 'modules' in tenant_data
|
||||
assert 'modules_config' in tenant_data
|
||||
|
||||
def test_tenant_registration_with_branding(self):
|
||||
"""Test tenant registration with branding information."""
|
||||
branding_data = self.tenant_data.copy()
|
||||
branding_data['branding'] = {
|
||||
'logo_url': 'https://example.com/logo.png',
|
||||
'primary_color': '#2563eb',
|
||||
'secondary_color': '#64748b',
|
||||
'company_website': 'https://testhealthcare.com',
|
||||
'social_media': {
|
||||
'facebook': 'testhealthcare',
|
||||
'instagram': 'testhealthcare_my'
|
||||
}
|
||||
}
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(branding_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
if response.status_code == status.HTTP_201_CREATED:
|
||||
tenant_data = response.json()
|
||||
# Should have branding information
|
||||
assert 'branding' in tenant_data
|
||||
assert tenant_data['branding']['primary_color'] == '#2563eb'
|
||||
|
||||
def test_tenant_registration_domain_setup(self):
|
||||
"""Test tenant registration with custom domain setup."""
|
||||
domain_data = self.tenant_data.copy()
|
||||
domain_data['domain'] = 'portal.testhealthcare.com'
|
||||
domain_data['settings'] = {
|
||||
'custom_domain_enabled': True,
|
||||
'ssl_enabled': True,
|
||||
'email_domain': 'testhealthcare.com'
|
||||
}
|
||||
|
||||
response = self.client.post(
|
||||
'/api/v1/tenants/',
|
||||
data=json.dumps(domain_data),
|
||||
content_type='application/json',
|
||||
**self.admin_auth
|
||||
)
|
||||
|
||||
if response.status_code == status.HTTP_201_CREATED:
|
||||
tenant_data = response.json()
|
||||
# Should have domain configuration
|
||||
assert 'domain' in tenant_data
|
||||
assert 'settings' in tenant_data
|
||||
assert tenant_data['domain'] == 'portal.testhealthcare.com'
|
||||
Reference in New Issue
Block a user