Merge remote-tracking branch 'origin/master' into livyInterperter

This commit is contained in:
Prabhjyot Singh 2016-03-23 12:15:42 +05:30
commit 01ec47493b
10 changed files with 251 additions and 159 deletions

View file

@ -105,6 +105,8 @@ public class Message {
ANGULAR_OBJECT_CLIENT_BIND, // [c-s] angular object updated from AngularJS z object
ANGULAR_OBJECT_CLIENT_UNBIND, // [c-s] angular object unbind from AngularJS z object
LIST_CONFIGURATIONS, // [c-s] ask all key/value pairs of configurations
CONFIGURATIONS_INFO, // [s-c] all key/value pairs of configurations
// @param settings serialized Map<String, String> object

View file

@ -190,6 +190,9 @@ public class NotebookServer extends WebSocketServlet implements
case ANGULAR_OBJECT_CLIENT_BIND:
angularObjectClientBind(conn, userAndRoles, notebook, messagereceived);
break;
case ANGULAR_OBJECT_CLIENT_UNBIND:
angularObjectClientUnbind(conn, userAndRoles, notebook, messagereceived);
break;
case LIST_CONFIGURATIONS:
sendAllConfigurations(conn, userAndRoles, notebook);
break;
@ -769,6 +772,45 @@ public class NotebookServer extends WebSocketServlet implements
}
}
/**
* Remove the given Angular variable to the target
* interpreter(s) angular registry given a noteId
* and an optional list of paragraph id(s)
* @param conn
* @param notebook
* @param fromMessage
* @throws Exception
*/
protected void angularObjectClientUnbind(NotebookSocket conn, HashSet<String> userAndRoles,
Notebook notebook, Message fromMessage)
throws Exception{
String noteId = fromMessage.getType("noteId");
String varName = fromMessage.getType("name");
String paragraphId = fromMessage.getType("paragraphId");
Note note = notebook.getNote(noteId);
if (paragraphId == null) {
throw new IllegalArgumentException("target paragraph not specified for " +
"angular value unBind");
}
if (note != null) {
final InterpreterGroup interpreterGroup = findInterpreterGroupForParagraph(note,
paragraphId);
final AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry();
if (registry instanceof RemoteAngularObjectRegistry) {
RemoteAngularObjectRegistry remoteRegistry = (RemoteAngularObjectRegistry) registry;
removeAngularFromRemoteRegistry(noteId, paragraphId, varName, remoteRegistry,
interpreterGroup.getId(), conn);
} else {
removeAngularObjectFromLocalRepo(noteId, paragraphId, varName, registry,
interpreterGroup.getId(), conn);
}
}
}
private InterpreterGroup findInterpreterGroupForParagraph(Note note, String paragraphId)
throws Exception {
final Paragraph paragraph = note.getParagraph(paragraphId);
@ -794,6 +836,20 @@ public class NotebookServer extends WebSocketServlet implements
conn);
}
private void removeAngularFromRemoteRegistry(String noteId, String paragraphId,
String varName, RemoteAngularObjectRegistry remoteRegistry,
String interpreterGroupId, NotebookSocket conn) {
final AngularObject ao = remoteRegistry.removeAndNotifyRemoteProcess(varName, noteId,
paragraphId);
this.broadcastExcept(
noteId,
new Message(OP.ANGULAR_OBJECT_REMOVE).put("angularObject", ao)
.put("interpreterGroupId", interpreterGroupId)
.put("noteId", noteId)
.put("paragraphId", paragraphId),
conn);
}
private void pushAngularObjectToLocalRepo(String noteId, String paragraphId, String varName,
Object varValue, AngularObjectRegistry registry,
String interpreterGroupId, NotebookSocket conn) {
@ -813,6 +869,20 @@ public class NotebookServer extends WebSocketServlet implements
conn);
}
private void removeAngularObjectFromLocalRepo(String noteId, String paragraphId, String varName,
AngularObjectRegistry registry, String interpreterGroupId, NotebookSocket conn) {
final AngularObject removed = registry.remove(varName, noteId, paragraphId);
if (removed != null) {
this.broadcastExcept(
noteId,
new Message(OP.ANGULAR_OBJECT_REMOVE).put("angularObject", removed)
.put("interpreterGroupId", interpreterGroupId)
.put("noteId", noteId)
.put("paragraphId", paragraphId),
conn);
}
}
private void moveParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");

