This is an automated email from the ASF dual-hosted git repository.
jongyoul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push:
new a31975a05b [ZEPPELIN-6525] Authenticate via REST for Selenium login
preconditions
a31975a05b is described below
commit a31975a05b93df960165ea292d72199c160fb323
Author: HwangRock <[email protected]>
AuthorDate: Fri Jul 24 11:28:55 2026 +0900
[ZEPPELIN-6525] Authenticate via REST for Selenium login preconditions
### What is this PR for?
`test-selenium-with-spark-module-for-spark-3-5` fails on ~88% of master
runs. Every failure lands in `AbstractZeppelinIT.authenticationUser`: the
Bootstrap 3 login modal races its fade animation and the WebSocket
`session_logout` auto-open, so the login click gets intercepted, the field is
not interactable, or the modal never reaches its shown state. Across eight
failing master runs the exception rotates between those three, which is why
hardening any single step never held on its own [...]
Test-only, no production changes.
- Add `authenticationUserViaRest`, which logs in with a synchronous XHR
`POST /classic/api/login` issued from inside the browser's own JS context, so
the browser session itself becomes authenticated. Reloading afterwards lets
`app.js`'s pre-bootstrap `GET /security/ticket` render the logged-in state. No
modal opens, so none of its races apply. Used wherever login is only a
precondition (35 call sites across the three ITs).
- Keep `authenticationUser` as hardened by ZEPPELIN-1836, and keep
`AuthenticationIT.testSimpleAuthentication` on it, so the classic login modal
keeps its automated coverage.
- Add `extractNoteIdFromCurrentUrl`, which strips any `?query`/`#fragment`
after the last path segment. After a reload the SPA appends `?ref=...` to note
URLs, which otherwise leaks into the extracted note id and breaks the
`<at>href` lookups.
- Correct `PersonalizeActionsIT.testDynamicFormAction` (see below).
An earlier approach injected a JSESSIONID obtained from a separate
`java.net.http` client via `addCookie`; that session never transferred to the
browser — the server logged a successful login while the browser stayed
anonymous. Issuing the request inside the page authenticates the real session,
which the server logs confirm (`LoginRestApi` returns the expected principal
and `SecurityRestApi` then reports it for the browser).
Rebased onto current `master` so it sits on top of #5250.
### Why `testDynamicFormAction` changes
The test asserted that a non-owner's dynamic-form edit is ignored (`Status:
Before`). The server does the opposite: `NotebookService.runParagraph` applies
the caller's params to that user's own paragraph copy, `Note.run` executes that
copy, and `GUI.textbox` prefers the params value over the default. Nothing
filters a non-owner's params.
The same wrong expectation was already corrected for `testGraphAction` in
238e03242 (ZEPPELIN-4355), which also added the owner-side check that proves
isolation; the dynamic-form case was missed at the time and still has no such
step. The assertion has not been revisited since 2017, and its message (`"The
output of graph mode is changed"`) is a leftover from the graph test.
It passed until now only because a late WebSocket broadcast replaces
`paragraph.settings` and reverts the typed form value before the run. The test
now waits for the input to actually hold the new value, so that race fails
loudly instead of passing silently.
Adding the owner-side isolation step would fail on a real production bug —
in personalized mode the caller's params are written to the shared master
paragraph before the personalized branch is taken, and then persisted. Filed
separately as ZEPPELIN-6556; not addressed here.
### Scope and related issues
- **ZEPPELIN-6525, login modal** — fixed, though not the way the ticket
proposed. Driving the modal defensively (retrying open/fill/submit, tolerating
`ElementClickInterceptedException`) was tried first and made things worse: one
error became six, and ignoring the interception threw away the diagnostic the
raw exception carried. Taking the modal out of the precondition path addresses
the class of failure rather than one instance of it.
- **ZEPPELIN-6525, `ParagraphActionsIT` dynamic-form sleeps** — out of
scope here. `ParagraphActionsIT` reports `Tests run: 21, Failures: 0, Errors:
0` on master and on this branch, so it is not what keeps the job red. Those
fixed sleeps remain a latent race and deserve a follow-up.
- **ZEPPELIN-6526, REST session instead of per-test UI logins** —
implemented, with one deviation: the proposed `addCookie` injection does not
work, for the reason above, so the request is issued from inside the page
instead. The `?ref=` risk the ticket flagged did materialise and is handled by
`extractNoteIdFromCurrentUrl`.
- **ZEPPELIN-6556** — production isolation bug found while investigating
this; filed, not fixed here.
### What type of PR is it?
Bug Fix (test infrastructure)
### What is the ticket?
https://issues.apache.org/jira/browse/ZEPPELIN-6525
### How should this be tested?
Re-run `test-selenium-with-spark-module-for-spark-3-5`. Locally:
```
ZEPPELIN_SELENIUM_BROWSER=chrome ./mvnw -o failsafe:integration-test
failsafe:verify \
-pl zeppelin-integration -Dit.test=AuthenticationIT -DfailIfNoTests=false
\
-Pintegration -Pusing-source-tree -Pweb-classic -Pspark-scala-2.12
-Pspark-3.5
```
`AuthenticationIT` (3/3, including the modal-based
`testSimpleAuthentication`) and `PersonalizeActionsIT#testDynamicFormAction`
pass locally.
### Questions
- Does this need documentation? No.
Closes #5335 from HwangRock/ZEPPELIN-6525.
Signed-off-by: Jongyoul Lee <[email protected]>
---
.../org/apache/zeppelin/AbstractZeppelinIT.java | 47 ++++++++++++++++++
.../zeppelin/integration/AuthenticationIT.java | 15 +++---
.../integration/InterpreterModeActionsIT.java | 55 ++++++++++------------
.../zeppelin/integration/PersonalizeActionsIT.java | 37 ++++++++-------
4 files changed, 99 insertions(+), 55 deletions(-)
diff --git
a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
index 58cf336a35..bc433bcb6f 100644
---
a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
+++
b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
@@ -50,6 +50,7 @@ abstract public class AbstractZeppelinIT {
protected static final long MAX_IMPLICIT_WAIT = 30;
protected static final long MAX_BROWSER_TIMEOUT_SEC = 30;
protected static final long MAX_PARAGRAPH_TIMEOUT_SEC = 120;
+ private static final String CLASSIC_LOGIN_PATH = "/classic/api/login";
protected void authenticationUser(String userName, String password) {
WebElement loginModal =
manager.getWebDriver().findElement(By.id("loginModal"));
@@ -119,6 +120,52 @@ abstract public class AbstractZeppelinIT {
});
}
+ // Logs in by issuing a synchronous XHR POST to the REST login endpoint from
inside the
+ // browser's own JS context, so the browser's own session (not a separate
HTTP client
+ // session) becomes authenticated. Refreshing afterwards lets app.js's
pre-bootstrap
+ // ticket check find that same authenticated session. Skips the login modal
entirely, so
+ // none of its fade/WebSocket-reopen races apply. Intended for tests where
login is only
+ // a precondition, not the behavior under test.
+ protected void authenticationUserViaRest(String userName, String password) {
+ String script = "var xhr = new XMLHttpRequest();"
+ + "xhr.open('POST', arguments[0], false);"
+ + "xhr.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');"
+ + "xhr.send('userName=' + encodeURIComponent(arguments[1]) + "
+ + "'&password=' + encodeURIComponent(arguments[2]));"
+ + "return xhr.status;";
+ Object result = ((JavascriptExecutor) manager.getWebDriver())
+ .executeScript(script, CLASSIC_LOGIN_PATH, userName, password);
+ int status = ((Number) result).intValue();
+ if (status != 200) {
+ throw new IllegalStateException("REST login failed with status " +
status);
+ }
+ manager.getWebDriver().navigate().refresh();
+ visibilityWait(loggedInUserMenuLocator(), MAX_BROWSER_TIMEOUT_SEC);
+ }
+
+ // Shared locator for the logged-in navbar user menu button. Uses a
class-order-agnostic
+ // partial match since AngularJS may render the class attribute in a
different order.
+ protected static By loggedInUserMenuLocator() {
+ return By.xpath("//button[contains(@class, 'nav-btn') and contains(@class,
'dropdown-toggle')]");
+ }
+
+ // Extracts the note id segment from the current URL, stripping any trailing
query string
+ // or fragment (e.g. the "?ref=%2F" a post-refresh SPA URL appends), so
callers get a clean
+ // note id instead of one polluted by a query string/fragment.
+ protected String extractNoteIdFromCurrentUrl() {
+ String url = manager.getWebDriver().getCurrentUrl();
+ String noteId = url.substring(url.lastIndexOf("/") + 1);
+ int queryIndex = noteId.indexOf("?");
+ if (queryIndex != -1) {
+ noteId = noteId.substring(0, queryIndex);
+ }
+ int fragmentIndex = noteId.indexOf("#");
+ if (fragmentIndex != -1) {
+ noteId = noteId.substring(0, fragmentIndex);
+ }
+ return noteId;
+ }
+
protected void logoutUser(String userName) throws URISyntaxException {
ZeppelinITUtils.sleep(500, false);
clickableWait(
diff --git
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
index 0eb414327e..fe77c65da7 100644
---
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
+++
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java
@@ -107,7 +107,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
@Test
void testAnyOfRolesUser() throws Exception {
try {
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -119,7 +119,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
logoutUser("admin");
- authenticationUser("finance1", "finance1");
+ authenticationUserViaRest("finance1", "finance1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -131,7 +131,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
logoutUser("finance1");
- authenticationUser("hr1", "hr1");
+ authenticationUserViaRest("hr1", "hr1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -155,11 +155,10 @@ public class AuthenticationIT extends AbstractZeppelinIT {
@Test
void testGroupPermission() throws Exception {
try {
- authenticationUser("finance1", "finance1");
+ authenticationUserViaRest("finance1", "finance1");
createNewNote();
- String noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String noteId = extractNoteIdFromCurrentUrl();
clickableWait(By.xpath("//span[@uib-tooltip='Note permissions']"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -179,7 +178,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
MAX_BROWSER_TIMEOUT_SEC).click();
logoutUser("finance1");
- authenticationUser("hr1", "hr1");
+ authenticationUserViaRest("hr1", "hr1");
try {
WebElement element =
visibilityWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]"),
MAX_BROWSER_TIMEOUT_SEC);
@@ -200,7 +199,7 @@ public class AuthenticationIT extends AbstractZeppelinIT {
"//div[@class='modal-footer']//button[2]")).click();
logoutUser("hr1");
- authenticationUser("finance2", "finance2");
+ authenticationUserViaRest("finance2", "finance2");
try {
WebElement element =
visibilityWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]"),
MAX_BROWSER_TIMEOUT_SEC);
diff --git
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
index 8f469e7a95..da204bf98e 100644
---
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
+++
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java
@@ -112,7 +112,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
void testGloballyAction() throws Exception {
try {
//step 1: (admin) login, set 'globally in shared' mode of python
interpreter, logout
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
@@ -135,7 +135,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
By locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
WebElement element =
@@ -144,8 +144,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String user1noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String user1noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setPythonParagraph(1, "user=\"user1\"");
waitForParagraph(2, "READY");
@@ -171,7 +170,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user2' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
element =
@@ -202,7 +201,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user2' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user1noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -267,7 +266,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
void testPerUserScopedAction() throws Exception {
try {
//step 1: (admin) login, set 'Per user in scoped' mode of python
interpreter, logout
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -297,7 +296,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
By locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
WebElement element =
@@ -306,8 +305,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String user1noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String user1noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setPythonParagraph(1, "user=\"user1\"");
@@ -333,7 +331,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
// paragraph: Check if the result is 'user2' in the
second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '2'
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
element =
@@ -342,8 +340,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String user2noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String user2noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setPythonParagraph(1, "user=\"user2\"");
waitForParagraph(2, "READY");
@@ -367,7 +364,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user1noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -421,7 +418,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//step 5: (user2) login, come back note user2 made, restart python
interpreter in note, check process, logout
//System: Check if the number of python interpreter process is '0'
//System: Check if the number of python process is '0'
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user2noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -464,7 +461,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
// (user2) login, come back note user2 made, run first paragraph,
check process, logout
//System: Check if the number of python process is '2'
//System: Check if the number of python interpreter process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user1noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -483,7 +480,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
}
logoutUser("user1");
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user2noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -512,7 +509,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//step 7: (admin) login, restart python interpreter in interpreter tab,
check process, logout
//System: Check if the number of python interpreter process is 0
//System: Check if the number of python process is 0
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
@@ -556,7 +553,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
void testPerUserIsolatedAction() throws Exception {
try {
//step 1: (admin) login, set 'Per user in isolated' mode of python
interpreter, logout
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]"));
@@ -582,7 +579,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
By locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
WebElement element =
@@ -591,8 +588,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String user1noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String user1noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setPythonParagraph(1, "user=\"user1\"");
waitForParagraph(2, "READY");
@@ -616,7 +612,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
// paragraph: Check if the result is 'user2' in the
second paragraph
//System: Check if the number of python interpreter process is '2'
//System: Check if the number of python process is '2'
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//div[contains(@class,
'col-md-4')]/div/h5/a[contains(.,'Create new" +
" note')]");
element =
@@ -625,8 +621,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String user2noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String user2noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setPythonParagraph(1, "user=\"user2\"");
waitForParagraph(2, "READY");
@@ -651,7 +646,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//paragraph: Check if the result is 'user1' in the second paragraph
//System: Check if the number of python interpreter process is '1'
//System: Check if the number of python process is '1'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user1noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -706,7 +701,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//step 5: (user2) login, come back note user2 made, restart python
interpreter in note, check process, logout
//System: Check if the number of python interpreter process is '0'
//System: Check if the number of python process is '0'
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user2noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -750,7 +745,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
// (user2) login, come back note user2 made, run first paragraph,
check process, logout
//System: Check if the number of python process is '2'
//System: Check if the number of python interpreter process is '2'
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user1noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -769,7 +764,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
}
logoutUser("user1");
- authenticationUser("user2", "password3");
+ authenticationUserViaRest("user2", "password3");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
user2noteId + "')]");
element =
(new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)))
@@ -798,7 +793,7 @@ public class InterpreterModeActionsIT extends
AbstractZeppelinIT {
//step 7: (admin) login, restart python interpreter in interpreter tab,
check process, logout
//System: Check if the number of python interpreter process is 0
//System: Check if the number of python process is 0
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn
dropdown-toggle ng-scope')]"),
MAX_BROWSER_TIMEOUT_SEC).click();
diff --git
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
index 943f059175..8abe1ca9a1 100644
---
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
+++
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java
@@ -100,7 +100,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
void testSimpleAction() throws Exception {
try {
// step 1 : (admin) create a new note, run a paragraph and turn on
personalized mode
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
By locator = By.xpath("//div[contains(@class,
\"col-md-4\")]/div/h5/a[contains(.,'Create new" +
" note')]");
WebDriverWait wait =
@@ -109,8 +109,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String noteId = extractNoteIdFromCurrentUrl();
waitForParagraph(1, "READY");
setParagraphText("Before");
assertEquals("Before", manager.getWebDriver()
@@ -124,7 +123,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
logoutUser("admin");
// step 2 : (user1) make sure it is on personalized mode and 'Before' in
result of paragraph
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
wait = new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC));
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
@@ -145,7 +144,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
logoutUser("user1");
// step 3 : (admin) change paragraph contents to 'After' and check
result of paragraph
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element.isDisplayed()) {
@@ -160,7 +159,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
logoutUser("admin");
// step 4 : (user1) check whether result is 'Before' or not
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element.isDisplayed()) {
@@ -180,7 +179,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
void testGraphAction() throws Exception {
try {
// step 1 : (admin) create a new note, run a paragraph, change active
graph to 'Bar chart', turn on personalized mode
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
By locator = By.xpath("//div[contains(@class,
\"col-md-4\")]/div/h5/a[contains(.,'Create new" +
" note')]");
WebDriverWait wait =
@@ -189,8 +188,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String noteId = extractNoteIdFromCurrentUrl();
setTextOfParagraph(1, "%python print(\"%table " +
"name\\\\tsize\\\\n" +
"sun\\\\t100\\\\n" +
@@ -222,7 +220,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
// step 2 : (user1) make sure it is on personalized mode and active
graph is 'Bar chart',
// try to change active graph to 'Table' and then check result
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element.isDisplayed()) {
@@ -248,7 +246,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
manager.getWebDriver().navigate().refresh();
// step 3: (admin) Admin view is still table because of it's
personalized!
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element.isDisplayed()) {
@@ -270,7 +268,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
void testDynamicFormAction() throws Exception {
try {
// step 1 : (admin) login, create a new note, run a paragraph with data
of spark tutorial, logout.
- authenticationUser("admin", "password1");
+ authenticationUserViaRest("admin", "password1");
By locator = By.xpath("//div[contains(@class,
\"col-md-4\")]/div/h5/a[contains(.,'Create new" +
" note')]");
WebDriverWait wait =
@@ -279,8 +277,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
if (element.isDisplayed()) {
createNewNote();
}
- String noteId = manager.getWebDriver().getCurrentUrl()
- .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") +
1);
+ String noteId = extractNoteIdFromCurrentUrl();
setTextOfParagraph(1, "%spark println(\"Status: \"+z.textbox(\"name\",
\"Before\")) ");
runParagraph(1);
try {
@@ -301,7 +298,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
// step 2 : (user1) make sure it is on personalized mode and dynamic
form value is 'Before',
// try to change dynamic form value to 'After' and then check result
- authenticationUser("user1", "password2");
+ authenticationUserViaRest("user1", "password2");
locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" +
noteId + "')]");
element =
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element.isDisplayed()) {
@@ -313,6 +310,7 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
"//button[contains(@class, 'btn btn-default btn-xs ng-scope
ng-hide')]"))
.getAttribute("uib-tooltip"));
+ waitForParagraph(1, "READY");
assertEquals("Before",
manager.getWebDriver().findElement(By.xpath(getParagraphXPath(1) +
"//input[contains(@name, 'name')]")).getAttribute("value"));
@@ -321,6 +319,11 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
visibilityWait(By.xpath(getParagraphXPath(1) +
"//input[contains(@name, 'name')]"),
MAX_BROWSER_TIMEOUT_SEC).sendKeys("After");
+ new WebDriverWait(manager.getWebDriver(),
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))
+ .until(ExpectedConditions.attributeToBe(
+ By.xpath(getParagraphXPath(1) + "//input[contains(@name,
'name')]"), "value",
+ "After"));
+
runParagraph(1);
try {
waitForParagraph(1, "FINISHED");
@@ -330,14 +333,14 @@ public class PersonalizeActionsIT extends
AbstractZeppelinIT {
"Exception in PersonalizeActionsIT while testDynamicFormAction,
status of 1st Spark Paragraph ");
}
- assertEquals("Status: Before", manager.getWebDriver()
+ assertEquals("Status: After", manager.getWebDriver()
.findElement(By
.xpath(getParagraphXPath(1) + "//div[contains(@class, 'text
plainTextContent')]"))
.getText());
logoutUser("user1");
} catch (Exception e) {
- handleException("Exception in PersonalizeActionsIT while testGraphAction
", e);
+ handleException("Exception in PersonalizeActionsIT while
testDynamicFormAction ", e);
}
}
}