/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.integration;
import org.apache.zeppelin.AbstractZeppelinIT;
import org.apache.zeppelin.WebDriverManager;
import org.apache.zeppelin.ZeppelinITUtils;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test Zeppelin with web browser.
*
* To test, ZeppelinServer should be running on port 8080
* On OSX, you'll need firefox 42.0 installed, then you can run with
*
* PATH=~/Applications/Firefox.app/Contents/MacOS/:$PATH TEST_SELENIUM="" \
* mvn -Dtest=org.apache.zeppelin.integration.ZeppelinIT -Denforcer.skip=true \
* test -pl zeppelin-server
*
*/
public class ZeppelinIT extends AbstractZeppelinIT {
private static final Logger LOG = LoggerFactory.getLogger(ZeppelinIT.class);
@Rule
public ErrorCollector collector = new ErrorCollector();
@Before
public void startUp() {
if (!endToEndTestEnabled()) {
return;
}
driver = WebDriverManager.getWebDriver();
}
@After
public void tearDown() {
if (!endToEndTestEnabled()) {
return;
}
driver.quit();
}
@Test
public void testAngularDisplay() throws Exception {
if (!endToEndTestEnabled()) {
return;
}
try {
createNewNote();
// wait for first paragraph's " READY " status text
waitForParagraph(1, "READY");
/*
* print angular template
* %angular <div id='angularTestButton' ng-click='myVar=myVar+1'>BindingTest_{{myVar}}_</div>
*/
setTextOfParagraph(1, "println(\"%angular <div id=\\'angularTestButton\\' ng-click=\\'myVar=myVar+1\\'>BindingTest_{{myVar}}_</div>\")");
runParagraph(1);
waitForParagraph(1, "FINISHED");
// check expected text
waitForText("BindingTest__", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
/*
* Bind variable
* z.angularBind("myVar", 1)
*/
assertEquals(1, driver.findElements(By.xpath(getParagraphXPath(2) + "//textarea")).size());
setTextOfParagraph(2, "z.angularBind(\"myVar\", 1)");
runParagraph(2);
waitForParagraph(2, "FINISHED");
// check expected text
waitForText("BindingTest_1_", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
/*
* print variable
* print("myVar="+z.angular("myVar"))
*/
setTextOfParagraph(3, "print(\"myVar=\"+z.angular(\"myVar\"))");
runParagraph(3);
waitForParagraph(3, "FINISHED");
// check expected text
waitForText("myVar=1", By.xpath(
getParagraphXPath(3) + "//div[contains(@id,\"_text\") and @class=\"text\"]"));
/*
* Click element
*/
driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click();
// check expected text
waitForText("BindingTest_2_", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
/*
* Register watcher
* z.angularWatch("myVar", (before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext) => {
* z.run(2, context)
* }
*/
setTextOfParagraph(4, "z.angularWatch(\"myVar\", (before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext)=>{ z.run(2, false)})");
runParagraph(4);
waitForParagraph(4, "FINISHED");
/*
* Click element, again and see watcher works
*/
driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click();
// check expected text
waitForText("BindingTest_3_", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
waitForParagraph(3, "FINISHED");
// check expected text by watcher
waitForText("myVar=3", By.xpath(
getParagraphXPath(3) + "//div[contains(@id,\"_text\") and @class=\"text\"]"));
/*
* Click element, again and see watcher still works
*/
driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]")).click();
// check expected text
waitForText("BindingTest_4_", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
waitForParagraph(3, "FINISHED");
// check expected text by watcher
waitForText("myVar=4", By.xpath(
getParagraphXPath(3) + "//div[contains(@id,\"_text\") and @class=\"text\"]"));
/*
* Unbind
* z.angularUnbind("myVar")
*/
setTextOfParagraph(5, "z.angularUnbind(\"myVar\")");
runParagraph(5);
waitForParagraph(5, "FINISHED");
// check expected text
waitForText("BindingTest__",
By.xpath(getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
/*
* Bind again and see rebind works.
*/
runParagraph(2);
waitForParagraph(2, "FINISHED");
// check expected text
waitForText("BindingTest_1_",
By.xpath(getParagraphXPath(1) + "//div[@id=\"angularTestButton\"]"));
driver.findElement(By.xpath(".//*[@id='main']//button[@ng-click='moveNoteToTrash(note.id)']"))
.sendKeys(Keys.ENTER);
ZeppelinITUtils.sleep(1000, true);
driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'This note will be moved to trash')]" +
"//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
ZeppelinITUtils.sleep(100, true);
LOG.info("testCreateNotebook Test executed");
} catch (Exception e) {
handleException("Exception in ZeppelinIT while testAngularDisplay ", e);
}
}
@Test
public void testSparkInterpreterDependencyLoading() throws Exception {
if (!endToEndTestEnabled()) {
return;
}
try {
// navigate to interpreter page
WebElement settingButton = driver.findElement(By.xpath("//button[@class='nav-btn dropdown-toggle ng-scope']"));
settingButton.click();
WebElement interpreterLink = driver.findElement(By.xpath("//a[@href='#/interpreter']"));
interpreterLink.click();
// add new dependency to spark interpreter
driver.findElement(By.xpath("//div[@id='spark']//button[contains(.,'edit')]")).sendKeys(Keys.ENTER);
WebElement depArtifact = pollingWait(By.xpath("//input[@ng-model='setting.depArtifact']"),
MAX_BROWSER_TIMEOUT_SEC);
String artifact = "org.apache.commons:commons-csv:1.1";
depArtifact.sendKeys(artifact);
driver.findElement(By.xpath("//div[@id='spark']//form//button[1]")).click();
clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to update this interpreter and restart with new settings?')]" +
"//div[@class='modal-footer']//button[contains(.,'OK')]"));
try {
clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to " +
"update this interpreter and restart with new settings?')]//" +
"div[@class='bootstrap-dialog-close-button']/button"));
} catch (TimeoutException | StaleElementReferenceException e) {
//Modal dialog got closed earlier than expected nothing to worry.
}
driver.navigate().back();
createNewNote();
// wait for first paragraph's " READY " status text
waitForParagraph(1, "READY");
setTextOfParagraph(1, "import org.apache.commons.csv.CSVFormat");
runParagraph(1);
waitForParagraph(1, "FINISHED");
// check expected text
WebElement paragraph1Result = driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[contains(@id,\"_text\")]"));
collector.checkThat("Paragraph from ZeppelinIT of testSparkInterpreterDependencyLoading result: ",
paragraph1Result.getText().toString(), CoreMatchers.containsString(
"import org.apache.commons.csv.CSVFormat"
)
);
//delete created notebook for cleanup.
deleteTestNotebook(driver);
ZeppelinITUtils.sleep(1000, false);
// reset dependency
settingButton.click();
interpreterLink.click();
driver.findElement(By.xpath("//div[@id='spark']//button[contains(.,'edit')]")).sendKeys(Keys.ENTER);
WebElement testDepRemoveBtn = pollingWait(By.xpath("//tr[descendant::text()[contains(.,'" +
artifact + "')]]/td[3]/button"), MAX_IMPLICIT_WAIT);
testDepRemoveBtn.sendKeys(Keys.ENTER);
driver.findElement(By.xpath("//div[@id='spark']//form//button[1]")).click();
driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to update this interpreter and restart with new settings?')]" +
"//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
} catch (Exception e) {
handleException("Exception in ZeppelinIT while testSparkInterpreterDependencyLoading ", e);
}
}
@Test
public void testAngularRunParagraph() throws Exception {
if (!endToEndTestEnabled()) {
return;
}
try {
createNewNote();
// wait for first paragraph's " READY " status text
waitForParagraph(1, "READY");
// Create 1st paragraph
setTextOfParagraph(1,
"%angular <div id=\\'angularRunParagraph\\'>Run second paragraph</div>");
runParagraph(1);
waitForParagraph(1, "FINISHED");
waitForText("Run second paragraph", By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularRunParagraph\"]"));
// Create 2nd paragraph
setTextOfParagraph(2, "%sh echo TEST");
runParagraph(2);
waitForParagraph(2, "FINISHED");
// Get 2nd paragraph id
final String secondParagraphId = driver.findElement(By.xpath(getParagraphXPath(2)
+ "//div[@class=\"control ng-scope\"]//ul[@class=\"dropdown-menu dropdown-menu-right\"]/li[1]"))
.getAttribute("textContent");
assertTrue("Cannot find paragraph id for the 2nd paragraph", isNotBlank(secondParagraphId));
// Update first paragraph to call z.runParagraph() with 2nd paragraph id
setTextOfParagraph(1,
"%angular <div id=\\'angularRunParagraph\\' ng-click=\\'z.runParagraph(\""
+ secondParagraphId.trim()
+ "\")\\'>Run second paragraph</div>");
runParagraph(1);
waitForParagraph(1, "FINISHED");
// Set new text value for 2nd paragraph
setTextOfParagraph(2, "%sh echo NEW_VALUE");
// Click on 1 paragraph to trigger z.runParagraph() function
driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@id=\"angularRunParagraph\"]")).click();
waitForParagraph(2, "FINISHED");
// Check that 2nd paragraph has been executed
waitForText("NEW_VALUE", By.xpath(
getParagraphXPath(2) + "//div[contains(@id,\"_text\") and @class=\"text\"]"));
//delete created notebook for cleanup.
deleteTestNotebook(driver);
ZeppelinITUtils.sleep(1000, true);
LOG.info("testAngularRunParagraph Test executed");
} catch (Exception e) {
handleException("Exception in ZeppelinIT while testAngularRunParagraph", e);
}
}
}