|
| 1 | +"""Test RBAC activity stream functionality.""" |
| 2 | + |
| 3 | +import uuid |
| 4 | + |
| 5 | +import pytest |
| 6 | +from crum import impersonate |
| 7 | +from django.apps import apps |
| 8 | +from django.contrib.auth import get_user_model |
| 9 | + |
| 10 | +from ansible_base.rbac.models import DABContentType, RoleDefinition, RoleTeamAssignment, RoleUserAssignment |
| 11 | + |
| 12 | +User = get_user_model() |
| 13 | + |
| 14 | + |
| 15 | +def verify_activity_entry_fields(entry, operation, admin_user, actor_id, role_def_id, actor_field): |
| 16 | + """Helper to verify activity entry has correct fields.""" |
| 17 | + assert entry.operation == operation |
| 18 | + assert entry.created_by == admin_user |
| 19 | + assert entry.changes, f"{operation.title()} entry should have changes recorded" |
| 20 | + |
| 21 | + # Get the appropriate fields dict based on operation |
| 22 | + fields_dict = entry.changes['added_fields'] if operation == 'create' else entry.changes['removed_fields'] |
| 23 | + |
| 24 | + # Verify required fields are present with correct values |
| 25 | + assert actor_field in fields_dict |
| 26 | + assert 'role_definition' in fields_dict |
| 27 | + assert str(actor_id) == fields_dict[actor_field] |
| 28 | + assert str(role_def_id) == fields_dict['role_definition'] |
| 29 | + |
| 30 | + |
| 31 | +@pytest.mark.skipif(not apps.is_installed('ansible_base.activitystream'), reason="Activity stream tests only run when activitystream app is installed") |
| 32 | +@pytest.mark.django_db |
| 33 | +def test_role_user_assignment_activity_stream_lifecycle(system_user, admin_user, organization): |
| 34 | + """Test role assignment create and delete both create proper activity entries.""" |
| 35 | + # Create unique test user, role, and org with distinctive names |
| 36 | + test_uuid = str(uuid.uuid4())[:8] |
| 37 | + unique_username = f'test_rbac_user_{test_uuid}' |
| 38 | + unique_role_name = f'TestRole_ActivityStream_{test_uuid}' |
| 39 | + unique_org_name = f'TestOrg_ActivityStream_{test_uuid}' |
| 40 | + |
| 41 | + test_user = User.objects.create_user(username=unique_username, email=f'{unique_username}@example.com') |
| 42 | + |
| 43 | + # Create unique organization for this test |
| 44 | + from test_app.models import Organization |
| 45 | + |
| 46 | + test_org = Organization.objects.create(name=unique_org_name) |
| 47 | + |
| 48 | + ct = DABContentType.objects.get_for_model(test_org) |
| 49 | + role_def = RoleDefinition.objects.create(name=unique_role_name, content_type=ct) |
| 50 | + |
| 51 | + # Create assignment (admin assigns role to user) |
| 52 | + with impersonate(admin_user): |
| 53 | + assignment = RoleUserAssignment.objects.create(user=test_user, role_definition=role_def, content_object=test_org, created_by=admin_user) |
| 54 | + |
| 55 | + # Verify CREATE entry |
| 56 | + assert assignment.activity_stream_entries.count() == 1 |
| 57 | + create_entry = assignment.activity_stream_entries.last() |
| 58 | + verify_activity_entry_fields(create_entry, 'create', admin_user, test_user.id, role_def.id, 'user') |
| 59 | + |
| 60 | + # Verify enhanced string representation |
| 61 | + entry_str = str(create_entry) |
| 62 | + assert "created" in entry_str.lower() |
| 63 | + assert str(admin_user) in entry_str |
| 64 | + |
| 65 | + |
| 66 | + # Delete assignment and verify DELETE entry |
| 67 | + assignment_id = assignment.id |
| 68 | + with impersonate(admin_user): |
| 69 | + assignment.delete() |
| 70 | + |
| 71 | + # Query entries directly since assignment pk=None after delete |
| 72 | + from django.contrib.contenttypes.models import ContentType |
| 73 | + |
| 74 | + from ansible_base.activitystream.models import Entry |
| 75 | + |
| 76 | + assignment_ct = ContentType.objects.get_for_model(RoleUserAssignment) |
| 77 | + assignment_entries = Entry.objects.filter(content_type=assignment_ct, object_id=str(assignment_id)).order_by('id') |
| 78 | + |
| 79 | + assert assignment_entries.count() == 2 |
| 80 | + delete_entry = assignment_entries.last() |
| 81 | + verify_activity_entry_fields(delete_entry, 'delete', admin_user, test_user.id, role_def.id, 'user') |
| 82 | + |
| 83 | + # Verify enhanced string representation for delete |
| 84 | + delete_str = str(delete_entry) |
| 85 | + assert "deleted" in delete_str.lower() |
| 86 | + assert str(admin_user) in delete_str |
| 87 | + |
| 88 | + |
| 89 | +@pytest.mark.skipif(not apps.is_installed('ansible_base.activitystream'), reason="Activity stream tests only run when activitystream app is installed") |
| 90 | +@pytest.mark.django_db |
| 91 | +def test_role_team_assignment_activity_stream(admin_user, team, organization): |
| 92 | + """Test team role assignment creates activity entries.""" |
| 93 | + # Create unique role and org names for isolation |
| 94 | + test_uuid = str(uuid.uuid4())[:8] |
| 95 | + unique_role_name = f'TestTeamRole_{test_uuid}' |
| 96 | + unique_org_name = f'TestTeamOrg_{test_uuid}' |
| 97 | + |
| 98 | + # Create unique organization for this test |
| 99 | + from test_app.models import Organization |
| 100 | + |
| 101 | + test_org = Organization.objects.create(name=unique_org_name) |
| 102 | + |
| 103 | + ct = DABContentType.objects.get_for_model(test_org) |
| 104 | + role_def = RoleDefinition.objects.create(name=unique_role_name, content_type=ct) |
| 105 | + |
| 106 | + # Create team assignment |
| 107 | + with impersonate(admin_user): |
| 108 | + assignment = RoleTeamAssignment.objects.create(team=team, role_definition=role_def, content_object=test_org, created_by=admin_user) |
| 109 | + |
| 110 | + # Verify CREATE entry |
| 111 | + assert assignment.activity_stream_entries.count() == 1 |
| 112 | + create_entry = assignment.activity_stream_entries.last() |
| 113 | + verify_activity_entry_fields(create_entry, 'create', admin_user, team.id, role_def.id, 'team') |
| 114 | + |
| 115 | + # Delete assignment and verify DELETE entry |
| 116 | + assignment_id = assignment.id |
| 117 | + with impersonate(admin_user): |
| 118 | + assignment.delete() |
| 119 | + |
| 120 | + # Query entries directly since assignment pk=None after delete |
| 121 | + from django.contrib.contenttypes.models import ContentType |
| 122 | + |
| 123 | + from ansible_base.activitystream.models import Entry |
| 124 | + |
| 125 | + assignment_ct = ContentType.objects.get_for_model(RoleTeamAssignment) |
| 126 | + assignment_entries = Entry.objects.filter(content_type=assignment_ct, object_id=str(assignment_id)).order_by('id') |
| 127 | + |
| 128 | + assert assignment_entries.count() == 2 |
| 129 | + delete_entry = assignment_entries.last() |
| 130 | + verify_activity_entry_fields(delete_entry, 'delete', admin_user, team.id, role_def.id, 'team') |
0 commit comments