Commit 493a638c authored by Stephane Glondu's avatar Stephane Glondu

New test scenario: one NH question + shuffle

parent 757b84ee
Pipeline #82946 passed with stages
in 19 minutes and 20 seconds
...@@ -64,6 +64,8 @@ build_and_run_automated_test_scenarios_with_preinstalled_image: ...@@ -64,6 +64,8 @@ build_and_run_automated_test_scenarios_with_preinstalled_image:
- source venv/bin/activate - source venv/bin/activate
# Install pip packages # Install pip packages
- pip install -r requirements.txt - pip install -r requirements.txt
# Run the automated test scenario 3
- python3 ./tests/test_scenario_3.py
# Run the automated test scenario 2 # Run the automated test scenario 2
- python3 ./tests/test_scenario_2.py - python3 ./tests/test_scenario_2.py
# Run the automated test scenario 1 # Run the automated test scenario 1
......
...@@ -80,6 +80,7 @@ let appendStdQuestion div num_questions i q answers = ...@@ -80,6 +80,7 @@ let appendStdQuestion div num_questions i q answers =
in in
let () = let () =
let choices = Dom_html.createDiv document in let choices = Dom_html.createDiv document in
choices##.className := Js.string "answer_div";
let choices_divs = Array.mapi (fun i a -> let choices_divs = Array.mapi (fun i a ->
let div = Dom_html.createDiv document in let div = Dom_html.createDiv document in
let checkbox = Dom_html.createInput ~_type:(Js.string "checkbox") document in let checkbox = Dom_html.createInput ~_type:(Js.string "checkbox") document in
...@@ -147,6 +148,7 @@ let appendOpenQuestion div q answers = ...@@ -147,6 +148,7 @@ let appendOpenQuestion div q answers =
in in
let () = let () =
let choices = Dom_html.createDiv document in let choices = Dom_html.createDiv document in
choices##.className := Js.string "answer_div";
let choices_divs = Array.mapi (fun i a -> let choices_divs = Array.mapi (fun i a ->
let div = Dom_html.createDiv document in let div = Dom_html.createDiv document in
let input = Dom_html.createInput document in let input = Dom_html.createInput document in
......
...@@ -201,6 +201,7 @@ let rec createQuestionDiv question answers props = ...@@ -201,6 +201,7 @@ let rec createQuestionDiv question answers props =
let x = Dom_html.createDiv document in let x = Dom_html.createDiv document in
Dom.appendChild container x; Dom.appendChild container x;
let cb_type = Dom_html.createInput ~_type:(Js.string "checkbox") document in let cb_type = Dom_html.createInput ~_type:(Js.string "checkbox") document in
cb_type##.className := Js.string "homomorphic_tally";
(match props with (match props with
| Some _ -> | Some _ ->
Dom.appendChild container prop_div_h; Dom.appendChild container prop_div_h;
......
...@@ -1976,7 +1976,7 @@ let election_admin election metadata state get_tokens_decrypt () = ...@@ -1976,7 +1976,7 @@ let election_admin election metadata state get_tokens_decrypt () =
div [ div [
div [ div [
pcdata "The ballots are being shuffled. "; pcdata "The ballots are being shuffled. ";
a ~service:election_shuffle_link [ a ~service:election_shuffle_link ~a:[a_id "shuffle-link"] [
pcdata "Shuffle link"; pcdata "Shuffle link";
] (uuid, token); ] (uuid, token);
pcdata "."; pcdata ".";
......
...@@ -10,7 +10,7 @@ FAKE_SENDMAIL_EXECUTABLE_FILE_PATH_RELATIVE_TO_GIT_REPOSITORY = "tests/tools/sen ...@@ -10,7 +10,7 @@ FAKE_SENDMAIL_EXECUTABLE_FILE_PATH_RELATIVE_TO_GIT_REPOSITORY = "tests/tools/sen
SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH = "/tmp/sendmail_fake" SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH = "/tmp/sendmail_fake"
USE_HEADLESS_BROWSER = True # Set this to True if you run this test in Continuous Integration (it has no graphical display) USE_HEADLESS_BROWSER = True # Set this to True if you run this test in Continuous Integration (it has no graphical display)
WAIT_TIME_BETWEEN_EACH_STEP = 0 # In seconds (float). Time we wait between each action that we tell Selenium driver to do in the browser. Set to 0 if you don't need to have the time to visually follow progress of actions in the browser WAIT_TIME_BETWEEN_EACH_STEP = 0 # In seconds (float). Time we wait between each action that we tell Selenium driver to do in the browser. Set to 0 if you don't need to have the time to visually follow progress of actions in the browser
EXPLICIT_WAIT_TIMEOUT = 10 # In seconds. Maximum duration Selenium driver will wait for appearance of a specific DOM element expected in the page (for example when transitioning from a page to another). This referes to Selenium's "Explicit Wait" concept EXPLICIT_WAIT_TIMEOUT = 30 # In seconds. Maximum duration Selenium driver will wait for appearance of a specific DOM element expected in the page (for example when transitioning from a page to another). This referes to Selenium's "Explicit Wait" concept
NUMBER_OF_INVITED_VOTERS = 20 # This is N in description of Scenario 1. N is between 6 (quick test) and 1000 (load testing) NUMBER_OF_INVITED_VOTERS = 20 # This is N in description of Scenario 1. N is between 6 (quick test) and 1000 (load testing)
NUMBER_OF_VOTING_VOTERS = 10 # This is K in description of Scenario 1. K is between 6 (quick test) and 1000 (load testing). K <= N. (Some invited voters don't vote, this is abstention, and its value is N - K) NUMBER_OF_VOTING_VOTERS = 10 # This is K in description of Scenario 1. K is between 6 (quick test) and 1000 (load testing). K <= N. (Some invited voters don't vote, this is abstention, and its value is N - K)
...@@ -28,4 +28,4 @@ GIT_REPOSITORY_ABSOLUTE_PATH = dirname(dirname(abspath(__file__))) ...@@ -28,4 +28,4 @@ GIT_REPOSITORY_ABSOLUTE_PATH = dirname(dirname(abspath(__file__)))
BROWSER_DOWNLOAD_FOLDER = "/tmp" BROWSER_DOWNLOAD_FOLDER = "/tmp"
ADMINISTRATOR_EMAIL_ADDRESS = "alice_aka_election_administrator@mailinator.com" ADMINISTRATOR_EMAIL_ADDRESS = "alice_aka_election_administrator@mailinator.com"
CREDENTIAL_AUTHORITY_EMAIL_ADDRESS = "cecily_aka_election_credential_authority@mailinator.com" CREDENTIAL_AUTHORITY_EMAIL_ADDRESS = "cecily_aka_election_credential_authority@mailinator.com"
TRUSTEES_EMAIL_ADDRESSES = ["tom_aka_trustee_1@mailinator.com", "taylor_aka_trustee_2@mailinator.com"] TRUSTEES_EMAIL_ADDRESSES = ["tom_aka_trustee_1@mailinator.com", "taylor_aka_trustee_2@mailinator.com"]
\ No newline at end of file
#!/usr/bin/python
# coding: utf-8
import unittest
import random
import os
import sys
from distutils.util import strtobool
from util.fake_sent_emails_manager import FakeSentEmailsManager
from util.selenium_tools import wait_for_element_exists, wait_for_an_element_with_partial_link_text_exists, wait_for_element_exists_and_has_non_empty_attribute, wait_for_element_exists_and_contains_expected_text
from util.election_testing import console_log, remove_database_folder, wait_a_bit, build_css_selector_to_find_buttons_in_page_content_by_value, initialize_server, initialize_browser, verify_election_consistency, create_election_data_snapshot, delete_election_data_snapshot, log_in_as_administrator
from util.election_test_base import BeleniosElectionTestBase
import settings
class BeleniosTestElectionScenario1(BeleniosElectionTestBase):
def setUp(self):
self.fake_sent_emails_manager = FakeSentEmailsManager(settings.SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH)
self.fake_sent_emails_manager.install_fake_sendmail_log_file()
remove_database_folder()
self.server = initialize_server()
self.browser = initialize_browser()
def tearDown(self):
self.browser.quit()
self.server.kill()
remove_database_folder()
self.fake_sent_emails_manager.uninstall_fake_sendmail_log_file()
def administrator_does_tallying_of_election(self):
browser = self.browser
# Alice goes to the election page
election_url = self.election_page_url # Could also be obtained with self.voters_data[self.voters_email_addresses[0]]["election_page_url"]
browser.get(election_url)
wait_a_bit()
# She clicks on the "Administer this election" link
administration_link_label = "Administer this election"
administration_link_element = wait_for_an_element_with_partial_link_text_exists(browser, administration_link_label, settings.EXPLICIT_WAIT_TIMEOUT)
administration_link_element.click()
# She logs in as administrator
log_in_as_administrator(browser, from_a_login_page=True)
wait_a_bit()
# She clicks on the "Close election" button
close_election_button_label = "Close election"
close_election_button_css_selector = build_css_selector_to_find_buttons_in_page_content_by_value(close_election_button_label)
close_election_button_element = wait_for_element_exists(browser, close_election_button_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
close_election_button_element.click()
wait_a_bit()
# She clicks on the "Proceed to vote counting" button
proceed_button_label = "Proceed to vote counting"
proceed_button_css_selector = build_css_selector_to_find_buttons_in_page_content_by_value(proceed_button_label)
proceed_button_element = wait_for_element_exists(browser, proceed_button_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
proceed_button_element.click()
wait_a_bit()
# She clicks on the "Shuffle link" link
shuffle_element = wait_for_element_exists(browser, "#shuffle-link", settings.EXPLICIT_WAIT_TIMEOUT)
shuffle_element.click()
wait_a_bit()
# She waits for the "shuffle" textarea to be filled
wait_for_element_exists_and_has_non_empty_attribute(browser, "#shuffle", "value", settings.EXPLICIT_WAIT_TIMEOUT)
# She clicks on the "Submit" button
submit_element = wait_for_element_exists(browser, "input", settings.EXPLICIT_WAIT_TIMEOUT)
submit_element.click()
wait_a_bit()
wait_for_element_exists_and_contains_expected_text(browser, "h1", "Success", settings.EXPLICIT_WAIT_TIMEOUT)
wait_a_bit()
browser.get(election_url)
# She clicks on the "Administer this election" link
administration_link_label = "Administer this election"
administration_link_element = wait_for_an_element_with_partial_link_text_exists(browser, administration_link_label, settings.EXPLICIT_WAIT_TIMEOUT)
administration_link_element.click()
# She clicks on the "Proceed to decryption" button
decrypt_button_label = "Proceed to decryption"
decrypt_button_css_selector = build_css_selector_to_find_buttons_in_page_content_by_value(decrypt_button_label)
decrypt_button_element = wait_for_element_exists(browser, decrypt_button_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
decrypt_button_element.click()
wait_a_bit()
def test_scenario_1_simple_vote(self):
console_log("### Starting step: administrator_creates_election")
self.administrator_creates_election(nh_question=True)
console_log("### Step complete: administrator_creates_election")
console_log("### Starting step: administrator_regenerates_passwords_for_some_voters")
self.administrator_regenerates_passwords_for_some_voters()
console_log("### Step complete: administrator_regenerates_passwords_for_some_voters")
console_log("### Starting step: verify_election_consistency using `belenios_tool verify` (0)")
verify_election_consistency(self.election_id)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify` (0)")
console_log("### Starting step: all_voters_vote_in_sequences")
self.all_voters_vote_in_sequences()
console_log("### Step complete: all_voters_vote_in_sequences")
console_log("### Starting step: verify_election_consistency using `belenios_tool verify` (1)")
verify_election_consistency(self.election_id)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify` (1)")
console_log("### Starting step: create_election_data_snapshot (0)")
snapshot_folder = create_election_data_snapshot(self.election_id)
console_log("### Step complete: create_election_data_snapshot (0)")
try:
console_log("### Starting step: some_voters_revote")
self.some_voters_revote()
console_log("### Step complete: some_voters_revote")
console_log("### Starting step: verify_election_consistency using `belenios_tool verify-diff` (0)")
verify_election_consistency(self.election_id, snapshot_folder)
finally:
delete_election_data_snapshot(snapshot_folder)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify-diff` (0)")
console_log("### Starting step: verify_election_consistency using `belenios_tool verify` (2)")
verify_election_consistency(self.election_id)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify` (2)")
console_log("### Starting step: administrator_does_tallying_of_election")
self.administrator_does_tallying_of_election()
console_log("### Step complete: administrator_does_tallying_of_election")
console_log("### Starting step: verify_election_consistency using `belenios_tool verify` (3)")
verify_election_consistency(self.election_id)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify` (3)")
console_log("### Starting step: voter votes after the election is closed")
self.one_voter_revotes_after_the_election_is_closed()
console_log("### Step complete: voter votes after the election is closed")
if __name__ == "__main__":
random_seed = os.getenv('RANDOM_SEED', None)
if not random_seed:
random_seed = random.randrange(sys.maxsize)
console_log("Python random seed being used:", random_seed)
random.seed(random_seed)
if os.getenv('USE_HEADLESS_BROWSER', None):
settings.USE_HEADLESS_BROWSER = bool(strtobool(os.getenv('USE_HEADLESS_BROWSER')))
settings.SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH = os.getenv('SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH', settings.SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH)
settings.WAIT_TIME_BETWEEN_EACH_STEP = float(os.getenv('WAIT_TIME_BETWEEN_EACH_STEP', settings.WAIT_TIME_BETWEEN_EACH_STEP))
settings.EXPLICIT_WAIT_TIMEOUT = int(os.getenv('EXPLICIT_WAIT_TIMEOUT', settings.EXPLICIT_WAIT_TIMEOUT))
settings.NUMBER_OF_INVITED_VOTERS = int(os.getenv('NUMBER_OF_INVITED_VOTERS', settings.NUMBER_OF_INVITED_VOTERS))
settings.NUMBER_OF_VOTING_VOTERS = int(os.getenv('NUMBER_OF_VOTING_VOTERS', settings.NUMBER_OF_VOTING_VOTERS))
settings.NUMBER_OF_REVOTING_VOTERS = int(os.getenv('NUMBER_OF_REVOTING_VOTERS', settings.NUMBER_OF_REVOTING_VOTERS))
settings.NUMBER_OF_REGENERATED_PASSWORD_VOTERS = int(os.getenv('NUMBER_OF_REGENERATED_PASSWORD_VOTERS', settings.NUMBER_OF_REGENERATED_PASSWORD_VOTERS))
settings.ADMINISTRATOR_USERNAME = os.getenv('ADMINISTRATOR_USERNAME', settings.ADMINISTRATOR_USERNAME)
settings.ADMINISTRATOR_PASSWORD = os.getenv('ADMINISTRATOR_PASSWORD', settings.ADMINISTRATOR_PASSWORD)
settings.ELECTION_TITLE = os.getenv('ELECTION_TITLE', settings.ELECTION_TITLE)
settings.ELECTION_DESCRIPTION = os.getenv('ELECTION_DESCRIPTION', settings.ELECTION_DESCRIPTION)
console_log("USE_HEADLESS_BROWSER:", settings.USE_HEADLESS_BROWSER)
console_log("SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH:", settings.SENT_EMAILS_TEXT_FILE_ABSOLUTE_PATH)
console_log("WAIT_TIME_BETWEEN_EACH_STEP:", settings.WAIT_TIME_BETWEEN_EACH_STEP)
console_log("EXPLICIT_WAIT_TIMEOUT:", settings.EXPLICIT_WAIT_TIMEOUT)
console_log("NUMBER_OF_INVITED_VOTERS:", settings.NUMBER_OF_INVITED_VOTERS)
console_log("NUMBER_OF_VOTING_VOTERS:", settings.NUMBER_OF_VOTING_VOTERS)
console_log("NUMBER_OF_REVOTING_VOTERS:", settings.NUMBER_OF_REVOTING_VOTERS)
console_log("NUMBER_OF_REGENERATED_PASSWORD_VOTERS:", settings.NUMBER_OF_REGENERATED_PASSWORD_VOTERS)
console_log("ELECTION_TITLE:", settings.ELECTION_TITLE)
console_log("ELECTION_DESCRIPTION:", settings.ELECTION_DESCRIPTION)
unittest.main()
...@@ -63,7 +63,7 @@ class BeleniosElectionTestBase(unittest.TestCase): ...@@ -63,7 +63,7 @@ class BeleniosElectionTestBase(unittest.TestCase):
return votes_for_answers return votes_for_answers
def administrator_creates_election(self): def administrator_creates_election(self, nh_question=False):
# # Setting up a new election (action of the administrator) # # Setting up a new election (action of the administrator)
browser = self.browser browser = self.browser
...@@ -85,7 +85,7 @@ class BeleniosElectionTestBase(unittest.TestCase): ...@@ -85,7 +85,7 @@ class BeleniosElectionTestBase(unittest.TestCase):
# - She arrives on the Questions page. She checks that the page title is correct # - She arrives on the Questions page. She checks that the page title is correct
# - She removes answer 3 # - She removes answer 3
# - She clicks on the "Save changes" button (this redirects to the "Preparation of election" page) # - She clicks on the "Save changes" button (this redirects to the "Preparation of election" page)
administrator_edits_election_questions(browser) administrator_edits_election_questions(browser, nh_question)
# She sets election's voters: # She sets election's voters:
# - She clicks on the "Edit voters" link, to then type the list of voters # - She clicks on the "Edit voters" link, to then type the list of voters
...@@ -333,7 +333,7 @@ pris en compte. ...@@ -333,7 +333,7 @@ pris en compte.
# (where "[ ]" is a checkbox, and [Next] is a button) # (where "[ ]" is a checkbox, and [Next] is a button)
# He fills his votes to each answer of the question # He fills his votes to each answer of the question
answers_css_selector = "#question_div input[type=checkbox]" answers_css_selector = ".answer_div input"
answers_elements = wait_for_elements_exist(browser, answers_css_selector, settings.EXPLICIT_WAIT_TIMEOUT) # or we could use find_element_by_xpath("//div[@id='question_div']/input[@type='checkbox'][2]") answers_elements = wait_for_elements_exist(browser, answers_css_selector, settings.EXPLICIT_WAIT_TIMEOUT) # or we could use find_element_by_xpath("//div[@id='question_div']/input[@type='checkbox'][2]")
assert len(answers_elements) is 2 assert len(answers_elements) is 2
...@@ -341,14 +341,20 @@ pris en compte. ...@@ -341,14 +341,20 @@ pris en compte.
question1_answer2_element = answers_elements[1] question1_answer2_element = answers_elements[1]
voter_vote_to_question_1_answer_1 = voter["votes"]["question1"]["answer1"] voter_vote_to_question_1_answer_1 = voter["votes"]["question1"]["answer1"]
voter_vote_to_question_1_answer_2 = voter["votes"]["question1"]["answer2"] voter_vote_to_question_1_answer_2 = voter["votes"]["question1"]["answer2"]
voter_vote_to_question_1_answer_1_is_checked = question1_answer1_element.get_attribute('checked') if question1_answer1_element.get_attribute('type') == 'checkbox':
voter_vote_to_question_1_answer_2_is_checked = question1_answer2_element.get_attribute('checked') voter_vote_to_question_1_answer_1_is_checked = question1_answer1_element.get_attribute('checked')
assert voter_vote_to_question_1_answer_1_is_checked is None voter_vote_to_question_1_answer_2_is_checked = question1_answer2_element.get_attribute('checked')
assert voter_vote_to_question_1_answer_2_is_checked is None assert voter_vote_to_question_1_answer_1_is_checked is None
if voter_vote_to_question_1_answer_1: assert voter_vote_to_question_1_answer_2_is_checked is None
question1_answer1_element.click() if voter_vote_to_question_1_answer_1:
if voter_vote_to_question_1_answer_2: question1_answer1_element.click()
question1_answer2_element.click() if voter_vote_to_question_1_answer_2:
question1_answer2_element.click()
else:
if voter_vote_to_question_1_answer_1:
question1_answer1_element.send_keys("1")
if voter_vote_to_question_1_answer_2:
question1_answer2_element.send_keys("1")
wait_a_bit() wait_a_bit()
......
...@@ -449,7 +449,7 @@ def administrator_starts_creation_of_election(browser, manual_credential_managem ...@@ -449,7 +449,7 @@ def administrator_starts_creation_of_election(browser, manual_credential_managem
wait_a_bit() wait_a_bit()
def administrator_edits_election_questions(browser): def administrator_edits_election_questions(browser, nh_question=False):
""" """
Initial browser (required) state: on the "Preparation of election" page, with questions not edited yet Initial browser (required) state: on the "Preparation of election" page, with questions not edited yet
Final browser state: on the "Preparation of election" page (with questions edited) Final browser state: on the "Preparation of election" page (with questions edited)
...@@ -473,6 +473,12 @@ def administrator_edits_election_questions(browser): ...@@ -473,6 +473,12 @@ def administrator_edits_election_questions(browser):
page_title_expected_content = "Questions for" page_title_expected_content = "Questions for"
wait_for_element_exists_and_contains_expected_text(browser, page_title_css_selector, page_title_expected_content, settings.EXPLICIT_WAIT_TIMEOUT) wait_for_element_exists_and_contains_expected_text(browser, page_title_css_selector, page_title_expected_content, settings.EXPLICIT_WAIT_TIMEOUT)
if nh_question:
# She unchecks "Homomorphic tally"
htally_css_selector = ".homomorphic_tally"
htally_checkbox_element = browser.find_element_by_css_selector(htally_css_selector)
htally_checkbox_element.click()
# She removes answer 3 # She removes answer 3
question_to_remove = 3 question_to_remove = 3
remove_button_css_selector = ".question_answer_item:nth-child(" + str(question_to_remove) + ") .btn_remove" remove_button_css_selector = ".question_answer_item:nth-child(" + str(question_to_remove) + ") .btn_remove"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment