/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.blogs.internal.util;
import com.liferay.blogs.model.BlogsEntry;
import com.liferay.blogs.service.BlogsEntryLocalService;
import com.liferay.blogs.service.BlogsEntryLocalServiceUtil;
import com.liferay.blogs.util.BlogsUtil;
import com.liferay.blogs.web.constants.BlogsPortletKeys;
import com.liferay.portal.kernel.comment.CommentManager;
import com.liferay.portal.kernel.comment.DuplicateCommentException;
import com.liferay.portal.kernel.language.Language;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
import com.liferay.portal.kernel.portlet.PortletProvider;
import com.liferay.portal.kernel.portlet.PortletProviderUtil;
import com.liferay.portal.kernel.security.pacl.permission.PortalSocketPermission;
import com.liferay.portal.kernel.service.PortletLocalService;
import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.ServiceContextFunction;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.util.RandomTestUtil;
import com.liferay.portal.kernel.util.Http;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.Portal;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.xmlrpc.Fault;
import com.liferay.portal.kernel.xmlrpc.XmlRpc;
import com.liferay.portal.kernel.xmlrpc.XmlRpcConstants;
import com.liferay.portal.kernel.xmlrpc.XmlRpcUtil;
import com.liferay.portal.util.PropsValues;
import com.liferay.registry.collections.ServiceTrackerCollections;
import com.liferay.registry.collections.ServiceTrackerMap;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
/**
* @author André de Oliveira
*/
@PrepareForTest(
{
BlogsEntryLocalServiceUtil.class, BlogsUtil.class,
PortalSocketPermission.class, PortletLocalServiceUtil.class,
PortletProviderUtil.class, PropsValues.class,
ServiceTrackerCollections.class, UserLocalServiceUtil.class
}
)
@RunWith(PowerMockRunner.class)
public class PingbackMethodImplTest extends PowerMockito {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
setUpBlogsEntryLocalServiceUtil();
setUpBlogsUtil();
setUpHttpUtil();
setUpLanguageUtil();
setUpPortalUtil();
setUpPortletLocalServiceUtil();
setUpPortletProviderUtil();
setUpUserLocalServiceUtil();
setUpXmlRpcUtil();
}
@Test
public void testAddPingbackWhenBlogEntryDisablesPingbacks()
throws Exception {
when(
_blogsEntry.isAllowPingbacks()
).thenReturn(
false
);
execute();
verifyFault(
XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND,
"Pingbacks are disabled");
}
@Test
public void testAddPingbackWhenPortalPropertyDisablesPingbacks()
throws Exception {
boolean previous = PropsValues.BLOGS_PINGBACK_ENABLED;
Whitebox.setInternalState(
PropsValues.class, "BLOGS_PINGBACK_ENABLED", false);
try {
execute();
verifyFault(
XmlRpcConstants.REQUESTED_METHOD_NOT_FOUND,
"Pingbacks are disabled");
}
finally {
Whitebox.setInternalState(
PropsValues.class, "BLOGS_PINGBACK_ENABLED", previous);
}
}
@Test
public void testAddPingbackWithFriendlyURL() throws Exception {
long plid = RandomTestUtil.randomLong();
String friendlyURL = RandomTestUtil.randomString();
when(
_portal.getPlidFromFriendlyURL(_COMPANY_ID, "/" + friendlyURL)
).thenReturn(
plid
);
long groupId = RandomTestUtil.randomLong();
when(
_portal.getScopeGroupId(plid)
).thenReturn(
groupId
);
String friendlyURLPath = RandomTestUtil.randomString();
whenFriendlyURLMapperPopulateParams(
"/" + friendlyURLPath, "urlTitle", _URL_TITLE);
String targetURI =
"http://" + RandomTestUtil.randomString() + "/" + friendlyURL +
"/-/" + friendlyURLPath;
whenHttpURLToString(
"<body><a href='" + targetURI + "'>" +
RandomTestUtil.randomString() + "</a></body>");
execute(targetURI);
verifySuccess();
Mockito.verify(
_blogsEntryLocalService
).getEntry(
groupId, _URL_TITLE
);
}
@Test
public void testAddPingbackWithFriendlyURLParameterEntryId()
throws Exception {
testAddPingbackWithFriendlyURLParameterEntryId(null);
}
@Test
public void testAddPingbackWithFriendlyURLParameterEntryIdInNamespace()
throws Exception {
String namespace = RandomTestUtil.randomString() + ".";
when(
_portal.getPortletNamespace(BlogsPortletKeys.BLOGS)
).thenReturn(
namespace
);
testAddPingbackWithFriendlyURLParameterEntryId(namespace);
}
@Test
public void testBuildServiceContext() throws Exception {
PingbackMethodImpl pingbackMethodImpl = getPingbackMethodImpl();
ServiceContext serviceContext = pingbackMethodImpl.buildServiceContext(
_COMPANY_ID, _GROUP_ID, _URL_TITLE);
Assert.assertEquals(
_PINGBACK_USER_NAME,
serviceContext.getAttribute("pingbackUserName"));
Assert.assertEquals(
_LAYOUT_FULL_URL + "/-/" + _FRIENDLY_URL_MAPPING + "/" + _URL_TITLE,
serviceContext.getAttribute("redirect"));
Assert.assertEquals(
_LAYOUT_FULL_URL, serviceContext.getLayoutFullURL());
}
@Test
public void testConvertDuplicateCommentExceptionToXmlRpcFault()
throws Exception {
Mockito.doThrow(
DuplicateCommentException.class
).when(
_commentManager
).addComment(
Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(),
Mockito.anyLong(), Mockito.anyString(),
Mockito.<ServiceContextFunction>any()
);
execute();
verifyFault(
PingbackMethodImpl.PINGBACK_ALREADY_REGISTERED,
"Pingback is already registered: null");
}
@Test
public void testExecuteWithSuccess() throws Exception {
execute();
verifySuccess();
Mockito.verify(
_commentManager
).addComment(
Matchers.eq(_USER_ID), Matchers.eq(_GROUP_ID),
Matchers.eq(BlogsEntry.class.getName()), Matchers.eq(_ENTRY_ID),
Matchers.eq(
"[...] " + _EXCERPT_BODY + " [...] [url=" + _SOURCE_URI + "]" +
_READ_MORE + "[/url]"),
Mockito.<ServiceContextFunction>any()
);
}
@Test
public void testGetExcerpt() throws Exception {
int previous = PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH;
Whitebox.setInternalState(
PropsValues.class, "BLOGS_LINKBACK_EXCERPT_LENGTH", 4);
try {
whenHttpURLToString(
"<body><a href='http://" + _TARGET_URI + "'>12345</a></body>");
execute();
verifyExcerpt("1...");
}
finally {
Whitebox.setInternalState(
PropsValues.class, "BLOGS_LINKBACK_EXCERPT_LENGTH", previous);
}
}
@Test
public void testGetExcerptWhenAnchorHasParent() throws Exception {
whenHttpURLToString(
"<body><p>Visit <a href='http://" + _TARGET_URI + "'>Liferay</a> " +
"to learn more</p></body>");
execute();
verifyExcerpt("Visit Liferay to learn more");
}
@Test
public void testGetExcerptWhenAnchorHasTwoParents() throws Exception {
int previous = PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH;
Whitebox.setInternalState(
PropsValues.class, "BLOGS_LINKBACK_EXCERPT_LENGTH", 18);
try {
whenHttpURLToString(
"<body>_____<p>12345<span>67890<a href='http://" + _TARGET_URI +
"'>Liferay</a>12345</span>67890</p>_____</body>");
execute();
verifyExcerpt("1234567890Lifer...");
}
finally {
Whitebox.setInternalState(
PropsValues.class, "BLOGS_LINKBACK_EXCERPT_LENGTH", previous);
}
}
@Test
public void testGetExcerptWhenAnchorIsMalformed() throws Exception {
whenHttpURLToString("<a href='MALFORMED' />");
execute("MALFORMED");
verifyFault(
PingbackMethodImpl.TARGET_URI_INVALID,
"Unable to parse target URI");
}
@Test
public void testGetExcerptWhenAnchorIsMissing() throws Exception {
whenHttpURLToString("");
execute();
verifyFault(
PingbackMethodImpl.SOURCE_URI_INVALID,
"Unable to find target URI in source");
}
@Test
public void testGetExcerptWhenReferrerIsUnavailable() throws Exception {
when(
_http.URLtoString(_SOURCE_URI)
).thenThrow(
IOException.class
);
execute();
verifyFault(
PingbackMethodImpl.SOURCE_URI_DOES_NOT_EXIST,
"Error accessing source URI");
}
protected void execute() {
execute("http://" + _TARGET_URI);
}
protected void execute(String targetURI) {
PingbackMethodImpl pingbackMethodImpl = getPingbackMethodImpl();
pingbackMethodImpl.setArguments(new Object[] {_SOURCE_URI, targetURI});
pingbackMethodImpl.execute(_COMPANY_ID);
}
protected PingbackMethodImpl getPingbackMethodImpl() {
PingbackMethodImpl pingbackMethodImpl = new PingbackMethodImpl();
ReflectionTestUtil.setFieldValue(
pingbackMethodImpl, "_commentManager", _commentManager);
ReflectionTestUtil.setFieldValue(
pingbackMethodImpl, "_http", HttpUtil.getHttp());
ReflectionTestUtil.setFieldValue(
pingbackMethodImpl, "_portal", PortalUtil.getPortal());
pingbackMethodImpl.setBlogsEntryLocalService(_blogsEntryLocalService);
pingbackMethodImpl.setPortletLocalService(_portletLocalService);
pingbackMethodImpl.setUserLocalService(_userLocalService);
return pingbackMethodImpl;
}
protected void setUpBlogsEntryLocalServiceUtil() throws Exception {
when(
_blogsEntry.getEntryId()
).thenReturn(
_ENTRY_ID
);
when(
_blogsEntry.getGroupId()
).thenReturn(
_GROUP_ID
);
when(
_blogsEntry.getUrlTitle()
).thenReturn(
_URL_TITLE
);
when(
_blogsEntry.isAllowPingbacks()
).thenReturn(
true
);
when(
_blogsEntryLocalService.getEntry(
Matchers.anyLong(), Matchers.anyString())
).thenReturn(
_blogsEntry
);
}
protected void setUpBlogsUtil() {
mockStatic(BlogsUtil.class, Mockito.RETURNS_SMART_NULLS);
}
protected void setUpHttpUtil() throws Exception {
whenHttpURLToString(
"<body><a href='http://" + _TARGET_URI + "'>" + _EXCERPT_BODY +
"</a></body>");
mockStatic(PortalSocketPermission.class, Mockito.RETURNS_DEFAULTS);
HttpUtil httpUtil = new HttpUtil();
httpUtil.setHttp(_http);
}
protected void setUpLanguageUtil() {
whenLanguageGet("pingback", _PINGBACK_USER_NAME);
whenLanguageGet("read-more", _READ_MORE);
LanguageUtil languageUtil = new LanguageUtil();
languageUtil.setLanguage(_language);
}
protected void setUpPortalUtil() throws Exception {
when(
_portal.getLayoutFullURL(
Matchers.anyLong(), Matchers.eq(BlogsPortletKeys.BLOGS))
).thenReturn(
_LAYOUT_FULL_URL
);
when(
_portal.getPlidFromFriendlyURL(
Matchers.eq(_COMPANY_ID), Matchers.anyString())
).thenReturn(
RandomTestUtil.randomLong()
);
when(
_portal.getScopeGroupId(Matchers.anyLong())
).thenReturn(
RandomTestUtil.randomLong()
);
PortalUtil portalUtil = new PortalUtil();
portalUtil.setPortal(_portal);
}
protected void setUpPortletLocalServiceUtil() {
Portlet portlet = Mockito.mock(Portlet.class);
when(
portlet.getFriendlyURLMapperInstance()
).thenReturn(
_friendlyURLMapper
);
when(
portlet.getFriendlyURLMapping()
).thenReturn(
_FRIENDLY_URL_MAPPING
);
when(
_portletLocalService.getPortletById(BlogsPortletKeys.BLOGS)
).thenReturn(
portlet
);
when(
_portletLocalService.getPortletById(
Matchers.anyLong(), Matchers.eq(BlogsPortletKeys.BLOGS))
).thenReturn(
portlet
);
}
protected void setUpPortletProviderUtil() {
mockStatic(ServiceTrackerCollections.class, Mockito.RETURNS_MOCKS);
stub(
method(
ServiceTrackerCollections.class, "singleValueMap", Class.class,
String.class)
).toReturn(
_serviceTrackerMap
);
mockStatic(PortletProviderUtil.class, Mockito.CALLS_REAL_METHODS);
stub(
method(
PortletProviderUtil.class, "getPortletId", String.class,
PortletProvider.Action.class)
).toReturn(
BlogsPortletKeys.BLOGS
);
}
protected void setUpUserLocalServiceUtil() throws Exception {
when(
_userLocalService.getDefaultUserId(Matchers.anyLong())
).thenReturn(
_USER_ID
);
}
protected void setUpXmlRpcUtil() {
Fault fault = Mockito.mock(Fault.class);
when(
_xmlRpc.createFault(Matchers.anyInt(), Matchers.anyString())
).thenReturn(
fault
);
XmlRpcUtil xmlRpcUtil = new XmlRpcUtil();
xmlRpcUtil.setXmlRpc(_xmlRpc);
}
protected void testAddPingbackWithFriendlyURLParameterEntryId(
String namespace)
throws Exception {
when(
_blogsEntryLocalService.getEntry(Matchers.anyLong())
).thenReturn(
_blogsEntry
);
String name = null;
if (namespace == null) {
name = "entryId";
}
else {
name = namespace + "entryId";
}
long entryId = RandomTestUtil.randomLong();
whenFriendlyURLMapperPopulateParams("", name, String.valueOf(entryId));
execute();
verifySuccess();
Mockito.verify(
_blogsEntryLocalService
).getEntry(
entryId
);
}
protected void verifyExcerpt(String excerpt) throws Exception {
verifySuccess();
Mockito.verify(
_commentManager
).addComment(
Matchers.anyLong(), Matchers.anyLong(), Matchers.anyString(),
Matchers.anyLong(),
Matchers.eq(
"[...] " + excerpt + " [...] [url=" + _SOURCE_URI + "]" +
_READ_MORE + "[/url]"),
Matchers.<ServiceContextFunction>any()
);
}
protected void verifyFault(int code, String description) {
Mockito.verify(
_xmlRpc
).createFault(
code, description
);
}
protected void verifySuccess() {
Mockito.verify(
_xmlRpc
).createSuccess(
"Pingback accepted"
);
}
protected void whenFriendlyURLMapperPopulateParams(
String friendlyURLPath, final String name, final String value) {
Mockito.doAnswer(
new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock)
throws Throwable {
Map<String, String[]> params =
(Map<String, String[]>)
invocationOnMock.getArguments()[1];
params.put(name, new String[] {value});
return null;
}
}
).when(
_friendlyURLMapper
).populateParams(
Matchers.eq(friendlyURLPath), Matchers.anyMap(), Matchers.anyMap()
);
}
protected void whenHttpURLToString(String returnValue) throws Exception {
when(
_http.URLtoString(_SOURCE_URI)
).thenReturn(
returnValue
);
}
protected void whenLanguageGet(String key, String returnValue) {
when(
_language.get((Locale)Matchers.any(), Matchers.eq(key))
).thenReturn(
returnValue
);
}
private static final long _COMPANY_ID = RandomTestUtil.randomLong();
private static final long _ENTRY_ID = RandomTestUtil.randomLong();
private static final String _EXCERPT_BODY = RandomTestUtil.randomString();
private static final String _FRIENDLY_URL_MAPPING =
RandomTestUtil.randomString();
private static final long _GROUP_ID = RandomTestUtil.randomLong();
private static final String _LAYOUT_FULL_URL =
RandomTestUtil.randomString();
private static final String _PINGBACK_USER_NAME =
RandomTestUtil.randomString();
private static final String _READ_MORE = RandomTestUtil.randomString();
private static final String _SOURCE_URI = RandomTestUtil.randomString();
private static final String _TARGET_URI = RandomTestUtil.randomString();
private static final String _URL_TITLE = RandomTestUtil.randomString();
private static final long _USER_ID = RandomTestUtil.randomLong();
@Mock
private BlogsEntry _blogsEntry;
@Mock
private BlogsEntryLocalService _blogsEntryLocalService;
@Mock
private CommentManager _commentManager;
@Mock
private FriendlyURLMapper _friendlyURLMapper;
@Mock
private Http _http;
@Mock
private Language _language;
@Mock
private Portal _portal;
@Mock
private PortletLocalService _portletLocalService;
@Mock
private ServiceTrackerMap<String, PortletProvider> _serviceTrackerMap;
@Mock
private UserLocalService _userLocalService;
@Mock
private XmlRpc _xmlRpc;
}