import pytest from unittest.mock import MagicMock, patch from datetime import datetime, timezone import main # convert_to_timestamp 함수 테스트 @pytest.mark.parametrize("input_date, expected_timestamp", [ ("2025-12-25", int(datetime(2025, 12, 25, tzinfo=timezone.utc).timestamp())), (1735084800, 1735084800), ("1735084800", 1735084800), (None, None), ("", None), ("invalid-date", None), ]) def test_convert_to_timestamp(input_date, expected_timestamp): """ 다양한 형식의 날짜 입력에 대해 convert_to_timestamp가 정확한 타임스탬프를 반환하는지 테스트합니다. """ assert main.convert_to_timestamp(input_date) == expected_timestamp # _prepare_user_data 함수 테스트 def test_prepare_user_data(): """ _prepare_user_data 함수가 사용자 정보를 올바르게 파싱하고, 특히 egBimLExpiryDate를 CLI 인자와 CSV 값에 따라 우선순위를 부여하여 처리하는지 테스트합니다. """ user_data = { 'login_id': 'test@example.com', 'tenants': '["tenant1", "tenant2"]', 'role_name': 'editor', 'company': 'Test Inc.', 'egBimLExpiryDate': '2024-12-31' } # 1. CLI expiry_timestamp가 주어질 경우 cli_timestamp = int(datetime(2025, 1, 1, tzinfo=timezone.utc).timestamp()) tenants, custom_attrs = main._prepare_user_data(user_data, expiry_timestamp=cli_timestamp) assert custom_attrs['egBimLExpiryDate'] == cli_timestamp assert custom_attrs['company'] == 'Test Inc.' assert len(tenants) == 2 assert tenants[0].tenant_id == 'tenant1' assert tenants[0].role_names == ['editor'] # 2. CLI expiry_timestamp가 없고, CSV에 값이 있을 경우 csv_timestamp = int(datetime(2024, 12, 31, tzinfo=timezone.utc).timestamp()) tenants, custom_attrs = main._prepare_user_data(user_data, expiry_timestamp=None) assert custom_attrs['egBimLExpiryDate'] == csv_timestamp # 3. 두 값 모두 없을 경우 user_data_no_date = user_data.copy() del user_data_no_date['egBimLExpiryDate'] tenants, custom_attrs = main._prepare_user_data(user_data_no_date, expiry_timestamp=None) assert 'egBimLExpiryDate' not in custom_attrs # update_or_create_users 함수 테스트 (DescopeClient 모킹) @patch('main.get_descope_client') def test_update_or_create_users_flow(mock_get_client): """ update_or_create_users 함수가 사용자의 존재 여부에 따라 user.update 또는 user.create를 올바르게 호출하는지 테스트합니다. """ # 가짜 DescopeClient 및 mgmt.user 객체 설정 mock_descope_client = MagicMock() mock_user_mgmt = MagicMock() mock_descope_client.mgmt.user = mock_user_mgmt mock_get_client.return_value = mock_descope_client users_to_process = [ {'login_id': 'existing.user@example.com', 'display_name': 'Existing User Updated'}, {'login_id': 'new.user@example.com', 'display_name': 'New User Created'}, ] # 'existing.user@example.com'에 대해서는 load가 성공하고, # 'new.user@example.com'에 대해서는 AuthException을 발생시키도록 설정 def load_user_side_effect(login_id): if login_id == 'existing.user@example.com': return {'user': 'details'} # 성공 시 반환값 (내용은 중요하지 않음) elif login_id == 'new.user@example.com': # Descope SDK는 사용자를 찾지 못하면 AuthException 발생 from descope import AuthException raise AuthException("user not found", "E062103", 404) mock_user_mgmt.load.side_effect = load_user_side_effect # 테스트 실행 main.update_or_create_users(users_to_process) # 검증: update가 'existing.user@example.com'에 대해 한 번 호출되었는지 확인 mock_user_mgmt.update.assert_called_once_with( login_id='existing.user@example.com', email=None, display_name='Existing User Updated', user_tenants=[], custom_attributes={'completeForm': True} ) # 검증: create가 'new.user@example.com'에 대해 한 번 호출되었는지 확인 mock_user_mgmt.create.assert_called_once_with( login_id='new.user@example.com', email=None, display_name='New User Created', user_tenants=[], custom_attributes={'completeForm': True} )