/*
* Copyright (C) 2003-2009 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.forum.service.impl;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.EventListenerIterator;
import javax.jcr.observation.ObservationManager;
import org.exoplatform.commons.testing.AssertUtils;
import org.exoplatform.commons.testing.KernelUtils;
import org.exoplatform.commons.testing.mock.JCRMockUtils;
import org.exoplatform.container.component.ComponentPlugin;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.forum.common.conf.RoleRulesPlugin;
import org.exoplatform.forum.common.jcr.JCRSessionManager;
import org.exoplatform.forum.common.jcr.JCRTask;
import org.exoplatform.forum.common.jcr.KSDataLocation;
import org.exoplatform.forum.common.jcr.KSDataLocation.Locations;
import org.exoplatform.forum.membership.AbstractJCRTestCase;
import org.exoplatform.forum.service.Category;
import org.exoplatform.forum.service.EmailNotifyPlugin;
import org.exoplatform.forum.service.Forum;
import org.exoplatform.forum.service.ForumAdministration;
import org.exoplatform.forum.service.ForumAttachment;
import org.exoplatform.forum.service.MessageBuilder;
import org.exoplatform.forum.service.Post;
import org.exoplatform.forum.service.Topic;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
/**
* @author <a href="mailto:patrice.lamarque@exoplatform.com">Patrice Lamarque</a>
* @version $Revision$
*/
// TODO :
// * Fix tests to not have to specify the order of execution like this
// * The order of tests execution changed in Junit 4.11 (https://github.com/KentBeck/junit/blob/master/doc/ReleaseNotes4.11.md)
@FixMethodOrder(MethodSorters.JVM)
public class JCRDataStorageTestCase extends AbstractJCRTestCase {
protected Log log = ExoLogger.getLogger(JCRDataStorageTestCase.class);
private JCRDataStorage storage;
@Override
public void beforeRunBare() {
try {
super.beforeRunBare();
} catch (Exception e) {
log.error(e);
}
}
@Override
public void setUp() throws Exception {
super.setUp();
storage = new JCRDataStorage();
storage.setDataLocator(dataLocation);
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
public void testConstructor() {
KSDataLocation location = new KSDataLocation("bar");
JCRDataStorage storage = new JCRDataStorage(location);
// assertEquals(storage.getRepository(), "foo");
assertEquals(storage.getWorkspace(), "bar");
assertEquals(storage.getPath(), location.getForumHomeLocation());
}
public void testPlugins() {
KSDataLocation location = new KSDataLocation("bar");
JCRDataStorage storage = new JCRDataStorage(location);
storage.getDefaultPlugins();
}
public void testUpdateModeratorInForum() throws Exception {
String moderatorsPropName = "exo:moderators";
String[] moderators = new String[] { "foo", "zed" };
JCRDataStorage storage = new JCRDataStorage();
Node node = JCRMockUtils.mockNode();
JCRMockUtils.stubProperty(node, moderatorsPropName, "foo", "bar");
String[] actual = storage.updateModeratorInForum(node, moderators);
AssertUtils.assertContains(actual, "foo", "bar", "zed");
Node node2 = JCRMockUtils.mockNode();
JCRMockUtils.stubNullProperty(node2, moderatorsPropName);
String[] actual2 = storage.updateModeratorInForum(node2, moderators);
AssertUtils.assertContains(actual2, "foo", "zed");
Node node3 = JCRMockUtils.mockNode();
JCRMockUtils.stubProperty(node3, moderatorsPropName, " ", "bar");
String[] actual3 = storage.updateModeratorInForum(node3, moderators);
AssertUtils.assertContains(actual3, "foo", "zed");
}
public void testSetDefaultAvatar() throws Exception {
addNode(storage.getDataLocation().getAvatarsLocation());
String avatarLocation = storage.getDataLocation().getAvatarsLocation() + "/username";
assertNodeNotExists(avatarLocation);
storage.setDefaultAvatar("username");
assertNodeNotExists(avatarLocation);
addFile(avatarLocation);
assertNodeExists(avatarLocation);
storage.setDefaultAvatar("username");
assertNodeNotExists(avatarLocation);
}
public void testGetAvatar() throws Exception {
String avatarLocation = storage.getDataLocation().getAvatarsLocation() + "/username2";
// assertNull(storage.getUserAvatar("username2"));
addFile(avatarLocation);
ForumAttachment attachment = storage.getUserAvatar("username2");
assertNotNull(attachment);
assertEquals("avatar.plain", attachment.getName());
assertEquals("text/plain", attachment.getMimeType());
assertEquals("/" + getWorkspace() + "/" + avatarLocation, attachment.getPath()); // /portal-test/ksUserAvatar/username
assertEquals("stuff", stringOf(attachment.getInputStream()));
}
public void testSaveAvatar() throws Exception {
String avatarLocation = storage.getDataLocation().getAvatarsLocation() + "/username3";
assertNull(storage.getUserAvatar("username3"));
addFile(avatarLocation);
storage.saveUserAvatar("username3", new TextForumAttachment("updated content"));
Node node = getNode(avatarLocation);
assertEquals("updated content", stringOf(node.getNode("jcr:content").getProperty("jcr:data").getStream()));
}
public void testAddPlugin() throws Exception {
// fixture
addNode(storage.getDataLocation().getForumCategoriesLocation(), "exo:categoryHome");
// null plugin
storage.addPlugin(null);
assertNull(storage.getServerConfig().get("foo"));
// not EmailNotifyPlugin
ComponentPlugin plugin = mock(ComponentPlugin.class);
storage.addPlugin(plugin);
assertNull(storage.getServerConfig().get("foo"));
// with EmailNotifyPlugin
InitParams params = new InitParams();
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "bar");
KernelUtils.addPropertiesParam(params, "email.configuration.info", map);
EmailNotifyPlugin notifPlugin = new EmailNotifyPlugin(params);
storage.addPlugin(notifPlugin);
assertEquals("bar", storage.getServerConfig().get("foo"));
}
public void testAddRolePlugin() throws Exception {
storage.addRolePlugin(null);
AssertUtils.assertEmpty(storage.getRulesPlugins());
// not RoleRulesPlugin
ComponentPlugin plugin = mock(ComponentPlugin.class);
storage.addRolePlugin(plugin);
AssertUtils.assertEmpty(storage.getRulesPlugins());
InitParams params = new InitParams();
KernelUtils.addValueParam(params, "role", "ADMIN");
KernelUtils.addValuesParam(params, "rules", "rule1", "rule2");
storage.addRolePlugin(new RoleRulesPlugin(params));
AssertUtils.assertNotEmpty(storage.getRulesPlugins());
}
private <T extends EventListener> boolean hasListenerOfType(ObservationManager manager, Class<T> clazz) throws RepositoryException {
EventListenerIterator it = manager.getRegisteredEventListeners();
boolean found = false;
while (it.hasNext()) {
EventListener listener = it.nextEventListener();
if (listener.getClass() == clazz) {
found = true;
break;
}
}
return found;
}
public void testSaveForumAdministration() throws Exception {
adminNodeFixture();
// test create
ForumAdministration admin = new ForumAdministration();
admin.setCensoredKeyword("4letterword");
admin.setEnableHeaderSubject(true);
admin.setForumSortBy("name");
admin.setForumSortByType("descending");
admin.setHeaderSubject("header");
admin.setNotifyEmailContent("content");
admin.setNotifyEmailMoved("moved");
admin.setTopicSortBy("postCount");
admin.setTopicSortByType("ascending");
storage.saveForumAdministration(admin);
assertAdminSaved(admin);
// test update
admin.setCensoredKeyword("censored");
admin.setEnableHeaderSubject(false);
admin.setForumSortBy("forum");
admin.setForumSortByType("ascending");
admin.setHeaderSubject("subject");
admin.setNotifyEmailContent("c");
admin.setNotifyEmailMoved("m");
admin.setTopicSortBy("topic");
admin.setTopicSortByType("descending");
storage.saveForumAdministration(admin);
assertAdminSaved(admin);
}
public void testGetForumAdministration() throws Exception {
// fixture
String adminPath = adminNodeFixture();
Session session = getSession();
Node adminNode = session.getRootNode().getNode(adminPath);
adminNode.setProperty("exo:forumSortBy", "a");
adminNode.setProperty("exo:forumSortByType", "b");
adminNode.setProperty("exo:topicSortBy", "c");
adminNode.setProperty("exo:topicSortByType", "d");
adminNode.setProperty("exo:censoredKeyword", "e");
adminNode.setProperty("exo:enableHeaderSubject", true);
adminNode.setProperty("exo:headerSubject", "f");
adminNode.setProperty("exo:notifyEmailContent", "g");
adminNode.setProperty("exo:notifyEmailMoved", "h");
session.save();
// call method and check values
ForumAdministration admin = storage.getForumAdministration();
assertEquals("a", admin.getForumSortBy());
assertEquals("b", admin.getForumSortByType());
assertEquals("c", admin.getTopicSortBy());
assertEquals("d", admin.getTopicSortByType());
assertEquals("e", admin.getCensoredKeyword());
assertEquals(true, admin.getEnableHeaderSubject());
assertEquals("f", admin.getHeaderSubject());
assertEquals("g", admin.getNotifyEmailContent());
assertEquals("h", admin.getNotifyEmailMoved());
}
public void testUpdatePostCount() throws Exception {
//
initDefaultData();
// default data
Forum forum = storage.getForum(categoryId, forumId);
assertNotNull(forum);
assertEquals(1, forum.getPostCount());
// Test auto update by JCR listener
Topic topic = createdTopic(USER_DEMO);
storage.saveTopic(categoryId, forumId, topic, true, false, new MessageBuilder());
assertEquals(2, storage.getForum(categoryId, forumId).getPostCount());
assertEquals(1, storage.getUserInfo(USER_ROOT).getTotalPost());
// add more 3 posts
storage.savePost(categoryId, forumId, topic.getId(), createdPost(), true, new MessageBuilder());
storage.savePost(categoryId, forumId, topic.getId(), createdPost(), true, new MessageBuilder());
storage.savePost(categoryId, forumId, topic.getId(), createdPost(), true, new MessageBuilder());
//
assertEquals(5, storage.getForum(categoryId, forumId).getPostCount());
assertEquals(3, storage.getTopic(categoryId, forumId, topic.getId(), "").getPostCount());
assertEquals(4, storage.getUserInfo(USER_ROOT).getTotalPost());
// manual call JCRDataStorage#updatePostCount
// save new post on default topic
Post p = createdPost();
storage.savePost(categoryId, forumId, topicId, p, true, new MessageBuilder());
assertEquals(6, storage.getForum(categoryId, forumId).getPostCount());
assertEquals(1, storage.getTopic(categoryId, forumId, topicId, "").getPostCount());
assertEquals(5, storage.getUserInfo(USER_ROOT).getTotalPost());
//
for (int i = 0; i < 3; i++) {
storage.updatePostCount(p.getPath(), USER_ROOT);
}
assertEquals(9, storage.getForum(categoryId, forumId).getPostCount());
assertEquals(4, storage.getTopic(categoryId, forumId, topicId, "").getPostCount());
// method JCRDataStorage#updatePostCount() can not update user profile
assertEquals(5, storage.getUserInfo(USER_ROOT).getTotalPost());
}
private String adminNodeFixture() throws Exception {
String adminPath = storage.getDataLocation().getAdministrationLocation();
if (!getSession().getRootNode().hasNode(adminPath)) {
addNode(adminPath, "exo:administrationHome");
}
adminPath += "/forumAdministration";
addNode(adminPath, "exo:administration");
return adminPath;
}
private void assertAdminSaved(ForumAdministration admin) {
String adminPath = storage.getDataLocation().getAdministrationLocation() + "/forumAdministration";
assertNodeExists(adminPath);
Node adminNode = getNode(adminPath);
assertPropertyEquals(admin.getForumSortBy(), adminNode, "exo:forumSortBy");
assertPropertyEquals(admin.getForumSortByType(), adminNode, "exo:forumSortByType");
assertPropertyEquals(admin.getTopicSortBy(), adminNode, "exo:topicSortBy");
assertPropertyEquals(admin.getTopicSortByType(), adminNode, "exo:topicSortByType");
assertPropertyEquals(admin.getCensoredKeyword(), adminNode, "exo:censoredKeyword");
assertPropertyEquals(admin.getEnableHeaderSubject(), adminNode, "exo:enableHeaderSubject");
assertPropertyEquals(admin.getHeaderSubject(), adminNode, "exo:headerSubject");
assertPropertyEquals(admin.getNotifyEmailContent(), adminNode, "exo:notifyEmailContent");
assertPropertyEquals(admin.getNotifyEmailMoved(), adminNode, "exo:notifyEmailMoved");
}
static class TextForumAttachment extends ForumAttachment {
private String text;
public TextForumAttachment(String content) {
this.text = content;
setMimeType("text/plain");
super.setSize(content.getBytes().length);
}
@Override
public InputStream getInputStream() throws Exception {
return new ByteArrayInputStream(text.getBytes("UTF-8"));
}
}
private String stringOf(InputStream inputStream) {
try {
return new BufferedReader(new InputStreamReader(inputStream, "UTF-8")).readLine();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void _testDefaultAvatarWithMocks() throws Exception {
JCRDataStorage storage = new JCRDataStorage();
KSDataLocation locator = new KSDataLocation("wp");
JCRSessionManager sessionManager = stubJCRSessionManager();
locator.setSessionManager(sessionManager);
storage.setDataLocator(locator);
Node avatarHome = stubNodeForPath(Locations.KS_USER_AVATAR, sessionManager);
storage.setDefaultAvatar("foo");
verify(avatarHome).hasNode("foo"); // verify we tried to load the node
Node avatar = stubChild(avatarHome, "foo", "nt:file");
storage.setDefaultAvatar("foo");
verify(avatar).remove();
verify(avatarHome).save();
}
@SuppressWarnings("unchecked")
private JCRSessionManager stubJCRSessionManager() {
JCRSessionManager sessionManager = mock(JCRSessionManager.class);
when(sessionManager.executeAndSave(any(JCRTask.class))).thenCallRealMethod();
when(sessionManager.execute(any(JCRTask.class))).thenCallRealMethod();
return sessionManager;
}
private Node stubChild(Node parent, String name, String type) throws Exception {
Node child = mock(Node.class);
when(child.isNodeType(type)).thenReturn(true);
when(child.getName()).thenReturn(name);
when(parent.getNode(name)).thenReturn(child);
when(parent.hasNode(name)).thenReturn(true);
return child;
}
private Node stubNodeForPath(String path, JCRSessionManager manager) throws Exception {
Node node = mock(Node.class);
Node root = mock(Node.class);
when(root.getNode(path)).thenReturn(node);
Session session = mock(Session.class);
when(session.getRootNode()).thenReturn(root);
when(manager.createSession()).thenReturn(session);
when(manager.openSession()).thenReturn(session);
when(manager.getCurrentSession()).thenReturn(session);
return node;
}
}