ZEPPELIN-3343. Interpreter Hook is broken

This commit is contained in:
Jeff Zhang 2018-03-16 16:05:31 +08:00
parent c6f7f2bdb3
commit 3c55f077f4
15 changed files with 407 additions and 114 deletions

View file

@ -259,7 +259,11 @@ public class PythonInterpreter extends Interpreter implements ExecuteResultHandl
// Add matplotlib display hook
InterpreterGroup intpGroup = getInterpreterGroup();
if (intpGroup != null && intpGroup.getInterpreterHookRegistry() != null) {
registerHook(HookType.POST_EXEC_DEV, "__zeppelin__._displayhook()");
try {
registerHook(HookType.POST_EXEC_DEV.getName(), "__zeppelin__._displayhook()");
} catch (InvalidHookException e) {
throw new InterpreterException(e);
}
}
// Add matplotlib display hook
try {

View file

@ -113,6 +113,29 @@ class PyZeppelinContext(object):
#)
body_buf.close(); header_buf.close()
def registerHook(self, event, cmd, replName=None):
if replName is None:
self.z.registerHook(event, cmd)
else:
self.z.registerHook(event, cmd, replName)
def unregisterHook(self, event, replName=None):
if replName is None:
self.z.unregisterHook(event)
else:
self.z.unregisterHook(event, replName)
def registerNoteHook(self, event, cmd, noteId, replName=None):
if replName is None:
self.z.registerNoteHook(event, cmd, noteId)
else:
self.z.registerNoteHook(event, cmd, noteId, replName)
def unregisterNoteHook(self, event, noteId, replName=None):
if replName is None:
self.z.unregisterNoteHook(event, noteId)
else:
self.z.unregisterNoteHook(event, noteId, replName)
# start JVM gateway
client = GatewayClient(address='127.0.0.1', port=${JVM_GATEWAY_PORT})

View file

@ -84,6 +84,30 @@ class PyZeppelinContext(object):
def noteCheckbox(self, name, options, defaultChecked=[]):
return self.z.noteCheckbox(name, self.getDefaultChecked(defaultChecked), self.getParamOptions(options))
def registerHook(self, event, cmd, replName=None):
if replName is None:
self.z.registerHook(event, cmd)
else:
self.z.registerHook(event, cmd, replName)
def unregisterHook(self, event, replName=None):
if replName is None:
self.z.unregisterHook(event)
else:
self.z.unregisterHook(event, replName)
def registerNoteHook(self, event, cmd, noteId, replName=None):
if replName is None:
self.z.registerNoteHook(event, cmd, noteId)
else:
self.z.registerNoteHook(event, cmd, noteId, replName)
def unregisterNoteHook(self, event, noteId, replName=None):
if replName is None:
self.z.unregisterNoteHook(event, noteId)
else:
self.z.unregisterNoteHook(event, noteId, replName)
def getParamOptions(self, options):
javaOptions = gateway.new_array(self.paramOption, len(options))
i = 0

View file

@ -38,6 +38,7 @@ import org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.InterpreterResultMessage;
import org.apache.zeppelin.interpreter.InvalidHookException;
import org.apache.zeppelin.interpreter.LazyOpenInterpreter;
import org.apache.zeppelin.interpreter.WrappedInterpreter;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
@ -152,7 +153,11 @@ public class PySparkInterpreter extends Interpreter implements ExecuteResultHand
// Add matplotlib display hook
InterpreterGroup intpGroup = getInterpreterGroup();
if (intpGroup != null && intpGroup.getInterpreterHookRegistry() != null) {
registerHook(HookType.POST_EXEC_DEV, "__zeppelin__._displayhook()");
try {
registerHook(HookType.POST_EXEC_DEV.getName(), "__zeppelin__._displayhook()");
} catch (InvalidHookException e) {
throw new InterpreterException(e);
}
}
DepInterpreter depInterpreter = getDepInterpreter();

View file

@ -133,6 +133,18 @@ class PyZeppelinContext(dict):
else:
self.z.unregisterHook(event, replName)
def registerNoteHook(self, event, cmd, noteId, replName=None):
if replName is None:
self.z.registerNoteHook(event, cmd, noteId)
else:
self.z.registerNoteHook(event, cmd, noteId, replName)
def unregisterNoteHook(self, event, noteId, replName=None):
if replName is None:
self.z.unregisterNoteHook(event, noteId)
else:
self.z.unregisterNoteHook(event, noteId, replName)
def getHook(self, event, replName=None):
if replName is None:
return self.z.getHook(event)

View file

@ -202,9 +202,6 @@ public abstract class BaseZeppelinContext {
this.noteGui = noteGui;
}
private void restartInterpreter() {
}
public InterpreterContext getInterpreterContext() {
return interpreterContext;
}
@ -743,15 +740,10 @@ public abstract class BaseZeppelinContext {
* Get the interpreter class name from name entered in paragraph
* @param replName if replName is a valid className, return that instead.
*/
public String getClassNameFromReplName(String replName) {
for (String name : getInterpreterClassMap().keySet()) {
if (replName.equals(name)) {
return replName;
}
}
if (replName.contains("spark.")) {
replName = replName.replace("spark.", "");
private String getClassNameFromReplName(String replName) {
String[] splits = replName.split(".");
if (splits.length > 1) {
replName = splits[splits.length - 1];
}
return getInterpreterClassMap().get(replName);
}
@ -763,10 +755,9 @@ public abstract class BaseZeppelinContext {
* @param replName Name of the interpreter
*/
@Experimental
public void registerHook(String event, String cmd, String replName) {
String noteId = interpreterContext.getNoteId();
public void registerHook(String event, String cmd, String replName) throws InvalidHookException {
String className = getClassNameFromReplName(replName);
hooks.register(noteId, className, event, cmd);
hooks.register(null, className, event, cmd);
}
/**
@ -775,43 +766,42 @@ public abstract class BaseZeppelinContext {
* @param cmd The code to be executed by the interpreter on given event
*/
@Experimental
public void registerHook(String event, String cmd) {
String className = interpreterContext.getInterpreterClassName();
registerHook(event, cmd, className);
public void registerHook(String event, String cmd) throws InvalidHookException {
String replClassName = interpreterContext.getInterpreterClassName();
hooks.register(null, replClassName, event, cmd);
}
/**
* Get the hook code
* @param event The type of event to hook to (pre_exec, post_exec)
* @param replName Name of the interpreter
*
* @param event
* @param cmd
* @param noteId
* @throws InvalidHookException
*/
@Experimental
public String getHook(String event, String replName) {
String noteId = interpreterContext.getNoteId();
public void registerNoteHook(String event, String cmd, String noteId)
throws InvalidHookException {
String replClassName = interpreterContext.getInterpreterClassName();
hooks.register(noteId, replClassName, event, cmd);
}
@Experimental
public void registerNoteHook(String event, String cmd, String noteId, String replName)
throws InvalidHookException {
String className = getClassNameFromReplName(replName);
return hooks.get(noteId, className, event);
hooks.register(noteId, className, event, cmd);
}
/**
* getHook() wrapper for current repl
* @param event The type of event to hook to (pre_exec, post_exec)
*/
@Experimental
public String getHook(String event) {
String className = interpreterContext.getInterpreterClassName();
return getHook(event, className);
}
/**
* Unbind code from given hook event
* Unbind code from given hook event and given repl
*
* @param event The type of event to hook to (pre_exec, post_exec)
* @param replName Name of the interpreter
*/
@Experimental
public void unregisterHook(String event, String replName) {
String noteId = interpreterContext.getNoteId();
String className = getClassNameFromReplName(replName);
hooks.unregister(noteId, className, event);
hooks.unregister(null, className, event);
}
/**
@ -820,10 +810,35 @@ public abstract class BaseZeppelinContext {
*/
@Experimental
public void unregisterHook(String event) {
String className = interpreterContext.getInterpreterClassName();
unregisterHook(event, className);
unregisterHook(event, interpreterContext.getReplName());
}
/**
* Unbind code from given hook event and given note
*
* @param noteId The id of note
* @param event The type of event to hook to (pre_exec, post_exec)
*/
@Experimental
public void unregisterNoteHook(String noteId, String event) {
String className = interpreterContext.getInterpreterClassName();
hooks.unregister(noteId, className, event);
}
/**
* Unbind code from given hook event, given note and given repl
* @param noteId The id of note
* @param event The type of event to hook to (pre_exec, post_exec)
* @param replName Name of the interpreter
*/
@Experimental
public void unregisterNoteHook(String noteId, String event, String replName) {
String className = getClassNameFromReplName(replName);
hooks.unregister(noteId, className, event);
}
/**
* Add object into resource pool
* @param name

View file

@ -240,7 +240,7 @@ public abstract class Interpreter {
* @param cmd The code to be executed by the interpreter on given event
*/
@Experimental
public void registerHook(String noteId, String event, String cmd) {
public void registerHook(String noteId, String event, String cmd) throws InvalidHookException {
InterpreterHookRegistry hooks = interpreterGroup.getInterpreterHookRegistry();
String className = getClassName();
hooks.register(noteId, className, event, cmd);
@ -253,7 +253,7 @@ public abstract class Interpreter {
* @param cmd The code to be executed by the interpreter on given event
*/
@Experimental
public void registerHook(String event, String cmd) {
public void registerHook(String event, String cmd) throws InvalidHookException {
registerHook(null, event, cmd);
}

View file

@ -88,6 +88,16 @@ public class InterpreterContext {
return this;
}
public Builder setInterpreterClassName(String intpClassName) {
context.interpreterClassName = intpClassName;
return this;
}
public Builder setReplName(String replName) {
context.replName = replName;
return this;
}
public InterpreterContext build() {
return context;
}

View file

@ -18,41 +18,29 @@
package org.apache.zeppelin.interpreter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The InterpreterinterpreterHookRegistry specifies code to be conditionally executed by an
* The InterpreterHookRegistry specifies code to be conditionally executed by an
* interpreter. The constants defined in this class denote currently
* supported events. Each instance is bound to a single InterpreterGroup.
* Scope is determined on a per-note basis (except when null for global scope).
*/
public class InterpreterHookRegistry {
public static final String GLOBAL_KEY = "_GLOBAL_";
private String interpreterId;
static final String GLOBAL_KEY = "_GLOBAL_";
// Scope (noteId/global scope) -> (ClassName -> (EventType -> Hook Code))
private Map<String, Map<String, Map<String, String>>> registry = new HashMap<>();
/**
* hookRegistry constructor.
*
* @param interpreterId The Id of the InterpreterGroup instance to bind to
*/
public InterpreterHookRegistry(final String interpreterId) {
this.interpreterId = interpreterId;
}
/**
* Get the interpreterGroup id this instance is bound to
*/
public String getInterpreterId() {
return interpreterId;
}
/**
* Adds a note to the registry
*
* @param noteId The Id of the Note instance to add
*/
public void addNote(String noteId) {
private void addNote(String noteId) {
synchronized (registry) {
if (registry.get(noteId) == null) {
registry.put(noteId, new HashMap<String, Map<String, String>>());
@ -66,7 +54,7 @@ public class InterpreterHookRegistry {
* @param noteId The note id
* @param className The name of the interpreter repl to map the hooks to
*/
public void addRepl(String noteId, String className) {
private void addRepl(String noteId, String className) {
synchronized (registry) {
addNote(noteId);
if (registry.get(noteId).get(className) == null) {
@ -84,19 +72,15 @@ public class InterpreterHookRegistry {
* @param cmd Code to be executed by the interpreter
*/
public void register(String noteId, String className,
String event, String cmd) throws IllegalArgumentException {
String event, String cmd) throws InvalidHookException {
synchronized (registry) {
if (!HookType.ValidEvents.contains(event)) {
throw new InvalidHookException("event " + event + " is not valid hook event");
}
if (noteId == null) {
noteId = GLOBAL_KEY;
}
addRepl(noteId, className);
if (!event.equals(HookType.POST_EXEC) && !event.equals(HookType.PRE_EXEC) &&
!event.equals(HookType.POST_EXEC_DEV) && !event.equals(HookType.PRE_EXEC_DEV)) {
throw new IllegalArgumentException("Must be " + HookType.POST_EXEC + ", " +
HookType.POST_EXEC_DEV + ", " +
HookType.PRE_EXEC + " or " +
HookType.PRE_EXEC_DEV);
}
registry.get(noteId).get(className).put(event, cmd);
}
}
@ -138,18 +122,36 @@ public class InterpreterHookRegistry {
/**
* Container for hook event type constants
*/
public static final class HookType {
public enum HookType {
// Execute the hook code PRIOR to main paragraph code execution
public static final String PRE_EXEC = "pre_exec";
PRE_EXEC("pre_exec"),
// Execute the hook code AFTER main paragraph code execution
public static final String POST_EXEC = "post_exec";
POST_EXEC("post_exec"),
// Same as above but reserved for interpreter developers, in order to allow
// notebook users to use the above without overwriting registry settings
// that are initialized directly in subclasses of Interpreter.
public static final String PRE_EXEC_DEV = "pre_exec_dev";
public static final String POST_EXEC_DEV = "post_exec_dev";
PRE_EXEC_DEV("pre_exec_dev"),
POST_EXEC_DEV("post_exec_dev");
private String name;
HookType(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static Set<String> ValidEvents = new HashSet();
static {
for (HookType type : values()) {
ValidEvents.add(type.getName());
}
}
}
}

View file

@ -0,0 +1,29 @@
/*
* 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.interpreter;
/**
* Exception for invalid hook
*/
public class InvalidHookException extends Exception {
public InvalidHookException(String message) {
super(message);
}
}

View file

@ -165,12 +165,12 @@ public class LazyOpenInterpreter
}
@Override
public void registerHook(String noteId, String event, String cmd) {
public void registerHook(String noteId, String event, String cmd) throws InvalidHookException {
intp.registerHook(noteId, event, cmd);
}
@Override
public void registerHook(String event, String cmd) {
public void registerHook(String event, String cmd) throws InvalidHookException {
intp.registerHook(event, cmd);
}

View file

@ -280,7 +280,7 @@ public class RemoteInterpreterServer extends Thread
if (interpreterGroup == null) {
interpreterGroup = new InterpreterGroup(interpreterGroupId);
angularObjectRegistry = new AngularObjectRegistry(interpreterGroup.getId(), this);
hookRegistry = new InterpreterHookRegistry(interpreterGroup.getId());
hookRegistry = new InterpreterHookRegistry();
resourcePool = new DistributedResourcePool(interpreterGroup.getId(), eventClient);
interpreterGroup.setInterpreterHookRegistry(hookRegistry);
interpreterGroup.setAngularObjectRegistry(angularObjectRegistry);
@ -563,8 +563,8 @@ public class RemoteInterpreterServer extends Thread
InterpreterHookListener hookListener = new InterpreterHookListener() {
@Override
public void onPreExecute(String script) {
String cmdDev = interpreter.getHook(noteId, HookType.PRE_EXEC_DEV);
String cmdUser = interpreter.getHook(noteId, HookType.PRE_EXEC);
String cmdDev = interpreter.getHook(noteId, HookType.PRE_EXEC_DEV.getName());
String cmdUser = interpreter.getHook(noteId, HookType.PRE_EXEC.getName());
// User defined hook should be executed before dev hook
List<String> cmds = Arrays.asList(cmdDev, cmdUser);
@ -579,8 +579,8 @@ public class RemoteInterpreterServer extends Thread
@Override
public void onPostExecute(String script) {
String cmdDev = interpreter.getHook(noteId, HookType.POST_EXEC_DEV);
String cmdUser = interpreter.getHook(noteId, HookType.POST_EXEC);
String cmdDev = interpreter.getHook(noteId, HookType.POST_EXEC_DEV.getName());
String cmdUser = interpreter.getHook(noteId, HookType.POST_EXEC.getName());
// User defined hook should be executed after dev hook
List<String> cmds = Arrays.asList(cmdUser, cmdDev);
@ -616,9 +616,16 @@ public class RemoteInterpreterServer extends Thread
if (result == null || result.code() == Code.SUCCESS) {
// Add hooks to script from registry.
// Global scope first, followed by notebook scope
processInterpreterHooks(null);
// note scope first, followed by global scope.
// Here's the code after hooking:
// global_pre_hook
// note_pre_hook
// script
// note_post_hook
// global_post_hook
processInterpreterHooks(context.getNoteId());
processInterpreterHooks(null);
logger.debug("Script after hooks: " + script);
result = interpreter.interpret(script, context);
}

View file

@ -0,0 +1,133 @@
/*
* 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.interpreter;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class BaseZeppelinContextTest {
@Test
public void testHooks() throws InvalidHookException {
InterpreterHookRegistry hookRegistry = new InterpreterHookRegistry();
TestZeppelinContext z = new TestZeppelinContext(hookRegistry, 10);
InterpreterContext context = InterpreterContext.builder()
.setNoteId("note_1")
.setParagraphId("paragraph_1")
.setInterpreterClassName("Test1Interpreter")
.setReplName("test1")
.build();
z.setInterpreterContext(context);
// register global hook for current interpreter
z.registerHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "pre_cmd");
z.registerHook(InterpreterHookRegistry.HookType.POST_EXEC.getName(), "post_cmd");
assertEquals("pre_cmd", hookRegistry.get(null, "Test1Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals("post_cmd", hookRegistry.get(null, "Test1Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
z.unregisterHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName());
z.unregisterHook(InterpreterHookRegistry.HookType.POST_EXEC.getName());
assertEquals(null, hookRegistry.get(null, "Test1Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals(null, hookRegistry.get(null, "Test1Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
// register global hook for interpreter test2
z.registerHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "pre_cmd2", "test2");
z.registerHook(InterpreterHookRegistry.HookType.POST_EXEC.getName(), "post_cmd2", "test2");
assertEquals("pre_cmd2", hookRegistry.get(null, "Test2Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals("post_cmd2", hookRegistry.get(null, "Test2Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
z.unregisterHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "test2");
z.unregisterHook(InterpreterHookRegistry.HookType.POST_EXEC.getName(), "test2");
assertEquals(null, hookRegistry.get(null, "Test2Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals(null, hookRegistry.get(null, "Test2Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
// register hook for note_1 and current interpreter
z.registerNoteHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "pre_cmd", "note_1");
z.registerNoteHook(InterpreterHookRegistry.HookType.POST_EXEC.getName(), "post_cmd", "note_1");
assertEquals("pre_cmd", hookRegistry.get("note_1", "Test1Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals("post_cmd", hookRegistry.get("note_1", "Test1Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
z.unregisterNoteHook("note_1", InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "test1");
z.unregisterNoteHook("note_1", InterpreterHookRegistry.HookType.POST_EXEC.getName(), "test1");
assertEquals(null, hookRegistry.get("note_1", "Test1Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals(null, hookRegistry.get("note_1", "Test1Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
// register hook for note_1 and interpreter test2
z.registerNoteHook(InterpreterHookRegistry.HookType.PRE_EXEC.getName(),
"pre_cmd2", "note_1", "test2");
z.registerNoteHook(InterpreterHookRegistry.HookType.POST_EXEC.getName(),
"post_cmd2", "note_1", "test2");
assertEquals("pre_cmd2", hookRegistry.get("note_1", "Test2Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals("post_cmd2", hookRegistry.get("note_1", "Test2Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
z.unregisterNoteHook("note_1", InterpreterHookRegistry.HookType.PRE_EXEC.getName(), "test2");
z.unregisterNoteHook("note_1", InterpreterHookRegistry.HookType.POST_EXEC.getName(), "test2");
assertEquals(null, hookRegistry.get("note_1", "Test2Interpreter",
InterpreterHookRegistry.HookType.PRE_EXEC.getName()));
assertEquals(null, hookRegistry.get("note_1", "Test2Interpreter",
InterpreterHookRegistry.HookType.POST_EXEC.getName()));
}
public static class TestZeppelinContext extends BaseZeppelinContext {
public TestZeppelinContext(InterpreterHookRegistry hooks, int maxResult) {
super(hooks, maxResult);
}
@Override
public Map<String, String> getInterpreterClassMap() {
Map<String, String> map = new HashMap<>();
map.put("test1", "Test1Interpreter");
map.put("test2", "Test2Interpreter");
return map;
}
@Override
public List<Class> getSupportedClasses() {
return null;
}
@Override
protected String showData(Object obj) {
return null;
}
}
}

View file

@ -19,54 +19,54 @@ package org.apache.zeppelin.interpreter;
import org.junit.Test;
import static org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType.POST_EXEC;
import static org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType.POST_EXEC_DEV;
import static org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType.PRE_EXEC;
import static org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType.PRE_EXEC_DEV;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class InterpreterHookRegistryTest {
@Test
public void testBasic() {
final String PRE_EXEC = InterpreterHookRegistry.HookType.PRE_EXEC;
final String POST_EXEC = InterpreterHookRegistry.HookType.POST_EXEC;
final String PRE_EXEC_DEV = InterpreterHookRegistry.HookType.PRE_EXEC_DEV;
final String POST_EXEC_DEV = InterpreterHookRegistry.HookType.POST_EXEC_DEV;
public void testBasic() throws InvalidHookException {
final String GLOBAL_KEY = InterpreterHookRegistry.GLOBAL_KEY;
final String noteId = "note";
final String className = "class";
final String preExecHook = "pre";
final String postExecHook = "post";
InterpreterHookRegistry registry = new InterpreterHookRegistry("intpId");
InterpreterHookRegistry registry = new InterpreterHookRegistry();
// Test register()
registry.register(noteId, className, PRE_EXEC, preExecHook);
registry.register(noteId, className, POST_EXEC, postExecHook);
registry.register(noteId, className, PRE_EXEC_DEV, preExecHook);
registry.register(noteId, className, POST_EXEC_DEV, postExecHook);
registry.register(noteId, className, PRE_EXEC.getName(), preExecHook);
registry.register(noteId, className, POST_EXEC.getName(), postExecHook);
registry.register(noteId, className, PRE_EXEC_DEV.getName(), preExecHook);
registry.register(noteId, className, POST_EXEC_DEV.getName(), postExecHook);
// Test get()
assertEquals(registry.get(noteId, className, PRE_EXEC), preExecHook);
assertEquals(registry.get(noteId, className, POST_EXEC), postExecHook);
assertEquals(registry.get(noteId, className, PRE_EXEC_DEV), preExecHook);
assertEquals(registry.get(noteId, className, POST_EXEC_DEV), postExecHook);
assertEquals(registry.get(noteId, className, PRE_EXEC.getName()), preExecHook);
assertEquals(registry.get(noteId, className, POST_EXEC.getName()), postExecHook);
assertEquals(registry.get(noteId, className, PRE_EXEC_DEV.getName()), preExecHook);
assertEquals(registry.get(noteId, className, POST_EXEC_DEV.getName()), postExecHook);
// Test Unregister
registry.unregister(noteId, className, PRE_EXEC);
registry.unregister(noteId, className, POST_EXEC);
registry.unregister(noteId, className, PRE_EXEC_DEV);
registry.unregister(noteId, className, POST_EXEC_DEV);
assertNull(registry.get(noteId, className, PRE_EXEC));
assertNull(registry.get(noteId, className, POST_EXEC));
assertNull(registry.get(noteId, className, PRE_EXEC_DEV));
assertNull(registry.get(noteId, className, POST_EXEC_DEV));
registry.unregister(noteId, className, PRE_EXEC.getName());
registry.unregister(noteId, className, POST_EXEC.getName());
registry.unregister(noteId, className, PRE_EXEC_DEV.getName());
registry.unregister(noteId, className, POST_EXEC_DEV.getName());
assertNull(registry.get(noteId, className, PRE_EXEC.getName()));
assertNull(registry.get(noteId, className, POST_EXEC.getName()));
assertNull(registry.get(noteId, className, PRE_EXEC_DEV.getName()));
assertNull(registry.get(noteId, className, POST_EXEC_DEV.getName()));
// Test Global Scope
registry.register(null, className, PRE_EXEC, preExecHook);
assertEquals(registry.get(GLOBAL_KEY, className, PRE_EXEC), preExecHook);
registry.register(null, className, PRE_EXEC.getName(), preExecHook);
assertEquals(registry.get(GLOBAL_KEY, className, PRE_EXEC.getName()), preExecHook);
}
@Test(expected = IllegalArgumentException.class)
public void testValidEventCode() {
InterpreterHookRegistry registry = new InterpreterHookRegistry("intpId");
@Test(expected = InvalidHookException.class)
public void testValidEventCode() throws InvalidHookException {
InterpreterHookRegistry registry = new InterpreterHookRegistry();
// Test that only valid event codes ("pre_exec", "post_exec") are accepted
registry.register("foo", "bar", "baz", "whatever");

View file

@ -379,7 +379,36 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
}
@Test
public void pySparkDepLoaderTest() throws IOException, InterpreterException {
public void testZeppelinContextHook() throws IOException {
Note note = ZeppelinServer.notebook.createNote(anonymous);
// register global hook & note1 hook
Paragraph p1 = note.addNewParagraph(anonymous);
p1.setText("%python from __future__ import print_function\n" +
"z.registerHook('pre_exec', 'print(1)')\n" +
"z.registerHook('post_exec', 'print(2)')\n" +
"z.registerNoteHook('pre_exec', 'print(3)', '" + note.getId() + "')\n" +
"z.registerNoteHook('post_exec', 'print(4)', '" + note.getId() + "')\n");
Paragraph p2 = note.addNewParagraph(anonymous);
p2.setText("%python print(5)");
note.run(p1.getId(), true);
note.run(p2.getId(), true);
assertEquals(Status.FINISHED, p1.getStatus());
assertEquals(Status.FINISHED, p2.getStatus());
assertEquals("1\n3\n5\n4\n2\n", p2.getResult().message().get(0).getData());
Note note2 = ZeppelinServer.notebook.createNote(anonymous);
Paragraph p3 = note2.addNewParagraph(anonymous);
p3.setText("%python print(6)");
note2.run(p3.getId(), true);
assertEquals("1\n6\n2\n", p3.getResult().message().get(0).getData());
}
@Test
public void pySparkDepLoaderTest() throws IOException {
Note note = ZeppelinServer.notebook.createNote(anonymous);
// restart spark interpreter to make dep loader work