def test_mutation_start_election_group_count_responses( client, db_session, logged_in_user, election_group_baz, election_group_foo, election_foo, election_list_pref_foo, election_keys_foo): """Verify that the mutation gives correct responses when the count fails""" variables = { 'id': str(election_group_foo.id), 'electionKey': election_keys_foo['private'] } mutation = """ mutation startElectionGroupCount($id: UUID!, $electionKey: String!) { startElectionGroupCount(id: $id, electionKey: $electionKey) { success code message } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') result = execution['data']['startElectionGroupCount'] # The mutation should fail because election_foo is not closed assert (not result['success'] and result['code'] == 'cannot-count-before-all-elections-are-closed') variables = { 'id': str(election_group_foo.id), 'electionKey': election_keys_foo['public'] } execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') result = execution['data']['startElectionGroupCount'] # The mutation should fail because the wrong code is given assert (not result['success'] and result['code'] == 'invalid-election-key')
def test_query_election_result_by_id(client, db_session, election_result_foo, logged_in_user): variables = {'id': str(election_result_foo.id)} query = """ query electionResult($id: UUID!) { electionResult(id: $id) { id electionId electionGroupCountId ballots result } } """ context = get_context() execution = client.execute(query, variables=variables, context=context) assert not execution.get('error') result = execution['data']['electionResult'] assert result assert str(election_result_foo.election_id) == result['electionId'] assert str(election_result_foo.election_group_count_id ) == result['electionGroupCountId'] assert result['ballots'] == election_result_foo.ballots assert result['result'] == election_result_foo.result
def test_set_election_group_key_mutation(key, success, client, make_election_group_from_template, logged_in_user): """Test the SetElectionGroupKey mutation.""" election_group = make_election_group_from_template('set_key_test', 'uio_dean', logged_in_user) variables = {'id': str(election_group.id), 'publicKey': key} mutation = """ mutation ($id: UUID!, $publicKey: String!) { setElectionGroupKey(id: $id, publicKey: $publicKey) { success code message } } """ execution = client.execute(mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['setElectionGroupKey'] assert response['success'] == success election_group_db = ElectionGroup.query.get(election_group.id) assert (election_group_db.public_key == key) == success
def test_unpublish_election_group( db_session, client, logged_in_user, make_election_group, make_person_publisher): election_group = make_election_group('Test unpublish EG', admin=True) db_session.flush() assert election_group.published make_person_publisher(db_session, logged_in_user.person) variables = {'id': str(election_group.id)} mutation = """ mutation ($id: UUID!) { unpublishElectionGroup(id: $id) { success } } """ execution = client.execute( mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['unpublishElectionGroup'] assert response['success'] election_group_after_after = ElectionGroup.query.get(election_group.id) assert not election_group_after_after.published
def test_delete_candidate_mutation(owned_election_group, db_session, client, logged_in_user): """Test the delete candidate mutation.""" election_list = owned_election_group( db_session, logged_in_user.person).elections[0].lists[0] candidates_before = {str(x.id): x for x in election_list.candidates} candidate = election_list.candidates[0] variables = {'id': str(candidate.id)} mutation = """ mutation ($id: UUID!) { deleteCandidate(id: $id) { ok } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['deleteCandidate'] assert response['ok'] candidate_after = Candidate.query.get(candidate.id) assert candidate_after is None election_list_after = ElectionList.query.get(election_list.id) assert election_list_after is not None assert len(election_list_after.candidates) == len(candidates_before) - 1 assert candidate.id not in [x.id for x in election_list_after.candidates]
def test_vote(db_session, client, pollbook_foo, make_pollbook_voter, make_pollbook_vote, election_pref_vote, logged_in_user): """Test the vote mutation.""" voter = make_pollbook_voter(person=logged_in_user.person, pollbook=pollbook_foo) variables = { 'voterId': str(voter.id), 'ballot': json.dumps(election_pref_vote) } mutation = """ mutation ($voterId: UUID!, $ballot: JSONString!) { vote(voterId: $voterId, ballot: $ballot) { ballotId electionId ok } } """ execution = client.execute(mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['vote'] assert response['ok'] assert response['ballotId'] ballot_after = Envelope.query.get(response['ballotId']) assert ballot_after
def test_create_election_group_mutation(template_name, expected_election_nr, election_type, client, make_ou, logged_in_user): """Test the CreateNewElectionGroup mutation.""" ou = make_ou(name='Test enhet') variables = { 'ouId': str(ou.id), 'template': True, 'templateName': template_name } mutation = """ mutation ($ouId: UUID!, $template: Boolean!, $templateName: String!) { createNewElectionGroup(ouId: $ouId, template: $template, templateName: $templateName) { ok electionGroup { id announced elections { id active } ouId publicKey published type } } } """ execution = client.execute(mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['createNewElectionGroup'] assert response['ok'] election_group = response['electionGroup'] assert not election_group['announced'] assert not election_group['published'] assert election_group['ouId'] == str(ou.id) assert election_group['publicKey'] is None assert election_group['type'] == election_type assert len(election_group['elections']) == expected_election_nr for election in election_group['elections']: if election_type == 'multiple_elections': assert not election['active'] else: assert election['active'] election_group_db = ElectionGroup.query.get(election_group['id']) assert election_group_db assert not election_group_db.announced assert election_group_db.ou_id == ou.id assert not election_group_db.published
def test_pollbook_voting_report(client, logged_in_user, make_full_election): """Test the pollbook voting report.""" full_election = make_full_election('Test voting report') election_group = full_election['election_group'] pollbook = full_election['elections'][0].pollbooks[0] variables = {'id': str(election_group.id)} query = """ query electionGroup($id: UUID!) { electionGroup(id: $id) { id elections { id pollbooks { id votersWithVote { id } votersWithoutVote { id } } } } } """ execution = client.execute(query, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['electionGroup'] assert response pollbook_res = response['elections'][0]['pollbooks'][0] pollbook_voters = full_election['pollbook_voters'][pollbook_res['id']] pollbook_voters_ids = [str(x.id) for x in pollbook_voters] voters_with_vote_ids = [ str(x.voter_id) for x in full_election['votes'] if str(x.voter_id) in pollbook_voters_ids ] voters_without_vote_ids = [ str(x.id) for x in pollbook_voters if str(x.id) not in voters_with_vote_ids ] for voter in pollbook_res['votersWithVote']: assert voter['id'] in voters_with_vote_ids assert voter['id'] not in voters_without_vote_ids for voter in pollbook_res['votersWithoutVote']: assert voter['id'] not in voters_with_vote_ids assert voter['id'] in voters_without_vote_ids
def test_update_team_pref_elec_candidate_mutation( team_pref_candidates_foo, client, logged_in_user): """Test the update team pref elec candidate mutation.""" candidate_before = team_pref_candidates_foo[0] election_list = ElectionList.query.get(candidate_before.list_id) variables = { 'id': str(candidate_before.id), 'name': 'Foo Bar', 'coCandidates': [{'name': 'Bar Baz'}, {'name': 'Jane Doe'}], 'listId': str(candidate_before.list_id) } mutation = """ mutation ( $id: UUID! $name: String! $coCandidates: [CoCandidatesInput]! $listId: UUID! ) { updateTeamPrefElecCandidate( id: $id name: $name coCandidates: $coCandidates listId: $listId ) { ok } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['updateTeamPrefElecCandidate'] assert response['ok'] # Get new election list election_list_after = ElectionList.query.get(election_list.id) assert election_list_after is not None assert len(election_list_after.candidates) == len( election_list.candidates) candidate_after = Candidate.query.get(candidate_before.id) assert candidate_after.list_id == candidate_before.list_id assert candidate_after.name != candidate_before.name assert candidate_after.name == variables['name'] assert candidate_after.meta['co_candidates'] != ( candidate_before.meta['coCandidates']) assert candidate_after.meta['co_candidates'] == variables['coCandidates']
def test_update_pref_elec_candidate_mutation(pref_candidates_foo, client, logged_in_user): """Test the update pref elec candidate mutation.""" candidate_before = pref_candidates_foo[0] election_list = ElectionList.query.get(candidate_before.list_id) variables = { 'id': str(candidate_before.id), 'name': 'FooBar', 'gender': 'Female' if candidate_before.meta['gender'] == 'Male' else 'Female', 'listId': str(candidate_before.list_id) } mutation = """ mutation ( $id: UUID! $name: String! $gender: String! $listId: UUID! ) { updatePrefElecCandidate( id: $id name: $name gender: $gender listId: $listId ) { ok } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['updatePrefElecCandidate'] assert response['ok'] # Get new election list election_list_after = ElectionList.query.get(candidate_before.list.id) assert election_list_after is not None assert len(election_list_after.candidates) == len( election_list.candidates) candidate_after = Candidate.query.get(candidate_before.id) assert candidate_after.list_id == candidate_before.list_id assert candidate_after.name != candidate_before.name assert candidate_after.name == variables['name'] assert candidate_after.meta['gender'] != candidate_before.meta['gender'] assert candidate_after.meta['gender'] == variables['gender']
def test_add_team_pref_elec_candidate_mutation(owned_multiple_election_group, db_session, client, logged_in_user): """Test the add pref elec candidate mutation.""" election_list = owned_multiple_election_group( db_session, logged_in_user.person).elections[0].lists[0] candidates_before = {str(x.id): x for x in election_list.candidates} variables = { 'name': 'Foo Bar', 'coCandidates': [{'name': 'Bar Baz'}, {'name': 'Jane Doe'}], 'listId': str(election_list.id) } mutation = """ mutation ( $name: String! $coCandidates: [CoCandidatesInput]! $listId: UUID! ) { addTeamPrefElecCandidate( name: $name coCandidates: $coCandidates listId: $listId ) { ok } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['addTeamPrefElecCandidate'] assert response['ok'] # Get new election list election_list_after = ElectionList.query.get(election_list.id) assert election_list_after is not None assert len(election_list_after.candidates) == len( candidates_before) + 1 for candidate in election_list_after.candidates: if str(candidate.id) not in candidates_before: assert candidate.name == variables['name'] assert str(candidate.list_id) == variables['listId'] assert candidate.meta['co_candidates'] == variables['coCandidates'] break
def test_add_election_admin_by_identifier_validates_role_type( db_session, election_group_foo, logged_in_user, client): """ Ensure addElectionGroupRoleByIdentifier validates the role field. """ variables = { 'electionGroupId': str(election_group_foo.id), 'role': 'bogus', 'idType': 'feide_id', 'idValue': '*****@*****.**', } execution = client.execute(add_election_group_role_by_identifier_mutation, variables=variables, context=get_context()) error_message = 'Expected type "ElectionGroupRoleType", found "bogus"' assert any( [error_message in x.get('message', '') for x in execution['errors']])
def test_add_election_admin_when_election_group_does_not_exist( db_session, election_group_foo, logged_in_user, client): """ Ensure addElectionGroupRoleByIdentifier fails gracefully when the election group does not exist. """ variables = { 'electionGroupId': str(uuid.uuid4()), 'role': 'admin', 'idType': PersonIdType('feide_id').value, 'idValue': '*****@*****.**', } execution = client.execute(add_election_group_role_by_identifier_mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['addElectionGroupRoleByIdentifier'] assert response['success'] is False assert response['code'] == 'election-group-not-found'
def test_query_election_group_count_by_id(client, election_group_count_foo, logged_in_user): variables = {'id': str(election_group_count_foo.id)} query = """ query electionGroupCount($id: UUID!) { electionGroupCount(id: $id) { id groupId electionGroup { id } } } """ context = get_context() execution = client.execute(query, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['electionGroupCount'] assert str(election_group_count_foo.id) == response['id'] assert str(election_group_count_foo.group_id) == response['groupId']
def test_add_election_admin_by_identifier_denies(db_session, election_group_baz, logged_in_user, client): """ Ensure addElectionGroupRoleByIdentifier disallows adding new roles if the current user is not an admin for the election. """ variables = { 'electionGroupId': str(election_group_baz.id), 'role': 'admin', 'idType': PersonIdType('feide_id').value, 'idValue': '*****@*****.**', } execution = client.execute(add_election_group_role_by_identifier_mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['addElectionGroupRoleByIdentifier'] assert response['success'] is False assert response['code'] == 'permission-denied'
def test_remove_election_group_role_by_grant(db_session, election_group_foo, logged_in_user, client): """ Ensure removeElectionGroupRoleByGrant removes the specified role grant. """ # Give the logged in user a role admin_principal = evalg.proc.authz.get_or_create_principal( session=db_session, principal_type='person', person_id=logged_in_user.person.id, ) evalg.proc.authz.add_election_group_role( session=db_session, election_group=election_group_foo, principal=admin_principal, role_name='admin', ) # Create a role to be removed principal = evalg.proc.authz.get_or_create_principal( session=db_session, principal_type='person_identifier', id_type='feide_id', id_value='*****@*****.**', ) role_to_be_removed = evalg.proc.authz.add_election_group_role( session=db_session, election_group=election_group_foo, principal=principal, role_name='admin') grant_id = str(role_to_be_removed.grant_id) variables = { 'grantId': grant_id, } execution = client.execute(remove_election_group_role_by_grant_mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['removeElectionGroupRoleByGrant'] assert response['success'] is True assert response['code'] == 'role-removed' assert evalg.proc.authz.get_role_by_grant_id(db_session, grant_id) is None
def test_add_election_admin_by_identifier(db_session, election_group_foo, logged_in_user, client): """ Ensure the addElectionGroupRoleByIdentifier mutation allows adding new admins if the current user is an admin for the election. """ variables = { 'electionGroupId': str(election_group_foo.id), 'role': 'admin', 'idType': PersonIdType('feide_id').value, 'idValue': '*****@*****.**', } # Give the logged in user a role principal = evalg.proc.authz.get_or_create_principal( session=db_session, principal_type='person', person_id=logged_in_user.person.id, ) evalg.proc.authz.add_election_group_role( session=db_session, election_group=election_group_foo, principal=principal, role_name='admin', ) execution = client.execute(add_election_group_role_by_identifier_mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['addElectionGroupRoleByIdentifier'] assert response['success'] is True assert response['code'] == 'role-added' # Make sure the created principal exists created_principal = evalg.database.query.lookup( db_session, PersonIdentifierPrincipal, id_type='feide_id', id_value='*****@*****.**') assert any([ x.group == election_group_foo and x.name == 'admin' for x in created_principal.roles ])
def test_query_electiongroup_by_id(make_election_group, client, logged_in_user): election_group = make_election_group('Test query EG by id') variables = {'id': str(election_group.id)} query = """ query electionGroup($id: UUID!) { electionGroup(id: $id) { id name description } } """ execution = client.execute( query, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['electionGroup'] assert str(election_group.id) == response['id'] assert election_group.name == response['name'] assert election_group.description == response['description']
def test_vote_denied(db_session, client, election_pref_vote, pollbook_voter_bar, logged_in_user): variables = { 'voterId': str(pollbook_voter_bar.id), 'ballot': json.dumps(election_pref_vote) } mutation = """ mutation ($voterId: UUID!, $ballot: JSONString!) { vote(voterId: $voterId, ballot: $ballot) { ballotId electionId ok } } """ execution = client.execute(mutation, variables=variables, context=get_context()) assert not execution.get('errors') response = execution['data']['vote'] assert response['ok'] is False
def test_mutation_start_election_group_count( client, db_session, logged_in_user, pref_candidates_bar, pollbook_voter_bar, election_group_bar, election_bar, pollbook_bar, election_list_pref_bar, election_keys_foo): variables = { 'id': str(election_group_bar.id), 'electionKey': election_keys_foo['private'] } mutation = """ mutation startElectionGroupCount($id: UUID!, $electionKey: String!) { startElectionGroupCount(id: $id, electionKey: $electionKey) { success code message } } """ context = get_context() execution = client.execute(mutation, variables=variables, context=context) assert not execution.get('errors') result = execution['data']['startElectionGroupCount'] print(result) assert result['success']
def test_query_election_group_counting_results(client, db_session, logged_in_user, election_group_count_foo): variables = {'id': str(election_group_count_foo.group_id)} query = """ query electionGroupCountingResults($id: UUID!) { electionGroupCountingResults(id: $id) { id groupId electionGroup { id } } } """ context = get_context() execution = client.execute(query, variables=variables, context=context) assert not execution.get('errors') response = execution['data']['electionGroupCountingResults'] assert len(response) == 1 assert str(election_group_count_foo.id) == response[0]['id'] assert str(election_group_count_foo.group_id) == response[0]['groupId']
def test_query_master_keys(client, db_session, master_key): """Tests the master_keys query""" privkey, master_key = master_key(db_session) query = """ query masterKeys { masterKeys { id publicKey description active } } """ execution = client.execute(query, variables={}, context=get_context()) assert not execution.get('errors') assert len(execution['data']['masterKeys']) == 1 master_key_data = execution['data']['masterKeys'][0] assert master_key_data['publicKey'] == master_key.public_key assert (privkey.public_key.encode( nacl.encoding.Base64Encoder).decode() == master_key_data['publicKey']) assert master_key_data['description'] == 'Master key for testing' assert master_key_data['active'] is True # change / remove the next case in case of new and different key-length assert master_key.public_key[-1] == '='
def test_mutation_add_election_group_key_backup(client, db_session, make_election_group, master_key): """Tests the add_election_group_key_backup mutation""" privkey, master_key = master_key(db_session) election_group = make_election_group('add_election_group_key_backup test', admin=True) mutation = """ mutation ( $electionGroupId: UUID! $encryptedPrivKey: String! $masterKeyId: UUID! ) { addElectionGroupKeyBackup( electionGroupId: $electionGroupId encryptedPrivKey: $encryptedPrivKey masterKeyId: $masterKeyId ) { success } } """ # could put any str, but let's do things properly... new_priv_key = nacl.public.PrivateKey.generate() message = 'privkey: '.encode() + new_priv_key.encode( encoder=nacl.encoding.Base64Encoder) ebox = nacl.public.Box(new_priv_key, privkey.public_key) encrypted_priv_key = ebox.encrypt(message, encoder=nacl.encoding.Base64Encoder) execution = client.execute(mutation, variables={ 'electionGroupId': str(election_group.id), 'encryptedPrivKey': encrypted_priv_key.decode(), 'masterKeyId': str(master_key.id) }, context=get_context()) assert not execution.get('errors') response = execution['data']['addElectionGroupKeyBackup'] assert response['success'] key_backups = ElectionGroupKeyBackup.query.filter_by( election_group_id=election_group.id, master_key_id=master_key.id, active=True).all() assert len(key_backups) == 1 assert isinstance(key_backups[0].encrypted_priv_key, str) dbox = nacl.public.Box(privkey, new_priv_key.public_key) assert (dbox.decrypt(key_backups[0].encrypted_priv_key, encoder=nacl.encoding.Base64Encoder) == message) # now create a new key and see if the previous backup will be invalidated new_priv_key = nacl.public.PrivateKey.generate() message = 'privkey: '.encode() + new_priv_key.encode( encoder=nacl.encoding.Base64Encoder) ebox = nacl.public.Box(new_priv_key, privkey.public_key) encrypted_priv_key = ebox.encrypt(message, encoder=nacl.encoding.Base64Encoder) execution = client.execute(mutation, variables={ 'electionGroupId': str(election_group.id), 'encryptedPrivKey': encrypted_priv_key.decode(), 'masterKeyId': str(master_key.id) }, context=get_context()) assert not execution.get('errors') response = execution['data']['addElectionGroupKeyBackup'] assert response['success'] key_backups = ElectionGroupKeyBackup.query.filter_by( election_group_id=election_group.id, master_key_id=master_key.id) # 2 backups and only 1 active assert key_backups.count() == 2 assert key_backups.filter_by(active=True).count() == 1