diff --git a/setup.py b/setup.py index bac7c64cc06f5e41706aca058791bf95188db174..d63c0e78e895b0cd7aa018ac1f27becbd1fed7c4 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( long_description=open('README.md').read(), long_description_content_type='text/markdown', url='https://gitlab.developers.cam.ac.uk/uis/devops/django/ucamlookup', - version='3.0.0', + version='3.0.2', license='MIT', author='DevOps Division, University Information Services, University of Cambridge', author_email='devops@uis.cam.ac.uk', diff --git a/tox.ini b/tox.ini index 1e75cd30a57b16dc2fc7566c607d703e8d5ad3d8..9c18e2b01ac02bf4cd83baba6a89d70961a274c4 100644 --- a/tox.ini +++ b/tox.ini @@ -36,6 +36,7 @@ setenv= COVERAGE_FILE={env:TOXINI_COVERAGE_FILE:{toxinidir}/.coverage} # Additional dependencies deps= + mock coverage django111: Django>=1.11,<2.0 django20: Django>=2.0,<2.1 @@ -52,6 +53,7 @@ deps= # We specify a specific version of flake8 to avoid introducing "false" # regressions when new checks are introduced. The version of flake8 used may # be overridden via the TOXINI_FLAKE8_VERSION environment variable. + mock flake8=={env:TOXINI_FLAKE8_VERSION:3.6.0} commands= flake8 --version @@ -61,6 +63,7 @@ commands= [testenv:coverage] basepython=python3 deps= + mock coverage django # Specify the default environment. Note that tox will *always* use the testsuite diff --git a/ucamlookup/tests.py b/ucamlookup/tests.py index 29ecb4dc7119d5a49af1be13706d8c9d40b5bc65..8c1ec6e6c71c9bb1af64c9bfdf85ec3b9d12a6a8 100644 --- a/ucamlookup/tests.py +++ b/ucamlookup/tests.py @@ -2,23 +2,25 @@ import json import sys from django.contrib.auth.models import User from django.core.exceptions import ValidationError +from mock import patch, Mock + try: from django.core.urlresolvers import reverse -except Exception: +except ImportError: from django.urls import reverse from django.test import TestCase, override_settings from ucamlookup.models import LookupGroup from ucamlookup.utils import user_in_groups, get_users_from_query, return_visibleName_by_crsid, get_groups_from_query, \ return_title_by_groupid, get_group_ids_of_a_user_in_lookup, get_institutions, get_institution_name_by_id, \ - validate_crsid_list, validate_groupid_list, get_connection + validate_crsid_list, validate_groupid_list, get_connection, get_user_lookupgroups, get_users_of_a_group -class UcamLookupTests(TestCase): +class UcamLookupOptionsTests(TestCase): @override_settings(UCAMLOOKUP_HOST="mock_host", UCAMLOOKUP_PORT=80, UCAMLOOKUP_URL_BASE="/mock", UCAMLOOKUP_CHECK_CERTS=False, UCAMLOOKUP_USERNAME="mock_username", UCAMLOOKUP_PASSWORD="mock_password") - def test_optional_settins(self): + def test_optional_settings(self): conn = get_connection() self.assertEqual(conn.host, "mock_host") self.assertEqual(conn.port, 80) @@ -27,6 +29,78 @@ class UcamLookupTests(TestCase): self.assertEqual(conn.username, "mock_username") self.assertEqual(conn.password, "mock_password") + +class UcamLookupTests(TestCase): + + def setUp(self): + # fixture for group 101888 + self.mock_101888 = Mock(groupid='101888', title='CS Information Systems team') + # fixture for institution UIS + mock_uis = Mock(instid='UIS') + mock_uis.name = 'University Information Services' + # fixture for institution CL + mock_cl = Mock(instid='CL') + mock_cl.name = 'Department of Computer Science and Technology' + + # patch the lookup get_connection() + self.patcher = patch('ucamlookup.utils.get_connection') + mock_get_connection = self.patcher.start() + + # a mock result returned by invoke_method() + mock_result = Mock(error=None) + + def side_effect(_, path, path_params, __, ___): + """ + Side effect method that mocks the lookup connection's invoke_method() and returns a + mock result. + """ + try: + path = path % path_params + except KeyError: + pass + + if path == 'api/v1/person/crsid/amc203': + mock_result.person.visibleName = 'Dr Abraham Martin' + elif path == 'api/v1/person/crsid/jw35': + mock_result.person.visibleName = 'John Warbrick' + elif path == 'api/v1/person/crsid/test0001': + mock_result.person.visibleName = 'Test User 1' + elif path == 'api/v1/person/crsid/amc20311': + mock_result.person = None + elif path == 'api/v1/group/101888': + mock_result.group.title = 'CS Information Systems team' + elif path == 'api/v1/group/101923': + mock_result.group.title = 'UIS Finance team' + elif path == 'api/v1/group/203840928304982': + mock_result.group = None + elif path == 'api/v1/person/search': + mock_result.people = [ + Mock(visibleName='Dr Abraham Martin', **{'identifier.value': 'amc203'}) + ] + elif path == 'api/v1/person/crsid/test0001/insts': + mock_result.institutions = [] + elif path == 'api/v1/person/crsid/amc203/insts': + mock_result.institutions = [mock_cl] + elif path == 'api/v1/inst/all-insts': + mock_result.institutions = [mock_uis, mock_cl] + elif path == 'api/v1/inst/UIS': + mock_result.institution.name = mock_uis.name + elif path == 'api/v1/group/search': + mock_result.groups = [self.mock_101888] + elif path == 'api/v1/person/crsid/amc203/groups': + mock_result.groups = [self.mock_101888] + elif path == 'api/v1/group/101888/members': + mock_result.people = [Mock(visibleName='Dr Abraham Martin', identifier='amc203')] + else: + self.fail("%s hasn't been mocked" % path) + return mock_result + + # mock connection returned by get_connectgion() + mock_connection = Mock() + mock_connection.invoke_method.side_effect = side_effect + + mock_get_connection.return_value = mock_connection + def test_add_name_to_user_and_add_title_to_group(self): with self.assertRaises(User.DoesNotExist): User.objects.get(username="amc203") @@ -93,8 +167,15 @@ class UcamLookupTests(TestCase): def test_get_institutions_with_user(self): amc203 = User.objects.create_user(username="amc203") results = get_institutions(user=amc203) + self.assertEquals(("CL", "Department of Computer Science and Technology"), results[0]) self.assertIn(("UIS", "University Information Services"), results) + def test_get_institutions_with_non_existant_user(self): + all_institutions = get_institutions() + test0001 = User.objects.create_user(username="test0001") + results = get_institutions(user=test0001) + self.assertEqual(all_institutions, results) + def test_get_institution_name_by_id(self): result = get_institution_name_by_id(institution_id="UIS") self.assertEqual("University Information Services", result) @@ -104,11 +185,6 @@ class UcamLookupTests(TestCase): result = get_institution_name_by_id(institution_id="UIS", all_institutions=all_institutions) self.assertEqual("University Information Services", result) - test_user = User.objects.create_user(username="test0001") - results = get_institutions(user=test_user) - - self.assertEqual(all_institutions, results) - def test_views_without_login(self): response = self.client.get(reverse('ucamlookup_find_people'), {'query': 'amc203', 'searchId_u': '1'}) self.assertEqual(response.status_code, 302) @@ -190,3 +266,19 @@ class UcamLookupTests(TestCase): with self.assertRaises(ValidationError): validate_groupid_list(["kaskvdkam20e9mciasmdimadf"]) + + def test_get_user_lookupgroups(self): + amc203 = User.objects.create_user(username="amc203") + groups = get_user_lookupgroups(amc203) + # check + group = next(group for group in groups if group.lookup_id == '101888') + self.assertEqual(group.name, 'CS Information Systems team') + + def test_get_users_of_a_group(self): + users = get_users_of_a_group(self.mock_101888) + # check + user = next(user for user in users if user.username == 'amc203') + self.assertEqual(user.last_name, 'Dr Abraham Martin') + + def tearDown(self): + self.patcher.stop() diff --git a/ucamlookup/utils.py b/ucamlookup/utils.py index 45867399fe6a6cc484ee24f9fb691ec2f39a34fd..2f20b28ff9dd92dfc7e5b839ea82157decc3d07b 100644 --- a/ucamlookup/utils.py +++ b/ucamlookup/utils.py @@ -50,7 +50,6 @@ def get_groups_from_query(search_string): def return_title_by_groupid(groupid): group = GroupMethods(get_connection()).getGroup(groupid=groupid) - # TODO If a group does not exists in lookup should we allow it? if group is None: raise ValidationError("The group with id %(groupid)s does not exist in Lookup", code='invalid', params={'groupid': groupid},) @@ -103,7 +102,7 @@ def get_institutions(user=None): all_institutions = InstitutionMethods(get_connection()).allInsts(includeCancelled=False) # filter all the institutions that were created for store year students - all_institutions = list(filter(lambda institution: re.match(r'.*\d{2}$', institution.id) is None, + all_institutions = list(filter(lambda institution: re.match(r'.*\d{2}$', institution.instid) is None, all_institutions)) if user is not None: