You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2016/10/18 01:25:02 UTC

zeppelin git commit: [ZEPPELIN-1437, 1438] Multi-user note management - user aware reload broadcast

Repository: zeppelin
Updated Branches:
  refs/heads/master b6e3c8ee8 -> b77f9ea8d


[ZEPPELIN-1437, 1438] Multi-user note management - user aware reload broadcast

### What is this PR for?
This PR addresses part of multi-user note management in Zeppelin. One of the tasks namely listing notes per user on Zeppelin start was addressed in #1330. However that PR didn't solve all problems, and reloading notes was incomplete as well as socket broadcast was not user aware [ZEPPELIN-1437](https://issues.apache.org/jira/browse/ZEPPELIN-1437), [ZEPPELIN-1438](https://issues.apache.org/jira/browse/ZEPPELIN-1438). This PR addresses those issue.

### What type of PR is it?
Improvement

### Todos
* [x] - list notes per user on reload
* [x] - broadcast per user (multicast)
* [x] - tests
* [x] - use authorization module to filter notes on sync
* [x] - broadcast on permissions change
* [ ] - discussion and review

### What is the Jira issue?
[Zeppelin-1437](https://issues.apache.org/jira/browse/ZEPPELIN-1437), [ZEPPELIN-1438](https://issues.apache.org/jira/browse/ZEPPELIN-1438)

### How should this be tested?
1. Start Zeppelin
2. Login as user1, and user2 on different windows
3. Each user should be able to see their own note workbench
4. If note changed to private (readers, writers not empty), that note should disappear from others note workbench.

### Screenshots (if appropriate)
![reload_broadcast](https://cloud.githubusercontent.com/assets/1642088/18679507/e4a0161c-7f9a-11e6-9d57-0930abf4b780.gif)

### Questions:
* Does the licenses files need update? no
* Is there breaking changes for older versions? no
* Does this needs documentation? yes

Author: Khalid Huseynov <kh...@gmail.com>

Closes #1392 from khalidhuseynov/feat/multi-user-notes and squashes the following commits:

a2ce268 [Khalid Huseynov] broadcast note list on perm update - zeppelin-1438
9cf1d88 [Khalid Huseynov] fix init not to initialize every time
17eae84 [Khalid Huseynov] bugfix: add precondition for NP
781207e [Khalid Huseynov] bugfix: reload only once
537cc0e [Khalid Huseynov] apply filter from authorization in sync
09e6723 [Khalid Huseynov] notebookAuthorization as singleton
9427e62 [Khalid Huseynov] multicast fine grained note lists to users instead of broadcast
6614e2b [Khalid Huseynov] improve tests
1399407 [Khalid Huseynov] remove unused imports
d9c3bc9 [Khalid Huseynov] filter reload using predicates
92f37f5 [Khalid Huseynov] substitute old getAllNotes(subject) with new implementation
b7f19c9 [Khalid Huseynov] separate getAllNotes() and getAllNotes(subject)
17e2d4c [Khalid Huseynov] first draft


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/b77f9ea8
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/b77f9ea8
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/b77f9ea8

Branch: refs/heads/master
Commit: b77f9ea8d7bb2b4e8a5a7a15fa828fcd33abf0d5
Parents: b6e3c8e
Author: Khalid Huseynov <kh...@gmail.com>
Authored: Tue Sep 27 12:56:29 2016 +0900
Committer: Lee moon soo <mo...@apache.org>
Committed: Tue Oct 18 10:24:57 2016 +0900

----------------------------------------------------------------------
 .../apache/zeppelin/rest/NotebookRestApi.java   |  1 +
 .../apache/zeppelin/server/ZeppelinServer.java  |  2 +-
 .../apache/zeppelin/socket/NotebookServer.java  | 64 +++++++++++++++++--
 .../apache/zeppelin/socket/NotebookSocket.java  | 10 +++
 .../zeppelin/rest/ZeppelinRestApiTest.java      |  5 +-
 .../org/apache/zeppelin/notebook/Notebook.java  |  5 +-
 .../notebook/NotebookAuthorization.java         | 67 ++++++++++++++------
 .../notebook/repo/NotebookRepoSync.java         |  5 +-
 .../helium/HeliumApplicationFactoryTest.java    |  2 +-
 .../apache/zeppelin/notebook/NotebookTest.java  | 38 ++++++++++-
 .../notebook/repo/NotebookRepoSyncTest.java     |  2 +-
 11 files changed, 169 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
index 7272112..b83a889 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
@@ -162,6 +162,7 @@ public class NotebookRestApi {
     AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal());
     note.persist(subject);
     notebookServer.broadcastNote(note);
+    notebookServer.broadcastNoteList(subject);
     return new JsonResponse<>(Status.OK).build();
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index 415abd7..c620235 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
@@ -92,7 +92,7 @@ public class ZeppelinServer extends Application {
         notebookWsServer, heliumApplicationFactory, depResolver);
     this.notebookRepo = new NotebookRepoSync(conf);
     this.notebookIndex = new LuceneSearch();
-    this.notebookAuthorization = new NotebookAuthorization(conf);
+    this.notebookAuthorization = NotebookAuthorization.init(conf);
     this.credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
     notebook = new Notebook(conf,
         notebookRepo, schedulerFactory, replFactory, notebookWsServer,

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index ab7394b..2eee99e 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -60,6 +60,7 @@ import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
@@ -86,6 +87,8 @@ public class NotebookServer extends WebSocketServlet implements
   Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
   final Map<String, List<NotebookSocket>> noteSocketMap = new HashMap<>();
   final Queue<NotebookSocket> connectedSockets = new ConcurrentLinkedQueue<>();
+  final Map<String, Queue<NotebookSocket>> userConnectedSockets = 
+    new ConcurrentHashMap<String, Queue<NotebookSocket>>();
 
   private Notebook notebook() {
     return ZeppelinServer.notebook;
@@ -161,6 +164,9 @@ public class NotebookServer extends WebSocketServlet implements
           userAndRoles.addAll(roles);
         }
       }
+      if (StringUtils.isEmpty(conn.getUser())) {
+        addUserConnection(messagereceived.principal, conn);
+      }
       AuthenticationInfo subject = new AuthenticationInfo(messagereceived.principal);
 
       /** Lets be elegant here */
@@ -268,6 +274,26 @@ public class NotebookServer extends WebSocketServlet implements
         .getRemoteAddr(), conn.getRequest().getRemotePort(), code, reason);
     removeConnectionFromAllNote(conn);
     connectedSockets.remove(conn);
+    removeUserConnection(conn.getUser(), conn);
+  }
+
+  private void removeUserConnection(String user, NotebookSocket conn) {
+    if (userConnectedSockets.containsKey(user)) {
+      userConnectedSockets.get(user).remove(conn);
+    } else {
+      LOG.warn("Closing connection that is absent in user connections");
+    }
+  }
+
+  private void addUserConnection(String user, NotebookSocket conn) {
+    conn.setUser(user);
+    if (userConnectedSockets.containsKey(user)) {
+      userConnectedSockets.get(user).add(conn);
+    } else {
+      Queue<NotebookSocket> socketQueue = new ConcurrentLinkedQueue<>();
+      socketQueue.add(conn);
+      userConnectedSockets.put(user, socketQueue);
+    }
   }
 
   protected Message deserializeMessage(String msg) {
@@ -383,8 +409,12 @@ public class NotebookServer extends WebSocketServlet implements
     }
   }
 
