From 243df5911dc9b608014ed93602796bdf74adc617 Mon Sep 17 00:00:00 2001 From: Ilya Shakhat Date: Fri, 25 Aug 2017 13:54:49 +0200 Subject: [PATCH] Keep only one current affiliation In OpenStackID user may specify multiple current affiliations. While it can be true, Stackalytics still need to choose only one. Keep the latest as current and update ends for all others. Change-Id: I99c3c134e4f6fab9bc252ef8f381a928fa0c88ae --- stackalytics/processor/openstackid_utils.py | 22 ++++ .../tests/unit/test_openstackid_utils.py | 102 +++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) 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)