import pytest from unittest.mock import Mock, patch, MagicMock from app.main import grant_fte_permissions, collect_all_pdp_vendor_uuids, expand_all_orchard_users_vendors from app.dtos import User, Vendor from app.migrate_to_v2_permissions import NewRole from app.config import ALL_ORCHARD_LABELS_UUID class TestCollectAllPdpVendorUuids: """Test collection of unique vendor UUIDs from PDP permissions""" def test_collect_all_pdp_vendor_uuids_multiple_users(self): """Test collecting vendor UUIDs from multiple users""" users_permissions = { "user1": { "vendor-uuid-1": ["role1"], "vendor-uuid-2": ["role2"], ALL_ORCHARD_LABELS_UUID: ["role3"] }, "user2": { "vendor-uuid-2": ["role4"], "vendor-uuid-3": ["role5"] } } result = collect_all_pdp_vendor_uuids(users_permissions) expected = {"vendor-uuid-1", "vendor-uuid-2", "vendor-uuid-3"} assert result == expected def test_collect_all_pdp_vendor_uuids_excludes_all_orchard_labels(self): """Test that ALL_ORCHARD_LABELS_UUID is excluded from result""" users_permissions = { "user1": { "vendor-uuid-1": ["role1"], ALL_ORCHARD_LABELS_UUID: ["role2"] } } result = collect_all_pdp_vendor_uuids(users_permissions) expected = {"vendor-uuid-1"} assert result == expected assert ALL_ORCHARD_LABELS_UUID not in result def test_collect_all_pdp_vendor_uuids_empty_permissions(self): """Test collecting from empty permissions""" users_permissions = {} result = collect_all_pdp_vendor_uuids(users_permissions) assert result == set() def test_collect_all_pdp_vendor_uuids_only_all_orchard_labels(self): """Test collecting when only ALL_ORCHARD_LABELS_UUID is present""" users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"] } } result = collect_all_pdp_vendor_uuids(users_permissions) assert result == set() class TestExpandAllOrchardUsersVendors: """Test expansion of vendor access for users with ALL_ORCHARD_LABELS_UUID""" def test_expand_all_orchard_users_vendors_basic(self): """Test basic expansion of vendors for user with ALL_ORCHARD_LABELS_UUID""" # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-2": ["role3"] } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1}, {"uuid": "vendor-uuid-2", "name": "Vendor Two", "id": 2} ] expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Should have original vendor plus two emulated vendors assert len(user.vendors) == 3 # Check emulated vendors emulated_vendors = [v for v in user.vendors if v.emulated] assert len(emulated_vendors) == 2 # Check vendor names have asterisk emulated_names = [v.name for v in emulated_vendors] assert "Vendor One *" in emulated_names assert "Vendor Two *" in emulated_names def test_expand_all_orchard_users_vendors_no_duplicates(self): """Test that expansion doesn't create duplicate vendors""" # Create user with ALL_ORCHARD_LABELS_UUID and existing vendor vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) existing_vendor = Vendor( name="Existing Vendor", id=1, uuid="vendor-uuid-1", emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard, existing_vendor] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], # User already has access to this vendor "vendor-uuid-2": ["role3"] } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1}, {"uuid": "vendor-uuid-2", "name": "Vendor Two", "id": 2} ] expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Should have original vendors plus one emulated vendor (no duplicate) assert len(user.vendors) == 3 # Check that only vendor-uuid-2 was added as emulated emulated_vendors = [v for v in user.vendors if v.emulated] assert len(emulated_vendors) == 1 assert emulated_vendors[0].name == "Vendor Two *" assert emulated_vendors[0].uuid == "vendor-uuid-2" def test_expand_all_orchard_users_vendors_user_without_all_orchard_access(self): """Test that users without ALL_ORCHARD_LABELS_UUID are not expanded""" # Create user without ALL_ORCHARD_LABELS_UUID regular_vendor = Vendor( name="Regular Vendor", id=1, uuid="vendor-uuid-1", emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [regular_vendor] users = [user] users_permissions = { "user1": { "vendor-uuid-1": ["role1"], "vendor-uuid-2": ["role2"] } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1}, {"uuid": "vendor-uuid-2", "name": "Vendor Two", "id": 2} ] expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Should have only original vendor (no expansion) assert len(user.vendors) == 1 assert user.vendors[0].name == "Regular Vendor" assert not user.vendors[0].emulated def test_expand_all_orchard_users_vendors_nonexistent_user(self): """Test expansion for user that doesn't exist""" user = User(email="test@example.com", identity="user1", role="admin") user.exists = False # User doesn't exist users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1} ] expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Should not be expanded since user doesn't exist assert len(user.vendors) == 0 def test_expand_all_orchard_users_vendors_missing_vendor_data(self): """Test expansion when vendor data is missing from pdp_vendors_data""" vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-missing": ["role3"] # This vendor not in pdp_vendors_data } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1} # vendor-uuid-missing is not in the data ] expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Should have original vendor plus one emulated vendor (missing vendor ignored) assert len(user.vendors) == 2 emulated_vendors = [v for v in user.vendors if v.emulated] assert len(emulated_vendors) == 1 assert emulated_vendors[0].name == "Vendor One *" class TestGrantFtePermissions: """Test granting FTE permissions to users with ALL_ORCHARD_LABELS_UUID""" @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_user_with_all_orchard_access(self, mock_add_permissions, mock_get_ssh): """Test granting FTE permissions to user with ALL_ORCHARD_LABELS_UUID""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-2": ["role3"] } } vendors_uuids = ["vendor-uuid-1", "vendor-uuid-2"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should call add_permissions for each specified vendor assert mock_add_permissions.call_count == 2 # Check that correct permissions were granted expected_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] calls = mock_add_permissions.call_args_list for call in calls: user_id, vendor_uuid, permissions, ssh_client = call[0] assert user_id == "user1" assert vendor_uuid in vendors_uuids assert permissions == expected_permissions assert ssh_client == mock_ssh mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_user_without_all_orchard_access(self, mock_add_permissions, mock_get_ssh): """Test that users without ALL_ORCHARD_LABELS_UUID are not granted FTE permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user without ALL_ORCHARD_LABELS_UUID regular_vendor = Vendor( name="Regular Vendor", id=1, uuid="vendor-uuid-1", emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [regular_vendor] users = [user] users_permissions = { "user1": { "vendor-uuid-1": ["role1"], "vendor-uuid-2": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should not call add_permissions since user doesn't have ALL_ORCHARD_LABELS_UUID mock_add_permissions.assert_not_called() mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_nonexistent_user(self, mock_add_permissions, mock_get_ssh): """Test that non-existent users are not granted FTE permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user that doesn't exist user = User(email="test@example.com", identity="user1", role="admin") user.exists = False users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should not call add_permissions since user doesn't exist mock_add_permissions.assert_not_called() mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_user_not_in_permissions(self, mock_add_permissions, mock_get_ssh): """Test that users not in permissions dict are not granted FTE permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { # user1 is not in permissions dict "user2": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should not call add_permissions since user not in permissions mock_add_permissions.assert_not_called() mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_mixed_users(self, mock_add_permissions, mock_get_ssh): """Test granting FTE permissions to mixed users (some with, some without ALL_ORCHARD_LABELS_UUID)""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create users - one with ALL_ORCHARD_LABELS_UUID, one without vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) regular_vendor = Vendor( name="Regular Vendor", id=1, uuid="vendor-uuid-1", emulated=False ) user1 = User(email="user1@example.com", identity="user1", role="admin") user1.exists = True user1.vendors = [vendor_all_orchard] user2 = User(email="user2@example.com", identity="user2", role="admin") user2.exists = True user2.vendors = [regular_vendor] users = [user1, user2] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-2": ["role3"] }, "user2": { "vendor-uuid-1": ["role4"] } } vendors_uuids = ["vendor-uuid-1", "vendor-uuid-2"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should call add_permissions only for user1 (2 tenants) assert mock_add_permissions.call_count == 2 calls = mock_add_permissions.call_args_list for call in calls: user_id, vendor_uuid, permissions, ssh_client = call[0] assert user_id == "user1" # Only user1 should get FTE permissions assert vendor_uuid in ["vendor-uuid-1", "vendor-uuid-2"] mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_api_error(self, mock_print, mock_add_permissions, mock_get_ssh): """Test error handling when add_permissions fails""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh mock_add_permissions.side_effect = Exception("API Error") # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should handle the error gracefully mock_add_permissions.assert_called_once() # Get the expected permissions for the print message expected_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] mock_print.assert_any_call(f"Granting missing FTE permissions to test@example.com for vendor vendor-uuid-1: {expected_permissions}") mock_print.assert_any_call("❌ Failed to grant FTE permissions to test@example.com for vendor vendor-uuid-1: API Error") mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_success_message(self, mock_print, mock_add_permissions, mock_get_ssh): """Test success messages when granting FTE permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should print success messages # Get the expected permissions for the print message expected_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] mock_print.assert_any_call(f"Granting missing FTE permissions to test@example.com for vendor vendor-uuid-1: {expected_permissions}") mock_print.assert_any_call("✅ Successfully granted FTE permissions to test@example.com for vendor vendor-uuid-1") mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_grant_fte_permissions_correct_roles(self, mock_add_permissions, mock_get_ssh): """Test that correct FTE roles are granted""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Check that correct FTE permissions were granted mock_add_permissions.assert_called_once() call_args = mock_add_permissions.call_args[0] user_id, vendor_uuid, permissions, ssh_client = call_args expected_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] assert user_id == "user1" assert vendor_uuid == "vendor-uuid-1" assert permissions == expected_permissions assert ssh_client == mock_ssh @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_user_already_has_all_permissions(self, mock_print, mock_add_permissions, mock_get_ssh): """Test that users who already have all FTE permissions are skipped""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] # User already has all FTE permissions users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should not call add_permissions since user already has all permissions mock_add_permissions.assert_not_called() # Should print skip message mock_print.assert_any_call("✅ test@example.com already has all FTE permissions for vendor vendor-uuid-1, skipping") mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_user_has_some_permissions(self, mock_print, mock_add_permissions, mock_get_ssh): """Test that users who have some FTE permissions get only the missing ones""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] # User has some FTE permissions but not all users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, # Missing: CREATE_AD_REPORTS, CONNECT_AD_ACCOUNTS, CREATE_EMAIL_CAMPAIGNS ] } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should call add_permissions once with missing permissions mock_add_permissions.assert_called_once() call_args = mock_add_permissions.call_args[0] user_id, vendor_uuid, permissions, ssh_client = call_args expected_missing_permissions = [ NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] assert user_id == "user1" assert vendor_uuid == "vendor-uuid-1" assert permissions == expected_missing_permissions assert ssh_client == mock_ssh # Should print message about missing permissions mock_print.assert_any_call(f"Granting missing FTE permissions to test@example.com for vendor vendor-uuid-1: {expected_missing_permissions}") mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_mixed_vendor_scenarios(self, mock_print, mock_add_permissions, mock_get_ssh): """Test mixed scenarios: one vendor with all permissions, one vendor with missing permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] # User has all permissions for vendor-uuid-1, but missing some for vendor-uuid-2 users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": [ # All FTE permissions NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ], "vendor-uuid-2": [ # Only one FTE permission NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, ] } } vendors_uuids = ["vendor-uuid-1", "vendor-uuid-2"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should call add_permissions only once (for vendor-uuid-2) mock_add_permissions.assert_called_once() call_args = mock_add_permissions.call_args[0] user_id, vendor_uuid, permissions, ssh_client = call_args expected_missing_permissions = [ NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] assert user_id == "user1" assert vendor_uuid == "vendor-uuid-2" assert permissions == expected_missing_permissions assert ssh_client == mock_ssh # Should print skip message for vendor-uuid-1 and grant message for vendor-uuid-2 mock_print.assert_any_call("✅ test@example.com already has all FTE permissions for vendor vendor-uuid-1, skipping") mock_print.assert_any_call(f"Granting missing FTE permissions to test@example.com for vendor vendor-uuid-2: {expected_missing_permissions}") mock_ssh.close.assert_called_once() @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') @patch('builtins.print') def test_grant_fte_permissions_vendor_has_no_permissions(self, mock_print, mock_add_permissions, mock_get_ssh): """Test that vendor with no existing permissions gets all FTE permissions""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] # User has no permissions for vendor-uuid-1 users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], # vendor-uuid-1 has no permissions - should get all FTE permissions } } vendors_uuids = ["vendor-uuid-1"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Should call add_permissions with all FTE permissions mock_add_permissions.assert_called_once() call_args = mock_add_permissions.call_args[0] user_id, vendor_uuid, permissions, ssh_client = call_args expected_all_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] assert user_id == "user1" assert vendor_uuid == "vendor-uuid-1" assert permissions == expected_all_permissions assert ssh_client == mock_ssh # Should print message about granting all permissions mock_print.assert_any_call(f"Granting missing FTE permissions to test@example.com for vendor vendor-uuid-1: {expected_all_permissions}") mock_ssh.close.assert_called_once() class TestFteIntegration: """Integration tests for FTE functionality""" def test_fte_permissions_enum_values(self): """Test that FTE permissions use correct enum values""" expected_permissions = [ "fansifter_can_view_fan_data", "fansifter_can_share_ad_campaign_audiences", "fansifter_can_create_ad_reports", "fansifter_can_connect_ad_accounts", "fansifter_can_create_email_campaigns" ] actual_permissions = [ NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value, NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value, NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value, NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value, NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value ] assert actual_permissions == expected_permissions def test_all_orchard_labels_uuid_constant(self): """Test that ALL_ORCHARD_LABELS_UUID constant is correct""" assert ALL_ORCHARD_LABELS_UUID == "053a1a75-acc5-4cd8-9206-a194335d2afa" def test_permission_prefix_removal(self): """Test that permission prefixes are removed correctly for display""" # Test permissions with various prefixes test_permissions = [ "audience_development_admin", "audience_development_analyst", "fansifter_can_view_fan_data", "fansifter_can_share_ad_campaign_audiences", "fansifter_can_create_ad_reports", "some_other_permission" ] # Apply the same logic as in tables.py cleaned_permissions = [p.removeprefix("audience_development_").removeprefix("fansifter_can_") for p in test_permissions] expected = [ "admin", "analyst", "view_fan_data", "share_ad_campaign_audiences", "create_ad_reports", "some_other_permission" ] assert cleaned_permissions == expected @patch('app.migrate_to_v2_permissions.get_ssh_client') @patch('app.migrate_to_v2_permissions.add_permissions') def test_fte_workflow_with_expand_vendors(self, mock_add_permissions, mock_get_ssh): """Test complete FTE workflow including vendor expansion""" mock_ssh = Mock() mock_get_ssh.return_value = mock_ssh # Create user with ALL_ORCHARD_LABELS_UUID vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] users = [user] users_permissions = { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-2": ["role3"] } } pdp_vendors_data = [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1}, {"uuid": "vendor-uuid-2", "name": "Vendor Two", "id": 2} ] # First expand vendors expand_all_orchard_users_vendors(users, users_permissions, pdp_vendors_data) # Verify expansion worked assert len(user.vendors) == 3 # Original + 2 emulated emulated_vendors = [v for v in user.vendors if v.emulated] assert len(emulated_vendors) == 2 # Then grant FTE permissions vendors_uuids = ["vendor-uuid-1", "vendor-uuid-2"] grant_fte_permissions(users, users_permissions, vendors_uuids) # Verify FTE permissions were granted assert mock_add_permissions.call_count == 2 calls = mock_add_permissions.call_args_list vendor_uuids = [call[0][1] for call in calls] assert "vendor-uuid-1" in vendor_uuids assert "vendor-uuid-2" in vendor_uuids # Verify all FTE permissions were granted for call in calls: permissions = call[0][2] assert len(permissions) == 5 # All 5 FTE permissions assert NewRole.FANSIFTER_CAN_VIEW_FAN_DATA.value in permissions assert NewRole.FANSIFTER_CAN_SHARE_AD_CAMPAIGN_AUDIENCES.value in permissions assert NewRole.FANSIFTER_CAN_CREATE_AD_REPORTS.value in permissions assert NewRole.FANSIFTER_CAN_CONNECT_AD_ACCOUNTS.value in permissions assert NewRole.FANSIFTER_CAN_CREATE_EMAIL_CAMPAIGNS.value in permissions # Fixtures for common test data @pytest.fixture def user_with_all_orchard_access(): """Fixture for user with ALL_ORCHARD_LABELS_UUID access""" vendor_all_orchard = Vendor( name="All Orchard Access", id=999, uuid=ALL_ORCHARD_LABELS_UUID, emulated=False ) user = User(email="test@example.com", identity="user1", role="admin") user.exists = True user.vendors = [vendor_all_orchard] return user @pytest.fixture def user_without_all_orchard_access(): """Fixture for user without ALL_ORCHARD_LABELS_UUID access""" regular_vendor = Vendor( name="Regular Vendor", id=1, uuid="vendor-uuid-1", emulated=False ) user = User(email="test@example.com", identity="user2", role="admin") user.exists = True user.vendors = [regular_vendor] return user @pytest.fixture def sample_permissions(): """Fixture for sample user permissions""" return { "user1": { ALL_ORCHARD_LABELS_UUID: ["role1"], "vendor-uuid-1": ["role2"], "vendor-uuid-2": ["role3"] }, "user2": { "vendor-uuid-1": ["role4"] } } @pytest.fixture def sample_pdp_vendors_data(): """Fixture for sample PDP vendors data""" return [ {"uuid": "vendor-uuid-1", "name": "Vendor One", "id": 1}, {"uuid": "vendor-uuid-2", "name": "Vendor Two", "id": 2} ]