Merge remote-tracking branch 'upstream/master' into ZEPPELIN-1363

# Conflicts:
#	zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
This commit is contained in:
tinkoff-dwh 2017-11-01 16:50:58 +05:00
commit f30033a16e
16 changed files with 308 additions and 322 deletions

View file

@ -1519,7 +1519,7 @@ public class NotebookServer extends WebSocketServlet
if (paragraph == null) {
throw new IllegalArgumentException("Unknown paragraph with id : " + paragraphId);
}
return paragraph.getCurrentRepl().getInterpreterGroup();
return paragraph.getBindedInterpreter().getInterpreterGroup();
}
private void pushAngularObjectToRemoteRegistry(String noteId, String paragraphId, String varName,
@ -1784,7 +1784,7 @@ public class NotebookServer extends WebSocketServlet
// if it's the last paragraph and not empty, let's add a new one
boolean isTheLastParagraph = note.isLastParagraph(p.getId());
if (!(Strings.isNullOrEmpty(p.getText()) ||
p.getText().trim().equals(p.getMagic())) &&
Strings.isNullOrEmpty(p.getScriptText())) &&
isTheLastParagraph) {
Paragraph newPara = note.addNewParagraph(p.getAuthenticationInfo());
broadcastNewParagraph(note, newPara);

View file

@ -208,7 +208,7 @@ public class NotebookServerTest extends AbstractTestRestApi {
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
when(paragraph.getBindedInterpreter().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject<String> ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");
@ -256,7 +256,7 @@ public class NotebookServerTest extends AbstractTestRestApi {
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
when(paragraph.getBindedInterpreter().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject<String> ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");
@ -302,7 +302,7 @@ public class NotebookServerTest extends AbstractTestRestApi {
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
when(paragraph.getBindedInterpreter().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject<String> ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");
when(mdRegistry.removeAndNotifyRemoteProcess(varName, "noteId", "paragraphId")).thenReturn(ao1);
@ -347,7 +347,7 @@ public class NotebookServerTest extends AbstractTestRestApi {
final InterpreterGroup mdGroup = new InterpreterGroup("mdGroup");
mdGroup.setAngularObjectRegistry(mdRegistry);
when(paragraph.getCurrentRepl().getInterpreterGroup()).thenReturn(mdGroup);
when(paragraph.getBindedInterpreter().getInterpreterGroup()).thenReturn(mdGroup);
final AngularObject<String> ao1 = AngularObjectBuilder.build(varName, value, "noteId", "paragraphId");

View file

@ -20,7 +20,6 @@ import com.google.gson.Gson;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterGroup;
import org.apache.zeppelin.interpreter.InterpreterSettingManager;
import org.apache.zeppelin.interpreter.ManagedInterpreterGroup;
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess;
@ -341,7 +340,7 @@ public class Helium {
public HeliumPackageSuggestion suggestApp(Paragraph paragraph) {
HeliumPackageSuggestion suggestion = new HeliumPackageSuggestion();
Interpreter intp = paragraph.getCurrentRepl();
Interpreter intp = paragraph.getBindedInterpreter();
if (intp == null) {
return suggestion;
}

View file

@ -78,7 +78,7 @@ public class HeliumApplicationFactory implements ApplicationEventListener, Noteb
public void run() {
try {
// get interpreter process
Interpreter intp = paragraph.getRepl(paragraph.getRequiredReplName());
Interpreter intp = paragraph.getBindedInterpreter();
ManagedInterpreterGroup intpGroup = (ManagedInterpreterGroup) intp.getInterpreterGroup();
RemoteInterpreterProcess intpProcess = intpGroup.getRemoteInterpreterProcess();
if (intpProcess == null) {
@ -200,7 +200,7 @@ public class HeliumApplicationFactory implements ApplicationEventListener, Noteb
"Can't unload application status " + appsToUnload.getStatus());
}
appStatusChange(paragraph, appsToUnload.getId(), ApplicationState.Status.UNLOADING);
Interpreter intp = paragraph.getCurrentRepl();
Interpreter intp = paragraph.getBindedInterpreter();
if (intp == null) {
throw new ApplicationException("No interpreter found");
}
@ -280,7 +280,7 @@ public class HeliumApplicationFactory implements ApplicationEventListener, Noteb
"Can't run application status " + app.getStatus());
}
Interpreter intp = paragraph.getCurrentRepl();
Interpreter intp = paragraph.getBindedInterpreter();
if (intp == null) {
throw new ApplicationException("No interpreter found");
}
@ -417,7 +417,7 @@ public class HeliumApplicationFactory implements ApplicationEventListener, Noteb
@Override
public void onUnbindInterpreter(Note note, InterpreterSetting setting) {
for (Paragraph p : note.getParagraphs()) {
Interpreter currentInterpreter = p.getCurrentRepl();
Interpreter currentInterpreter = p.getBindedInterpreter();
List<InterpreterInfo> infos = setting.getInterpreterInfos();
for (InterpreterInfo info : infos) {
if (currentInterpreter != null &&

View file

@ -841,4 +841,11 @@ public class InterpreterSetting {
}
throw new RuntimeException("Can not convert this type: " + properties.getClass());
}
public void waitForReady() throws InterruptedException {
while (getStatus().equals(
org.apache.zeppelin.interpreter.InterpreterSetting.Status.DOWNLOADING_DEPENDENCIES)) {
Thread.sleep(200);
}
}
}

View file

@ -56,7 +56,7 @@ public class ManagedInterpreterGroup extends InterpreterGroup {
public synchronized RemoteInterpreterProcess getOrCreateInterpreterProcess() throws IOException {
if (remoteInterpreterProcess == null) {
LOGGER.info("Create InterperterProcess for InterpreterGroup: " + getId());
LOGGER.info("Create InterpreterProcess for InterpreterGroup: " + getId());
remoteInterpreterProcess = interpreterSetting.createInterpreterProcess();
}
return remoteInterpreterProcess;

View file

@ -162,7 +162,7 @@ public class RemoteInterpreter extends Interpreter {
private void internal_create() throws IOException {
synchronized (this) {
if (!isCreated) {
RemoteInterpreterProcess interpreterProcess = getOrCreateInterpreterProcess();
this.interpreterProcess = getOrCreateInterpreterProcess();
interpreterProcess.callRemoteFunction(new RemoteInterpreterProcess.RemoteFunction<Void>() {
@Override
public Void call(Client client) throws Exception {

View file

@ -29,6 +29,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.common.JsonSerializable;
import org.apache.zeppelin.completer.CompletionType;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
@ -243,7 +244,7 @@ public class Note implements ParagraphJobListener, JsonSerializable {
this.noteNameListener = listener;
}
void setInterpreterFactory(InterpreterFactory factory) {
public void setInterpreterFactory(InterpreterFactory factory) {
this.factory = factory;
synchronized (paragraphs) {
for (Paragraph p : paragraphs) {
@ -254,11 +255,6 @@ public class Note implements ParagraphJobListener, JsonSerializable {
void setInterpreterSettingManager(InterpreterSettingManager interpreterSettingManager) {
this.interpreterSettingManager = interpreterSettingManager;
synchronized (paragraphs) {
for (Paragraph p : paragraphs) {
p.setInterpreterSettingManager(interpreterSettingManager);
}
}
}
public void initializeJobListenerForParagraph(Paragraph paragraph) {
@ -324,8 +320,7 @@ public class Note implements ParagraphJobListener, JsonSerializable {
void addCloneParagraph(Paragraph srcParagraph) {
// Keep paragraph original ID
final Paragraph newParagraph = new Paragraph(srcParagraph.getId(), this, this, factory,
interpreterSettingManager);
final Paragraph newParagraph = new Paragraph(srcParagraph.getId(), this, this, factory);
Map<String, Object> config = new HashMap<>(srcParagraph.getConfig());
Map<String, Object> param = srcParagraph.settings.getParams();
@ -368,7 +363,7 @@ public class Note implements ParagraphJobListener, JsonSerializable {
}
private Paragraph createParagraph(int index, AuthenticationInfo authenticationInfo) {
Paragraph p = new Paragraph(this, this, factory, interpreterSettingManager);
Paragraph p = new Paragraph(this, this, factory);
p.setAuthenticationInfo(authenticationInfo);
setParagraphMagic(p, index);
return p;
@ -589,14 +584,14 @@ public class Note implements ParagraphJobListener, JsonSerializable {
private void setParagraphMagic(Paragraph p, int index) {
if (paragraphs.size() > 0) {
String magic;
String replName;
if (index == 0) {
magic = paragraphs.get(0).getMagic();
replName = paragraphs.get(0).getIntpText();
} else {
magic = paragraphs.get(index - 1).getMagic();
replName = paragraphs.get(index - 1).getIntpText();
}
if (StringUtils.isNotEmpty(magic)) {
p.setText(magic + "\n");
if (p.isValidInterpreter(replName) && StringUtils.isNotEmpty(replName)) {
p.setText("%" + replName + "\n");
}
}
}
@ -639,44 +634,7 @@ public class Note implements ParagraphJobListener, JsonSerializable {
public boolean run(String paragraphId, boolean blocking) {
Paragraph p = getParagraph(paragraphId);
p.setListener(jobListenerFactory.getParagraphJobListener(this));
if (p.isBlankParagraph()) {
logger.info("skip to run blank paragraph. {}", p.getId());
p.setStatus(Job.Status.FINISHED);
return true;
}
p.clearRuntimeInfo(null);
String requiredReplName = p.getRequiredReplName();
Interpreter intp = factory.getInterpreter(p.getUser(), getId(), requiredReplName);
if (intp == null) {
String intpExceptionMsg =
p.getJobName() + "'s Interpreter " + requiredReplName + " not found";
RuntimeException intpException = new RuntimeException(intpExceptionMsg);
InterpreterResult intpResult =
new InterpreterResult(InterpreterResult.Code.ERROR, intpException.getMessage());
p.setReturn(intpResult, intpException);
p.setStatus(Job.Status.ERROR);
throw intpException;
}
if (p.getConfig().get("enabled") == null || (Boolean) p.getConfig().get("enabled")) {
p.setAuthenticationInfo(p.getAuthenticationInfo());
intp.getScheduler().submit(p);
}
if (blocking) {
while (!p.getStatus().isCompleted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return p.getStatus() == Status.FINISHED;
} else {
return true;
}
return p.execute(blocking);
}
/**
@ -709,6 +667,23 @@ public class Note implements ParagraphJobListener, JsonSerializable {
return p.completion(buffer, cursor);
}
public List<InterpreterCompletion> getInterpreterCompletion() {
List<InterpreterCompletion> completion = new LinkedList();
for (InterpreterSetting intp : interpreterSettingManager.getInterpreterSettings(getId())) {
List<InterpreterInfo> intInfo = intp.getInterpreterInfos();
if (intInfo.size() > 1) {
for (InterpreterInfo info : intInfo) {
String name = intp.getName() + "." + info.getName();
completion.add(new InterpreterCompletion(name, name, CompletionType.setting.name()));
}
} else {
completion.add(new InterpreterCompletion(intp.getName(), intp.getName(),
CompletionType.setting.name()));
}
}
return completion;
}
public List<Paragraph> getParagraphs() {
synchronized (paragraphs) {
return new LinkedList<>(paragraphs);
@ -939,6 +914,10 @@ public class Note implements ParagraphJobListener, JsonSerializable {
this.noteEventListener = noteEventListener;
}
boolean hasInterpreterBinded() {
return !interpreterSettingManager.getInterpreterSettings(getId()).isEmpty();
}
public String toJson() {
return gson.toJson(this);
}

View file

@ -28,10 +28,11 @@ import java.util.List;
import java.util.Map;
import java.security.SecureRandom;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.common.JsonSerializable;
import org.apache.zeppelin.completer.CompletionType;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.GUI;
@ -43,7 +44,6 @@ import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterContextRunner;
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterFactory;
import org.apache.zeppelin.interpreter.InterpreterInfo;
import org.apache.zeppelin.interpreter.InterpreterOption;
import org.apache.zeppelin.interpreter.InterpreterOutput;
import org.apache.zeppelin.interpreter.InterpreterOutputListener;
@ -52,7 +52,7 @@ import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.InterpreterResultMessage;
import org.apache.zeppelin.interpreter.InterpreterResultMessageOutput;
import org.apache.zeppelin.interpreter.InterpreterSetting;
import org.apache.zeppelin.interpreter.InterpreterSettingManager;
import org.apache.zeppelin.interpreter.ManagedInterpreterGroup;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.resource.ResourcePool;
import org.apache.zeppelin.scheduler.Job;
@ -73,21 +73,24 @@ import com.google.common.collect.Maps;
*/
public class Paragraph extends Job implements Cloneable, JsonSerializable {
private static final long serialVersionUID = -6328572073497992016L;
private static Logger logger = LoggerFactory.getLogger(Paragraph.class);
private transient InterpreterFactory factory;
private transient InterpreterSettingManager interpreterSettingManager;
private static Pattern REPL_PATTERN = Pattern.compile("(\\s*)%([\\w\\.]+).*", Pattern.DOTALL);
private transient InterpreterFactory interpreterFactory;
private transient Interpreter interpreter;
private transient Note note;
private transient AuthenticationInfo authenticationInfo;
private transient Map<String, Paragraph> userParagraphMap = Maps.newHashMap(); // personalized
String title;
String text;
String user;
Date dateUpdated;
private Map<String, Object> config; // paragraph configs like isOpen, colWidth, etc
public GUI settings; // form and parameter settings
private String title;
private String text; // text is composed of intpText and scriptText.
private transient String intpText;
private transient String scriptText;
private String user;
private Date dateUpdated;
// paragraph configs like isOpen, colWidth, etc
private Map<String, Object> config = new HashMap<>();
public GUI settings = new GUI(); // form and parameter settings
// since zeppelin-0.7.0, zeppelin stores multiple results of the paragraph
// see ZEPPELIN-212
@ -105,37 +108,19 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
@VisibleForTesting
Paragraph() {
super(generateId(), null);
config = new HashMap<>();
settings = new GUI();
}
public Paragraph(String paragraphId, Note note, JobListener listener,
InterpreterFactory factory, InterpreterSettingManager interpreterSettingManager) {
InterpreterFactory interpreterFactory) {
super(paragraphId, generateId(), listener);
this.note = note;
this.factory = factory;
this.interpreterSettingManager = interpreterSettingManager;
title = null;
text = null;
authenticationInfo = null;
user = null;
dateUpdated = null;
settings = new GUI();
config = new HashMap<>();
this.interpreterFactory = interpreterFactory;
}
public Paragraph(Note note, JobListener listener, InterpreterFactory factory,
InterpreterSettingManager interpreterSettingManager) {
public Paragraph(Note note, JobListener listener, InterpreterFactory interpreterFactory) {
super(generateId(), listener);
this.note = note;
this.factory = factory;
this.interpreterSettingManager = interpreterSettingManager;
title = null;
text = null;
authenticationInfo = null;
dateUpdated = null;
settings = new GUI();
config = new HashMap<>();
this.interpreterFactory = interpreterFactory;
}
private static String generateId() {
@ -160,9 +145,14 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
public Paragraph cloneParagraphForUser(String user) {
Paragraph p = new Paragraph();
p.interpreterFactory = interpreterFactory;
p.note = note;
p.settings.setParams(Maps.newHashMap(settings.getParams()));
p.settings.setForms(Maps.newLinkedHashMap(settings.getForms()));
p.setConfig(Maps.newHashMap(config));
if (getAuthenticationInfo() != null) {
p.setAuthenticationInfo(getAuthenticationInfo());
}
p.setTitle(getTitle());
p.setText(getText());
p.setResult(getReturn());
@ -189,8 +179,23 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
}
public void setText(String newText) {
// strip white space from the beginning
this.text = newText;
this.dateUpdated = new Date();
// parse text to get interpreter component
if (this.text != null) {
Matcher matcher = REPL_PATTERN.matcher(this.text);
if (matcher.matches()) {
String headingSpace = matcher.group(1);
this.intpText = matcher.group(2);
this.interpreter = interpreterFactory.getInterpreter(user, note.getId(), intpText);
this.scriptText = this.text.substring(headingSpace.length() + intpText.length() + 1).trim();
} else {
this.intpText = "";
this.interpreter = interpreterFactory.getInterpreter(user, note.getId(), "");
this.scriptText = this.text;
}
}
}
public AuthenticationInfo getAuthenticationInfo() {
@ -210,6 +215,14 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
this.title = title;
}
public String getIntpText() {
return intpText;
}
public String getScriptText() {
return scriptText;
}
public void setNote(Note note) {
this.note = note;
}
@ -223,100 +236,33 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
return enabled == null || enabled.booleanValue();
}
public String getRequiredReplName() {
return getRequiredReplName(text != null ? text.trim() : text);
public Interpreter getBindedInterpreter() {
return this.interpreterFactory.getInterpreter(user, note.getId(), intpText);
}
public static String getRequiredReplName(String text) {
if (text == null) {
return null;
}
if (!text.startsWith("%")) {
return null;
}
// get script head
int scriptHeadIndex = 0;
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (Character.isWhitespace(ch) || ch == '(' || ch == '\n') {
break;
}
scriptHeadIndex = i;
}
if (scriptHeadIndex < 1) {
return null;
}
String head = text.substring(1, scriptHeadIndex + 1);
return head;
}
public String getScriptBody() {
return getScriptBody(text);
}
public static String getScriptBody(String text) {
if (text == null) {
return null;
}
String magic = getRequiredReplName(text);
if (magic == null) {
return text;
}
if (magic.length() + 1 >= text.length()) {
return "";
}
return text.substring(magic.length() + 1).trim();
}
public Interpreter getRepl(String name) {
return factory.getInterpreter(user, note.getId(), name);
}
public Interpreter getCurrentRepl() {
return getRepl(getRequiredReplName());
}
public List<InterpreterCompletion> getInterpreterCompletion() {
List<InterpreterCompletion> completion = new LinkedList();
for (InterpreterSetting intp : interpreterSettingManager.getInterpreterSettings(note.getId())) {
List<InterpreterInfo> intInfo = intp.getInterpreterInfos();
if (intInfo.size() > 1) {
for (InterpreterInfo info : intInfo) {
String name = intp.getName() + "." + info.getName();
completion.add(new InterpreterCompletion(name, name, CompletionType.setting.name()));
}
} else {
completion.add(new InterpreterCompletion(intp.getName(), intp.getName(),
CompletionType.setting.name()));
}
}
return completion;
public void setInterpreter(Interpreter interpreter) {
this.interpreter = interpreter;
}
public List<InterpreterCompletion> completion(String buffer, int cursor) {
String lines[] = buffer.split(System.getProperty("line.separator"));
if (lines.length > 0 && lines[0].startsWith("%") && cursor <= lines[0].trim().length()) {
int idx = lines[0].indexOf(' ');
if (idx < 0 || (idx > 0 && cursor <= idx)) {
return getInterpreterCompletion();
return note.getInterpreterCompletion();
}
}
String trimmedBuffer = buffer != null ? buffer.trim() : null;
cursor = calculateCursorPosition(buffer, trimmedBuffer, cursor);
String replName = getRequiredReplName(trimmedBuffer);
String body = getScriptBody(trimmedBuffer);
InterpreterContext interpreterContext = getInterpreterContextWithoutRunner(null);
try {
Interpreter repl = getRepl(replName);
return repl.completion(body, cursor, interpreterContext);
if (this.interpreter != null) {
return this.interpreter.completion(scriptText, cursor, interpreterContext);
} else {
return null;
}
} catch (InterpreterException e) {
throw new RuntimeException("Fail to get completion", e);
}
@ -328,21 +274,25 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
cursor -= countWhitespacesAtStart;
}
String replName = getRequiredReplName(trimmedBuffer);
if (replName != null && cursor > replName.length()) {
String body = trimmedBuffer.substring(replName.length() + 1);
cursor -= replName.length() + 1 + body.indexOf(body.trim());
// parse text to get interpreter component
String repl = null;
if (trimmedBuffer != null) {
Matcher matcher = REPL_PATTERN.matcher(trimmedBuffer);
if (matcher.matches()) {
repl = matcher.group(2);
}
}
if (repl != null && cursor > repl.length()) {
String body = trimmedBuffer.substring(repl.length() + 1);
cursor -= repl.length() + 1 + body.indexOf(body.trim());
}
return cursor;
}
public void setInterpreterFactory(InterpreterFactory factory) {
this.factory = factory;
}
public void setInterpreterSettingManager(InterpreterSettingManager interpreterSettingManager) {
this.interpreterSettingManager = interpreterSettingManager;
this.interpreterFactory = factory;
}
public InterpreterResult getResult() {
@ -360,14 +310,12 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
@Override
public int progress() {
String replName = getRequiredReplName();
try {
Interpreter repl = getRepl(replName);
if (repl == null) {
if (this.interpreter != null) {
return this.interpreter.getProgress(getInterpreterContext(null));
} else {
return 0;
}
return repl.getProgress(getInterpreterContext(null));
} catch (InterpreterException e) {
throw new RuntimeException("Fail to get progress", e);
}
@ -388,31 +336,67 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
}
public boolean isBlankParagraph() {
return Strings.isNullOrEmpty(getText()) || getText().trim().equals(getMagic());
return Strings.isNullOrEmpty(scriptText);
}
public boolean execute(boolean blocking) {
if (isBlankParagraph()) {
logger.info("skip to run blank paragraph. {}", getId());
setStatus(Job.Status.FINISHED);
return true;
}
clearRuntimeInfo(null);
this.interpreter = getBindedInterpreter();
if (interpreter == null) {
String intpExceptionMsg =
getJobName() + "'s Interpreter " + getIntpText() + " not found";
RuntimeException intpException = new RuntimeException(intpExceptionMsg);
InterpreterResult intpResult =
new InterpreterResult(InterpreterResult.Code.ERROR, intpException.getMessage());
setReturn(intpResult, intpException);
setStatus(Job.Status.ERROR);
throw intpException;
}
if (getConfig().get("enabled") == null || (Boolean) getConfig().get("enabled")) {
setAuthenticationInfo(getAuthenticationInfo());
interpreter.getScheduler().submit(this);
}
if (blocking) {
while (!getStatus().isCompleted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return getStatus() == Status.FINISHED;
} else {
return true;
}
}
@Override
protected Object jobRun() throws Throwable {
String replName = getRequiredReplName();
Interpreter repl = getRepl(replName);
logger.info("run paragraph {} using {} " + repl, getId(), replName);
if (repl == null) {
logger.error("Can not find interpreter name " + repl);
throw new RuntimeException("Can not find interpreter for " + getRequiredReplName());
logger.info("Run paragraph {} using {} ", getId(), intpText);
this.interpreter = getBindedInterpreter();
if (this.interpreter == null) {
logger.error("Can not find interpreter name " + intpText);
throw new RuntimeException("Can not find interpreter for " + intpText);
}
//TODO(zjffdu) check interpreter setting status in interpreter setting itself
InterpreterSetting intp = getInterpreterSettingById(repl.getInterpreterGroup().getId());
while (intp.getStatus().equals(
org.apache.zeppelin.interpreter.InterpreterSetting.Status.DOWNLOADING_DEPENDENCIES)) {
Thread.sleep(200);
InterpreterSetting interpreterSetting = ((ManagedInterpreterGroup)
interpreter.getInterpreterGroup()).getInterpreterSetting();
if (interpreterSetting != null) {
interpreterSetting.waitForReady();
}
if (this.noteHasUser() && this.noteHasInterpreters()) {
if (intp != null && interpreterHasUser(intp)
&& isUserAuthorizedToAccessInterpreter(intp.getOption()) == false) {
logger.error("{} has no permission for {} ", authenticationInfo.getUser(), repl);
if (this.hasUser() && this.note.hasInterpreterBinded()) {
if (interpreterSetting != null && interpreterHasUser(interpreterSetting)
&& isUserAuthorizedToAccessInterpreter(interpreterSetting.getOption()) == false) {
logger.error("{} has no permission for {} ", authenticationInfo.getUser(), intpText);
return new InterpreterResult(Code.ERROR,
authenticationInfo.getUser() + " has no permission for " + getRequiredReplName());
authenticationInfo.getUser() + " has no permission for " + intpText);
}
}
@ -420,19 +404,18 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
p.setText(getText());
}
String script = getScriptBody();
// inject form
if (repl.getFormType() == FormType.NATIVE) {
String script = this.scriptText;
if (interpreter.getFormType() == FormType.NATIVE) {
settings.clear();
} else if (repl.getFormType() == FormType.SIMPLE) {
String scriptBody = getScriptBody();
} else if (interpreter.getFormType() == FormType.SIMPLE) {
// inputs will be built from script body
LinkedHashMap<String, Input> inputs = Input.extractSimpleQueryForm(scriptBody, false);
LinkedHashMap<String, Input> noteInputs = Input.extractSimpleQueryForm(scriptBody, true);
LinkedHashMap<String, Input> inputs = Input.extractSimpleQueryForm(script, false);
LinkedHashMap<String, Input> noteInputs = Input.extractSimpleQueryForm(script, true);
final AngularObjectRegistry angularRegistry =
repl.getInterpreterGroup().getAngularObjectRegistry();
interpreter.getInterpreterGroup().getAngularObjectRegistry();
String scriptBody = extractVariablesFromAngularRegistry(script, inputs, angularRegistry);
scriptBody = extractVariablesFromAngularRegistry(scriptBody, inputs, angularRegistry);
settings.setForms(inputs);
if (!noteInputs.isEmpty()) {
if (!note.getNoteForms().isEmpty()) {
@ -453,9 +436,9 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
try {
InterpreterContext context = getInterpreterContext();
InterpreterContext.set(context);
InterpreterResult ret = repl.interpret(script, context);
InterpreterResult ret = interpreter.interpret(script, context);
if (repl.getFormType() == FormType.NATIVE) {
if (interpreter.getFormType() == FormType.NATIVE) {
note.setNoteParams(context.getNoteGui().getParams());
note.setNoteForms(context.getNoteGui().getForms());
}
@ -482,16 +465,13 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
}
}
private boolean noteHasUser() {
private boolean hasUser() {
return this.user != null;
}
private boolean noteHasInterpreters() {
return !interpreterSettingManager.getInterpreterSettings(note.getId()).isEmpty();
}
private boolean interpreterHasUser(InterpreterSetting intp) {
return intp.getOption().permissionIsSet() && intp.getOption().getOwners() != null;
private boolean interpreterHasUser(InterpreterSetting interpreterSetting) {
return interpreterSetting.getOption().permissionIsSet() &&
interpreterSetting.getOption().getOwners() != null;
}
private boolean isUserAuthorizedToAccessInterpreter(InterpreterOption intpOpt) {
@ -499,24 +479,12 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
intpOpt.getOwners());
}
private InterpreterSetting getInterpreterSettingById(String id) {
InterpreterSetting setting = null;
for (InterpreterSetting i : interpreterSettingManager.getInterpreterSettings(note.getId())) {
if (id.startsWith(i.getId())) {
setting = i;
break;
}
}
return setting;
}
@Override
protected boolean jobAbort() {
Interpreter repl = getRepl(getRequiredReplName());
if (repl == null) {
if (interpreter == null) {
return true;
}
Scheduler scheduler = repl.getScheduler();
Scheduler scheduler = interpreter.getScheduler();
if (scheduler == null) {
return true;
}
@ -526,7 +494,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
job.setStatus(Status.ABORT);
} else {
try {
repl.cancel(getInterpreterContextWithoutRunner(null));
interpreter.cancel(getInterpreterContextWithoutRunner(null));
} catch (InterpreterException e) {
throw new RuntimeException(e);
}
@ -577,13 +545,9 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
AngularObjectRegistry registry = null;
ResourcePool resourcePool = null;
if (!interpreterSettingManager.getInterpreterSettings(note.getId()).isEmpty()) {
InterpreterSetting intpGroup =
interpreterSettingManager.getInterpreterSettings(note.getId()).get(0);
registry = intpGroup.getOrCreateInterpreterGroup(getUser(), note.getId())
.getAngularObjectRegistry();
resourcePool = intpGroup.getOrCreateInterpreterGroup(getUser(), note.getId())
.getResourcePool();
if (this.interpreter != null) {
registry = this.interpreter.getInterpreterGroup().getAngularObjectRegistry();
resourcePool = this.interpreter.getInterpreterGroup().getResourcePool();
}
List<InterpreterContextRunner> runners = new LinkedList<>();
@ -600,7 +564,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
}
InterpreterContext interpreterContext =
new InterpreterContext(note.getId(), getId(), getRequiredReplName(), this.getTitle(),
new InterpreterContext(note.getId(), getId(), intpText, this.getTitle(),
this.getText(), this.getAuthenticationInfo(), this.getConfig(), this.settings,
getNoteGui(), registry, resourcePool, runners, output);
return interpreterContext;
@ -610,13 +574,9 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
AngularObjectRegistry registry = null;
ResourcePool resourcePool = null;
if (!interpreterSettingManager.getInterpreterSettings(note.getId()).isEmpty()) {
InterpreterSetting intpGroup =
interpreterSettingManager.getInterpreterSettings(note.getId()).get(0);
registry = intpGroup.getOrCreateInterpreterGroup(getUser(), note.getId())
.getAngularObjectRegistry();
resourcePool = intpGroup.getOrCreateInterpreterGroup(getUser(), note.getId())
.getResourcePool();
if (this.interpreter != null) {
registry = this.interpreter.getInterpreterGroup().getAngularObjectRegistry();
resourcePool = this.interpreter.getInterpreterGroup().getResourcePool();
}
List<InterpreterContextRunner> runners = new LinkedList<>();
@ -634,7 +594,7 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
}
InterpreterContext interpreterContext =
new InterpreterContext(note.getId(), getId(), getRequiredReplName(), this.getTitle(),
new InterpreterContext(note.getId(), getId(), intpText, this.getTitle(),
this.getText(), this.getAuthenticationInfo(), this.getConfig(), this.settings,
getNoteGui(), registry, resourcePool, runners, output);
return interpreterContext;
@ -744,22 +704,8 @@ public class Paragraph extends Job implements Cloneable, JsonSerializable {
return scriptBody;
}
public String getMagic() {
String magic = StringUtils.EMPTY;
String text = getText();
if (text != null && text.startsWith("%")) {
magic = text.split("\\s+")[0];
if (isValidInterpreter(magic.substring(1))) {
return magic;
} else {
return StringUtils.EMPTY;
}
}
return magic;
}
private boolean isValidInterpreter(String replName) {
return factory.getInterpreter(user, note.getId(), replName) != null;
public boolean isValidInterpreter(String replName) {
return interpreterFactory.getInterpreter(user, note.getId(), replName) != null;
}
public void updateRuntimeInfos(String label, String tooltip, Map<String, String> infos,

View file

@ -168,8 +168,6 @@ public class VFSNotebookRepo implements NotebookRepo {
ins.close();
Note note = Note.fromJson(json);
// note.setReplLoader(replLoader);
// note.jobListenerFactory = jobListenerFactory;
for (Paragraph p : note.getParagraphs()) {
if (p.getStatus() == Status.PENDING || p.getStatus() == Status.RUNNING) {

View file

@ -229,7 +229,7 @@ public class HeliumApplicationFactoryTest extends AbstractInterpreterTest implem
p1.setText("%fake ");
// make sure that p1's repl is null
Interpreter intp = p1.getCurrentRepl();
Interpreter intp = p1.getBindedInterpreter();
assertEquals(intp, null);
// Unbind all interpreter from note

View file

@ -5,6 +5,7 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.display.AngularObjectRegistryListener;
import org.apache.zeppelin.helium.ApplicationEventListener;
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
import org.apache.zeppelin.notebook.Note;
import org.junit.After;
import org.junit.Before;
import org.slf4j.Logger;
@ -69,4 +70,8 @@ public abstract class AbstractInterpreterTest {
FileUtils.deleteDirectory(confDir);
FileUtils.deleteDirectory(notebookDir);
}
protected Note createNote() {
return new Note(null, interpreterFactory, interpreterSettingManager, null, null, null, null);
}
}

View file

@ -247,7 +247,6 @@ public class NoteTest {
note.getInfo().put("info_1", "value_1");
String pText = "%spark sc.version";
Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
p.dateUpdated = new Date();
p.setText(pText);
p.setResult("1.6.2");
p.settings.getForms().put("textbox_1", new TextBox("name", "default_name"));

View file

@ -144,7 +144,7 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
// then interpreter factory should be injected into all the paragraphs
Note note = notebook.getAllNotes().get(0);
assertNull(note.getParagraphs().get(0).getRepl(null));
assertNull(note.getParagraphs().get(0).getBindedInterpreter());
}
@Test
@ -184,8 +184,8 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
copiedNote.getParagraphs().get(0).getText());
assertEquals(notes.get(1).getParagraphs().get(0).settings,
copiedNote.getParagraphs().get(0).settings);
assertEquals(notes.get(1).getParagraphs().get(0).title,
copiedNote.getParagraphs().get(0).title);
assertEquals(notes.get(1).getParagraphs().get(0).getTitle(),
copiedNote.getParagraphs().get(0).getTitle());
// delete the notebook
for (String note : noteNames) {
@ -470,7 +470,7 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
// Test
assertEquals(p.getId(), p2.getId());
assertEquals(p.text, p2.text);
assertEquals(p.getText(), p2.getText());
assertEquals(p.getResult().message().get(0).getData(), p2.getResult().message().get(0).getData());
// Verify import note with subject
@ -503,7 +503,7 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
// Keep same ParagraphId
assertEquals(cp.getId(), p.getId());
assertEquals(cp.text, p.text);
assertEquals(cp.getText(), p.getText());
assertEquals(cp.getResult().message().get(0).getData(), p.getResult().message().get(0).getData());
// Verify clone note with subject
@ -549,7 +549,7 @@ public class NotebookTest extends AbstractInterpreterTest implements JobListener
// Keep same ParagraphId
assertEquals(cp.getId(), p.getId());
assertEquals(cp.text, p.text);
assertEquals(cp.getText(), p.getText());
assertNull(cp.getResult());
notebook.removeNote(note.getId(), anonymous);
notebook.removeNote(cloneNote.getId(), anonymous);

View file

@ -43,7 +43,6 @@ import org.apache.zeppelin.display.Input;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.Interpreter.FormType;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterGroup;
import org.apache.zeppelin.interpreter.InterpreterOption;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
@ -58,55 +57,104 @@ import java.util.HashMap;
import java.util.Map;
import org.mockito.Mockito;
public class ParagraphTest {
public class ParagraphTest extends AbstractInterpreterTest {
@Test
public void scriptBodyWithReplName() {
String text = "%spark(1234567";
assertEquals("(1234567", Paragraph.getScriptBody(text));
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("%test(1234567");
assertEquals("test", paragraph.getIntpText());
assertEquals("(1234567", paragraph.getScriptText());
text = "%table 1234567";
assertEquals("1234567", Paragraph.getScriptBody(text));
paragraph.setText("%test 1234567");
assertEquals("test", paragraph.getIntpText());
assertEquals("1234567", paragraph.getScriptText());
}
@Test
public void scriptBodyWithoutReplName() {
String text = "12345678";
assertEquals(text, Paragraph.getScriptBody(text));
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("1234567");
assertEquals("", paragraph.getIntpText());
assertEquals("1234567", paragraph.getScriptText());
}
@Test
public void replNameAndNoBody() {
String text = "%md";
assertEquals("md", Paragraph.getRequiredReplName(text));
assertEquals("", Paragraph.getScriptBody(text));
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("%test");
assertEquals("test", paragraph.getIntpText());
assertEquals("", paragraph.getScriptText());
}
@Test
public void replSingleCharName() {
String text = "%r a";
assertEquals("r", Paragraph.getRequiredReplName(text));
assertEquals("a", Paragraph.getScriptBody(text));
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("%r a");
assertEquals("r", paragraph.getIntpText());
assertEquals("a", paragraph.getScriptText());
}
@Test
public void replInvalid() {
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("foo %r");
assertEquals("", paragraph.getIntpText());
assertEquals("foo %r", paragraph.getScriptText());
paragraph.setText("foo%r");
assertEquals("", paragraph.getIntpText());
assertEquals("foo%r", paragraph.getScriptText());
paragraph.setText("% foo");
assertEquals("", paragraph.getIntpText());
assertEquals("% foo", paragraph.getScriptText());
}
@Test
public void replNameEndsWithWhitespace() {
String text = "%md\r\n###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
Note note = createNote();
Paragraph paragraph = new Paragraph(note, null, interpreterFactory);
paragraph.setText("%test\r\n###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
text = "%md\t###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
paragraph.setText("%test\t###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
text = "%md\u000b###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
paragraph.setText("%test\u000b###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
text = "%md\f###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
paragraph.setText("%test\f###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
text = "%md\n###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
paragraph.setText("%test\n###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
text = "%md ###Hello";
assertEquals("md", Paragraph.getRequiredReplName(text));
paragraph.setText("%test ###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
paragraph.setText(" %test ###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
paragraph.setText("\n\r%test ###Hello");
assertEquals("test", paragraph.getIntpText());
assertEquals("###Hello", paragraph.getScriptText());
paragraph.setText("%\r\n###Hello");
assertEquals("", paragraph.getIntpText());
assertEquals("%\r\n###Hello", paragraph.getScriptText());
}
@Test
@ -124,7 +172,7 @@ public class ParagraphTest {
final String scriptBody = "My name is ${name} and I am ${age=20} years old. " +
"My occupation is ${ job = engineer | developer | artists}";
final Paragraph paragraph = new Paragraph(note, null, null, null);
final Paragraph paragraph = new Paragraph(note, null, null);
final String paragraphId = paragraph.getId();
final AngularObject nameAO = AngularObjectBuilder.build("name", "DuyHai DOAN", noteId,
@ -150,7 +198,7 @@ public class ParagraphTest {
@Test
public void returnDefaultParagraphWithNewUser() {
Paragraph p = new Paragraph("para_1", null, null, null, null);
Paragraph p = new Paragraph("para_1", null, null, null);
Object defaultValue = "Default Value";
p.setResult(defaultValue);
Paragraph newUserParagraph = p.getUserParagraph("new_user");
@ -160,16 +208,13 @@ public class ParagraphTest {
@Test
public void returnUnchangedResultsWithDifferentUser() throws Throwable {
InterpreterSettingManager mockInterpreterSettingManager = mock(InterpreterSettingManager.class);
Note mockNote = mock(Note.class);
when(mockNote.getCredentials()).thenReturn(mock(Credentials.class));
Paragraph spyParagraph = spy(new Paragraph("para_1", mockNote, null, null, mockInterpreterSettingManager));
doReturn("spy").when(spyParagraph).getRequiredReplName();
Paragraph spyParagraph = spy(new Paragraph("para_1", mockNote, null, null));
Interpreter mockInterpreter = mock(Interpreter.class);
doReturn(mockInterpreter).when(spyParagraph).getRepl(anyString());
spyParagraph.setInterpreter(mockInterpreter);
doReturn(mockInterpreter).when(spyParagraph).getBindedInterpreter();
ManagedInterpreterGroup mockInterpreterGroup = mock(ManagedInterpreterGroup.class);
when(mockInterpreter.getInterpreterGroup()).thenReturn(mockInterpreterGroup);
@ -187,9 +232,6 @@ public class ParagraphTest {
when(mockInterpreterSetting.getOrCreateInterpreterGroup(anyString(), anyString())).thenReturn(mockInterpreterGroup);
spyInterpreterSettingList.add(mockInterpreterSetting);
when(mockNote.getId()).thenReturn("any_id");
when(mockInterpreterSettingManager.getInterpreterSettings(anyString())).thenReturn(spyInterpreterSettingList);
doReturn("spy script body").when(spyParagraph).getScriptBody();
when(mockInterpreter.getFormType()).thenReturn(FormType.NONE);
@ -229,7 +271,7 @@ public class ParagraphTest {
@Test
public void testCursorPosition() {
Paragraph paragraph = spy(new Paragraph());
doReturn(null).when(paragraph).getRepl(anyString());
doReturn(null).when(paragraph).getIntpText();
// left = buffer, middle = cursor position into source code, right = cursor position after parse
List<Triple<String, Integer, Integer>> dataSet = Arrays.asList(
Triple.of("%jdbc schema.", 13, 7),

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.notebook.repo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.io.IOException;
@ -28,6 +29,7 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
import org.apache.zeppelin.interpreter.InterpreterFactory;
import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.NoteInfo;
import org.apache.zeppelin.notebook.Paragraph;
@ -141,6 +143,7 @@ public class GitNotebookRepoTest {
//modify, save and checkpoint first note
Note note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
Map<String, Object> config = p.getConfig();
config.put("enabled", true);
@ -156,6 +159,7 @@ public class GitNotebookRepoTest {
//modify, save and checkpoint second note
note = notebookRepo.get(TEST_NOTE_ID2, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
config = p.getConfig();
config.put("enabled", false);
@ -182,6 +186,7 @@ public class GitNotebookRepoTest {
// add changes to note
Note note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
Map<String, Object> config = p.getConfig();
config.put("enabled", true);
@ -221,6 +226,7 @@ public class GitNotebookRepoTest {
// add paragraph and save
Note note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
Paragraph p1 = note.addNewParagraph(AuthenticationInfo.ANONYMOUS);
Map<String, Object> config = p1.getConfig();
config.put("enabled", true);
@ -240,6 +246,7 @@ public class GitNotebookRepoTest {
// get current note
note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_2);
// add one more paragraph and save
@ -249,6 +256,7 @@ public class GitNotebookRepoTest {
p2.setText("get revision when modified note test text");
notebookRepo.save(note, null);
note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
int paragraphCount_3 = note.getParagraphs().size();
assertThat(paragraphCount_3).isEqualTo(paragraphCount_2 + 1);
@ -276,6 +284,7 @@ public class GitNotebookRepoTest {
// get current note
Note note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_1);
// add one more paragraph and save
@ -293,6 +302,7 @@ public class GitNotebookRepoTest {
// get current note
note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
assertThat(note.getParagraphs().size()).isEqualTo(paragraphCount_2);
// test for absent revision
@ -311,6 +321,7 @@ public class GitNotebookRepoTest {
// get current note
Note note = notebookRepo.get(TEST_NOTE_ID, null);
note.setInterpreterFactory(mock(InterpreterFactory.class));
int paragraphCount_1 = note.getParagraphs().size();
LOG.info("initial paragraph count: {}", paragraphCount_1);