From acded28ab5874ada05c7d5a2211325e84c4ceba2 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Wed, 25 Jul 2018 16:19:04 +1000 Subject: [PATCH] Raise and exception if a candidate isn't found in the OSF directory Change-Id: Ic2bc8a3daae53e714bd77359a904f296ad6635a5 --- openstack_election/exception.py | 42 ++++++++++++++++++++++++++ openstack_election/tests/test_utils.py | 37 +++++++++++++++++++++++ openstack_election/utils.py | 5 +++ 3 files changed, 84 insertions(+) create mode 100644 openstack_election/exception.py diff --git a/openstack_election/exception.py b/openstack_election/exception.py new file mode 100644 index 00000000..c5705a24 --- /dev/null +++ b/openstack_election/exception.py @@ -0,0 +1,42 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + + +class ElectionException(Exception): + """Base Election Exception + + To correctly use this class, inherit from it and define + a 'msg_fmt' property. That msg_fmt will get printf'd + with the keyword arguments provided to the constructor. + + """ + msg_fmt = 'An unknown exception occurred.' + + def __init__(self, message=None, **kwargs): + self.kwargs = kwargs + + if not message: + message = self.msg_fmt % kwargs + + self.message = message + super(ElectionException, self).__init__(message) + + +class MemberNotFoundException(ElectionException): + msg_fmt = ('No Openstack Foundation (OSF) data found for %(email)s please ' + 'check that %(email)s is a valid email address and linked to a ' + 'valid OSF account') + pass diff --git a/openstack_election/tests/test_utils.py b/openstack_election/tests/test_utils.py index 09221069..30408266 100644 --- a/openstack_election/tests/test_utils.py +++ b/openstack_election/tests/test_utils.py @@ -14,8 +14,10 @@ from __future__ import absolute_import from __future__ import print_function from __future__ import unicode_literals +import mock import testtools +from openstack_election import exception from openstack_election.tests import fixtures as election_fixtures from openstack_election import utils @@ -45,3 +47,38 @@ class TestGerritUtils(ElectionTestCase): name = "nova" dirname = "Nova" self.assertEqual(dirname, utils.name2dir(name)) + + +class TestBuildCandidatesList(ElectionTestCase): + @mock.patch.object(utils, 'lookup_member') + @mock.patch.object(utils, 'is_tc_election', + return_value=False) + @mock.patch('os.path.exists', return_value=True) + @mock.patch('os.listdir', side_effect=[['SomeProject'], + ['invalid@example.com']]) + def test_invalid_candidate(self, mock_listdir, mock_path_exists, + mock_is_tc_election, mock_lookup_member): + mock_lookup_member.return_value = dict(data=[]) + + self.assertRaises(exception.MemberNotFoundException, + utils.build_candidates_list, + 'fake') + + @mock.patch.object(utils, 'lookup_member') + @mock.patch.object(utils, 'is_tc_election', + return_value=False) + @mock.patch('os.path.exists', return_value=True) + @mock.patch('os.listdir', side_effect=[['SomeProject'], + ['invalid@example.com']]) + def test_valid_candidate(self, mock_listdir, mock_path_exists, + mock_is_tc_election, mock_lookup_member): + + member = dict(irc='ircnick', + first_name='Avery', + last_name='Developer') + mock_lookup_member.return_value = dict(data=[member]) + + expected = dict(candidates=mock.ANY, election='fake', + projects=['SomeProject']) + observed = utils.build_candidates_list('fake') + self.assertEqual(expected, observed) diff --git a/openstack_election/utils.py b/openstack_election/utils.py index b9fb3266..ff20d349 100644 --- a/openstack_election/utils.py +++ b/openstack_election/utils.py @@ -28,6 +28,7 @@ from six.moves.urllib.parse import quote_plus from six.moves.urllib.request import urlopen from openstack_election import config +from openstack_election import exception # Library constants @@ -286,6 +287,10 @@ def build_candidates_list(election=conf['release']): filepath = os.path.join(project_prefix, candidate_file) email = get_email(filepath) member = lookup_member(email) + + if member.get('data', []) == []: + raise exception.MemberNotFoundException(email=email) + candidates_list.append( { 'url': ('%s/%s/plain/%s' %