Files
multitenetsaas/backend/tests/contract/test_subscriptions_post.py
AHMET YILMAZ b3fff546e9
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
project initialization
2025-10-05 02:37:33 +08:00

264 lines
9.5 KiB
Python

"""
Contract test for POST /subscriptions endpoint.
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 SubscriptionsPostContractTest(TestCase):
def setUp(self):
self.client = APIClient()
self.subscriptions_url = '/api/v1/subscriptions/'
# Admin authentication header
self.admin_auth = {'HTTP_AUTHORIZATION': 'Bearer admin_token'}
# Tenant admin authentication header
self.tenant_admin_auth = {'HTTP_AUTHORIZATION': 'Bearer tenant_admin_token'}
# Valid subscription data
self.subscription_data = {
'tenant_id': 'test-tenant-id',
'plan': 'GROWTH',
'pricing_model': 'SUBSCRIPTION',
'billing_cycle': 'MONTHLY',
'payment_method': {
'type': 'CARD',
'card_last4': '4242',
'expiry_month': 12,
'expiry_year': 2025,
'brand': 'visa'
},
'modules': ['retail', 'inventory'],
'trial_days': 14,
'notes': 'Subscription for retail business'
}
def test_create_subscription_success_admin(self):
"""Test successful subscription creation by admin."""
response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json',
**self.admin_auth
)
# This should fail before implementation
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert 'id' in data
assert data['tenant_id'] == self.subscription_data['tenant_id']
assert data['plan'] == self.subscription_data['plan']
assert data['pricing_model'] == self.subscription_data['pricing_model']
assert data['billing_cycle'] == self.subscription_data['billing_cycle']
assert data['status'] == 'TRIAL' # Default status with trial_days
# Should have timestamps
assert 'created_at' in data
assert 'updated_at' in data
# Should have billing period information
assert 'current_period_start' in data
assert 'current_period_end' in data
assert 'trial_end' in data
# Should include modules
assert 'modules' in data
assert data['modules'] == self.subscription_data['modules']
def test_create_subscription_success_tenant_admin(self):
"""Test successful subscription creation by tenant admin."""
# Tenant admin creates subscription for their own tenant
tenant_subscription_data = self.subscription_data.copy()
del tenant_subscription_data['tenant_id'] # Should be inferred from context
response = self.client.post(
self.subscriptions_url,
data=json.dumps(tenant_subscription_data),
content_type='application/json',
**self.tenant_admin_auth
)
# This should fail before implementation
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert 'id' in data
assert data['plan'] == tenant_subscription_data['plan']
assert data['tenant_id'] # Should be auto-populated
def test_create_subscription_unauthorized(self):
"""Test subscription creation without authentication."""
response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json'
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
def test_create_subscription_forbidden(self):
"""Test subscription creation by regular user (no permissions)."""
user_auth = {'HTTP_AUTHORIZATION': 'Bearer user_token'}
response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json',
**user_auth
)
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_create_subscription_missing_required_fields(self):
"""Test subscription creation with missing required fields."""
incomplete_data = self.subscription_data.copy()
del incomplete_data['plan']
response = self.client.post(
self.subscriptions_url,
data=json.dumps(incomplete_data),
content_type='application/json',
**self.admin_auth
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
data = response.json()
assert 'plan' in data.get('errors', {})
def test_create_subscription_invalid_plan(self):
"""Test subscription creation with invalid plan."""
invalid_data = self.subscription_data.copy()
invalid_data['plan'] = 'INVALID_PLAN'
response = self.client.post(
self.subscriptions_url,
data=json.dumps(invalid_data),
content_type='application/json',
**self.admin_auth
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
def test_create_subscription_invalid_billing_cycle(self):
"""Test subscription creation with invalid billing cycle."""
invalid_data = self.subscription_data.copy()
invalid_data['billing_cycle'] = 'INVALID_CYCLE'
response = self.client.post(
self.subscriptions_url,
data=json.dumps(incomplete_data),
content_type='application/json',
**self.admin_auth
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
def test_create_subscription_duplicate_tenant(self):
"""Test subscription creation with duplicate tenant."""
# First request should succeed (if implemented)
first_response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json',
**self.admin_auth
)
if first_response.status_code == status.HTTP_201_CREATED:
# Second request with same tenant should fail
second_response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json',
**self.admin_auth
)
assert second_response.status_code == status.HTTP_400_BAD_REQUEST
def test_create_subscription_without_trial(self):
"""Test subscription creation without trial period."""
no_trial_data = self.subscription_data.copy()
del no_trial_data['trial_days']
response = self.client.post(
self.subscriptions_url,
data=json.dumps(no_trial_data),
content_type='application/json',
**self.admin_auth
)
if response.status_code == status.HTTP_201_CREATED:
data = response.json()
# Should be active immediately without trial
assert data['status'] == 'ACTIVE'
assert 'trial_end' not in data or data['trial_end'] is None
def test_create_subscription_with_invalid_modules(self):
"""Test subscription creation with invalid modules."""
invalid_data = self.subscription_data.copy()
invalid_data['modules'] = ['invalid_module']
response = self.client.post(
self.subscriptions_url,
data=json.dumps(invalid_data),
content_type='application/json',
**self.admin_auth
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
def test_create_subscription_tenant_admin_cross_tenant(self):
"""Test that tenant admin cannot create subscription for other tenant."""
# Tenant admin trying to create subscription for different tenant
response = self.client.post(
self.subscriptions_url,
data=json.dumps(self.subscription_data),
content_type='application/json',
**self.tenant_admin_auth
)
# Should fail because tenant_id doesn't match their tenant
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_create_subscription_payment_method_validation(self):
"""Test subscription creation with invalid payment method."""
invalid_data = self.subscription_data.copy()
invalid_data['payment_method'] = {
'type': 'CARD',
'card_last4': '4242',
# Missing required expiry fields
}
response = self.client.post(
self.subscriptions_url,
data=json.dumps(invalid_data),
content_type='application/json',
**self.admin_auth
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
def test_create_subscription_with_promo_code(self):
"""Test subscription creation with promo code."""
promo_data = self.subscription_data.copy()
promo_data['promo_code'] = 'WELCOME20'
response = self.client.post(
self.subscriptions_url,
data=json.dumps(promo_data),
content_type='application/json',
**self.admin_auth
)
if response.status_code == status.HTTP_201_CREATED:
data = response.json()
# Should include discount information
assert 'discount' in data
assert data['promo_code'] == 'WELCOME20'