|
3 | 3 | import pytest
|
4 | 4 |
|
5 | 5 | from ansible_base.lib.utils.response import get_relative_url
|
6 |
| -from ansible_base.rbac.models import DABContentType, DABPermission, RoleDefinition, RoleTeamAssignment, RoleUserAssignment |
| 6 | +from ansible_base.rbac.models import DABContentType, DABPermission, RoleDefinition, RoleUserAssignment |
7 | 7 | from test_app.models import Team, User
|
8 | 8 |
|
9 | 9 |
|
@@ -492,6 +492,7 @@ def test_serializer_allows_null_values_in_validation(self, admin_api_client, ran
|
492 | 492 | validated_data = serializer.validated_data
|
493 | 493 | assert 'created_by' not in validated_data or validated_data.get('created_by') is None
|
494 | 494 |
|
| 495 | + |
495 | 496 | def test_service_assignment_created_timestamp_sync(admin_api_client, rando, inv_rd, inventory):
|
496 | 497 | """
|
497 | 498 | Test that demonstrates the field sync issue: the 'created' timestamp field is displayed
|
@@ -539,3 +540,114 @@ def test_service_assignment_created_timestamp_sync(admin_api_client, rando, inv_
|
539 | 540 | response_created = parse_datetime(response.data['created'])
|
540 | 541 | # Note: This will show the auto-generated timestamp, not our custom one
|
541 | 542 | assert response_created == expected_created, f"Response created timestamp should match: expected '{expected_created}' but got '{response_created}'"
|
| 543 | + |
| 544 | + |
| 545 | +@pytest.mark.django_db |
| 546 | +def test_service_assignment_object_created_timestamp_sync(admin_api_client, rando, inv_rd, inventory): |
| 547 | + """ |
| 548 | + Test that the 'object_created' field can be synchronized in both directions: |
| 549 | + 1. POST to /assign/ accepts a provided 'object_created' value |
| 550 | + 2. Serializing local assignments includes the 'object_created' field from the DB |
| 551 | + """ |
| 552 | + from datetime import datetime, timezone |
| 553 | + |
| 554 | + from django.utils.dateparse import parse_datetime |
| 555 | + |
| 556 | + url = get_relative_url('serviceuserassignment-assign') |
| 557 | + |
| 558 | + creator_user = User.objects.create(username='object_created_creator') |
| 559 | + |
| 560 | + # Set a specific object_created timestamp that's different from the actual object's created time |
| 561 | + custom_object_created = datetime(2022, 6, 15, 14, 30, 0, tzinfo=timezone.utc) |
| 562 | + custom_object_created_str = custom_object_created.isoformat() |
| 563 | + |
| 564 | + post_data = { |
| 565 | + "role_definition": inv_rd.name, |
| 566 | + "user_ansible_id": str(rando.resource.ansible_id), |
| 567 | + "object_id": str(inventory.pk), |
| 568 | + "created_by_ansible_id": str(creator_user.resource.ansible_id), |
| 569 | + "object_created": custom_object_created_str, |
| 570 | + "from_service": "test_service", |
| 571 | + } |
| 572 | + |
| 573 | + # Test 1: POST accepts object_created value |
| 574 | + response = admin_api_client.post(url, data=post_data) |
| 575 | + assert response.status_code == 201, response.data |
| 576 | + |
| 577 | + assignment = RoleUserAssignment.objects.get(user=rando, role_definition=inv_rd, object_id=inventory.pk) |
| 578 | + |
| 579 | + # Verify the custom object_created timestamp was properly set |
| 580 | + expected_object_created = custom_object_created |
| 581 | + actual_object_created = assignment.object_created |
| 582 | + |
| 583 | + assert ( |
| 584 | + actual_object_created == expected_object_created |
| 585 | + ), f"object_created should be synchronized: Expected '{expected_object_created}' but got '{actual_object_created}'" |
| 586 | + |
| 587 | + # Test 2: Serializing local assignments includes object_created field |
| 588 | + list_url = get_relative_url('serviceuserassignment-list') |
| 589 | + response = admin_api_client.get(list_url + '?page_size=200', format="json") |
| 590 | + assert response.status_code == 200, response.data |
| 591 | + |
| 592 | + # Find our assignment in the list |
| 593 | + assignments = [a for a in response.data['results'] if a['role_definition'] == inv_rd.name and str(a['object_id']) == str(inventory.pk)] |
| 594 | + assert len(assignments) >= 1, "Should find at least our assignment" |
| 595 | + |
| 596 | + # Check that object_created is properly serialized |
| 597 | + assignment_data = assignments[0] |
| 598 | + assert 'object_created' in assignment_data, "object_created field should be present in serialized output" |
| 599 | + |
| 600 | + response_object_created = parse_datetime(assignment_data['object_created']) |
| 601 | + assert ( |
| 602 | + response_object_created == expected_object_created |
| 603 | + ), f"Serialized object_created should match stored value: expected '{expected_object_created}' but got '{response_object_created}'" |
| 604 | + |
| 605 | + |
| 606 | +@pytest.mark.django_db |
| 607 | +def test_service_assignment_object_created_from_local_object(admin_api_client, rando, org_inv_rd, organization): |
| 608 | + """ |
| 609 | + Test that when no object_created is provided in POST, the field is automatically set |
| 610 | + from the local object's created timestamp and properly serialized. |
| 611 | + """ |
| 612 | + url = get_relative_url('serviceuserassignment-assign') |
| 613 | + |
| 614 | + post_data = { |
| 615 | + "role_definition": org_inv_rd.name, |
| 616 | + "user_ansible_id": str(rando.resource.ansible_id), |
| 617 | + "object_id": str(organization.pk), |
| 618 | + "from_service": "test_service", |
| 619 | + # Note: no object_created provided - should default to organization.created |
| 620 | + } |
| 621 | + |
| 622 | + # Create assignment without providing object_created |
| 623 | + response = admin_api_client.post(url, data=post_data) |
| 624 | + assert response.status_code == 201, response.data |
| 625 | + |
| 626 | + assignment = RoleUserAssignment.objects.get(user=rando, role_definition=org_inv_rd, object_id=organization.pk) |
| 627 | + |
| 628 | + # Verify object_created was set to the organization's created timestamp |
| 629 | + expected_object_created = organization.created |
| 630 | + actual_object_created = assignment.object_created |
| 631 | + |
| 632 | + assert ( |
| 633 | + actual_object_created == expected_object_created |
| 634 | + ), f"object_created should default to organization.created: Expected '{expected_object_created}' but got '{actual_object_created}'" |
| 635 | + |
| 636 | + # Verify serialization includes the correct object_created value |
| 637 | + list_url = get_relative_url('serviceuserassignment-list') |
| 638 | + response = admin_api_client.get(list_url + '?page_size=200', format="json") |
| 639 | + assert response.status_code == 200, response.data |
| 640 | + |
| 641 | + # Find our assignment |
| 642 | + assignments = [a for a in response.data['results'] if a['role_definition'] == org_inv_rd.name and str(a['object_id']) == str(organization.pk)] |
| 643 | + assert len(assignments) >= 1, "Should find at least our assignment" |
| 644 | + |
| 645 | + assignment_data = assignments[0] |
| 646 | + assert 'object_created' in assignment_data, "object_created field should be present in serialized output" |
| 647 | + |
| 648 | + from django.utils.dateparse import parse_datetime |
| 649 | + |
| 650 | + response_object_created = parse_datetime(assignment_data['object_created']) |
| 651 | + assert ( |
| 652 | + response_object_created == expected_object_created |
| 653 | + ), f"Serialized object_created should match organization.created: expected '{expected_object_created}' but got '{response_object_created}'" |
0 commit comments