diff --git a/app/extension/jira/extension_ui.py b/app/extension/jira/extension_ui.py
index 26e4b69aa..3ad126b68 100644
--- a/app/extension/jira/extension_ui.py
+++ b/app/extension/jira/extension_ui.py
@@ -25,6 +25,7 @@ def app_specific_action(webdriver, datasets):
# login_page.go_to()
# login_page.wait_for_login_page_loaded()
# login_page.set_credentials(username=username, password=password)
+ # login_page.wait_for_dashboard_or_first_login_loaded()
# if login_page.is_first_login():
# login_page.first_login_setup()
# if login_page.is_first_login_second_page():
diff --git a/app/jmeter/jira.jmx b/app/jmeter/jira.jmx
index 8a783bfb6..f16f52509 100644
--- a/app/jmeter/jira.jmx
+++ b/app/jmeter/jira.jmx
@@ -245,54 +245,11 @@ props.put("project_pages", String.valueOf(pages));
UTF-8
${application.postfix}/login.jsp
true
- POST
+ GET
true
false
-
-
- false
- os_username
- ${username}
- =
- true
-
-
- false
- os_password
- ${password}
- =
- true
-
-
- false
- os_destination
-
- =
- true
-
-
- false
- user_role
-
- =
- true
-
-
- false
- atl_token
-
- =
- true
-
-
- true
- login
- Log In
- =
- true
-
-
+
@@ -329,6 +286,199 @@ props.put("project_pages", String.valueOf(pages));
+
+
+ 200
+
+
+ Assertion.response_code
+ false
+ 2
+
+
+
+ false
+ legacy_form
+ login-form-remember-me
+ $1$
+ NOT_FOUND
+ 1
+ all
+
+ false
+
+
+
+ groovy
+
+
+ true
+ String loginform = vars.get("legacy_form");
+
+if ("NOT_FOUND".equals(loginform)) {
+ vars.put("legacy_login_form", "false");
+ log.info("2sv flow detected");
+} else {
+ vars.put("legacy_login_form", "true");
+ log.info("Legacy login flow detected");
+}
+
+
+
+
+ groovy
+
+
+ true
+ log.info("Legacy login flow: ${legacy_login_form}")
+
+
+
+
+
+ ${__groovy(vars.get("legacy_login_form") == 'true')}
+ false
+ true
+
+
+
+ Detected the start of a redirect chain
+ UTF-8
+ ${application.postfix}/login.jsp
+ true
+ POST
+ true
+ false
+
+
+
+ false
+ os_username
+ ${username}
+ =
+ true
+
+
+ false
+ os_password
+ ${password}
+ =
+ true
+
+
+ false
+ os_destination
+
+ =
+ true
+
+
+ false
+ user_role
+
+ =
+ true
+
+
+ false
+ atl_token
+
+ =
+ true
+
+
+ true
+ login
+ Log In
+ =
+ true
+
+
+
+
+
+
+
+
+ Accept-Language
+ en-US,en;q=0.5
+
+
+ Pragma
+ no-cache
+
+
+ Accept
+ text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
+
+
+ Upgrade-Insecure-Requests
+ 1
+
+
+ Content-Type
+ application/x-www-form-urlencoded
+
+
+ Cache-Control
+ no-cache
+
+
+ Accept-Encoding
+ gzip, deflate
+
+
+
+
+
+
+
+ ${__groovy(vars.get("legacy_login_form") == 'false')}
+ false
+ true
+
+
+
+ 2sv login flow
+ ${application.postfix}/rest/tsv/1.0/authenticate
+ POST
+ true
+ true
+
+
+
+ false
+ {"username": "${username}",
+ "password": "${password}",
+ "rememberMe": "True",
+ "targetUrl": ""
+}
+ =
+
+
+
+
+
+
+
+
+ Content-Type
+ application/json
+
+
+
+
+
+
+ 200
+
+
+ Assertion.response_code
+ false
+ 2
+
+
+
${application.postfix}/
@@ -2005,7 +2155,7 @@ if ( sleep_time > 0 ) {
false
-
+
${application.postfix}/browse/${issue_key}
true
GET
@@ -2045,7 +2195,7 @@ if ( sleep_time > 0 ) {
-
+
false
x_issue_id
id="key-val" rel="(\d+)"
@@ -7115,104 +7265,159 @@ if ( sleep_time > 0 ) {
-
- Detected the start of a redirect chain
- UTF-8
- ${application.postfix}/login.jsp
- true
- POST
- true
- false
-
-
-
- false
- os_username
- ${app_specific_username}
- =
- true
-
-
- false
- os_password
- ${app_specific_password}
- =
- true
-
-
- false
- os_destination
-
- =
- true
-
-
- false
- user_role
-
- =
- true
-
-
- false
- atl_token
-
- =
- true
-
-
- true
- login
- Log In
- =
- true
-
-
-
-
+
+ ${__groovy(vars.get("legacy_login_form") == 'true')}
+ false
+ true
+
-
-
-
- Accept-Language
- en-US,en;q=0.5
-
-
- Pragma
- no-cache
-
-
- Accept
- text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
-
-
- Upgrade-Insecure-Requests
- 1
-
-
- Content-Type
- application/x-www-form-urlencoded
-
-
- Cache-Control
- no-cache
-
-
- Accept-Encoding
- gzip, deflate
-
-
-
-
-
- groovy
-
-
- true
- vars.put("run_as_specific_user", "true")
+
+ Detected the start of a redirect chain
+ UTF-8
+ ${application.postfix}/login.jsp
+ true
+ POST
+ true
+ false
+
+
+
+ false
+ os_username
+ ${app_specific_username}
+ =
+ true
+
+
+ false
+ os_password
+ ${app_specific_password}
+ =
+ true
+
+
+ false
+ os_destination
+
+ =
+ true
+
+
+ false
+ user_role
+
+ =
+ true
+
+
+ false
+ atl_token
+
+ =
+ true
+
+
+ true
+ login
+ Log In
+ =
+ true
+
+
+
+
+
+
+
+
+ Accept-Language
+ en-US,en;q=0.5
+
+
+ Pragma
+ no-cache
+
+
+ Accept
+ text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
+
+
+ Upgrade-Insecure-Requests
+ 1
+
+
+ Content-Type
+ application/x-www-form-urlencoded
+
+
+ Cache-Control
+ no-cache
+
+
+ Accept-Encoding
+ gzip, deflate
+
+
+
+
+
+ groovy
+
+
+ true
+ vars.put("run_as_specific_user", "true")
prev.setIgnore()
-
-
+
+
+
+
+
+ ${__groovy(vars.get("legacy_login_form") == 'false')}
+ false
+ true
+
+
+
+ 2sv login flow
+ ${application.postfix}/rest/tsv/1.0/authenticate
+ POST
+ true
+ true
+
+
+
+ false
+ {"username": "${app_specific_username}",
+ "password": "${app_specific_password}",
+ "rememberMe": "True",
+ "targetUrl": ""
+}
+ =
+
+
+
+
+
+
+
+
+ Content-Type
+ application/json
+
+
+
+
+
+
+ 200
+
+
+ Assertion.response_code
+ false
+ 2
+
+
+
${application.postfix}/rest/api/2/myself
diff --git a/app/locustio/jira/http_actions.py b/app/locustio/jira/http_actions.py
index ec5a3eb9e..3e6b02661 100644
--- a/app/locustio/jira/http_actions.py
+++ b/app/locustio/jira/http_actions.py
@@ -25,11 +25,38 @@ def login_and_view_dashboard(locust):
body = params.login_body
body['os_username'] = user[0]
body['os_password'] = user[1]
+ legacy_form = False
+
+ # Check if 2sv login form
+ r = locust.get('/login.jsp', catch_response=True)
+ if 'login-form-remember-me' in r.content:
+ legacy_form = True
+
# 100 /login.jsp
- locust.post('/login.jsp', body,
- TEXT_HEADERS,
- catch_response=True)
+ if legacy_form:
+ locust.post('/login.jsp', body,
+ TEXT_HEADERS,
+ catch_response=True)
+ logger.locust_info(f"Legacy login flow for user {user[0]}")
+ else:
+ logger.locust_info(f"2SV login flow for user {user[0]}")
+
+ login_body = {'username': user[0],
+ 'password': user[1],
+ 'rememberMe': 'True',
+ 'targetUrl': ''
+ }
+
+ headers = {
+ "Content-Type": "application/json"
+ }
+
+ # 15 /rest/tsv/1.0/authenticate
+ locust.post('/rest/tsv/1.0/authenticate',
+ json=login_body,
+ headers=headers,
+ catch_response=True)
r = locust.get('/', catch_response=True)
if not r.content:
diff --git a/app/selenium_ui/jira/modules.py b/app/selenium_ui/jira/modules.py
index 091553a85..04e462d23 100644
--- a/app/selenium_ui/jira/modules.py
+++ b/app/selenium_ui/jira/modules.py
@@ -79,6 +79,7 @@ def sub_measure():
login_page.set_credentials(
username=datasets['current_session']['username'],
password=datasets['current_session']['password'])
+ login_page.wait_for_dashboard_or_first_login_loaded()
if login_page.is_first_login():
login_page.first_login_setup()
if login_page.is_first_login_second_page():
diff --git a/app/selenium_ui/jira/pages/pages.py b/app/selenium_ui/jira/pages/pages.py
index e38bcf51e..197a11c0b 100644
--- a/app/selenium_ui/jira/pages/pages.py
+++ b/app/selenium_ui/jira/pages/pages.py
@@ -20,6 +20,10 @@ class Login(BasePage):
page_loaded_selector = LoginPageLocators.system_dashboard
base_url = UrlManager().host
+ def __init__(self, driver):
+ super().__init__(driver)
+ self.is_2sv_login = False
+
def is_first_login(self):
return True if self.get_elements(LoginPageLocators.continue_button) else False
@@ -28,6 +32,10 @@ def wait_for_login_page_loaded(self):
# Jira 10.0.1 has issue when clicking too fast on login button resulting in user is not logged in.
from time import sleep
sleep(1)
+ if not self.get_elements(LoginPageLocators.login_submit_button):
+ self.is_2sv_login = True
+ print("INFO: 2sv login form")
+
def is_first_login_second_page(self):
return True if self.get_elements(LoginPageLocators.avatar_page_next_button) else False
@@ -44,9 +52,21 @@ def first_login_second_page_setup(self):
self.wait_until_visible(DashboardLocators.dashboard_window)
def set_credentials(self, username, password):
- self.get_element(LoginPageLocators.login_field).send_keys(username)
- self.get_element(LoginPageLocators.password_field).send_keys(password)
- self.get_element(LoginPageLocators.login_submit_button).click()
+ login_field = LoginPageLocators.login_field
+ password_field = LoginPageLocators.password_field
+ submit_button = LoginPageLocators.login_submit_button
+ if self.is_2sv_login:
+ login_field = LoginPageLocators.login_field_2sv
+ password_field = LoginPageLocators.password_field_2sv
+ submit_button = LoginPageLocators.login_submit_button_2sv
+
+ self.wait_until_visible(login_field).send_keys(username)
+ self.wait_until_visible(password_field).send_keys(password)
+ self.wait_until_visible(submit_button).click()
+
+ def wait_for_dashboard_or_first_login_loaded(self):
+ self.wait_until_any_ec_presented((LoginPageLocators.system_dashboard,
+ LoginPageLocators.continue_button))
def __get_footer_text(self):
return self.get_element(LoginPageLocators.footer).text
diff --git a/app/selenium_ui/jira/pages/selectors.py b/app/selenium_ui/jira/pages/selectors.py
index 43f75557c..d59b4ee26 100644
--- a/app/selenium_ui/jira/pages/selectors.py
+++ b/app/selenium_ui/jira/pages/selectors.py
@@ -79,6 +79,9 @@ class LoginPageLocators:
login_field = (By.ID, 'login-form-username')
password_field = (By.ID, 'login-form-password')
login_submit_button = (By.ID, 'login-form-submit')
+ login_field_2sv = (By.ID, 'username-field')
+ password_field_2sv = (By.ID, 'password-field')
+ login_submit_button_2sv = (By.ID, 'login-button')
system_dashboard = (By.ID, "dashboard")
footer = (By.ID, 'footer-build-information')