Esempio n. 1
0
    def test_search_event(self, es_with_collector, setup_data):
        """Tests detailed event search."""
        event_name = '012345catsinspace'
        EventFactory(
            name=event_name,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'original_query': event_name,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['name'] == event_name
    def test_change_non_event_service_delivery_to_event(self):
        """Test making a non-event service delivery an event service delivery."""
        service_delivery = ServiceDeliveryFactory()
        event = EventFactory()

        url = reverse('api-v3:interaction:item', kwargs={'pk': service_delivery.pk})
        response = self.api_client.patch(
            url,
            data={
                'is_event': True,
                'event': event.pk,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['is_event'] is True
        assert response_data['event'] == {
            'id': str(event.pk),
            'name': event.name,
        }
Esempio n. 3
0
    def test_search_event_name(self, es_with_collector, setup_data):
        """Tests event_name filter."""
        event_name = '0000000000'
        EventFactory(
            name=event_name,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'name': event_name[:5],
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['name'] == event_name
Esempio n. 4
0
    def test_search_event_address_country(self, es_with_collector, setup_data):
        """Tests address_country filter."""
        country_id = constants.Country.united_states.value.id
        EventFactory(
            address_country_id=country_id,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'address_country': country_id,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['address_country']['id'] == country_id
Esempio n. 5
0
    def test_search_event_organiser(self, es_with_collector, setup_data):
        """Tests organiser filter."""
        organiser = AdviserFactory()
        EventFactory(
            organiser=organiser,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'organiser': organiser.id,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['organiser']['id'] == str(organiser.id)
Esempio n. 6
0
    def test_enable_selected_events(self):
        """Tests enable selected action."""
        events = []
        for _ in range(5):
            events.append(
                EventFactory(
                    disabled_on=now(),
                ),
            )

        ids = [event.id for event in events]

        url = reverse('admin:event_event_changelist')
        data = {
            'action': 'enable_selected',
            helpers.ACTION_CHECKBOX_NAME: ids,
        }
        response = self.client.post(url, data)

        assert response.status_code == status.HTTP_200_OK

        # Check if we get confirmation page in the response.
        assert 'Are you sure you want to enable the selected events?' in str(response.content)

        # Make sure none of selected events has been enabled.
        for event in events:
            event.refresh_from_db()
            assert event.disabled_on is not None

        # Confirm the action
        data['confirm'] = 'yes'
        response = self.client.post(url, data)
        assert response.status_code == status.HTTP_302_FOUND

        # Check if selected events have been enabled.
        for event in events:
            event.refresh_from_db()
            assert event.disabled_on is None
Esempio n. 7
0
    def test_search_event_date(self, es_with_collector, setup_data):
        """Tests start_date filter."""
        start_date = datetime.date(2017, 7, 2)
        event = EventFactory(
            start_date=start_date,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'original_query': '',
                'start_date_after': start_date,
                'start_date_before': start_date,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['id'] == str(event.id)
Esempio n. 8
0
    def test_search_event_organiser_name(self, opensearch_with_collector,
                                         setup_data):
        """Tests organiser_name filter."""
        organiser_name = '00000000 000000000'
        EventFactory(organiser=AdviserFactory(
            first_name=organiser_name.split(' ', maxsplit=1)[0],
            last_name=organiser_name.split(' ', maxsplit=1)[1],
        ), )
        opensearch_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'organiser_name': '00000',
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['organiser'][
            'name'] == organiser_name
Esempio n. 9
0
    def test_search_event_uk_region(self, es_with_collector):
        """Tests uk_region filter."""
        country_id = constants.Country.united_kingdom.value.id
        uk_region_id = constants.UKRegion.jersey.value.id
        EventFactory(
            address_country_id=country_id,
            uk_region_id=uk_region_id,
        )
        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:event')

        response = self.api_client.post(
            url,
            data={
                'uk_region': uk_region_id,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['count'] == 1
        assert len(response.data['results']) == 1
        assert response.data['results'][0]['address_country']['id'] == country_id
        assert response.data['results'][0]['uk_region']['id'] == uk_region_id
Esempio n. 10
0
    def test_permissions(self, es_with_collector, permission,
                         permission_entity, entity):
        """
        Tests model permissions enforcement in basic search.

        TODO: we should test permissions relevant to a specific search app in the tests for that
            search app, and remove this test.
        """
        user = create_test_user(permission_codenames=[permission],
                                dit_team=TeamFactory())
        api_client = self.create_api_client(user=user)

        InvestmentProjectFactory(created_by=user)
        CompanyFactory()
        ContactFactory()
        EventFactory()
        CompanyInteractionFactory()
        OrderFactory()

        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:basic')
        response = api_client.get(
            url,
            data={
                'term': '',
                'entity': entity,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert (response_data['count'] == 0) == (permission_entity != entity)

        assert len(response_data['aggregations']) == 1
        assert response_data['aggregations'][0]['entity'] == permission_entity
Esempio n. 11
0
    def test_patch_all_fields(self):
        """Test updating an event."""
        event = EventFactory()
        organiser = AdviserFactory()
        url = reverse('api-v3:event:item', kwargs={'pk': event.pk})

        request_data = {
            'name': 'Annual exhibition',
            'event_type': EventType.exhibition.value.id,
            'start_date': '2021-01-01',
            'end_date': '2021-01-02',
            'location_type': LocationType.post.value.id,
            'notes': 'Updated notes',
            'address_1': 'Annual Court Exhibition Centre',
            'address_2': 'Annual Court Lane',
            'address_town': 'Annual',
            'address_county': 'County Annual',
            'address_postcode': 'SW9 9AB',
            'address_country': Country.isle_of_man.value.id,
            'uk_region': None,
            'organiser': str(organiser.pk),
            'lead_team': Team.food_from_britain.value.id,
            'teams':
            [Team.food_from_britain.value.id, Team.healthcare_uk.value.id],
            'related_programmes': [Programme.great_challenge_fund.value.id],
            'service': Service.account_management.value.id,
        }
        response = self.api_client.patch(url, request_data)
        assert response.status_code == status.HTTP_200_OK

        response_data = _get_canonical_response_data(response)

        assert response_data == {
            'id':
            str(event.pk),
            'name':
            'Annual exhibition',
            'event_type': {
                'id': EventType.exhibition.value.id,
                'name': EventType.exhibition.value.name,
            },
            'start_date':
            '2021-01-01',
            'end_date':
            '2021-01-02',
            'location_type': {
                'id': LocationType.post.value.id,
                'name': LocationType.post.value.name,
            },
            'notes':
            'Updated notes',
            'address_1':
            'Annual Court Exhibition Centre',
            'address_2':
            'Annual Court Lane',
            'address_town':
            'Annual',
            'address_county':
            'County Annual',
            'address_postcode':
            'SW9 9AB',
            'address_country': {
                'id': Country.isle_of_man.value.id,
                'name': Country.isle_of_man.value.name,
            },
            'disabled_on':
            None,
            'uk_region':
            None,
            'organiser': {
                'id': str(organiser.pk),
                'first_name': organiser.first_name,
                'last_name': organiser.last_name,
                'name': organiser.name,
            },
            'lead_team': {
                'id': Team.food_from_britain.value.id,
                'name': Team.food_from_britain.value.name,
            },
            'teams': [
                {
                    'id': Team.healthcare_uk.value.id,
                    'name': Team.healthcare_uk.value.name,
                },
                {
                    'id': Team.food_from_britain.value.id,
                    'name': Team.food_from_britain.value.name,
                },
            ],
            'related_programmes': [{
                'id':
                Programme.great_challenge_fund.value.id,
                'name':
                Programme.great_challenge_fund.value.name,
            }],
            'service': {
                'id': Service.account_management.value.id,
                'name': Service.account_management.value.name,
            },
            'archived_documents_url_path':
            event.archived_documents_url_path,
        }
Esempio n. 12
0
def setup_data():
    """Sets up data for the tests."""
    EventFactory.create_batch(2)
Esempio n. 13
0
def test_null_event_service(api_client):
    EventFactory(service_id=None)
    run_none_type_tests(api_client)
Esempio n. 14
0
def test_null_event_location_type(api_client):
    EventFactory(location_type_id=None)
    run_none_type_tests(api_client)
Esempio n. 15
0
def test_null_event_lead_team(api_client):
    EventFactory(lead_team_id=None)
    run_none_type_tests(api_client)
Esempio n. 16
0
def test_null_event_organiser(api_client):
    EventFactory(organiser=None)
    run_none_type_tests(api_client)
Esempio n. 17
0
def test_null_event_region(api_client):
    EventFactory(uk_region_id=None)
    run_none_type_tests(api_client)
Esempio n. 18
0
def test_event_activity(api_client):
    """
    Get a list of Events and test the returned JSON is valid
    """
    start = datetime.datetime(year=2012,
                              month=7,
                              day=12,
                              hour=15,
                              minute=6,
                              second=3)
    with freeze_time(start) as frozen_datetime:
        event = EventFactory()
        frozen_datetime.tick(datetime.timedelta(seconds=1, microseconds=1))
        response = hawk.get(api_client,
                            get_url('api-v3:activity-stream:events'))

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == {
            '@context':
            'https://www.w3.org/ns/activitystreams',
            'summary':
            'Event',
            'type':
            'OrderedCollectionPage',
            'next':
            'http://testserver/v3/activity-stream/event' +
            '?cursor=2012-07-12T15%3A06%3A03.000000%2B00%3A00' +
            f'&cursor={str(event.id)}',
            'orderedItems': [
                {
                    'id': f'dit:DataHubEvent:{event.id}:Announce',
                    'type': 'Announce',
                    'published': format_date_or_datetime(event.created_on),
                    'generator': {
                        'name': 'dit:dataHub',
                        'type': 'Application'
                    },
                    'object': {
                        'id':
                        f'dit:DataHubEvent:{event.id}',
                        'type': [
                            'dit:dataHub:Event',
                        ],
                        'name':
                        event.name,
                        'dit:eventType': {
                            'name': event.event_type.name
                        },
                        'content':
                        event.notes,
                        'startTime':
                        format_date_or_datetime(event.start_date),
                        'endTime':
                        format_date_or_datetime(event.end_date),
                        'url':
                        event.get_absolute_url(),
                        'dit:locationType': {
                            'name': event.location_type.name
                        },
                        'dit:address_1':
                        event.address_1,
                        'dit:address_2':
                        event.address_2,
                        'dit:address_town':
                        event.address_town,
                        'dit:address_county':
                        event.address_county,
                        'dit:address_postcode':
                        event.address_postcode,
                        'dit:address_country': {
                            'name': event.address_country.name
                        },
                        'dit:leadTeam': {
                            'name': event.lead_team.name
                        },
                        'dit:organiser': {
                            'name': event.organiser.name
                        },
                        'dit:disabledOn':
                        event.disabled_on,
                        'dit:service': {
                            'name': event.service.name
                        },
                        'dit:archivedDocumentsUrlPath':
                        event.archived_documents_url_path,
                        'dit:ukRegion': {
                            'name': event.uk_region.name
                        },
                        'dit:teams': [
                            *[{
                                'id': f'dit:DataHubTeam:{team.pk}',
                                'type': ['Group', 'dit:Team'],
                                'name': team.name,
                            } for team in event.teams.order_by('pk')],
                        ],
                        'dit:relatedProgrammes': [
                            *[{
                                'id':
                                f'dit:DataHubEventProgramme:{programme.pk}',
                                'name': programme.name,
                            } for programme in
                              event.related_programmes.order_by('pk')],
                        ],
                        'dit:hasRelatedTradeAgreements':
                        event.has_related_trade_agreements,
                        'dit:relatedTradeAgreements': [
                            *[{
                                'id':
                                f'dit:DataHubTradeAgreement:{trade_agreement.pk}',
                                'name': trade_agreement.name,
                            } for trade_agreement in
                              event.related_trade_agreements.order_by('pk')],
                        ],
                    },
                },
            ],
        }
Esempio n. 19
0
def test_event_get_absolute_url():
    """Test that Event.get_absolute_url() returns the correct URL."""
    event = EventFactory.build()
    assert event.get_absolute_url() == (
        f'{settings.DATAHUB_FRONTEND_URL_PREFIXES["event"]}/{event.pk}')
Esempio n. 20
0
class TestInteractionCSVRowForm:
    """Tests for InteractionCSVRowForm."""
    @pytest.mark.parametrize(
        'data,errors',
        (
            # kind blank
            (
                {
                    'kind': ''
                },
                {
                    'kind': ['This field is required.']
                },
            ),
            # kind invalid
            (
                {
                    'kind': 'invalid'
                },
                {
                    'kind': [
                        'Select a valid choice. invalid is not one of the available choices.'
                    ]
                },
            ),
            # date blank
            (
                {
                    'date': ''
                },
                {
                    'date': ['This field is required.']
                },
            ),
            # invalid date
            (
                {
                    'date': '08/31/2020'
                },
                {
                    'date': ['Enter a valid date.']
                },
            ),
            # invalid contact_email
            (
                {
                    'contact_email': 'invalid'
                },
                {
                    'contact_email': ['Enter a valid email address.']
                },
            ),
            # blank adviser_1
            (
                {
                    'adviser_1': ''
                },
                {
                    'adviser_1': ['This field is required.']
                },
            ),
            # adviser_1 doesn't exist
            (
                {
                    'adviser_1': 'Non-existent adviser'
                },
                {
                    'adviser_1': [ADVISER_NOT_FOUND_MESSAGE]
                },
            ),
            # multiple matching values for adviser_1
            (
                {
                    'adviser_1':
                    lambda: AdviserFactory.create_batch(
                        2,
                        first_name='Pluto',
                        last_name='Doris',
                    )[0].name,
                },
                {
                    'adviser_1': [MULTIPLE_ADVISERS_FOUND_MESSAGE]
                },
            ),
            # adviser_1 and team_1 mismatch
            (
                {
                    'adviser_1':
                    lambda: AdviserFactory(
                        first_name='Pluto',
                        last_name='Doris',
                        dit_team__name='Team Advantage',
                    ).name,
                    'team_1':
                    lambda: TeamFactory(name='Team Disadvantage', ).name,
                },
                {
                    'adviser_1': [ADVISER_WITH_TEAM_NOT_FOUND_MESSAGE]
                },
            ),
            # adviser_2 doesn't exist
            (
                {
                    'adviser_2': 'Non-existent adviser'
                },
                {
                    'adviser_2': [ADVISER_NOT_FOUND_MESSAGE]
                },
            ),
            # multiple matching values for adviser_2
            (
                {
                    'adviser_2':
                    lambda: AdviserFactory.create_batch(
                        2,
                        first_name='Pluto',
                        last_name='Doris',
                    )[0].name,
                },
                {
                    'adviser_2': [MULTIPLE_ADVISERS_FOUND_MESSAGE]
                },
            ),
            # adviser_2 and team_2 mismatch
            (
                {
                    'adviser_2':
                    lambda: AdviserFactory(
                        first_name='Pluto',
                        last_name='Doris',
                        dit_team__name='Team Advantage',
                    ).name,
                    'team_2':
                    lambda: TeamFactory(name='Team Disadvantage', ).name,
                },
                {
                    'adviser_2': [ADVISER_WITH_TEAM_NOT_FOUND_MESSAGE]
                },
            ),
            # service doesn't exist
            (
                {
                    'service': 'Non-existent service'
                },
                {
                    'service': [
                        'Select a valid choice. That choice is not one of the available choices.',
                    ],
                },
            ),
            # service is disabled
            (
                {
                    'service': lambda: _random_service(disabled=True).name,
                },
                {
                    'service': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # Multiple matching services
            (
                {
                    'service':
                    lambda: ServiceFactory.create_batch(2, name='Duplicate')[0]
                    .name,
                },
                {
                    'service': ['There is more than one matching service.'],
                },
            ),
            # communication_channel doesn't exist
            (
                {
                    'communication_channel':
                    'Non-existent communication channel'
                },
                {
                    'communication_channel': [
                        'Select a valid choice. That choice is not one of the available choices.',
                    ],
                },
            ),
            # Multiple matching communication channels
            (
                {
                    'communication_channel':
                    lambda: CommunicationChannelFactory.create_batch(
                        2,
                        name='Duplicate',
                    )[0].name,
                },
                {
                    'communication_channel': [
                        'There is more than one matching communication channel.',
                    ],
                },
            ),
            # communication_channel is disabled
            (
                {
                    'communication_channel':
                    lambda: _random_communication_channel(disabled=True, ).
                    name,
                },
                {
                    'communication_channel': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # event_id invalid
            (
                {
                    'event_id': 'non_existent_event_id'
                },
                {
                    'event_id': [
                        "'non_existent_event_id' is not a valid UUID.",
                    ],
                },
            ),
            # event_id is for a disabled event
            (
                {
                    'event_id': lambda: str(DisabledEventFactory().pk),
                },
                {
                    'event_id': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # event_id non-existent
            (
                {
                    'event_id': '00000000-0000-0000-0000-000000000000'
                },
                {
                    'event_id': [
                        'Select a valid choice. That choice is not one of the available '
                        'choices.',
                    ],
                },
            ),
            # cannot specify event_id for an interaction
            (
                {
                    'kind': Interaction.KINDS.interaction,
                    'event_id': lambda: str(EventFactory().pk),
                },
                {
                    'event_id': [INTERACTION_CANNOT_HAVE_AN_EVENT_MESSAGE],
                },
            ),
        ),
    )
    def test_validation_errors(self, data, errors):
        """Test validation for various fields."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            **_resolve_data(data),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert form.errors == errors

    @pytest.mark.parametrize(
        'field,input_value,expected_value',
        (
            # UK date format without leading zeroes
            (
                'date',
                '1/2/2013',
                date(2013, 2, 1),
            ),
            # UK date format with leading zeroes
            (
                'date',
                '03/04/2015',
                date(2015, 4, 3),
            ),
            # ISO date format
            (
                'date',
                '2016-05-04',
                date(2016, 5, 4),
            ),
            # Subject
            (
                'subject',
                'A subject',
                'A subject',
            ),
            # Notes (trailing blank lines are stripped)
            (
                'notes',
                'Notes with\nmultiple lines\n',
                'Notes with\nmultiple lines',
            ),
        ),
    )
    def test_simple_value_cleaning(self, field, input_value, expected_value):
        """Test the conversion and cleaning of various non-relationship fields."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_value,
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == expected_value

    @pytest.mark.parametrize(
        'kind',
        (Interaction.KINDS.interaction, Interaction.KINDS.service_delivery),
    )
    @pytest.mark.parametrize(
        'field,object_creator,input_transformer',
        (
            # adviser_1 look-up (same case)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name,
            ),
            # adviser_1 look-up (case-insensitive)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name.upper(),
            ),
            # adviser_2 look-up (same case)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name,
            ),
            # adviser_2 look-up (case-insensitive)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name.upper(),
            ),
            # service look-up (same case)
            (
                'service',
                lambda: ServiceFactory(name='UNIQUE EXPORT DEAL'),
                lambda obj: obj.name,
            ),
            # service look-up (case-insensitive)
            (
                'service',
                lambda: ServiceFactory(name='UNIQUE EXPORT DEAL'),
                lambda obj: obj.name.lower(),
            ),
        ),
    )
    def test_common_relation_fields(self, kind, field, object_creator,
                                    input_transformer):
        """
        Test the looking up of values for relationship fields common to interactions and
        service deliveries.
        """
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': kind,
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == obj

    @pytest.mark.parametrize(
        'field,object_creator,input_transformer',
        (
            # communication channel look-up (same case)
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name,
            ),
            # communication channel look-up (case-insensitive)
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name.upper(),
            ),
        ),
    )
    def test_interaction_relation_fields(self, field, object_creator,
                                         input_transformer):
        """Test the looking up of values for relationship fields specific to interactions."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == obj

    @pytest.mark.parametrize(
        'field,object_creator,input_transformer,expected_value_transformer',
        (
            # communication channel should be ignored
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name,
                lambda obj: None,
            ),
            # event look-up
            (
                'event_id',
                lambda: EventFactory(),
                lambda obj: str(obj.pk),
                lambda obj: obj,
            ),
        ),
    )
    def test_service_delivery_relation_fields(
        self,
        field,
        object_creator,
        input_transformer,
        expected_value_transformer,
    ):
        """Test the looking up of values for relationship fields specific to service deliveries."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': 'service_delivery',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == expected_value_transformer(obj)

    @pytest.mark.parametrize(
        'kind',
        (Interaction.KINDS.interaction, Interaction.KINDS.service_delivery),
    )
    def test_subject_falls_back_to_service(self, kind):
        """Test that if subject is not specified, the name of the service is used instead."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        data = {
            'kind': kind,
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
        }

        form = InteractionCSVRowForm(data=data)
        assert not form.errors
        assert form.cleaned_data['subject'] == service.name