|
1 | 1 | """Test suite for user-role assignment API functions.""" |
2 | 2 |
|
| 3 | +from unittest.mock import patch |
| 4 | + |
3 | 5 | from ddt import data, ddt, unpack |
| 6 | +from django.contrib.auth import get_user_model |
4 | 7 |
|
5 | 8 | from openedx_authz.api.data import ContentLibraryData, RoleAssignmentData, RoleData, UserData |
6 | 9 | from openedx_authz.api.users import ( |
|
14 | 17 | is_user_allowed, |
15 | 18 | unassign_all_roles_from_user, |
16 | 19 | unassign_role_from_user, |
| 20 | + validate_users, |
17 | 21 | ) |
18 | 22 | from openedx_authz.constants import permissions, roles |
19 | 23 | from openedx_authz.constants.roles import LIBRARY_ADMIN_PERMISSIONS, LIBRARY_AUTHOR_PERMISSIONS |
@@ -514,3 +518,66 @@ def test_is_user_allowed(self, username, action, scope_name, expected_result): |
514 | 518 | scope_external_key=scope_name, |
515 | 519 | ) |
516 | 520 | self.assertEqual(result, expected_result) |
| 521 | + |
| 522 | + |
| 523 | +@ddt |
| 524 | +class TestValidateUsersAPI(UserAssignmentsSetupMixin): |
| 525 | + """Test suite for validate_users API function - focused on business logic.""" |
| 526 | + |
| 527 | + def test_validate_users_empty_list(self): |
| 528 | + """Test validate_users with empty input list.""" |
| 529 | + valid_users, invalid_users = validate_users([]) |
| 530 | + |
| 531 | + self.assertEqual(valid_users, []) |
| 532 | + self.assertEqual(invalid_users, []) |
| 533 | + |
| 534 | + def test_validate_users_inactive_user_edge_case(self): |
| 535 | + """Test that inactive users are correctly identified as invalid.""" |
| 536 | + User = get_user_model() |
| 537 | + |
| 538 | + # Create an inactive user for this test |
| 539 | + inactive_user = User.objects.create_user( |
| 540 | + username="inactive_api_test", email="[email protected]", is_active=False |
| 541 | + ) |
| 542 | + |
| 543 | + valid_users, invalid_users = validate_users([inactive_user.username]) |
| 544 | + |
| 545 | + # Cleanup |
| 546 | + inactive_user.delete() |
| 547 | + |
| 548 | + self.assertEqual(valid_users, []) |
| 549 | + self.assertEqual(invalid_users, [inactive_user.username]) |
| 550 | + |
| 551 | + @patch("openedx_authz.api.users.get_user_by_username_or_email") |
| 552 | + def test_validate_users_unexpected_exception_propagation(self, mock_get_user): |
| 553 | + """Test that unexpected exceptions from get_user_by_username_or_email are re-raised.""" |
| 554 | + # Simulate an unexpected database error |
| 555 | + mock_get_user.side_effect = Exception("Database connection lost") |
| 556 | + |
| 557 | + with self.assertRaises(Exception) as cm: |
| 558 | + validate_users(["any_user"]) |
| 559 | + |
| 560 | + self.assertEqual(str(cm.exception), "Database connection lost") |
| 561 | + mock_get_user.assert_called_once_with("any_user") |
| 562 | + |
| 563 | + @patch("openedx_authz.api.users.get_user_by_username_or_email") |
| 564 | + def test_validate_users_user_does_not_exist_handling(self, mock_get_user): |
| 565 | + """Test handling of User.DoesNotExist exception.""" |
| 566 | + User = get_user_model() |
| 567 | + mock_get_user.side_effect = User.DoesNotExist("User not found") |
| 568 | + |
| 569 | + valid_users, invalid_users = validate_users(["nonexistent_user"]) |
| 570 | + |
| 571 | + self.assertEqual(valid_users, []) |
| 572 | + self.assertEqual(invalid_users, ["nonexistent_user"]) |
| 573 | + |
| 574 | + @patch("openedx_authz.api.users.logger") |
| 575 | + def test_validate_users_logs_unexpected_exceptions(self, mock_logger): |
| 576 | + """Test that unexpected exceptions are properly logged before re-raising.""" |
| 577 | + with patch("openedx_authz.api.users.get_user_by_username_or_email") as mock_get_user: |
| 578 | + mock_get_user.side_effect = Exception("Connection timeout") |
| 579 | + with self.assertRaises(Exception): |
| 580 | + validate_users(["test_user"]) |
| 581 | + mock_logger.error.assert_called_once() |
| 582 | + log_call_args = mock_logger.error.call_args[0][0] |
| 583 | + self.assertIn("Unexpected error validating user test_user", log_call_args) |
0 commit comments