-  private void broadcastAll(Message m) {
-    for (NotebookSocket conn : connectedSockets) {
+  private void multicastToUser(String user, Message m) {
+    if (!userConnectedSockets.containsKey(user)) {
+      LOG.warn("Broadcasting to user that is not in connections map");
+      return;
+    }
+    for (NotebookSocket conn: userConnectedSockets.get(user)) {
       try {
         conn.send(serializeMessage(m));
       } catch (IOException e) {
@@ -476,6 +506,7 @@ public class NotebookServer extends WebSocketServlet implements
         LOG.error("Fail to reload notes from repository", e);
       }
     }
+
     List<Note> notes = notebook.getAllNotes(subject);
     List<Map<String, String>> notesInfo = new LinkedList<>();
     for (Note note : notes) {
@@ -504,8 +535,20 @@ public class NotebookServer extends WebSocketServlet implements
   }
 
   public void broadcastNoteList(AuthenticationInfo subject) {
+    if (subject == null) {
+      subject = new AuthenticationInfo(StringUtils.EMPTY);
+    }
+    //send first to requesting user
     List<Map<String, String>> notesInfo = generateNotebooksInfo(false, subject);
-    broadcastAll(new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    multicastToUser(subject.getUser(), new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    //to others afterwards
+    for (String user: userConnectedSockets.keySet()) {
+      if (subject.getUser() == user) {
+        continue;
+      }
+      notesInfo = generateNotebooksInfo(false, new AuthenticationInfo(user));
+      multicastToUser(user, new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    }
   }
 
   public void unicastNoteList(NotebookSocket conn, AuthenticationInfo subject) {
@@ -514,8 +557,21 @@ public class NotebookServer extends WebSocketServlet implements
   }
 
   public void broadcastReloadedNoteList(AuthenticationInfo subject) {
+    if (subject == null) {
+      subject = new AuthenticationInfo(StringUtils.EMPTY);
+    }
+    //reload and reply first to requesting user
     List<Map<String, String>> notesInfo = generateNotebooksInfo(true, subject);
-    broadcastAll(new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    multicastToUser(subject.getUser(), new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    //to others afterwards
+    for (String user: userConnectedSockets.keySet()) {
+      if (subject.getUser() == user) {
+        continue;
+      }
+      //reloaded already above; parameter - false
+      notesInfo = generateNotebooksInfo(false, new AuthenticationInfo(user));
+      multicastToUser(user, new Message(OP.NOTES_INFO).put("notes", notesInfo));
+    }
   }
 
   void permissionError(NotebookSocket conn, String op,

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookSocket.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookSocket.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookSocket.java
index f491ed7..baee746 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookSocket.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookSocket.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.commons.lang.StringUtils;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
 
@@ -32,12 +33,14 @@ public class NotebookSocket extends WebSocketAdapter {
   private NotebookSocketListener listener;
   private HttpServletRequest request;
   private String protocol;
+  private String user;
 
   public NotebookSocket(HttpServletRequest req, String protocol,
       NotebookSocketListener listener) {
     this.listener = listener;
     this.request = req;
     this.protocol = protocol;
+    this.user = StringUtils.EMPTY;
   }
 
   @Override
@@ -69,4 +72,11 @@ public class NotebookSocket extends WebSocketAdapter {
     connection.getRemote().sendString(serializeMessage);
   }
 
+  public String getUser() {
+    return user;
+  }
+
+  public void setUser(String user) {
+    this.user = user;
+  }
 }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
index 4390d74..ad48b50 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java
@@ -32,6 +32,7 @@ import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.scheduler.Job.Status;
 import org.apache.zeppelin.server.ZeppelinServer;
+import org.apache.zeppelin.user.AuthenticationInfo;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
@@ -341,7 +342,9 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
     Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
     }.getType());
     List<Map<String, String>> body = (List<Map<String, String>>) resp.get("body");
-    assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes().size(), body.size());
+    //TODO(khalid): anonymous or specific user notes?
+    AuthenticationInfo subject = new AuthenticationInfo("anonymous");
+    assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes(subject).size(), body.size());
     get.releaseConnection();
   }
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
index d961ac0..1e65a86 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
@@ -31,14 +31,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-
 import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Sets;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.stream.JsonReader;
-import org.apache.commons.codec.binary.StringUtils;
 import org.quartz.CronScheduleBuilder;
 import org.quartz.CronTrigger;
 import org.quartz.JobBuilder;
@@ -484,6 +482,7 @@ public class Notebook implements NoteEventListener {
     }
 
     List<NoteInfo> noteInfos = notebookRepo.list(subject);
+
     for (NoteInfo info : noteInfos) {
       loadNoteFromRepo(info.getId(), subject);
     }
@@ -534,7 +533,7 @@ public class Notebook implements NoteEventListener {
       return noteList;
     }
   }
-
+  
   public List<Note> getAllNotes(AuthenticationInfo subject) {
     final Set<String> entities = Sets.newHashSet();
     if (subject != null) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
index 0633906..75dc61b 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/NotebookAuthorization.java
@@ -17,9 +17,13 @@
 
 package org.apache.zeppelin.notebook;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Sets;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.user.AuthenticationInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,29 +35,44 @@ import java.util.*;
  */
 public class NotebookAuthorization {
   private static final Logger LOG = LoggerFactory.getLogger(NotebookAuthorization.class);
-
+  private static NotebookAuthorization instance = null;
   /*
    * { "note1": { "owners": ["u1"], "readers": ["u1", "u2"], "writers": ["u1"] },  "note2": ... } }
    */
-  private Map<String, Map<String, Set<String>>> authInfo = new HashMap<>();
-  private ZeppelinConfiguration conf;
-  private Gson gson;
-  private String filePath;
-
-  public NotebookAuthorization(ZeppelinConfiguration conf) {
-    this.conf = conf;
-    filePath = conf.getNotebookAuthorizationPath();
-    GsonBuilder builder = new GsonBuilder();
-    builder.setPrettyPrinting();
-    gson = builder.create();
-    try {
-      loadFromFile();
-    } catch (IOException e) {
-      LOG.error("Error loading NotebookAuthorization", e);
+  private static Map<String, Map<String, Set<String>>> authInfo = new HashMap<>();
+  private static ZeppelinConfiguration conf;
+  private static Gson gson;
+  private static String filePath;
+
+  private NotebookAuthorization() {}
+
+  public static NotebookAuthorization init(ZeppelinConfiguration config) {
+    if (instance == null) {
+      instance = new NotebookAuthorization();
+      conf = config;
+      filePath = conf.getNotebookAuthorizationPath();
+      GsonBuilder builder = new GsonBuilder();
+      builder.setPrettyPrinting();
+      gson = builder.create();
+      try {
+        loadFromFile();
+      } catch (IOException e) {
+        LOG.error("Error loading NotebookAuthorization", e);
+      }
     }
+    return instance;
   }
 
-  private void loadFromFile() throws IOException {
+  public static NotebookAuthorization getInstance() {
+    if (instance == null) {
+      LOG.warn("Notebook authorization module was called without initialization,"
+          + " initializing with default configuration");
+      init(ZeppelinConfiguration.create());
+    }
+    return instance;
+  }
+
+  private static void loadFromFile() throws IOException {
     File settingFile = new File(filePath);
     LOG.info(settingFile.getAbsolutePath());
     if (!settingFile.exists()) {
@@ -74,7 +93,7 @@ public class NotebookAuthorization {
     String json = sb.toString();
     NotebookAuthorizationInfoSaving info = gson.fromJson(json,
             NotebookAuthorizationInfoSaving.class);
-    this.authInfo = info.authInfo;
+    authInfo = info.authInfo;
   }
 
   private void saveToFile() {
@@ -225,4 +244,16 @@ public class NotebookAuthorization {
     saveToFile();
   }
 
+  public List<NoteInfo> filterByUser(List<NoteInfo> notes, AuthenticationInfo subject) {
+    final Set<String> entities = Sets.newHashSet();
+    if (subject != null) {
+      entities.add(subject.getUser());
+    }
+    return FluentIterable.from(notes).filter(new Predicate<NoteInfo>() {
+      @Override
+      public boolean apply(NoteInfo input) {
+        return input != null && isReader(input.getId(), entities);
+      }
+    }).toList();
+  }
 }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
index 6ddaa33..4f414d5 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
@@ -31,6 +31,7 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
 import org.apache.zeppelin.notebook.Note;
 import org.apache.zeppelin.notebook.NoteInfo;
+import org.apache.zeppelin.notebook.NotebookAuthorization;
 import org.apache.zeppelin.notebook.Paragraph;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.slf4j.Logger;
@@ -178,9 +179,11 @@ public class NotebookRepoSync implements NotebookRepo {
    */
   void sync(int sourceRepoIndex, int destRepoIndex, AuthenticationInfo subject) throws IOException {
     LOG.info("Sync started");
+    NotebookAuthorization auth = NotebookAuthorization.getInstance();
     NotebookRepo srcRepo = getRepo(sourceRepoIndex);
     NotebookRepo dstRepo = getRepo(destRepoIndex);
-    List <NoteInfo> srcNotes = srcRepo.list(subject);
+    List <NoteInfo> allSrcNotes = srcRepo.list(subject);
+    List <NoteInfo> srcNotes = auth.filterByUser(allSrcNotes, subject);
     List <NoteInfo> dstNotes = dstRepo.list(subject);
 
     Map<String, List<String>> noteIDs = notesCheckDiff(srcNotes, srcRepo, dstNotes, dstRepo);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
index b32b3d8..29cdf55 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/helium/HeliumApplicationFactoryTest.java
@@ -89,7 +89,7 @@ public class HeliumApplicationFactoryTest implements JobListenerFactory {
 
     SearchService search = mock(SearchService.class);
     notebookRepo = new VFSNotebookRepo(conf);
-    NotebookAuthorization notebookAuthorization = new NotebookAuthorization(conf);
+    NotebookAuthorization notebookAuthorization = NotebookAuthorization.init(conf);
     notebook = new Notebook(
         conf,
         notebookRepo,

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
index 18d343c..7d7ae34 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
@@ -92,7 +92,7 @@ public class NotebookTest implements JobListenerFactory{
 
     SearchService search = mock(SearchService.class);
     notebookRepo = new VFSNotebookRepo(conf);
-    notebookAuthorization = new NotebookAuthorization(conf);
+    notebookAuthorization = NotebookAuthorization.init(conf);
     credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
 
     notebook = new Notebook(conf, notebookRepo, schedulerFactory, factory, this, search,
@@ -207,6 +207,7 @@ public class NotebookTest implements JobListenerFactory{
     Notebook notebook2 = new Notebook(
         conf, notebookRepo, schedulerFactory,
         new InterpreterFactory(conf, null, null, null, depResolver), this, null, null, null);
+
     assertEquals(1, notebook2.getAllNotes().size());
   }
 
@@ -588,7 +589,7 @@ public class NotebookTest implements JobListenerFactory{
     // create a note and a paragraph
     Note note = notebook.createNote(null);
     NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
-    // empty owners, readers and writers means note is public
+    // empty owners, readers or writers means note is public
     assertEquals(notebookAuthorization.isOwner(note.getId(),
             new HashSet<String>(Arrays.asList("user2"))), true);
     assertEquals(notebookAuthorization.isReader(note.getId(),
@@ -873,6 +874,39 @@ public class NotebookTest implements JobListenerFactory{
     assertEquals(1, notebook.getAllNotes(new AuthenticationInfo("user2")).size());
   }
 
+
+  @Test
+  public void testGetAllNotesWithDifferentPermissions() throws IOException {
+    AuthenticationInfo user1 = new AuthenticationInfo("user1");
+    AuthenticationInfo user2 = new AuthenticationInfo("user2");
+    List<Note> notes1 = notebook.getAllNotes(user1);
+    List<Note> notes2 = notebook.getAllNotes(user2);
+    assertEquals(notes1.size(), 0);
+    assertEquals(notes2.size(), 0);
+
+    //creates note and sets user1 owner
+    Note note = notebook.createNote(user1);
+
+    // note is public since readers and writers empty
+    notes1 = notebook.getAllNotes(user1);
+    notes2 = notebook.getAllNotes(user2);
+    assertEquals(notes1.size(), 1);
+    assertEquals(notes2.size(), 1);
+    
+    notebook.getNotebookAuthorization().setReaders(note.getId(), Sets.newHashSet("user1"));
+    //note is public since writers empty
+    notes1 = notebook.getAllNotes(user1);
+    notes2 = notebook.getAllNotes(user2);
+    assertEquals(notes1.size(), 1);
+    assertEquals(notes2.size(), 1);
+    
+    notebook.getNotebookAuthorization().setWriters(note.getId(), Sets.newHashSet("user1"));
+    notes1 = notebook.getAllNotes(user1);
+    notes2 = notebook.getAllNotes(user2);
+    assertEquals(notes1.size(), 1);
+    assertEquals(notes2.size(), 0);
+  }
+
   private void delete(File file){
     if(file.isFile()) file.delete();
     else if(file.isDirectory()){

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/b77f9ea8/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
index c768df8..95b9209 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java
@@ -99,7 +99,7 @@ public class NotebookRepoSyncTest implements JobListenerFactory {
     
     search = mock(SearchService.class);
     notebookRepoSync = new NotebookRepoSync(conf);
-    notebookAuthorization = new NotebookAuthorization(conf);
+    notebookAuthorization = NotebookAuthorization.init(conf);
     credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
     notebookSync = new Notebook(conf, notebookRepoSync, schedulerFactory, factory, this, search,
             notebookAuthorization, credentials);