def test_it_lists_profiles_in_slices(): profiles = SQLAlchemyProfiles(db) profiles.add(Profile('11111111', Name('Name 1'))) profiles.add(Profile('11111112', Name('Name 2'))) profiles.add(Profile('11111113', Name('Name 3'))) profiles_list = profiles.list(limit=1) assert len(profiles_list) == 1 assert str(profiles_list[0].name) == 'Name 3' profiles_list = profiles.list(offset=1) assert len(profiles_list) == 2 assert str(profiles_list[0].name) == 'Name 2' assert str(profiles_list[1].name) == 'Name 1' profiles_list = profiles.list(limit=1, offset=1) assert len(profiles_list) == 1 assert str(profiles_list[0].name) == 'Name 2' profiles_list = profiles.list(offset=10) assert len(profiles_list) == 0
def test_it_gets_profiles_by_their_email_address(): profiles = SQLAlchemyProfiles(db) profile1 = Profile('12345678', Name('name1')) profile1.add_email_address('*****@*****.**') profile1.add_email_address('*****@*****.**') profile2 = Profile('12345679', Name('name2')) profile2.add_email_address('*****@*****.**') profiles.add(profile1) profiles.add(profile2) assert profiles.get_by_email_address('*****@*****.**') == profile1 assert profiles.get_by_email_address('*****@*****.**') == profile1 assert profiles.get_by_email_address('*****@*****.**', '*****@*****.**') == profile1 assert profiles.get_by_email_address('*****@*****.**', '*****@*****.**') == profile1 assert profiles.get_by_email_address('*****@*****.**') == profile2 with pytest.raises(ProfileNotFound): profiles.get_by_email_address() with pytest.raises(ProfileNotFound): profiles.get_by_email_address('*****@*****.**') with pytest.raises(ProfileNotFound): profiles.get_by_email_address('*****@*****.**', '*****@*****.**')
def test_it_does_not_updates_the_name_if_its_missing(name): profile = Profile('12345678', Name('Old Name')) orcid_record = {'person': {'name': name}} update_profile_from_orcid_record(profile, orcid_record) assert profile.name == Name('Old Name')
def test_it_can_be_compared(): name = Name('Foo Bar') name1 = Name('Foo Bar', 'Bar, Foo') name2 = Name('Foo Bar', 'Bar, Foo') name3 = Name('Bar Foo') assert name == name1 assert name == name2 assert name != name3
def test_it_avoids_orcid_conflicts(): profiles = SQLAlchemyProfiles(db) profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097') profile2 = Profile('12345679', Name('name2'), '0000-0002-1825-0097') profile1 = profiles.add(profile1) profile2 = profiles.add(profile2) assert profile1 == profile2 with pytest.raises(ProfileNotFound): profiles.get('12345679')
def test_it_gets_profiles_by_their_orcid(): profiles = SQLAlchemyProfiles(db) profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097') profile2 = Profile('12345679', Name('name2')) profiles.add(profile1) profiles.add(profile2) assert profiles.get_by_orcid('0000-0002-1825-0097') == profile1 with pytest.raises(ProfileNotFound): profiles.get_by_orcid('0000-0002-1825-0098')
def _update_name_from_orcid_record(profile: Profile, orcid_record: dict) -> None: given_name = jmespath.search('person.name."given-names".value', orcid_record) family_name = jmespath.search('person.name."family-name".value', orcid_record) if given_name and family_name: profile.name = Name('{} {}'.format(given_name, family_name), '{}, {}'.format(family_name, given_name)) elif given_name: profile.name = Name(given_name, given_name) elif family_name: profile.name = Name(family_name, family_name)
def test_it_contains_profiles(): profiles = SQLAlchemyProfiles(db) profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097') profile2 = Profile('12345679', Name('name2')) profile1 = profiles.add(profile1) profile2 = profiles.add(profile2) assert profiles.get('12345678') == profile1 assert profiles.get('12345679') == profile2 with pytest.raises(ProfileNotFound): profiles.get('12345670')
def test_it_avoids_email_address_conflicts(): profiles = SQLAlchemyProfiles(db) profile1 = Profile('12345678', Name('name1')) profile1.add_email_address('*****@*****.**') profile2 = Profile('12345679', Name('name2')) profile2.add_email_address('*****@*****.**') profile1 = profiles.add(profile1) profile2 = profiles.add(profile2) assert profile1 == profile2 with pytest.raises(ProfileNotFound): profiles.get('12345679')
def test_it_can_get_all_affiliations_including_restricted(yesterday): address = Address(countries.get('gb'), 'City') affiliation = Affiliation('1', address=address, organisation='Org', starts=yesterday) affiliation2 = Affiliation('2', address=address, organisation='Org', starts=yesterday, restricted=True) affiliation3 = Affiliation('3', address=address, organisation='Org', starts=yesterday) profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097') profile.add_affiliation(affiliation, position=1) profile.add_affiliation(affiliation2, position=0) profile.add_affiliation(affiliation3, position=2) affiliations = profile.get_affiliations(include_restricted=True) assert len(affiliations) == 3
def test_it_does_not_return_null_values_in_response( test_client: FlaskClient, yesterday: Date, commit: Callable[[], None]) -> None: address = Address(country=countries.get('gb'), city='City', region=None) # produces null value when serialized affiliation = Affiliation( '2', address=address, organisation='Org', department=None, # produces null value when serialized starts=yesterday, restricted=False) profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097') profile.add_email_address('*****@*****.**', restricted=False) profile.add_affiliation(affiliation) db.session.add(profile) commit() headers = Headers() headers.set('X-Consumer-Groups', 'View-restricted-profiles, Something else') response = test_client.get('/profiles/a1b2c3d4', headers=headers) data = json.loads(response.data.decode('UTF-8')) assert response.status_code == 200, response.status_code assert response.headers.get( 'Content-Type') == 'application/vnd.elife.profile+json;version=1' assert validate_json(data, schema_name='profile.v1') is True assert contains_none_values(data) is False
def test_it_does_not_return_restricted_data_when_authenticated( test_client: FlaskClient, yesterday: Date, commit: Callable[[], None]) -> None: address = Address(country=countries.get('gb'), city='City', region='Region') affiliation = Affiliation('1', address=address, organisation='Org', department='Dep', starts=yesterday, restricted=True) profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097') profile.add_email_address('*****@*****.**', restricted=True) profile.add_affiliation(affiliation) db.session.add(profile) commit() response = test_client.get('/profiles/a1b2c3d4') data = json.loads(response.data.decode('UTF-8')) assert response.status_code == 200 assert response.headers.get( 'Content-Type') == 'application/vnd.elife.profile+json;version=1' assert validate_json(data, schema_name='profile.v1') is True assert not data['affiliations'] assert not data['emailAddresses']
def test_get_profile_response_contains_affiliations( test_client: FlaskClient, yesterday, commit: Callable[[], None]) -> None: address = Address(country=countries.get('gb'), city='City', region='Region') affiliation = Affiliation('1', address=address, organisation='Org', department='Dep', starts=yesterday) profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097') db.session.add(profile) profile.add_affiliation(affiliation) commit() response = test_client.get('/profiles/a1b2c3d4') data = json.loads(response.data.decode('UTF-8')) assert response.status_code == 200 assert response.headers.get( 'Content-Type') == 'application/vnd.elife.profile+json;version=1' assert validate_json(data, schema_name='profile.v1') is True assert len(data['affiliations']) == 1
def test_list_of_profiles_in_pages(test_client: FlaskClient, commit: Callable[[], None]) -> None: for number in range(1, 11): number = str(number).zfill(2) db.session.add(Profile(str(number), Name('Profile %s' % number))) commit() response = test_client.get('/profiles?page=1&per-page=5') assert response.status_code == 200 assert response.headers.get( 'Content-Type') == 'application/vnd.elife.profile-list+json;version=1' data = json.loads(response.data.decode('UTF-8')) assert validate_json(data, schema_name='profile-list.v1') is True assert data['total'] == 10 assert len(data['items']) == 5 for number in range(5, 0): assert data['items'][number - 1]['id'] == str(number).zfill(2) response = test_client.get('/profiles?page=2&per-page=5') assert response.status_code == 200 assert response.headers.get( 'Content-Type') == 'application/vnd.elife.profile-list+json;version=1' data = json.loads(response.data.decode('UTF-8')) assert validate_json(data, schema_name='profile-list.v1') is True assert data['total'] == 10 assert len(data['items']) == 5 for number in range(5, 0): assert data['items'][number - 1]['id'] == str(number + 5).zfill(2)
def test_it_updates_and_returns_204_if_a_profile_is_found( test_client: FlaskClient, webhook_payload: str, commit: Callable[[], None]) -> None: profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097') orcid_token = OrcidToken('0000-0002-1825-0097', 'access-token', expires_at(1234)) db.session.add(profile) db.session.add(orcid_token) commit() with requests_mock.Mocker() as mocker: mocker.get( 'http://www.example.com/api/v2.1/0000-0002-1825-0097/record', json={ 'person': { 'name': { 'family-name': { 'value': 'Family Name' }, 'given-names': { 'value': 'Given Names' } } } }) response = test_client.post( '/orcid-webhook/{}'.format(webhook_payload)) assert response.status_code == 204 assert profile.name.preferred == 'Given Names Family Name'
def test_it_updates_email_addresses(): profile = Profile('12345678', Name('Name')) profile.add_email_address('*****@*****.**', True, True) orcid_record = { 'person': { 'emails': { 'email': [ { 'email': '*****@*****.**', 'primary': True, 'verified': True, 'visibility': 'PUBLIC' }, ] }, } } update_profile_from_orcid_record(profile, orcid_record) assert len(profile.email_addresses) == 1 assert profile.email_addresses[0].email == '*****@*****.**' assert profile.email_addresses[0].restricted is False assert profile.email_addresses[0].position == 0
def _create_profile(token_data: dict) -> Profile: if not token_data['name']: raise InvalidRequest('No name visible') profile = Profile(profiles.next_id(), Name(token_data['name']), token_data['orcid']) return profiles.add(profile)
def test_it_clears_profiles(): profiles = SQLAlchemyProfiles(db) profiles.add(Profile('11111111', Name('name'))) profiles.clear() with pytest.raises(ProfileNotFound): profiles.get('11111111')
def test_it_can_get_only_non_restricted_email_addresses(): profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097') profile.add_email_address('*****@*****.**', restricted=True) profile.add_email_address('*****@*****.**') profile.add_email_address('*****@*****.**') assert len(profile.get_email_addresses()) == 2
def test_it_can_get_all_email_addresses_including_restricted(): profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097') profile.add_email_address('*****@*****.**', restricted=True) profile.add_email_address('*****@*****.**') profile.add_email_address('*****@*****.**') assert len(profile.get_email_addresses(include_restricted=True)) == 3
def test_it_normalizes_profile_with_single_email_address( id_, preferred, index, orcid, email): profile = Profile(id_, Name(preferred, index), orcid) profile.add_email_address(email) normalized_profile = normalize(profile) assert len(normalized_profile['emailAddresses']) == 1
def test_it_removes_email_addresses(): profile = Profile('12345678', Name('Name')) profile.add_email_address('*****@*****.**') orcid_record = {'person': {}} update_profile_from_orcid_record(profile, orcid_record) assert len(profile.email_addresses) == 0
def test_it_finds_a_profile_by_email_address_when_exchanging( test_client: FlaskClient) -> None: original_profile = Profile('a1b2c3d4', Name('Foo', 'Bar')) original_profile.add_email_address('*****@*****.**') original_profile.add_email_address('*****@*****.**') db.session.add(original_profile) db.session.commit() with requests_mock.Mocker() as mocker: mocker.post('http://www.example.com/oauth/token', json={ 'access_token': '1/fFAGRNJru1FTz70BzhT3Zg', 'expires_in': 3920, 'foo': 'bar', 'token_type': 'Bearer', 'orcid': '0000-0002-1825-0097', 'name': 'Josiah Carberry' }) mocker.get( 'http://www.example.com/api/v2.1/0000-0002-1825-0097/record', json={ 'person': { 'emails': { 'email': [ { 'email': '*****@*****.**', 'primary': True, 'verified': True, 'visibility': 'PUBLIC' }, { 'email': '*****@*****.**', 'primary': False, 'verified': True, 'visibility': 'PUBLIC' }, ] }, } }) response = test_client.post( '/oauth2/token', data={ 'client_id': 'client_id', 'client_secret': 'client_secret', 'redirect_uri': 'http://www.example.com/client/redirect', 'grant_type': 'authorization_code', 'code': '1234' }) assert Profile.query.count() == 1 assert str(original_profile.name) == 'Josiah Carberry' assert [e.email for e in original_profile.email_addresses ] == ['*****@*****.**', '*****@*****.**'] assert response.status_code == 200
def test_it_removes_affiliations(): profile = Profile('12345678', Name('Name')) profile.add_affiliation( Affiliation('1', Address(countries.get('gb'), 'City 1'), 'Organisation 1', Date(2017))) orcid_record = {} update_profile_from_orcid_record(profile, orcid_record) assert len(profile.affiliations) == 0
def test_it_lists_profiles(): profiles = SQLAlchemyProfiles(db) profiles.add(Profile('11111111', Name('Name 1'))) profiles.add(Profile('11111112', Name('Name 2'))) profiles.add(Profile('11111113', Name('Name 3'))) profiles_list = profiles.list() assert len(profiles_list) == 3 assert str(profiles_list[0].name) == 'Name 3' assert str(profiles_list[1].name) == 'Name 2' assert str(profiles_list[2].name) == 'Name 1' profiles_list = profiles.list(desc=False) assert len(profiles_list) == 3 assert str(profiles_list[0].name) == 'Name 1' assert str(profiles_list[1].name) == 'Name 2' assert str(profiles_list[2].name) == 'Name 3'
def test_it_limits_retrying_when_generating_the_next_profile_id(): def id_generator(): return '11111111' profiles = SQLAlchemyProfiles(db, id_generator) profiles.add(Profile('11111111', Name('name'))) with pytest.raises(RuntimeError): assert profiles.next_id()
def test_it_normalizes_profiles(id_, preferred, index): profile = Profile(id_, Name(preferred, index)) assert normalize(profile) == { 'id': id_, 'name': { 'preferred': preferred, 'index': index }, 'emailAddresses': [], 'affiliations': [] }
def test_it_normalizes_profile_snippets(id_, preferred, index, orcid): profile = Profile(id_, Name(preferred, index)) assert normalize_snippet(profile) == { 'id': id_, 'name': { 'preferred': preferred, 'index': index }, } profile = Profile(id_, Name(preferred, index), orcid) assert normalize_snippet(profile) == { 'id': id_, 'name': { 'preferred': preferred, 'index': index, }, 'orcid': orcid, }
def test_it_retries_generating_the_next_profile_id(): counter = 0 def id_generator(): nonlocal counter counter = counter + 1 return str(11111110 + counter) profiles = SQLAlchemyProfiles(db, id_generator) profiles.add(Profile('11111111', Name('name'))) assert profiles.next_id() == '11111112'
def test_it_normalizes_profile_with_multiple_email_addresses_with_primary_address_first( ): primary_address = '*****@*****.**' profile = Profile('12345678', Name('Foo Bar', 'Bar, Foo'), '0000-0002-1825-0097') profile.add_email_address('*****@*****.**') profile.add_email_address('*****@*****.**') profile.add_email_address(primary_address, primary=True) normalized_profile = normalize(profile) assert len(normalized_profile['emailAddresses']) == 3 assert normalized_profile['emailAddresses'][0]['value'] == primary_address