diff --git a/stackalytics/processor/openstackid_utils.py b/stackalytics/processor/openstackid_utils.py index 93ed08368..216a9f32e 100644 --- a/stackalytics/processor/openstackid_utils.py +++ b/stackalytics/processor/openstackid_utils.py @@ -46,6 +46,27 @@ def _openstack_profile_by_email(email): Interval = collections.namedtuple('Interval', ['start', 'end', 'value']) +def _cut_open_ended_intervals(intervals): + """Keep only one open interval + + If there are multiple open intervals keep only the latest open; + cut others so they no longer intersect each other. + + :param intervals: [Interval] + :return: processed intervals: [Interval] + """ + filtered_intervals = [] + cut = 0 + for interval in reversed(intervals): + if not interval.end: + new_interval = Interval(interval.start, cut, interval.value) + filtered_intervals.append(new_interval) + cut = interval.start + else: + filtered_intervals.append(interval) + return list(reversed(filtered_intervals)) + + def _iterate_intervals(intervals, threshold=INTERVAL_GAP_THRESHOLD): """Iterate intervals and fill gaps around of them @@ -56,6 +77,7 @@ def _iterate_intervals(intervals, threshold=INTERVAL_GAP_THRESHOLD): yield Interval(0, 0, None) else: intervals.sort(key=lambda x: x.start) + intervals = _cut_open_ended_intervals(intervals) prev_start = 0 diff --git a/stackalytics/tests/unit/test_openstackid_utils.py b/stackalytics/tests/unit/test_openstackid_utils.py index a64172658..5c7f32bc8 100644 --- a/stackalytics/tests/unit/test_openstackid_utils.py +++ b/stackalytics/tests/unit/test_openstackid_utils.py @@ -23,7 +23,6 @@ USER_PROFILE = { "id": 5555, "first_name": "John", "last_name": "Smith", - "pic": "https://www.openstack.org/profile_images/members/5555", "affiliations": [ { "start_date": 1193875200, @@ -108,6 +107,53 @@ USER_PROFILE_MULTIPLE_RECORDS = { } ] } +USER_PROFILE_NO_CURRENT = { + "total": 1, + "data": [ + { + "id": 5555, + "first_name": "John", + "last_name": "Smith", + "affiliations": [ + { + "start_date": 1193875200, + "end_date": 1496188800, + "organization": { + "name": "Mirantis" + } + } + ] + } + ] +} +USER_PROFILE_MULTIPLE_CURRENT = { + "total": 1, + "data": [ + { + "id": 1111, + "first_name": "John", + "last_name": "Smith", + "affiliations": [ + { + "start_date": 1378339200, + "end_date": None, + "is_current": True, + "organization": { + "name": "NTT" + } + }, + { + "start_date": 1442880000, + "end_date": None, + "is_current": True, + "organization": { + "name": "NTT DATA" + } + } + ] + } + ] +} class TestOpenStackIDUtils(testtools.TestCase): @@ -253,3 +299,57 @@ class TestOpenStackIDUtils(testtools.TestCase): reader_mock.assert_called_once_with( ou.OSID_URI % email, session=ou._openstackid_session) self.assertEqual(expected, observed) + + @mock.patch('stackalytics.processor.utils.read_json_from_uri') + def test_user_profile_by_email_no_current(self, reader_mock): + reader_mock.return_value = USER_PROFILE_NO_CURRENT + email = 'dummy@dummy.org' + + expected = { + 'openstack_id': 5555, + 'user_name': 'John Smith', + 'emails': [email], + 'companies': [{ + 'company_name': '*independent', + 'end_date': 1193875200 + }, { + 'company_name': 'Mirantis', + 'end_date': 1496188800 + }, { + 'company_name': '*independent', + 'end_date': 0 + }] + } + + observed = ou.user_profile_by_email(email) + + reader_mock.assert_called_once_with( + ou.OSID_URI % email, session=ou._openstackid_session) + self.assertEqual(expected, observed) + + @mock.patch('stackalytics.processor.utils.read_json_from_uri') + def test_user_profile_by_email_multiple_current(self, reader_mock): + reader_mock.return_value = USER_PROFILE_MULTIPLE_CURRENT + email = 'dummy@dummy.org' + + expected = { + 'openstack_id': 1111, + 'user_name': 'John Smith', + 'emails': [email], + 'companies': [{ + 'company_name': '*independent', + 'end_date': 1378339200 + }, { + 'company_name': 'NTT', + 'end_date': 1442880000 + }, { + 'company_name': 'NTT DATA', + 'end_date': 0 + }] + } + + observed = ou.user_profile_by_email(email) + + reader_mock.assert_called_once_with( + ou.OSID_URI % email, session=ou._openstackid_session) + self.assertEqual(expected, observed)