package notifications; import static org.fest.assertions.Assertions.assertThat; import static test.AorraTestUtils.absoluteUrl; import static test.AorraTestUtils.asAdminUser; import static test.AorraTestUtils.fileStore; import static test.AorraTestUtils.flagStore; import static test.AorraTestUtils.jcrom; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Collections; import java.util.List; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.mail.MessagingException; import models.Flag; import models.Notification; import models.User; import models.UserDAO; import org.junit.Test; import play.libs.F; import play.test.FakeRequest; import service.EventManager; import service.EventManager.Event; import service.OrderedEvent; import service.filestore.FileStore; import service.filestore.FlagStore; import service.filestore.FlagStore.FlagType; public class NotificationManagerTest { @Test public void sendsNotificationsForWatchedFiles() { asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() { @Override public Session apply(Session session, User user, FakeRequest newRequest) throws RepositoryException, InterruptedException, IOException, MessagingException { User flaguser = createFlagUser(session); final FlagStore.Manager flm = flagStore().getManager(session); final FileStore.File f = fileStore().getManager(session) .getRoot() .createFile("test.txt", "text/plain", new ByteArrayInputStream("Test content.".getBytes())); // Wait, so we don't end up watching retroactively Thread.sleep(100); flm.setFlag(FlagType.WATCH, f.getIdentifier(), flaguser); // Perform update and trigger event f.update("text/plain", new ByteArrayInputStream("Test content.".getBytes())); assertThat(fileStore().getEventManager().getSince(null)).hasSize(2); awaitNotifications(1); flaguser = new UserDAO(session, jcrom()).loadById(flaguser.getId()); final List<Notification> notifications = flaguser.getNotifications(); assertThat(notifications).hasSize(1); assertThat(fileStore().getEventManager().getSince(null)).hasSize(3); for (Notification notification : flaguser.getNotifications()) { String messageContent = notification.getMessage(); assertThat(messageContent).isNotNull(); assertThat(messageContent).contains("/test.txt"); assertThat(messageContent).contains( absoluteUrl(controllers.routes.FileStoreController.showFile( f.getIdentifier()))); } return session; } }); } @Test public void sendsNotificationsForWatchedFolders() { asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() { @Override public Session apply(Session session, User user, FakeRequest newRequest) throws RepositoryException, InterruptedException, IOException, MessagingException { User flaguser = createFlagUser(session); final FlagStore.Manager flm = flagStore().getManager(session); final FileStore.Folder folder = fileStore().getManager(session) .getRoot() .createFolder("test"); // Wait, so we don't end up watching retroactively Thread.sleep(100); flm.setFlag(FlagType.WATCH, folder.getIdentifier(), flaguser); final FileStore.File f = folder.createFile("test.txt", "text/plain", new ByteArrayInputStream("Test content.".getBytes())); awaitNotifications(1); flaguser = new UserDAO(session, jcrom()).loadById(flaguser.getId()); final List<Notification> notifications = flaguser.getNotifications(); assertThat(notifications).hasSize(1); for (Notification notification : flaguser.getNotifications()) { String messageContent = notification.getMessage(); assertThat(messageContent).isNotNull(); assertThat(messageContent).contains("/test/test.txt"); assertThat(messageContent).contains("created"); assertThat(messageContent).contains( absoluteUrl(controllers.routes.FileStoreController.showFile( f.getIdentifier()))); } return session; } }); } @Test public void sendsNotificationsOncePerUser() { asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() { @Override public Session apply(Session session, User user, FakeRequest newRequest) throws RepositoryException, InterruptedException, IOException, MessagingException { User flaguser = createFlagUser(session); final FlagStore.Manager flm = flagStore().getManager(session); final FileStore.Folder folder = fileStore().getManager(session) .getRoot() .createFolder("test"); final FileStore.File f = folder.createFile("test.txt", "text/plain", new ByteArrayInputStream("Test content.".getBytes())); // Wait, so we don't end up watching retroactively Thread.sleep(100); // Watch both the the folder & file flm.setFlag(FlagType.WATCH, folder.getIdentifier(), flaguser); flm.setFlag(FlagType.WATCH, f.getIdentifier(), flaguser); // Try multiple times to ensure we really are de-duplicating for (int i = 1; i < 5; i++) { // Perform update and trigger event f.update("text/plain", new ByteArrayInputStream("Test content.".getBytes())); awaitNotifications(i); flaguser = new UserDAO(session, jcrom()).loadById(flaguser.getId()); final List<Notification> notifications = flaguser.getNotifications(); assertThat(notifications).hasSize(i); for (Notification notification : flaguser.getNotifications()) { String messageContent = notification.getMessage(); assertThat(messageContent).isNotNull(); assertThat(messageContent).contains("/test/test.txt"); assertThat(messageContent).contains("updated"); assertThat(messageContent).contains( absoluteUrl(controllers.routes.FileStoreController.showFile( f.getIdentifier()))); } } return session; } }); } @Test public void sendsEditingNotifications() { asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() { @Override public Session apply(Session session, User user, FakeRequest newRequest) throws RepositoryException, InterruptedException, IOException, MessagingException { User flaguser = createFlagUser(session); final FlagStore.Manager flm = flagStore().getManager(session); final FileStore.File f = fileStore().getManager(session) .getRoot() .createFile("test.txt", "text/plain", new ByteArrayInputStream("Test content.".getBytes())); // Wait, so we don't end up watching retroactively Thread.sleep(100); flm.setFlag(FlagType.WATCH, f.getIdentifier(), flaguser); assertThat(fileStore().getEventManager().getSince(null)).hasSize(1); // Perform set flag and trigger event final Flag flag = flm.setFlag(FlagType.EDIT, f.getIdentifier(), user); fileStore().getEventManager().tell(FlagStore.Events.create( flag, FlagType.EDIT, user)); awaitNotifications(1); assertThat(fileStore().getEventManager().getSince(null)).hasSize(3); flaguser = (new UserDAO(session, jcrom())).loadById(flaguser.getId()); assertThat(flaguser.getNotifications()).hasSize(1); Notification notification = flaguser.getNotifications().get(0); String messageContent = notification.getMessage(); assertThat(messageContent).isNotNull(); assertThat(messageContent).contains("editing"); assertThat(messageContent).contains("/test.txt"); assertThat(messageContent).contains( absoluteUrl(controllers.routes.FileStoreController.showFile( f.getIdentifier()))); return session; } }); } private User createFlagUser(Session session) { final User u = new User(); u.setEmail("flaguser@flagtest.test"); u.setName("Flag User"); return (new UserDAO(session, jcrom())).create(u); } public static void awaitNotifications(int count) { for (int retries = 50; retries > 0; retries--) { try { Iterable<OrderedEvent> events = fileStore().getEventManager().getSince(null); int actualCount = 0; for(OrderedEvent oe : events) { EventManager.Event event = oe.event(); if (event.type.startsWith("notification")) { actualCount++; } } if (actualCount >= count) return; Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } throw new RuntimeException(String.format( "Time out waiting for %s notifications.", count)); } }