Skip to content

Commit

Permalink
Merge pull request #7 from usegalaxy-au/uplift_code
Browse files Browse the repository at this point in the history
Uplift code
  • Loading branch information
nuwang authored Sep 25, 2024
2 parents 9e96722 + 669998a commit 8a932f1
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 47 deletions.
16 changes: 15 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
# https://github.com/joyzoursky/docker-python-chromedriver
# https://github.com/TomRoush/python-selenium-firefox-docker
FROM tomroush/python-selenium-firefox-docker:latest
FROM ubuntu:22.04 AS selenium

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
python3 python3-pip \
# firefox needs the following installed on 22.04
libgtk-3-common libasound2 libdbus-glib-1-2 \
firefox \
xvfb \
&& rm -rf /var/lib/apt/lists/*

RUN pip3 install --no-cache-dir selenium requests

FROM selenium

ENV SELENIUM_HEADLESS=true
ARG DEBIAN_FRONTEND=noninteractive

ADD page_perf_timer.py /opt/page_timer/

Expand Down
174 changes: 132 additions & 42 deletions page_perf_timer.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import argparse
import functools
import hashlib
import os
import sys
import time
import uuid

import requests

# Generated by Selenium IDE
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
Expand Down Expand Up @@ -38,6 +41,7 @@ class EndStepReached(Exception):
"""
Raised when a specific action step has been reached
"""

pass


Expand Down Expand Up @@ -127,7 +131,7 @@ def wait_for_history_panel_to_load(self):
@clock_action("login_page_load")
def load_galaxy_login(self):
# Open Galaxy window
self.driver.get(f"{self.server}/login")
self.driver.get(f"{self.server}login")
# Wait for username entry to appear
self.wait.until(self.is_able_to_login)

Expand All @@ -154,10 +158,51 @@ def login_to_galaxy_homepage(self):
# Wait for tool panel to load
self.wait.until(
expected_conditions.presence_of_element_located(
(By.XPATH, "//div[@class='tool-panel-section']//a[@class='title-link' and contains(., 'Get Data')]")
(
By.XPATH,
"//div[@class='tool-panel-section']//a[contains(@class, 'title-link') and contains(., 'Get Data')]",
)
)
)

@clock_action("dummy_file_upload")
def upload_dummy_file(self):
upload_activity = self.driver.find_element(By.ID, "activity-upload")
upload_activity.click()
# paste/fetch data
paste_button = self.driver.find_element(By.ID, "btn-new")
paste_button.click()
# paste/fetch data
upload_row = self.driver.find_element(By.XPATH, "//div[@id='upload-row-0']//textarea")
upload_row.send_keys("https://zenodo.org/records/13711466/files/(Galaxy%20History)%20Selenium_test_1_Input_data.rocrate.zip?download=1")
# start
start_button = self.driver.find_element(By.ID, "btn-start")
start_button.click()
# close
close_button = self.driver.find_element(By.ID, "btn-close")
close_button.click()
# wait for history item to appear
self.wait.until(
expected_conditions.presence_of_element_located(
(
By.XPATH,
"//div[@data-index='0']//div[@data-state='running' and contains(., 'Selenium_test_1_Input_data')]",
)
)
)

@clock_action("dummy_file_download")
def download_dummy_file(self):
open_download_link = self.driver.find_element(By.XPATH, "//div[@data-index='0']//div[@data-state='running' and contains(., 'Selenium_test_1_Input_data')]")
open_download_link.click()
with SeleniumCustomWait(self.driver, 1200):
download_link = self.driver.find_element(By.XPATH, "//div[@data-index='0']//div[@data-state='ok' and contains(., 'Selenium_test_1_Input_data')]//a[@title='Download']")
r = requests.get(download_link.get_attribute("href"), stream=True)
sig = hashlib.md5()
for line in r.iter_lines():
sig.update(line)
assert sig.hexdigest() == "a62aaaefa04bdc7acd3b29a127bba3e6"

@clock_action("tool_search_load")
def search_for_tool(self):
# Select tool search box
Expand Down Expand Up @@ -190,38 +235,52 @@ def load_tool_form(self):
expected_conditions.presence_of_element_located((By.ID, "execute"))
)

@clock_action("shared_histories_page_load")
def load_shared_histories(self):
@clock_action("published_histories_page_load")
def load_published_histories(self):
# Request history page
self.driver.get(f"{self.server}/histories/list_shared")
self.driver.get(f"{self.server}histories/list_published")

# Wait for history page to load
self.wait.until(
expected_conditions.presence_of_element_located(
(By.XPATH, "//h2[contains(., 'Histories shared with you by others')]")
(
By.XPATH,
"//li[@id='histories-published-tab' and contains(., 'Public Histories')]",
)
)
)
self.wait_for_history_panel_to_load()

@clock_action("import_shared_history")
def import_shared_history(self):
@clock_action("import_published_history")
def import_published_history(self):
# Search for the relevant history
search_history_input = self.driver.find_element(
By.XPATH,
f"//div[@id='histories-published-grid']//input[@placeholder='search histories']",
)
search_history_input.click()
search_history_input.send_keys(f"{self.workflow_name.lower()}_input_data")

# Select relevant history
import_history_btn = self.driver.find_element(
By.XPATH,
f"//tbody[@id='grid-table-body']//button[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{self.workflow_name.lower()}_input_data')]",
f"//table[@class='grid-table']//button[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{self.workflow_name.lower()}_input_data')]",
)
import_history_btn.click()
self.wait_for_history_panel_to_load()
# Workaround for ElementClickInterceptedException
self.driver.execute_script("arguments[0].click();", import_history_btn)

# View history details
view_history_menu_item = self.driver.find_element(
view_history_menu_item = import_history_btn.find_element(
By.XPATH,
f"//div[@id='{import_history_btn.get_attribute('id')}-menu']//a[contains(., 'View')]",
f"./following-sibling::div//button[contains(@data-description, 'grid operation view')]",
)
view_history_menu_item.click()
self.wait.until(
expected_conditions.presence_of_element_located(
(By.XPATH, f"//h3[contains(., '{self.workflow_name.lower()}_input_data')]")
(
By.XPATH,
f"//h3[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '{self.workflow_name.lower()}_input_data')]",
)
)
)
# Invoke copy history dialogue
Expand All @@ -239,6 +298,20 @@ def import_shared_history(self):
By.XPATH,
f"//button[contains(., 'Copy History')]",
).click()

# activate the history
self.wait.until(
expected_conditions.presence_of_element_located(
(
By.XPATH,
f"//div[@class='alert alert-info' and contains(., 'History imported and is now your active history')]",
)
)
)

# Request history page
self.driver.get(f"{self.server}histories/list")

# Wait for history panel to load with new history
self.wait.until(
expected_conditions.presence_of_element_located(
Expand All @@ -252,20 +325,37 @@ def import_shared_history(self):
@clock_action("workflow_list_page_load")
def load_workflow_list(self):
# Request workflows list page
self.driver.get(f"{self.server}/workflows/list")
self.driver.get(f"{self.server}workflows/list_published")
# Wait for workflow page to load and import button to appear
self.wait.until(
expected_conditions.presence_of_element_located((By.ID, "workflow-import"))
expected_conditions.presence_of_element_located(
(By.XPATH, "//li[@id='published' and contains(., 'Public workflows')]")
)
)

@clock_action("workflow_run_page_load")
def load_workflow_run_form(self):
# Select relevant workflow
run_workflow_btn = self.driver.find_element(
# Search for the relevant history
search_workflow_input = self.driver.find_element(
By.XPATH,
f"//table[@id='workflow-table']//tr[contains(., '{self.workflow_name}')]//button[@title='Run workflow']",
f"//div[@id='workflow-list-filter']//input",
)
run_workflow_btn.click()
search_workflow_input.click()
search_workflow_input.send_keys(f"{self.workflow_name.lower()}")

# wait for list to be filtered
self.wait.until(
lambda d: len(
d.find_elements(By.CSS_SELECTOR, "#workflow-cards .workflow-card")
)
== 1
)

# Select relevant workflow
run_workflow_btn = self.driver.find_element(By.ID, "workflow-run-button")
# Workaround for ElementClickInterceptedException
self.driver.execute_script("arguments[0].click();", run_workflow_btn)

# Wait for workflow form to load and run button to appear
self.wait.until(
expected_conditions.presence_of_element_located((By.ID, "run-workflow"))
Expand All @@ -277,13 +367,13 @@ def run_workflow(self):
# Select relevant choice
input_1_select = self.driver.find_element(
By.XPATH,
"//a[@class='select2-choice' and contains(., 'Subsample of reads from')]",
"//div[@class='ui-form-composite']//input/following-sibling::span[contains(., 'Subsample of reads from Human exome R2')][1]",
)
input_1_select.click()
# Select relevant choice
input_1_select = self.driver.find_element(
By.XPATH,
"//div[@id='select2-drop']//ul/li/div[contains(., 'Subsample of reads from human exome R1')]",
"//div[@class='ui-form-composite']//ul[@role='listbox']//li[@role='option']//span[contains(., 'Subsample of reads from human exome R1')]",
)
input_1_select.click()
workflow_wait = 14400
Expand All @@ -293,55 +383,55 @@ def run_workflow(self):
# Select relevant choice
input_1_select = self.driver.find_element(
By.XPATH,
"//div[@data-label='Forward Reads']//a[@class='select2-choice']",
"//div[@class='ui-form-composite']//input/following-sibling::span[contains(., 'ERR019289_2.fastq.gz')][1]",
)
input_1_select.click()
# Select relevant choice
input_1_select = self.driver.find_element(
By.XPATH,
"//div[@id='select2-drop']//ul/li/div[contains(., 'ERR019289_1.fastq.gz')]",
"//div[@class='ui-form-composite']//ul[@role='listbox']//li[@role='option']//span[contains(., 'ERR019289_1.fastq.gz')]",
)
input_1_select.click()
workflow_wait = 14400
elif self.workflow_name == "Selenium_test_4":
input_select = self.driver.find_element(
input_1_select = self.driver.find_element(
By.XPATH,
"//div[@data-label='ARTIC primers to amplicon assignments']//a[@class='select2-choice']",
"//div[@class='ui-form-composite']//div[@data-label='ARTIC primers to amplicon assignments']//input/following-sibling::span[contains(., 'NC_045512.2.fna.fasta')][1]",
)
input_select.click()
input_1_select.click()
# Select relevant choice
input_select = self.driver.find_element(
input_1_select = self.driver.find_element(
By.XPATH,
"//div[@id='select2-drop']//ul/li/div[contains(., 'ARTIC_SARS_CoV-2_amplicon_info_v3.tsv')]",
"//div[@class='ui-form-composite']//div[@data-label='ARTIC primers to amplicon assignments']//ul[@role='listbox']//li[@role='option']//span[contains(., 'ARTIC_SARS_CoV-2_amplicon_info_v3.tsv')]",
)
input_select.click()
input_1_select.click()
workflow_wait = 14400
else:
raise Exception(f"Workflow name not in known list: {self.workflow_name}")

# Run the workflow
self.driver.find_element(By.ID, "run-workflow").click()
# Wait for view reports button to appear (workflow to finish)
with SeleniumCustomWait(self.driver, workflow_wait):
self.wait.until(
expected_conditions.presence_of_element_located(
(
By.XPATH,
"//div[@id='center']//a[contains(@class, 'invocation-report-link') and contains(., 'View Report')]",
)
)
)

# wait for the running message to appear
loading_xpath = "//div[@id='center']//div[@role='tabpanel']//div[@role='alert']//span[@data-description='loading message' and contains(., 'Waiting to complete invocation')]"
self.wait.until(expected_conditions.presence_of_element_located((By.XPATH, loading_xpath)))

# Wait for running message to disappear
custom_wait = WebDriverWait(self.driver, workflow_wait)
custom_wait.until(expected_conditions.invisibility_of_element_located((By.XPATH, loading_xpath)))

def run_test_sequence(self):
self.load_galaxy_login()
self.login_to_galaxy_homepage()
self.search_for_tool()
self.load_tool_form()
self.load_shared_histories()
self.import_shared_history()
self.load_published_histories()
self.import_published_history()
self.load_workflow_list()
self.load_workflow_run_form()
self.run_workflow()
self.upload_dummy_file()
self.download_dummy_file()

def measure_timings(self):
self.timings = {}
Expand Down
10 changes: 6 additions & 4 deletions registration_email/registration_email_perf_timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,16 @@ def register_new_account(self):
def delete_test_account(self):
gi = galaxy.GalaxyInstance(url=self.server, key=self.api_key)
user = gi.users.get_users(f_name=self.username)[0]
if user['email'] == self.email:
gi.users.delete_user(user['id'])
gi.users.delete_user(user['id'], purge=True)
if user["email"] == self.email:
gi.users.delete_user(user["id"])
gi.users.delete_user(user["id"], purge=True)

@tenacity.retry(
retry=tenacity.retry_if_result(lambda result: not result),
wait=tenacity.wait_fixed(int(os.environ.get("IMAP_POLL_SECONDS", 10))),
stop=tenacity.stop_after_attempt(int(os.environ.get("IMAP_MAX_POLL_ATTEMPTS", 12))),
stop=tenacity.stop_after_attempt(
int(os.environ.get("IMAP_MAX_POLL_ATTEMPTS", 12))
),
retry_error_callback=(lambda _: False),
)
def verify_email_received(self):
Expand Down

0 comments on commit 8a932f1

Please sign in to comment.