Exemplo n.º 1
0
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""

    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context["request"]
        user = User()
        user.username = self.user_data["username"]
        user.account = self.customer_data["account_id"]
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data["username"])
            self.principal.save()
            self.principalB = Principal(username="******")
            self.principalB.save()
            self.principalC = Principal(username="******")
            self.principalC.save()
            self.group = Group(name="groupA")
            self.group.save()
            self.role = Role.objects.create(name="roleA", description="A role for a group.", system=True)
            self.policy = Policy.objects.create(name="policyA", group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal, self.principalB)
            self.group.save()

            self.defGroup = Group(name="groupDef", platform_default=True, system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.emptyGroup = Group(name="groupE")
            self.emptyGroup.save()

            self.groupB = Group.objects.create(name="groupB")
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name="policyB", group=self.groupB)
            self.roleB = Role.objects.create(name="roleB", system=False)
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

            # role that's not assigned to principal
            self.roleOrphan = Role.objects.create(name="roleOrphan")

            # group that associates with multipal roles
            self.groupMultiRole = Group.objects.create(name="groupMultiRole")
            self.policyMultiRole = Policy.objects.create(name="policyMultiRole")
            self.policyMultiRole.roles.add(self.role)
            self.policyMultiRole.roles.add(self.roleB)
            self.groupMultiRole.policies.add(self.policyMultiRole)

    def tearDown(self):
        """Tear down group viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_create_group_success(self, mock_request):
        """Test that we can create a group."""
        group_name = "groupC"
        test_data = {"name": group_name}

        # create a group
        url = reverse("group-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse("group-detail", kwargs={"uuid": response.data.get("uuid")})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(group_name, response.data.get("name"))

    def test_create_default_group(self):
        """Test that system groups can be created."""
        group_name = "groupDef"

        # test group retrieval
        client = APIClient()
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertIsNotNone(response.data.get("name"))
        self.assertTrue(response.data.get("platform_default"))
        self.assertEqual(group_name, response.data.get("name"))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse("group-list")
        client = APIClient()
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_group_filter_by_any_role_name_in_a_list_success(self):
        """Test default behaviour that filter groups by any role name in a list success."""
        url = "{}?role_names={},{}".format(reverse("group-list"), "Rolea", "RoleB")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get("meta").get("count") == 3)

        expected_groups = [self.group.name, self.groupB.name, self.groupMultiRole.name]
        self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")])

    def test_group_filter_by_all_role_name_in_a_list_success(self):
        """Test that filter groups by all role names in a list success."""
        url = "{}?role_names={},{}&role_discriminator=all".format(reverse("group-list"), "Rolea", "roleB")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get("meta").get("count") == 1)

        expected_groups = [self.groupMultiRole.name]
        self.assertEqual(expected_groups, [group.get("name") for group in response.data.get("data")])

    def test_group_filter_with_invalid_discriminator_failure(self):
        """Test that filter groups with invalid discriminator returns failed validation."""
        url = "{}?role_names={},{}&role_discriminator=invalid".format(reverse("group-list"), "roleA", "ROLEb")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_read_group_success(self, mock_request):
        """Test that we can read a group."""
        url = reverse("group-detail", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get("name"))
        self.assertEqual(self.group.name, response.data.get("name"))
        self.assertEqual(len(response.data.get("roles")), 1)
        self.assertEqual(response.data.get("roles")[0]["uuid"], str(self.role.uuid))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_nonguid(self):
        """Test that reading a group with an invalid UUID returns an error."""
        url = reverse("group-detail", kwargs={"uuid": "potato"})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse("group-list")
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 5)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)

    def test_get_group_by_partial_name_by_default(self):
        """Test that getting groups by name returns partial match by default."""
        url = reverse("group-list")
        url = "{}?name={}".format(url, "group")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 5)

    def test_get_group_by_partial_name_explicit(self):
        """Test that getting groups by name returns partial match when specified."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "partial")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 5)

    def test_get_group_by_name_invalid_criteria(self):
        """Test that getting groups by name fails with invalid name_match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "bad_criteria")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_group_by_exact_name_match(self):
        """Test that getting groups by name returns exact match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, self.group.name, "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)
        group = response.data.get("data")[0]
        self.assertEqual(group.get("name"), self.group.name)

    def test_get_group_by_exact_name_no_match(self):
        """Test that getting groups by name returns no results with exact match."""
        url = reverse("group-list")
        url = "{}?name={}&name_match={}".format(url, "group", "exact")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_filter_group_list_by_uuid_success(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 1)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)

    def test_filter_group_list_by_uuid_multiple(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid},{self.groupB.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get("data"), list)
        self.assertEqual(len(response.data.get("data")), 2)

        group = response.data.get("data")[0]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.group.name)
        group = response.data.get("data")[1]
        self.assertIsNotNone(group.get("name"))
        self.assertEqual(group.get("name"), self.groupB.name)

    def test_filter_group_list_by_uuid_fail(self):
        """Test that filtering by a nonexistant uuid returns nothing."""
        url = f"{reverse('group-list')}?uuid={uuid4()}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ["meta", "links", "data"]:
            self.assertIn(keyname, response.data)
        self.assertEqual(response.data.get("data"), [])
        self.assertEqual(len(response.data.get("data")), 0)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_update_group_success(self, mock_request):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + "_update"
        test_data = {"name": updated_name}
        url = reverse("group-detail", kwargs={"uuid": group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get("uuid"))
        self.assertEqual(updated_name, response.data.get("name"))

    def test_update_default_group(self):
        """Test that platform_default groups are protected from updates"""
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        test_data = {"name": self.defGroup.name + "_updated"}
        client = APIClient()
        response = client.put(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse("group-detail", kwargs={"uuid": group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_default_group(self):
        """Test that platform_default groups are protected from deletion"""
        url = reverse("group-detail", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse("group-detail", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse("group-principals", kwargs={"uuid": uuid4()})
        client = APIClient()
        response = client.put(url, {}, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={
            "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
            "errors": [
                {
                    "detail": "Unexpected error.",
                    "status": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "source": "principals",
                }
            ],
        },
    )
    def test_add_group_principals_failure(self, mock_request):
        """Test that adding a principal to a group returns has proper response when it is failed."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {"principals": [{"username": self.principal.username}, {"username": new_username}]}
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
        self.assertEqual(response.data[0]["detail"], "Unexpected error.")
        self.assertEqual(response.data[0]["status"], 500)
        self.assertEqual(response.data[0]["source"], "principals")

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_add_group_principals_success(self, mock_request):
        """Test that adding a principal to a group returns successfully."""
        # Create a group and a cross account user.
        with tenant_context(self.tenant):
            test_group = Group.objects.create(name="test")
            cross_account_user = Principal.objects.create(username="******", cross_account=True)
        url = reverse("group-principals", kwargs={"uuid": test_group.uuid})
        client = APIClient()
        test_data = {"principals": [{"username": "******"}, {"username": "******"}]}
        response = client.post(url, test_data, format="json", **self.headers)

        # Only the user exists in IT will be added to the group.
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data.get("principals")), 1)
        self.assertEqual(response.data.get("principals")[0], {"username": "******"})

        test_group.delete()
        cross_account_user.delete()

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_principals_empty(self, mock_request):
        """Test that getting principals from an empty group returns successfully."""
        client = APIClient()
        url = reverse("group-principals", kwargs={"uuid": self.emptyGroup.uuid})
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get("meta").get("count"), 0)
        self.assertEqual(response.data.get("data"), [])

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_principals_nonempty(self, mock_request):
        """Test that getting principals from a nonempty group returns successfully."""
        mock_request.return_value["data"] = [
            {"username": self.principal.username},
            {"username": self.principalB.username},
        ]

        client = APIClient()
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        response = client.get(url, **self.headers)

        call_args, kwargs = mock_request.call_args_list[0]
        username_arg = call_args[0]

        for username in [self.principal.username, self.principalB.username]:
            self.assertTrue(username in username_arg)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get("meta").get("count"), 2)
        self.assertEqual(response.data.get("data")[0].get("username"), self.principal.username)
        self.assertEqual(response.data.get("data")[1].get("username"), self.principalB.username)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?usernames={}".format(url, self.principal.username)
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_get_group_by_username(self, mock_request):
        """Test that getting groups for a principal returns successfully."""
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 3)

        # User who is not added to a group explicitly will return platform default group
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principalC.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 1)

        # Return bad request when user does not exist
        url = reverse("group-list")
        url = "{}?username={}".format(url, uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_group_by_username_for_cross_account_principal(self):
        """Test that getting groups for a cross account principal won't have platform default group."""
        with tenant_context(self.tenant):
            self.principalC.cross_account = True
            self.principalC.save()
        url = reverse("group-list")
        url = "{}?username={}".format(url, self.principalC.username)
        client = APIClient()

        # User who is not added to a group explicitly will not return platform default group if he is cross account principal.
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 0)

    def test_get_group_by_username_with_capitalization(self):
        """Test that getting groups for a user name with capitalization returns successfully."""
        url = reverse("group-list")
        username = "".join(random.choice([k.upper(), k]) for k in self.principal.username)
        url = "{}?username={}".format(url, username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get("meta").get("count"), 3)

    def test_get_group_roles_success(self):
        """Test that getting roles for a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)

    def test_get_group_roles_with_exclude_false_success(self):
        """Test that getting roles with 'exclude=false' for a group works as default."""
        url = "%s?exclude=FALSE" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)

    def test_get_group_roles_with_exclude_success(self):
        """Test that getting roles with 'exclude=True' for a group returns successfully."""
        url = "%s?exclude=True" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertTrue(role.uuid in [self.roleB.uuid, self.roleOrphan.uuid] for role in roles)

    def test_get_group_roles_with_exclude_in_principal_scope_success(self):
        """Test that getting roles with 'exclude=True' for a group in principal scope."""
        url = "%s?exclude=True&scope=principal" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.roleB.uuid))
        self.assertEqual(roles[0].get("name"), self.roleB.name)
        self.assertEqual(roles[0].get("description"), self.roleB.description)

    def test_get_group_roles_ordered(self):
        """Test getting roles with 'order_by=' returns properly."""
        url = f"{reverse('group-roles', kwargs={'uuid': self.group.uuid})}?order_by=-name"
        client = APIClient()

        test_data = {"roles": [self.roleB.uuid]}
        response = client.post(url, test_data, format="json", **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        response = client.get(url, **self.headers)
        roles = response.data.get("data")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("name"), self.roleB.name)
        self.assertEqual(roles[1].get("name"), self.role.name)

    def test_exclude_input_invalid(self):
        """Test that getting roles with 'exclude=' for a group returns failed validation."""
        url = "%s?exclude=sth" % (reverse("group-roles", kwargs={"uuid": self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_role_name_filter_for_group_roles_no_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_name_filter_for_group_roles_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_name={}".format(url, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_display_name_filter_for_group_roles_no_match(self):
        """Test role_display_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_display_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_display_name_filter_for_group_roles_match(self):
        """Test role_display_name filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_display_name={}".format(url, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_description_filter_for_group_roles_no_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_description_filter_for_group_roles_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description={}".format(url, self.role.description)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_all_role_filters_for_group_roles_no_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description=test&role_name=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_all_role_filters_for_group_roles_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        url = "{}?role_description={}&role_name={}".format(url, self.role.description, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))

    def test_role_system_filter_for_group_roles(self):
        """Test role_system filter for getting roles for a group."""
        base_url = reverse("group-roles", kwargs={"uuid": self.groupMultiRole.uuid})
        client = APIClient()
        response = client.get(base_url, **self.headers)
        self.assertEqual(len(response.data.get("data")), 2)

        url = f"{base_url}?role_system=true"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), True)

        url = f"{base_url}?role_system=false"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(len(response.data.get("data")), 1)
        role = response.data.get("data")[0]
        self.assertEqual(role.get("system"), False)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": []},
    )
    def test_principal_username_filter_for_group_roles_no_match(self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        url = "{}?principal_username=test".format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        mock_request.assert_called_with([], ANY, options={"sort_order": None})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 0)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_username_filter_for_group_roles_match(self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse("group-principals", kwargs={"uuid": self.group.uuid})
        url = "{}?principal_username={}".format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        mock_request.assert_called_with([self.principal.username], ANY, options={"sort_order": None})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_get_ordering_username_success(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=username"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")
        expected_principals = sorted([self.principal.username, self.principalB.username])
        mock_request.assert_called_with(expected_principals, ANY, options={"sort_order": "asc"})
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        "management.principal.proxy.PrincipalProxy.request_filtered_principals",
        return_value={"status_code": 200, "data": [{"username": "******"}]},
    )
    def test_principal_get_ordering_nonusername_fail(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=best_joke"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get("data")

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(principals, None)

    def test_add_group_roles_system_policy_create_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format="json", **self.headers)

        roles = response.data.get("data")
        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_system_flag_update_on_add(self):
        """Test that adding a role to a platform_default group flips the system flag."""
        url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}

        self.assertTrue(self.defGroup.system)
        response = client.post(url, test_data, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default access")
        self.assertFalse(self.defGroup.system)

    def test_system_flag_update_on_remove(self):
        """Test that removing a role from a platform_default group flips the system flag."""
        url = reverse("group-roles", kwargs={"uuid": self.defGroup.uuid})
        client = APIClient()
        url = "{}?roles={}".format(url, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()

        self.assertTrue(self.defGroup.system)
        response = client.delete(url, format="json", **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default access")
        self.assertFalse(self.defGroup.system)

    def test_add_group_roles_system_policy_create_new_group_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        group_url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        groupB_url = reverse("group-roles", kwargs={"uuid": self.groupB.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid]}

        response = client.post(group_url, test_data, format="json", **self.headers)
        responseB = client.post(groupB_url, test_data, format="json", **self.headers)

        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)
        system_policyB = system_policies.get(group=self.groupB)

        self.assertEqual(len(system_policies), 2)
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.roleB], list(system_policyB.roles.all()))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(responseB.status_code, status.HTTP_200_OK)

    def test_add_group_roles_system_policy_get_success(self):
        """Test that adding a role to a group with existing system policy returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        test_data = {"roles": [self.roleB.uuid, self.dummy_role_id]}
        system_policy_name = "System Policy for Group {}".format(self.group.uuid)
        system_policy = Policy.objects.create(system=True, group=self.group, name=system_policy_name)

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format="json", **self.headers)

        roles = response.data.get("data")
        system_policies = Policy.objects.filter(system=True, group=self.group)
        system_policy = system_policies.first()

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy], list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get("uuid"), str(self.role.uuid))
        self.assertEqual(roles[0].get("name"), self.role.name)
        self.assertEqual(roles[0].get("description"), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_success(self):
        """Test that adding multiple roles to a group returns successfully."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": [self.role.uuid, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([self.role, self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_invalid(self):
        """Test that adding invalid roles to a group fails the request and does not add any."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": ["abc123", self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_group_multiple_roles_not_found_success(self):
        """Test that adding roles to a group skips ids not found, and returns success."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name="groupC")
            url = reverse("group-roles", kwargs={"uuid": groupC.uuid})
            client = APIClient()
            test_data = {"roles": [self.dummy_role_id, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url, test_data, format="json", **self.headers)

            self.assertCountEqual([self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_roles_success(self):
        """Test that removing a role from a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={}".format(url, self.role.uuid)

        self.policyB.roles.add(self.role)
        self.policyB.save()
        self.assertCountEqual([self.role], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertCountEqual([self.role, self.roleB], list(self.groupB.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_success(self):
        """Test that removing multiple roles from a group returns successfully."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{}".format(url, self.role.uuid, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_invalid(self):
        """Test that removing invalid roles from a group fails the request and does not remove any."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{}".format(url, "abc123", self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_remove_group_multiple_roles_not_found_success(self):
        """Test that removing roles from a group skips ids not found, and returns success."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()
        url = "{}?roles={},{},{}".format(url, self.role.uuid, self.roleB.uuid, self.dummy_role_id)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB], list(self.group.roles()))

        response = client.delete(url, format="json", **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_roles_invalid(self):
        """Test that removing a role returns an error with invalid data format."""
        url = reverse("group-roles", kwargs={"uuid": self.group.uuid})
        client = APIClient()

        response = client.delete(url, format="json", **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_admin_RonR(self):
        """Test that a admin user can group RBAC resources"""
        url = "{}?application={}".format(reverse("group-list"), "rbac")
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User(username=self.user_data['username'], tenant=self.tenant)
        user.save()
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.role = Role.objects.create(name='roleA')
            self.policy = Policy.objects.create(name='policyA',
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal)
            self.group.save()

            self.defGroup = Group(name='groupDef',
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.groupB = Group.objects.create(name='groupB')
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name='policyB',
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name='roleB')
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

    def tearDown(self):
        """Tear down group viewset tests."""
        User.objects.all().delete()
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_create_group_success(self, mock_request):
        """Test that we can create a group."""
        group_name = 'groupC'
        test_data = {'name': group_name}

        # create a group
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse('group-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_default_group(self):
        """Test that system groups can be created."""
        group_name = 'groupDef'

        # test group retrieval
        client = APIClient()
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertTrue(response.data.get('platform_default'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_read_group_success(self, mock_request):
        """Test that we can read a group."""
        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(self.group.name, response.data.get('name'))
        self.assertEqual(len(response.data.get('roles')), 1)
        self.assertEqual(
            response.data.get('roles')[0]['uuid'], str(self.role.uuid))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse('group-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 3)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_update_group_success(self, mock_request):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + '_update'
        test_data = {'name': updated_name}
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_default_group(self):
        """Test that platform_default groups are protected from deletion"""
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse('group-principals', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_add_group_principals_success(self, mock_request):
        """Test that adding a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        url = reverse('group-list')
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get('meta').get('count'), 3)
        self.assertEqual(response.data.get('data')[0].get('principalCount'), 1)
        self.assertEqual(response.data.get('data')[0].get('policyCount'), None)
        self.assertEqual(response.data.get('data')[0].get('roleCount'), 1)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?usernames={}'.format(url, self.principal.username)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_get_group_by_username(self, mock_request):
        """Test that getting groups for a principalreturns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        url = reverse('group-list')
        url = '{}?username={}'.format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 3)

        url = reverse('group-list')
        url = '{}?username={}'.format(url, uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 0)

    def test_get_group_roles_success(self):
        """Test that getting roles for a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)

    def test_add_group_roles_system_policy_create_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_system_flag_update_on_add(self):
        """Test that adding a role to a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertTrue(self.defGroup.system)
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.defGroup.refresh_from_db()
        self.assertFalse(self.defGroup.system)

    def test_system_flag_update_on_remove(self):
        """Test that removing a role from a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()

        self.assertTrue(self.defGroup.system)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.defGroup.refresh_from_db()
        self.assertFalse(self.defGroup.system)

    def test_add_group_roles_system_policy_create_new_group_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        group_url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        groupB_url = reverse('group-roles', kwargs={'uuid': self.groupB.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid]}

        response = client.post(group_url,
                               test_data,
                               format='json',
                               **self.headers)
        responseB = client.post(groupB_url,
                                test_data,
                                format='json',
                                **self.headers)

        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)
        system_policyB = system_policies.get(group=self.groupB)

        self.assertEqual(len(system_policies), 2)
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.roleB], list(system_policyB.roles.all()))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(responseB.status_code, status.HTTP_200_OK)

    def test_add_group_roles_system_policy_get_success(self):
        """Test that adding a role to a group with existing system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}
        system_policy_name = 'System Policy for Group {}'.format(
            self.group.uuid)
        system_policy = Policy.objects.create(system=True,
                                              group=self.group,
                                              name=system_policy_name)

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True, group=self.group)
        system_policy = system_policies.first()

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_success(self):
        """Test that adding multiple roles to a group returns successfully."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.role.uuid, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.role, self.roleB],
                                  list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_invalid(self):
        """Test that adding invalid roles to a group fails the request and does not add any."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': ['abc123', self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_group_multiple_roles_not_found_success(self):
        """Test that adding roles to a group skips ids not found, and returns success."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.dummy_role_id, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_roles_success(self):
        """Test that removing a role from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.role.uuid)

        self.policyB.roles.add(self.role)
        self.policyB.save()
        self.assertCountEqual([self.role], list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.groupB.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_success(self):
        """Test that removing multiple roles from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, self.role.uuid, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_invalid(self):
        """Test that removing invalid roles from a group fails the request and does not remove any."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, 'abc123', self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_remove_group_multiple_roles_not_found_success(self):
        """Test that removing roles from a group skips ids not found, and returns success."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{},{}'.format(url, self.role.uuid, self.roleB.uuid,
                                         self.dummy_role_id)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_roles_invalid(self):
        """Test that removing a role returns an error with invalid data format."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()

        response = client.delete(url, format='json', **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemplo n.º 3
0
class GroupViewsetTests(IdentityRequest):
    """Test the group viewset."""
    def setUp(self):
        """Set up the group viewset tests."""
        super().setUp()
        request = self.request_context['request']
        user = User()
        user.username = self.user_data['username']
        user.account = self.customer_data['account_id']
        request.user = user
        self.dummy_role_id = uuid4()

        with tenant_context(self.tenant):
            self.principal = Principal(username=self.user_data['username'])
            self.principal.save()
            self.principalB = Principal(username='******')
            self.principalB.save()
            self.principalC = Principal(
                username='******')
            self.principalC.save()
            self.group = Group(name='groupA')
            self.group.save()
            self.role = Role.objects.create(name='roleA',
                                            description='A role for a group.')
            self.policy = Policy.objects.create(name='policyA',
                                                group=self.group)
            self.policy.roles.add(self.role)
            self.policy.save()
            self.group.policies.add(self.policy)
            self.group.principals.add(self.principal, self.principalB)
            self.group.save()

            self.defGroup = Group(name='groupDef',
                                  platform_default=True,
                                  system=True)
            self.defGroup.save()
            self.defGroup.principals.add(self.principal)
            self.defGroup.save()

            self.emptyGroup = Group(name='groupE')
            self.emptyGroup.save()

            self.groupB = Group.objects.create(name='groupB')
            self.groupB.principals.add(self.principal)
            self.policyB = Policy.objects.create(name='policyB',
                                                 group=self.groupB)
            self.roleB = Role.objects.create(name='roleB')
            self.policyB.roles.add(self.roleB)
            self.policyB.save()

            # role that's not assigned to principal
            self.roleOrphan = Role.objects.create(name='roleOrphan')

            # group that associates with multipal roles
            self.groupMultiRole = Group.objects.create(name='groupMultiRole')
            self.policyMultiRole = Policy.objects.create(
                name='policyMultiRole')
            self.policyMultiRole.roles.add(self.role)
            self.policyMultiRole.roles.add(self.roleB)
            self.groupMultiRole.policies.add(self.policyMultiRole)

    def tearDown(self):
        """Tear down group viewset tests."""
        with tenant_context(self.tenant):
            Group.objects.all().delete()
            Principal.objects.all().delete()
            Role.objects.all().delete()
            Policy.objects.all().delete()

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_create_group_success(self, mock_request):
        """Test that we can create a group."""
        group_name = 'groupC'
        test_data = {'name': group_name}

        # create a group
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # test that we can retrieve the group
        url = reverse('group-detail',
                      kwargs={'uuid': response.data.get('uuid')})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_default_group(self):
        """Test that system groups can be created."""
        group_name = 'groupDef'

        # test group retrieval
        client = APIClient()
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        response = client.get(url, **self.headers)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertIsNotNone(response.data.get('name'))
        self.assertTrue(response.data.get('platform_default'))
        self.assertEqual(group_name, response.data.get('name'))

    def test_create_group_invalid(self):
        """Test that creating an invalid group returns an error."""
        test_data = {}
        url = reverse('group-list')
        client = APIClient()
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_group_filter_by_any_role_name_in_a_list_success(self):
        """Test default behaviour that filter groups by any role name in a list success."""
        url = '{}?role_names={},{}'.format(reverse('group-list'), 'Rolea',
                                           'RoleB')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get('meta').get('count') == 3)

        expected_groups = [
            self.group.name, self.groupB.name, self.groupMultiRole.name
        ]
        self.assertEqual(
            expected_groups,
            [group.get('name') for group in response.data.get('data')])

    def test_group_filter_by_all_role_name_in_a_list_success(self):
        """Test that filter groups by all role names in a list success."""
        url = '{}?role_names={},{}&role_discriminator=all'.format(
            reverse('group-list'), 'Rolea', 'roleB')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertTrue(response.data.get('meta').get('count') == 1)

        expected_groups = [self.groupMultiRole.name]
        self.assertEqual(
            expected_groups,
            [group.get('name') for group in response.data.get('data')])

    def test_group_filter_with_invalid_discriminator_failure(self):
        """Test that filter groups with invalid discriminator returns failed validation."""
        url = '{}?role_names={},{}&role_discriminator=invalid'.format(
            reverse('group-list'), 'roleA', 'ROLEb')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_read_group_success(self, mock_request):
        """Test that we can read a group."""
        url = reverse('group-detail', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNotNone(response.data.get('name'))
        self.assertEqual(self.group.name, response.data.get('name'))
        self.assertEqual(len(response.data.get('roles')), 1)
        self.assertEqual(
            response.data.get('roles')[0]['uuid'], str(self.role.uuid))

    def test_read_group_invalid(self):
        """Test that reading an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_read_group_list_success(self):
        """Test that we can read a list of groups."""
        url = reverse('group-list')
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 5)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)

    def test_filter_group_list_by_uuid_success(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 1)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)

    def test_filter_group_list_by_uuid_multiple(self):
        """Test that we can filter a list of groups by uuid."""
        url = f"{reverse('group-list')}?uuid={self.group.uuid},{self.groupB.uuid}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertIsInstance(response.data.get('data'), list)
        self.assertEqual(len(response.data.get('data')), 2)

        group = response.data.get('data')[0]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.group.name)
        group = response.data.get('data')[1]
        self.assertIsNotNone(group.get('name'))
        self.assertEqual(group.get('name'), self.groupB.name)

    def test_filter_group_list_by_uuid_fail(self):
        """Test that filtering by a nonexistant uuid returns nothing."""
        url = f"{reverse('group-list')}?uuid={uuid4()}"
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        for keyname in ['meta', 'links', 'data']:
            self.assertIn(keyname, response.data)
        self.assertEqual(response.data.get('data'), [])
        self.assertEqual(len(response.data.get('data')), 0)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_update_group_success(self, mock_request):
        """Test that we can update an existing group."""
        group = Group.objects.first()
        updated_name = group.name + '_update'
        test_data = {'name': updated_name}
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        self.assertIsNotNone(response.data.get('uuid'))
        self.assertEqual(updated_name, response.data.get('name'))

    def test_update_default_group(self):
        """Test that platform_default groups are protected from updates"""
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        test_data = {'name': self.defGroup.name + '_updated'}
        client = APIClient()
        response = client.put(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_group_invalid(self):
        """Test that updating an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_group_success(self):
        """Test that we can delete an existing group."""
        group = Group.objects.first()
        url = reverse('group-detail', kwargs={'uuid': group.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # verify the group no longer exists
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_delete_default_group(self):
        """Test that platform_default groups are protected from deletion"""
        url = reverse('group-detail', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_delete_group_invalid(self):
        """Test that deleting an invalid group returns an error."""
        url = reverse('group-detail', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.delete(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_group_principals_invalid_method(self):
        """Test that using an unsupported REST method returns an error."""
        url = reverse('group-principals', kwargs={'uuid': uuid4()})
        client = APIClient()
        response = client.put(url, {}, format='json', **self.headers)
        self.assertEqual(response.status_code,
                         status.HTTP_405_METHOD_NOT_ALLOWED)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code':
            status.HTTP_500_INTERNAL_SERVER_ERROR,
            'errors': [{
                'detail': 'Unexpected error.',
                'status': status.HTTP_500_INTERNAL_SERVER_ERROR,
                'source': 'principals'
            }]
        })
    def test_add_group_principals_failure(self, mock_request):
        """Test that adding a principal to a group returns has proper response when it is failed."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code,
                         status.HTTP_500_INTERNAL_SERVER_ERROR)
        self.assertEqual(response.data[0]['detail'], 'Unexpected error.')
        self.assertEqual(response.data[0]['status'], 500)
        self.assertEqual(response.data[0]['source'], 'principals')

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_add_group_principals_success(self, mock_request):
        """Test that adding a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        new_username = uuid4()
        test_data = {
            'principals': [{
                'username': self.principal.username
            }, {
                'username': new_username
            }]
        }
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        url = reverse('group-list')
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get('meta').get('count'), 5)
        self.assertEqual(response.data.get('data')[0].get('principalCount'), 2)
        self.assertEqual(response.data.get('data')[0].get('policyCount'), None)
        self.assertEqual(response.data.get('data')[0].get('roleCount'), 1)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_get_group_principals_empty(self, mock_request):
        """Test that getting principals from an empty group returns successfully."""
        client = APIClient()
        url = reverse('group-principals',
                      kwargs={'uuid': self.emptyGroup.uuid})
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get('meta').get('count'), 0)
        self.assertEqual(response.data.get('data'), [])

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_get_group_principals_nonempty(self, mock_request):
        """Test that getting principals from a nonempty group returns successfully."""
        mock_request.return_value['data'] = [{
            'username':
            self.principal.username
        }, {
            'username':
            self.principalB.username
        }]

        client = APIClient()
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        response = client.get(url, **self.headers)

        call_args, kwargs = mock_request.call_args_list[0]
        username_arg = call_args[0]

        for username in [self.principal.username, self.principalB.username]:
            self.assertTrue(username in username_arg)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data.get('meta').get('count'), 2)
        self.assertEqual(
            response.data.get('data')[0].get('username'),
            self.principal.username)
        self.assertEqual(
            response.data.get('data')[1].get('username'),
            self.principalB.username)

    def test_remove_group_principals_success(self):
        """Test that removing a principal to a group returns successfully."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?usernames={}'.format(url, self.principal.username)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_principals_invalid(self):
        """Test that removing a principal returns an error with invalid data format."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_get_group_by_username(self, mock_request):
        """Test that getting groups for a principal returns successfully."""
        url = reverse('group-list')
        url = '{}?username={}'.format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 3)

        # User who is not added to a group explicitly will return platform default group
        url = reverse('group-list')
        url = '{}?username={}'.format(url, self.principalC.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 1)

        # Return bad request when user does not exist
        url = reverse('group-list')
        url = '{}?username={}'.format(url, uuid4())
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_get_group_by_username_with_capitalization(self):
        """Test that getting groups for a user name with capitalization returns successfully."""
        url = reverse('group-list')
        username = "".join(
            random.choice([k.upper(), k]) for k in self.principal.username)
        url = '{}?username={}'.format(url, username)
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.data.get('meta').get('count'), 3)

    def test_get_group_roles_success(self):
        """Test that getting roles for a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)

    def test_get_group_roles_with_exclude_false_success(self):
        """Test that getting roles with 'exclude=false' for a group works as default."""
        url = "%s?exclude=FALSE" % (reverse('group-roles',
                                            kwargs={'uuid': self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)

    def test_get_group_roles_with_exclude_success(self):
        """Test that getting roles with 'exclude=True' for a group returns successfully."""
        url = "%s?exclude=True" % (reverse('group-roles',
                                           kwargs={'uuid': self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertTrue(role.uuid in [self.roleB.uuid, self.roleOrphan.uuid]
                        for role in roles)

    def test_get_group_roles_with_exclude_in_principal_scope_success(self):
        """Test that getting roles with 'exclude=True' for a group in principal scope."""
        url = "%s?exclude=True&scope=principal" % (reverse(
            'group-roles', kwargs={'uuid': self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.roleB.uuid))
        self.assertEqual(roles[0].get('name'), self.roleB.name)
        self.assertEqual(roles[0].get('description'), self.roleB.description)

    def test_get_group_roles_ordered(self):
        """Test getting roles with 'order_by=' returns properly."""
        url = f"{reverse('group-roles', kwargs={'uuid': self.group.uuid})}?order_by=-name"
        client = APIClient()

        test_data = {'roles': [self.roleB.uuid]}
        response = client.post(url, test_data, format='json', **self.headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)

        response = client.get(url, **self.headers)
        roles = response.data.get('data')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('name'), self.roleB.name)
        self.assertEqual(roles[1].get('name'), self.role.name)

    def test_exclude_input_invalid(self):
        """Test that getting roles with 'exclude=' for a group returns failed validation."""
        url = "%s?exclude=sth" % (reverse('group-roles',
                                          kwargs={'uuid': self.group.uuid}))
        client = APIClient()
        response = client.get(url, **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_role_name_filter_for_group_roles_no_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_name=test'.format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_name_filter_for_group_roles_match(self):
        """Test role_name filter for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_name={}'.format(url, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))

    def test_role_description_filter_for_group_roles_no_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_description=test'.format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_role_description_filter_for_group_roles_match(self):
        """Test role_description filter for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_description={}'.format(url, self.role.description)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))

    def test_all_role_filters_for_group_roles_no_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_description=test&role_name=test'.format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 0)

    def test_all_role_filters_for_group_roles_match(self):
        """Test role filters for getting roles for a group."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        url = '{}?role_description={}&role_name={}'.format(
            url, self.role.description, self.role.name)
        client = APIClient()
        response = client.get(url, **self.headers)
        roles = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(roles), 1)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': []
        })
    def test_principal_username_filter_for_group_roles_no_match(
            self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        url = '{}?principal_username=test'.format(url)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get('data')

        mock_request.assert_called_with([], ANY, sort_order=None)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 0)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': [{
                'username': '******'
            }]
        })
    def test_principal_username_filter_for_group_roles_match(
            self, mock_request):
        """Test principal_username filter for getting principals for a group."""
        url = reverse('group-principals', kwargs={'uuid': self.group.uuid})
        url = '{}?principal_username={}'.format(url, self.principal.username)
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get('data')

        mock_request.assert_called_with([self.principal.username],
                                        ANY,
                                        sort_order=None)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': [{
                'username': '******'
            }]
        })
    def test_principal_get_ordering_username_success(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=username"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get('data')
        expected_principals = sorted(
            [self.principal.username, self.principalB.username])
        mock_request.assert_called_with(expected_principals,
                                        ANY,
                                        sort_order='asc')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(principals), 1)

    @patch(
        'management.principal.proxy.PrincipalProxy.request_filtered_principals',
        return_value={
            'status_code': 200,
            'data': [{
                'username': '******'
            }]
        })
    def test_principal_get_ordering_nonusername_fail(self, mock_request):
        """Test that passing a username order_by parameter calls the proxy correctly."""
        url = f"{reverse('group-principals', kwargs={'uuid': self.group.uuid})}?order_by=best_joke"
        client = APIClient()
        response = client.get(url, **self.headers)
        principals = response.data.get('data')

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(principals, None)

    def test_add_group_roles_system_policy_create_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([self.policy], list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_system_flag_update_on_add(self):
        """Test that adding a role to a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}

        self.assertTrue(self.defGroup.system)
        response = client.post(url, test_data, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default user access")
        self.assertFalse(self.defGroup.system)

    def test_system_flag_update_on_remove(self):
        """Test that removing a role from a platform_default group flips the system flag."""
        url = reverse('group-roles', kwargs={'uuid': self.defGroup.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()

        self.assertTrue(self.defGroup.system)
        response = client.delete(url, format='json', **self.headers)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.defGroup.refresh_from_db()
        self.assertEqual(self.defGroup.name, "Custom default user access")
        self.assertFalse(self.defGroup.system)

    def test_add_group_roles_system_policy_create_new_group_success(self):
        """Test that adding a role to a group without a system policy returns successfully."""
        group_url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        groupB_url = reverse('group-roles', kwargs={'uuid': self.groupB.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid]}

        response = client.post(group_url,
                               test_data,
                               format='json',
                               **self.headers)
        responseB = client.post(groupB_url,
                                test_data,
                                format='json',
                                **self.headers)

        system_policies = Policy.objects.filter(system=True)
        system_policy = system_policies.get(group=self.group)
        system_policyB = system_policies.get(group=self.groupB)

        self.assertEqual(len(system_policies), 2)
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.roleB], list(system_policyB.roles.all()))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(responseB.status_code, status.HTTP_200_OK)

    def test_add_group_roles_system_policy_get_success(self):
        """Test that adding a role to a group with existing system policy returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        test_data = {'roles': [self.roleB.uuid, self.dummy_role_id]}
        system_policy_name = 'System Policy for Group {}'.format(
            self.group.uuid)
        system_policy = Policy.objects.create(system=True,
                                              group=self.group,
                                              name=system_policy_name)

        self.assertCountEqual([self.role], list(self.group.roles()))
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))

        response = client.post(url, test_data, format='json', **self.headers)

        roles = response.data.get('data')
        system_policies = Policy.objects.filter(system=True, group=self.group)
        system_policy = system_policies.first()

        self.assertEqual(len(system_policies), 1)
        self.assertCountEqual([system_policy, self.policy],
                              list(self.group.policies.all()))
        self.assertCountEqual([self.roleB], list(system_policy.roles.all()))
        self.assertCountEqual([self.role], list(self.policy.roles.all()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(len(roles), 2)
        self.assertEqual(roles[0].get('uuid'), str(self.role.uuid))
        self.assertEqual(roles[0].get('name'), self.role.name)
        self.assertEqual(roles[0].get('description'), self.role.description)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_success(self):
        """Test that adding multiple roles to a group returns successfully."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.role.uuid, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.role, self.roleB],
                                  list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_add_group_multiple_roles_invalid(self):
        """Test that adding invalid roles to a group fails the request and does not add any."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': ['abc123', self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_group_multiple_roles_not_found_success(self):
        """Test that adding roles to a group skips ids not found, and returns success."""
        with tenant_context(self.tenant):
            groupC = Group.objects.create(name='groupC')
            url = reverse('group-roles', kwargs={'uuid': groupC.uuid})
            client = APIClient()
            test_data = {'roles': [self.dummy_role_id, self.roleB.uuid]}

            self.assertCountEqual([], list(groupC.roles()))

            response = client.post(url,
                                   test_data,
                                   format='json',
                                   **self.headers)

            self.assertCountEqual([self.roleB], list(groupC.roles()))
            self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_remove_group_roles_success(self):
        """Test that removing a role from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={}'.format(url, self.role.uuid)

        self.policyB.roles.add(self.role)
        self.policyB.save()
        self.assertCountEqual([self.role], list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertCountEqual([self.role, self.roleB],
                              list(self.groupB.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_success(self):
        """Test that removing multiple roles from a group returns successfully."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, self.role.uuid, self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_multiple_roles_invalid(self):
        """Test that removing invalid roles from a group fails the request and does not remove any."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{}'.format(url, 'abc123', self.roleB.uuid)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_remove_group_multiple_roles_not_found_success(self):
        """Test that removing roles from a group skips ids not found, and returns success."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()
        url = '{}?roles={},{},{}'.format(url, self.role.uuid, self.roleB.uuid,
                                         self.dummy_role_id)

        self.policy.roles.add(self.roleB)
        self.policy.save()
        self.assertCountEqual([self.role, self.roleB],
                              list(self.group.roles()))

        response = client.delete(url, format='json', **self.headers)

        self.assertCountEqual([], list(self.group.roles()))
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_remove_group_roles_invalid(self):
        """Test that removing a role returns an error with invalid data format."""
        url = reverse('group-roles', kwargs={'uuid': self.group.uuid})
        client = APIClient()

        response = client.delete(url, format='json', **self.headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_admin_RonR(self):
        """Test that a admin user can group RBAC resources"""
        url = '{}?application={}'.format(reverse('group-list'), 'rbac')
        client = APIClient()
        response = client.get(url, **self.headers)
        self.assertEqual(response.status_code, status.HTTP_200_OK)