Loading dev/testing/README.md +2 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ The structure of the `settings.json` file: randomization is used for offsetting the actions between different teams - `start_offset_from`, `start_offset_to` - randomization offset interval in seconds, inclusive on both sides, set both to `0` for no offset - `verify_ssl` - boolean flag specifying whether to verify the SSL certificate, set to `false` for self-signed certificates - `sandbox` - boolean flag used for creating the exercise The settings file should be present in the same directory as `sequence_test.py`. Loading dev/testing/action_mapper.py +23 −15 Original line number Diff line number Diff line Loading @@ -50,13 +50,16 @@ def load_exercise_data(logs_path: str) -> ExerciseData: for tool in load_file(os.path.join(logs_path, "exercise_tools.jsonl")) } participants = load_file( os.path.join(logs_path, "email_participants.jsonl") ) email_participants_path = os.path.join(logs_path, "email_participants.jsonl") if os.path.exists(email_participants_path): participants = load_file(email_participants_path) participant_mapping = { participant["participant_id"]: participant["address"] for participant in participants } else: participants = [] participant_mapping = {} questionnaires = { questionnaire["questionnaire_id"]: questionnaire Loading Loading @@ -162,8 +165,16 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: team_participant = participant break if team_participant is None: raise Exception("did not find email participant for the given team") participant_id = team_participant["participant_id"] if team_participant else 0 participant_address = team_participant["address"] if team_participant else "" emails_path = os.path.join(team_path, "emails.jsonl") email_threads = {} if os.path.exists(emails_path): email_threads = { thread["thread_id"]: thread for thread in load_file(emails_path) } data = TeamData( seconds_since_epoch(exercise_state["start_time"]), Loading @@ -171,10 +182,7 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: log["action_log_id"]: log for log in load_file(os.path.join(team_path, "action_logs.jsonl")) }, { thread["thread_id"]: thread for thread in load_file(os.path.join(team_path, "emails.jsonl")) }, email_threads, { state["questionnaire_state_id"]: state for state in load_file( Loading @@ -187,8 +195,8 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: os.path.join(team_path, "milestones.jsonl") ) }, team_participant["participant_id"], team_participant["address"], participant_id, participant_address, {}, ) return data Loading dev/testing/client.py +46 −8 Original line number Diff line number Diff line import requests import urllib3 import logging from requests import RequestException from graphene_django.utils import camelize from requests import Response Loading @@ -6,15 +9,32 @@ from common_lib.graphql.api import APIAction def login( session: requests.Session, url: str, username: str, password: str session: requests.Session, url: str, username: str, password: str, verify_ssl: bool = True, ) -> Response: login_url = f"{url}/auth/login/" session.verify = verify_ssl try: response = session.post( url=f"{url}/auth/login/", url=login_url, json={"username": username, "password": password}, timeout=15, ) except RequestException as exc: raise Exception( f"Failed to login as {username}: {exc} | url={login_url} | verify={verify_ssl}" ) from exc if response.status_code != 200: raise Exception(f"Failed to login as {username}: {response.content}") raise Exception( "Failed to login as " f"{username}: status={response.status_code}, " f"reason={response.reason}, url={response.url}, verify={verify_ssl}, " f"body={response.text}" ) data = response.json() session.headers["session-id"] = data["sessionid"] Loading @@ -25,8 +45,17 @@ class Client: url: str session: requests.Session def __init__(self, host: str, admin_username: str, admin_password: str): def __init__( self, host: str, admin_username: str, admin_password: str, verify_ssl: bool = True, ): self.session = requests.session() self.session.verify = verify_ssl if not verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) self.url = host self.session.headers["Accept"] = "application/json" Loading @@ -35,6 +64,7 @@ class Client: self.url, admin_username, admin_password, verify_ssl, ) def send_action( Loading @@ -57,11 +87,19 @@ class Client: raise Exception("Unauthorized") response_data = response.json() if "errors" in response_data: raise Exception(f"GraphQL errors: {response_data['errors']}") if response.status_code != 200: if throw: raise Exception(f"{action.query_name}: {response_data}") action.result = response_data else: action.result = response_data["data"][action.query_name] data = response_data.get("data") or {} action_result = data.get(action.query_name) if action_result is None: raise Exception( f"Empty result for {action.query_name}: {response_data}" ) action.result = action_result return response dev/testing/example_settings.json +3 −1 Original line number Diff line number Diff line Loading @@ -10,5 +10,7 @@ "preserve_data": true, "seed": 0, "start_offset_from": 0, "start_offset_to": 10 "start_offset_to": 10, "verify_ssl": true, "sandbox": false } dev/testing/prepare_environment.py +1 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ class PerfTestPreparer: "config_override": { "update_interval_s": self.settings.update_interval_s }, "sandbox": self.settings.sandbox, }, {}, ) Loading Loading
dev/testing/README.md +2 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ The structure of the `settings.json` file: randomization is used for offsetting the actions between different teams - `start_offset_from`, `start_offset_to` - randomization offset interval in seconds, inclusive on both sides, set both to `0` for no offset - `verify_ssl` - boolean flag specifying whether to verify the SSL certificate, set to `false` for self-signed certificates - `sandbox` - boolean flag used for creating the exercise The settings file should be present in the same directory as `sequence_test.py`. Loading
dev/testing/action_mapper.py +23 −15 Original line number Diff line number Diff line Loading @@ -50,13 +50,16 @@ def load_exercise_data(logs_path: str) -> ExerciseData: for tool in load_file(os.path.join(logs_path, "exercise_tools.jsonl")) } participants = load_file( os.path.join(logs_path, "email_participants.jsonl") ) email_participants_path = os.path.join(logs_path, "email_participants.jsonl") if os.path.exists(email_participants_path): participants = load_file(email_participants_path) participant_mapping = { participant["participant_id"]: participant["address"] for participant in participants } else: participants = [] participant_mapping = {} questionnaires = { questionnaire["questionnaire_id"]: questionnaire Loading Loading @@ -162,8 +165,16 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: team_participant = participant break if team_participant is None: raise Exception("did not find email participant for the given team") participant_id = team_participant["participant_id"] if team_participant else 0 participant_address = team_participant["address"] if team_participant else "" emails_path = os.path.join(team_path, "emails.jsonl") email_threads = {} if os.path.exists(emails_path): email_threads = { thread["thread_id"]: thread for thread in load_file(emails_path) } data = TeamData( seconds_since_epoch(exercise_state["start_time"]), Loading @@ -171,10 +182,7 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: log["action_log_id"]: log for log in load_file(os.path.join(team_path, "action_logs.jsonl")) }, { thread["thread_id"]: thread for thread in load_file(os.path.join(team_path, "emails.jsonl")) }, email_threads, { state["questionnaire_state_id"]: state for state in load_file( Loading @@ -187,8 +195,8 @@ def load_team_data(team_path: str, exercise: ExerciseData) -> TeamData: os.path.join(team_path, "milestones.jsonl") ) }, team_participant["participant_id"], team_participant["address"], participant_id, participant_address, {}, ) return data Loading
dev/testing/client.py +46 −8 Original line number Diff line number Diff line import requests import urllib3 import logging from requests import RequestException from graphene_django.utils import camelize from requests import Response Loading @@ -6,15 +9,32 @@ from common_lib.graphql.api import APIAction def login( session: requests.Session, url: str, username: str, password: str session: requests.Session, url: str, username: str, password: str, verify_ssl: bool = True, ) -> Response: login_url = f"{url}/auth/login/" session.verify = verify_ssl try: response = session.post( url=f"{url}/auth/login/", url=login_url, json={"username": username, "password": password}, timeout=15, ) except RequestException as exc: raise Exception( f"Failed to login as {username}: {exc} | url={login_url} | verify={verify_ssl}" ) from exc if response.status_code != 200: raise Exception(f"Failed to login as {username}: {response.content}") raise Exception( "Failed to login as " f"{username}: status={response.status_code}, " f"reason={response.reason}, url={response.url}, verify={verify_ssl}, " f"body={response.text}" ) data = response.json() session.headers["session-id"] = data["sessionid"] Loading @@ -25,8 +45,17 @@ class Client: url: str session: requests.Session def __init__(self, host: str, admin_username: str, admin_password: str): def __init__( self, host: str, admin_username: str, admin_password: str, verify_ssl: bool = True, ): self.session = requests.session() self.session.verify = verify_ssl if not verify_ssl: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) self.url = host self.session.headers["Accept"] = "application/json" Loading @@ -35,6 +64,7 @@ class Client: self.url, admin_username, admin_password, verify_ssl, ) def send_action( Loading @@ -57,11 +87,19 @@ class Client: raise Exception("Unauthorized") response_data = response.json() if "errors" in response_data: raise Exception(f"GraphQL errors: {response_data['errors']}") if response.status_code != 200: if throw: raise Exception(f"{action.query_name}: {response_data}") action.result = response_data else: action.result = response_data["data"][action.query_name] data = response_data.get("data") or {} action_result = data.get(action.query_name) if action_result is None: raise Exception( f"Empty result for {action.query_name}: {response_data}" ) action.result = action_result return response
dev/testing/example_settings.json +3 −1 Original line number Diff line number Diff line Loading @@ -10,5 +10,7 @@ "preserve_data": true, "seed": 0, "start_offset_from": 0, "start_offset_to": 10 "start_offset_to": 10, "verify_ssl": true, "sandbox": false }
dev/testing/prepare_environment.py +1 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ class PerfTestPreparer: "config_override": { "update_interval_s": self.settings.update_interval_s }, "sandbox": self.settings.sandbox, }, {}, ) Loading