diff --git a/SAS/TMSS/test/t_permissions.py b/SAS/TMSS/test/t_permissions.py new file mode 100755 index 0000000000000000000000000000000000000000..1ccfe0fd7a3839cd51c169ce7db34ef18eb9d2e5 --- /dev/null +++ b/SAS/TMSS/test/t_permissions.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2018 ASTRON (Netherlands Institute for Radio Astronomy) +# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +# +# This file is part of the LOFAR software suite. +# The LOFAR software suite is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# The LOFAR software suite is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. + +# $Id: $ + + +# This functional test talks to the API like a regular user would. +# It is supposed to cover all REST http methods for all ViewSets. +# I am still a bit under the impression that we re-test Django functionality that we can expect to just work +# with some of these tests. On the other hand a lot of these provide us a nice basis for differentiating out +# behavior in a controlled way. +# We should probably also fully test behavior wrt mandatory and nullable fields. + +from datetime import datetime +import unittest +import logging +logger = logging.getLogger(__name__) +logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) + +from lofar.common.test_utils import skip_integration_tests +if skip_integration_tests(): + exit(3) + +# Do Mandatory setup step: +# use setup/teardown magic for tmss test database, ldap server and django server +# (ignore pycharm unused import statement, python unittests does use at RunTime the tmss_test_environment_unittest_setup module) +from lofar.sas.tmss.test.tmss_test_environment_unittest_setup import * +from lofar.sas.tmss.test.tmss_test_data_django_models import * +from lofar.sas.tmss.tmss.tmssapp import models +from lofar.sas.tmss.test.test_utils import assertUrlList + + +# import and setup test data creator +from lofar.sas.tmss.test.tmss_test_data_rest import TMSSRESTTestDataCreator +test_data_creator = TMSSRESTTestDataCreator(BASE_URL, AUTH) + +from django.test import TestCase + +class ProjectPermissionTestCase(TestCase): + + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + + # create projects with magic names for which permission exists (or which have no whitelisted generic name) + cls.project_pi_url = test_data_creator.post_data_and_get_url(test_data_creator.Project(name='test_user_is_pi'), '/project/') + cls.project_contact_url = test_data_creator.post_data_and_get_url(test_data_creator.Project(name='test_user_is_contact'), '/project/') + cls.project_forbidden_url = test_data_creator.post_data_and_get_url(test_data_creator.Project(name='forbidden'), '/project/') + + cls.task_template_url = test_data_creator.post_data_and_get_url(test_data_creator.TaskTemplate(), '/task_template/') + + # user is pi + cls.scheduling_set_pi_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingSet(project_url=cls.project_pi_url), '/scheduling_set/') + cls.scheduling_unit_draft_pi_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingUnitDraft(scheduling_set_url=cls.scheduling_set_pi_url), '/scheduling_unit_draft/') + + # user is contact + cls.scheduling_set_contact_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingSet(project_url=cls.project_contact_url), '/scheduling_set/') + cls.scheduling_unit_draft_contact_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingUnitDraft(scheduling_set_url=cls.scheduling_set_contact_url), '/scheduling_unit_draft/') + + # user has no role + cls.scheduling_set_forbidden_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingSet(project_url=cls.project_forbidden_url), '/scheduling_set/') + cls.scheduling_unit_draft_forbidden_url = test_data_creator.post_data_and_get_url(test_data_creator.SchedulingUnitDraft(scheduling_set_url=cls.scheduling_set_contact_url), '/scheduling_unit_draft/') + + # TaskDraft + + def test_task_draft_GET_works_if_user_has_permission_for_related_project(self): + # create task draft connected to project where we have PI role + taskdraft_test_data = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_pi_url, template_url=self.task_template_url) + taskdraft_url = POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data, 201, taskdraft_test_data)['url'] + + # make sure we can access it + GET_and_assert_equal_expected_code(self, taskdraft_url, 200) + + def test_task_draft_GET_raises_error_if_user_has_no_permission_for_related_project(self): + # create task draft connected to project where we have no role + taskdraft_test_data = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_forbidden_url, template_url=self.task_template_url) + taskdraft_url = POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data, 201, taskdraft_test_data)['url'] + + # make sure we cannot access it + GET_and_assert_equal_expected_code(self, taskdraft_url, 403) + + def test_task_draft_GET_raises_error_if_user_has_permission_for_related_project_but_with_wrong_role(self): + # create task draft connected to project where we have Contact Author role (Task Draft access requires role 'PI') + taskdraft_test_data = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_contact_url, template_url=self.task_template_url) + taskdraft_url = POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data, 201, taskdraft_test_data)['url'] + + # make sure we cannot access it + GET_and_assert_equal_expected_code(self, taskdraft_url, 403) + + def test_GET_task_draft_list_returns_filtered_list_reflecting_user_permission_for_related_projects(self): + nbr_results = GET_and_assert_equal_expected_code(self, BASE_URL + '/task_draft/', 200)["count"] # note: this does not guarantee the correct number with permission-based filtering: nbr_results = models.TaskDraft.objects.count() + + # create task draft connected to project where we have PI role + taskdraft_test_data_pi = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_pi_url, template_url=self.task_template_url) + POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data_pi, 201, taskdraft_test_data_pi) + + # create task draft connected to project where we have unsufficient contact role + taskdraft_test_data_contact = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_contact_url, template_url=self.task_template_url) + POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data_contact, 201, taskdraft_test_data_contact) + + # create task draft connected to project where we have no role + taskdraft_test_data_forbidden = test_data_creator.TaskDraft(scheduling_unit_draft_url=self.scheduling_unit_draft_contact_url, template_url=self.task_template_url) + POST_and_assert_expected_response(self, BASE_URL + '/task_draft/', taskdraft_test_data_forbidden, 201, taskdraft_test_data_forbidden) + + # make sure the list contains only the one more item we have permission for + GET_and_assert_in_expected_response_result_list(self, BASE_URL + '/task_draft/', taskdraft_test_data_pi, nbr_results + 1) + + # todo: add tests for other models with project permissions + +if __name__ == "__main__": + logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', + level=logging.INFO) + unittest.main() + diff --git a/SAS/TMSS/test/t_permissions.run b/SAS/TMSS/test/t_permissions.run new file mode 100755 index 0000000000000000000000000000000000000000..4adc6f4186ebd66e1d329c4a174dcbaf05a4754f --- /dev/null +++ b/SAS/TMSS/test/t_permissions.run @@ -0,0 +1,6 @@ +#!/bin/bash + +# Run the unit test +source python-coverage.sh +python_coverage_test "*tmss*" t_permissions.py + diff --git a/SAS/TMSS/test/t_permissions.sh b/SAS/TMSS/test/t_permissions.sh new file mode 100755 index 0000000000000000000000000000000000000000..c66d4e64d5c2a8d5494146563785bd567baf23c0 --- /dev/null +++ b/SAS/TMSS/test/t_permissions.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./runctest.sh t_permissions \ No newline at end of file