View file

@ -41,6 +41,7 @@ abstract public class AbstractZeppelinIT {
protected WebDriver driver;
protected final static Logger LOG = LoggerFactory.getLogger(AbstractZeppelinIT.class);
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 = 60;
@ -59,6 +60,19 @@ abstract public class AbstractZeppelinIT {
}
}
protected void setTextOfParagraph(int paragraphNo, String text) {
String editorId = driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + "//div[contains(@class, 'editor')]")).getAttribute("id");
if (driver instanceof JavascriptExecutor) {
((JavascriptExecutor) driver).executeScript("ace.edit('" + editorId + "'). setValue('" + text + "')");
} else {
throw new IllegalStateException("This driver does not support JavaScript!");
}
}
protected void runParagraph(int paragraphNo) {
driver.findElement(By.xpath(getParagraphXPath(paragraphNo) + "//span[@class='icon-control-play']")).click();
}
protected String getParagraphXPath(int paragraphNo) {
return "//div[@ng-controller=\"ParagraphCtrl\"][" + paragraphNo + "]";
@ -135,40 +149,6 @@ abstract public class AbstractZeppelinIT {
sleep(100, true);
}
public enum HelperKeys implements CharSequence {
OPEN_PARENTHESIS(Keys.chord(Keys.SHIFT, "9")),
EXCLAMATION(Keys.chord(Keys.SHIFT, "1")),
PERCENTAGE(Keys.chord(Keys.SHIFT, "5")),
SHIFT_ENTER(Keys.chord(SHIFT, ENTER));
private final CharSequence keyCode;
HelperKeys(CharSequence keyCode) {
this.keyCode = keyCode;
}
public char charAt(int index) {
return index == 0 ? keyCode.charAt(index) : '\ue000';
}
public int length() {
return 1;
}
public CharSequence subSequence(int start, int end) {
if (start == 0 && end == 1) {
return String.valueOf(this.keyCode);
} else {
throw new IndexOutOfBoundsException();
}
}
public String toString() {
return String.valueOf(this.keyCode);
}
}
protected void handleException(String message, Exception e) throws Exception {
LOG.error(message, e);
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

View file

@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.fail;
@ -114,6 +115,8 @@ public class WebDriverManager {
long start = System.currentTimeMillis();
boolean loaded = false;
driver.manage().timeouts().implicitlyWait(AbstractZeppelinIT.MAX_IMPLICIT_WAIT,
TimeUnit.SECONDS);
driver.get(url);
while (System.currentTimeMillis() - start < 60 * 1000) {

View file

@ -87,8 +87,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
"//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
ZeppelinITUtils.sleep(1000, false);
WebElement oldParagraphEditor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
oldParagraphEditor.sendKeys(" original paragraph ");
setTextOfParagraph(1, " original paragraph ");
WebElement newPara = driver.findElement(By.xpath(getParagraphXPath(1) + "//div[contains(@class,'new-paragraph')][1]"));
action.moveToElement(newPara).click().build().perform();
@ -98,8 +97,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
collector.checkThat("Paragraph is created above",
driver.findElement(By.xpath(getParagraphXPath(1) + "//div[contains(@class, 'editor')]")).getText(),
CoreMatchers.equalTo(""));
WebElement aboveParagraphEditor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
aboveParagraphEditor.sendKeys(" this is above ");
setTextOfParagraph(1, " this is above ");
newPara = driver.findElement(By.xpath(getParagraphXPath(2) + "//div[contains(@class,'new-paragraph')][2]"));
action.moveToElement(newPara).click().build().perform();
@ -109,8 +107,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
collector.checkThat("Paragraph is created below",
driver.findElement(By.xpath(getParagraphXPath(3) + "//div[contains(@class, 'editor')]")).getText(),
CoreMatchers.equalTo(""));
WebElement belowParagraphEditor = driver.findElement(By.xpath(getParagraphXPath(3) + "//textarea"));
belowParagraphEditor.sendKeys(" this is below ");
setTextOfParagraph(3, " this is below ");
collector.checkThat("The output field of paragraph1 contains",
driver.findElement(By.xpath(getParagraphXPath(1) + "//div[contains(@class, 'editor')]")).getText(),
@ -163,7 +160,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
deleteTestNotebook(driver);
} catch (Exception e) {
handleException("Exception in ParagraphActionsIT while testMoveUpAndDown ", e);
handleException("Exception in ParagraphActionsIT while testRemoveButton ", e);
}
}
@ -176,16 +173,14 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
createNewNote();
waitForParagraph(1, "READY");
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("1");
setTextOfParagraph(1, "1");
driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='insertNew()']")).click();
waitForParagraph(2, "READY");
WebElement paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea"));
paragraph2Editor.sendKeys("2");
setTextOfParagraph(2, "2");
collector.checkThat("The paragraph1 value contains",
@ -236,9 +231,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
createNewNote();
waitForParagraph(1, "READY");
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\""
+ "abcd\")");
setTextOfParagraph(1, "println (\"abcd\")");
driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click();
driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/a[@ng-click='toggleEnableDisable()']")).click();
@ -275,9 +268,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
waitForParagraph(1, "READY");
String xpathToOutputField=getParagraphXPath(1) + "//div[contains(@ng-if,'getResultType()')]";
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\""
+ "abcd\")");
setTextOfParagraph(1, "println (\"abcd\")");
collector.checkThat("Before Run Output field contains ",
driver.findElement(By.xpath(xpathToOutputField)).getText(),
CoreMatchers.equalTo(""));

View file

@ -32,9 +32,6 @@ import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.zeppelin.AbstractZeppelinIT.HelperKeys.*;
import static org.openqa.selenium.Keys.*;
public class SparkParagraphIT extends AbstractZeppelinIT {
private static final Logger LOG = LoggerFactory.getLogger(SparkParagraphIT.class);
@ -67,17 +64,10 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
return;
}
try {
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("sc.version");
paragraph1Editor.sendKeys(SHIFT_ENTER);
setTextOfParagraph(1, "sc.version");
runParagraph(1);
waitForParagraph(1, "FINISHED");
WebElement paragraph1Result = driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@class=\"tableDisplay\"]"));
Float sparkVersion = Float.parseFloat(paragraph1Result.getText().split("= ")[1].substring(0, 3));
WebElement paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea"));
/*
equivalent of
@ -90,50 +80,15 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
val bank = bankText.map(s => s.split(";")).filter(s => s(0) != "\"age\"").map(s => Bank(s(0).toInt,s(1).replaceAll("\"", ""),s(2).replaceAll("\"", ""),s(3).replaceAll("\"", ""),s(5).replaceAll("\"", "").toInt)).toDF()
bank.registerTempTable("bank")
*/
paragraph2Editor.sendKeys("import org.apache.commons.io.IOUtils" +
ENTER +
"import java.net.URL" +
ENTER +
"import java.nio.charset.Charset" +
ENTER +
"val bankText = sc.parallelize" + OPEN_PARENTHESIS +
"IOUtils.toString" + OPEN_PARENTHESIS + "new URL" + OPEN_PARENTHESIS
+ "\"https://s3.amazonaws.com/apache" + SUBTRACT + "zeppelin/tutorial/bank/bank." +
"csv\"),Charset.forName" + OPEN_PARENTHESIS + "\"utf8\"))" +
".split" + OPEN_PARENTHESIS + "\"\\n\"))" +
ENTER +
"case class Bank" + OPEN_PARENTHESIS +
"age: Integer, job: String, marital: String, education: String, balance: Integer)" +
ENTER +
ENTER +
"val bank = bankText.map" + OPEN_PARENTHESIS + "s => s.split" +
OPEN_PARENTHESIS + "\";\")).filter" + OPEN_PARENTHESIS +
"s => s" + OPEN_PARENTHESIS + "0) " + EXCLAMATION +
"= \"\\\"age\\\"\").map" + OPEN_PARENTHESIS +
"s => Bank" + OPEN_PARENTHESIS + "s" + OPEN_PARENTHESIS +
"0).toInt,s" + OPEN_PARENTHESIS + "1).replaceAll" +
OPEN_PARENTHESIS + "\"\\\"\", \"\")," +
"s" + OPEN_PARENTHESIS + "2).replaceAll" +
OPEN_PARENTHESIS + "\"\\\"\", \"\")," +
"s" + OPEN_PARENTHESIS + "3).replaceAll" +
OPEN_PARENTHESIS + "\"\\\"\", \"\")," +
"s" + OPEN_PARENTHESIS + "5).replaceAll" +
OPEN_PARENTHESIS + "\"\\\"\", \"\").toInt" + ")" +
")" + (sparkVersion < 1.3f ? "" : ".toDF" + OPEN_PARENTHESIS + ")") +
ENTER +
"bank.registerTempTable" + OPEN_PARENTHESIS + "\"bank\")"
);
paragraph2Editor.sendKeys("" + END + BACK_SPACE + BACK_SPACE +
BACK_SPACE + BACK_SPACE + BACK_SPACE + BACK_SPACE +
BACK_SPACE + BACK_SPACE + BACK_SPACE + BACK_SPACE + BACK_SPACE);
paragraph2Editor.sendKeys(SHIFT_ENTER);
setTextOfParagraph(2, "import org.apache.commons.io.IOUtils\\n" +
"import java.net.URL\\n" +
"import java.nio.charset.Charset\\n" +
"val bankText = sc.parallelize(IOUtils.toString(new URL(\"https://s3.amazonaws.com/apache-zeppelin/tutorial/bank/bank.csv\"),Charset.forName(\"utf8\")).split(\"\\\\n\"))\\n" +
"case class Bank(age: Integer, job: String, marital: String, education: String, balance: Integer)\\n" +
"\\n" +
"val bank = bankText.map(s => s.split(\";\")).filter(s => s(0) != \"\\\\\"age\\\\\"\").map(s => Bank(s(0).toInt,s(1).replaceAll(\"\\\\\"\", \"\"),s(2).replaceAll(\"\\\\\"\", \"\"),s(3).replaceAll(\"\\\\\"\", \"\"),s(5).replaceAll(\"\\\\\"\", \"\").toInt)).toDF()\\n" +
"bank.registerTempTable(\"bank\")");
runParagraph(2);
try {
waitForParagraph(2, "FINISHED");
@ -164,14 +119,11 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
return;
}
try {
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
setTextOfParagraph(1, "%pyspark\\n" +
"for x in range(0, 3):\\n" +
" print \"test loop %d\" % (x)");
paragraph1Editor.sendKeys(PERCENTAGE + "pyspark" + ENTER +
"for x in range" + OPEN_PARENTHESIS + "0, 3):" + ENTER +
" print \"test loop " + PERCENTAGE + "d\" " +
PERCENTAGE + " " + OPEN_PARENTHESIS + "x)" + ENTER);
paragraph1Editor.sendKeys(SHIFT_ENTER);
runParagraph(1);
try {
waitForParagraph(1, "FINISHED");
@ -199,12 +151,9 @@ public class SparkParagraphIT extends AbstractZeppelinIT {
return;
}
try {
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys(PERCENTAGE + "sql" + ENTER +
setTextOfParagraph(1,"%sql\\n" +
"select * from bank limit 1");
paragraph1Editor.sendKeys(SHIFT_ENTER);
runParagraph(1);
try {
waitForParagraph(1, "FINISHED");

View file

@ -17,21 +17,21 @@
package org.apache.zeppelin.integration;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.zeppelin.AbstractZeppelinIT;
import org.apache.zeppelin.WebDriverManager;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.*;
import org.junit.rules.ErrorCollector;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test Zeppelin with web browser.
@ -47,6 +47,8 @@ import static org.junit.Assert.assertTrue;
public class ZeppelinIT extends AbstractZeppelinIT {
private static final Logger LOG = LoggerFactory.getLogger(ZeppelinIT.class);
@Rule
public ErrorCollector collector = new ErrorCollector();
@Before
public void startUp() {
@ -80,13 +82,8 @@ public class ZeppelinIT extends AbstractZeppelinIT {
* print angular template
* %angular <div id='angularTestButton' ng-click='myVar=myVar+1'>BindingTest_{{myVar}}_</div>
*/
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("println" + Keys.chord(Keys.SHIFT, "9") + "\""
+ Keys.chord(Keys.SHIFT, "5")
+ "angular <div id='angularTestButton' "
+ "ng" + Keys.chord(Keys.SUBTRACT) + "click='myVar=myVar+1'>"
+ "BindingTest_{{myVar}}_</div>\")");
paragraph1Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(1, "println(\"%angular <div id=\\'angularTestButton\\' ng-click=\\'myVar=myVar+1\\'>BindingTest_{{myVar}}_</div>\")");
runParagraph(1);
waitForParagraph(1, "FINISHED");
// check expected text
@ -98,9 +95,8 @@ public class ZeppelinIT extends AbstractZeppelinIT {
* z.angularBind("myVar", 1)
*/
assertEquals(1, driver.findElements(By.xpath(getParagraphXPath(2) + "//textarea")).size());
WebElement paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea"));
paragraph2Editor.sendKeys("z.angularBind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", 1)");
paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(2, "z.angularBind(\"myVar\", 1)");
runParagraph(2);
waitForParagraph(2, "FINISHED");
// check expected text
@ -112,11 +108,8 @@ public class ZeppelinIT extends AbstractZeppelinIT {
* print variable
* print("myVar="+z.angular("myVar"))
*/
WebElement paragraph3Editor = driver.findElement(By.xpath(getParagraphXPath(3) + "//textarea"));
paragraph3Editor.sendKeys(
"print" + Keys.chord(Keys.SHIFT, "9") + "\"myVar=\"" + Keys.chord(Keys.ADD)
+ "z.angular" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\"))");
paragraph3Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(3, "print(\"myVar=\"+z.angular(\"myVar\"))");
runParagraph(3);
waitForParagraph(3, "FINISHED");
// check expected text
@ -139,13 +132,8 @@ public class ZeppelinIT extends AbstractZeppelinIT {
* z.run(2, context)
* }
*/
WebElement paragraph4Editor = driver.findElement(By.xpath(getParagraphXPath(4) + "//textarea"));
paragraph4Editor.sendKeys(
"z.angularWatch" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\", "
+ Keys.chord(Keys.SHIFT, "9")
+ "before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext)"
+ Keys.EQUALS + ">{ z.run" +Keys.chord(Keys.SHIFT, "9") + "2, context)}");
paragraph4Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(4, "z.angularWatch(\"myVar\", (before:Object, after:Object, context:org.apache.zeppelin.interpreter.InterpreterContext)=>{ z.run(2, context)})");
runParagraph(4);
waitForParagraph(4, "FINISHED");
@ -168,10 +156,8 @@ public class ZeppelinIT extends AbstractZeppelinIT {
* Unbind
* z.angularUnbind("myVar")
*/
WebElement paragraph5Editor = driver.findElement(By.xpath(getParagraphXPath(5) + "//textarea"));
paragraph5Editor.sendKeys(
"z.angularUnbind" + Keys.chord(Keys.SHIFT, "9") + "\"myVar\")");
paragraph5Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(5, "z.angularUnbind(\"myVar\")");
runParagraph(5);
waitForParagraph(5, "FINISHED");
// check expected text
@ -181,8 +167,7 @@ public class ZeppelinIT extends AbstractZeppelinIT {
/*
* Bind again and see rebind works.
*/
paragraph2Editor = driver.findElement(By.xpath(getParagraphXPath(2) + "//textarea"));
paragraph2Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
runParagraph(2);
waitForParagraph(2, "FINISHED");
// check expected text
@ -228,15 +213,19 @@ public class ZeppelinIT extends AbstractZeppelinIT {
// wait for first paragraph's " READY " status text
waitForParagraph(1, "READY");
WebElement paragraph1Editor = driver.findElement(By.xpath(getParagraphXPath(1) + "//textarea"));
paragraph1Editor.sendKeys("import org.apache.commons.csv.CSVFormat");
paragraph1Editor.sendKeys(Keys.chord(Keys.SHIFT, Keys.ENTER));
setTextOfParagraph(1, "import org.apache.commons.csv.CSVFormat");
runParagraph(1);
waitForParagraph(1, "FINISHED");
// check expected text
assertTrue(waitForText("import org.apache.commons.csv.CSVFormat",
By.xpath(getParagraphXPath(1) + "//div[starts-with(@id, 'p') and contains(@id, 'text')]/div")));
WebElement paragraph1Result = driver.findElement(By.xpath(
getParagraphXPath(1) + "//div[@class=\"tableDisplay\"]"));
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);

View file

@ -262,6 +262,96 @@ public class NotebookServerTest extends AbstractTestRestApi {
verify(otherConn).send(mdMsg1);
}
@Test
public void should_unbind_angular_object_from_remote_for_paragraphs() throws Exception {
//Given
final String varName = "name";
final String value = "val";
final Message messageReceived = new Message(OP.ANGULAR_OBJECT_CLIENT_UNBIND)
.put("noteId", "noteId")
.put("name", varName)
.put("paragraphId", "paragraphId");
final NotebookServer server = new NotebookServer();
final Notebook notebook = mock(Notebook.class);
final Note note = mock(Note.class, RETURNS_DEEP_STUBS);
when(notebook.getNote("noteId")).thenReturn(note);
final Paragraph paragraph = mock(Paragraph.class, RETURNS_DEEP_STUBS);
when(note.getParagraph("paragraphId")).thenReturn(paragraph);
final RemoteAngularObjectRegistry mdRegistry = mock(RemoteAngularObjectRegistry.class);
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");
when(mdRegistry.removeAndNotifyRemoteProcess(varName, "noteId", "paragraphId")).thenReturn(ao1);
NotebookSocket conn = mock(NotebookSocket.class);
NotebookSocket otherConn = mock(NotebookSocket.class);
final String mdMsg1 = server.serializeMessage(new Message(OP.ANGULAR_OBJECT_REMOVE)
.put("angularObject", ao1)
.put("interpreterGroupId", "mdGroup")
.put("noteId", "noteId")
.put("paragraphId", "paragraphId"));
server.noteSocketMap.put("noteId", asList(conn, otherConn));
// When
server.angularObjectClientUnbind(conn, new HashSet<String>(), notebook, messageReceived);
// Then
verify(mdRegistry, never()).removeAndNotifyRemoteProcess(varName, "noteId", null);
verify(otherConn).send(mdMsg1);
}
@Test
public void should_unbind_angular_object_from_local_for_paragraphs() throws Exception {
//Given
final String varName = "name";
final String value = "val";
final Message messageReceived = new Message(OP.ANGULAR_OBJECT_CLIENT_UNBIND)
.put("noteId", "noteId")
.put("name", varName)
.put("paragraphId", "paragraphId");
final NotebookServer server = new NotebookServer();
final Notebook notebook = mock(Notebook.class);
final Note note = mock(Note.class, RETURNS_DEEP_STUBS);
when(notebook.getNote("noteId")).thenReturn(note);
final Paragraph paragraph = mock(Paragraph.class, RETURNS_DEEP_STUBS);
when(note.getParagraph("paragraphId")).thenReturn(paragraph);
final AngularObjectRegistry mdRegistry = mock(AngularObjectRegistry.class);
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");
when(mdRegistry.remove(varName, "noteId", "paragraphId")).thenReturn(ao1);
NotebookSocket conn = mock(NotebookSocket.class);
NotebookSocket otherConn = mock(NotebookSocket.class);
final String mdMsg1 = server.serializeMessage(new Message(OP.ANGULAR_OBJECT_REMOVE)
.put("angularObject", ao1)
.put("interpreterGroupId", "mdGroup")
.put("noteId", "noteId")
.put("paragraphId", "paragraphId"));
server.noteSocketMap.put("noteId", asList(conn, otherConn));
// When
server.angularObjectClientUnbind(conn, new HashSet<String>(), notebook, messageReceived);
// Then
verify(otherConn).send(mdMsg1);
}
private NotebookSocket createWebSocket() {
NotebookSocket sock = mock(NotebookSocket.class);
when(sock.getRequest()).thenReturn(createHttpServletRequest());

View file

@ -35,6 +35,13 @@ angular.module('zeppelinWebApp')
if (paragraphId) {
websocketMsgSrv.clientBindAngularObject($routeParams.noteId, varName, value, paragraphId);
}
},
// Example: z.angularUnBind('my_var', '20150213-231621_168813393')
angularUnbind: function(varName, paragraphId) {
// Only push to server if paragraphId is defined
if (paragraphId) {
websocketMsgSrv.clientUnbindAngularObject($routeParams.noteId, varName, paragraphId);
}
}
};

View file

@ -82,6 +82,17 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
});
},
clientUnbindAngularObject: function(noteId, name, paragraphId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_CLIENT_UNBIND',
data: {
noteId: noteId,
name: name,
paragraphId: paragraphId
}
});
},
cancelParagraphRun: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'CANCEL_PARAGRAPH', data: {id: paragraphId}});
},