/**
* 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.portal.resiliency.spi;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.model.PortletApp;
import com.liferay.portal.kernel.resiliency.spi.MockSPI;
import com.liferay.portal.kernel.resiliency.spi.SPI;
import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
import com.liferay.portal.kernel.resiliency.spi.SPIRegistryUtil;
import com.liferay.portal.kernel.test.CaptureHandler;
import com.liferay.portal.kernel.test.JDKLoggerTestUtil;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.rule.NewEnv;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.test.rule.AdviseWith;
import com.liferay.portal.test.rule.AspectJNewEnvTestRule;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class SPIRegistryImplTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new AggregateTestRule(
CodeCoverageAssertor.INSTANCE, AspectJNewEnvTestRule.INSTANCE);
@Before
public void setUp() {
_spiRegistryImpl = new SPIRegistryImpl();
_spiRegistryImpl.setErrorSPI(new ErrorSPI());
SPIRegistryUtil spiRegistryUtil = new SPIRegistryUtil();
spiRegistryUtil.setSPIRegistry(_spiRegistryImpl);
_excludedPortletIds = ReflectionTestUtil.getFieldValue(
_spiRegistryImpl, "_excludedPortletIds");
_portletIds = ReflectionTestUtil.getFieldValue(
_spiRegistryImpl, "_portletIds");
_portletSPIs = ReflectionTestUtil.getFieldValue(
_spiRegistryImpl, "_portletSPIs");
}
@Test
public void testExcludedPortletIds() {
Assert.assertSame(
_excludedPortletIds, _spiRegistryImpl.getExcludedPortletIds());
String portlet1 = "portlet1";
_spiRegistryImpl.addExcludedPortletId(portlet1);
Assert.assertEquals(
_excludedPortletIds.toString(), 1, _excludedPortletIds.size());
Assert.assertTrue(_excludedPortletIds.contains(portlet1));
String portlet2 = "portlet2";
SPI spi = new MockSPI();
_portletSPIs.put(portlet2, spi);
Assert.assertNull(_spiRegistryImpl.getPortletSPI(portlet1));
Assert.assertSame(spi, _spiRegistryImpl.getPortletSPI(portlet2));
_spiRegistryImpl.setSPIRegistryValidator(
new MockSPIRegistryValidator());
Assert.assertNull(_spiRegistryImpl.getPortletSPI(portlet1));
Assert.assertSame(
_spiRegistryImpl.getErrorSPI(),
_spiRegistryImpl.getPortletSPI(portlet2));
_spiRegistryImpl.setSPIRegistryValidator(null);
_spiRegistryImpl.removeExcludedPortletId(portlet1);
Assert.assertTrue(_excludedPortletIds.isEmpty());
}
@AdviseWith(adviceClasses = {PortletLocalServiceUtilAdvice.class})
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testRegistration() throws RemoteException {
PortletLocalServiceUtilAdvice._portletIds = Arrays.asList(
"portlet3", "portlet4");
SPIConfiguration spiConfiguration = new SPIConfiguration(
"", "", 8081, "", new String[] {"portlet1", "portlet2"},
new String[] {"portletApp1", "portletApp2"}, null);
final AtomicBoolean throwException = new AtomicBoolean();
MockSPI mockSPI = new MockSPI() {
@Override
public boolean equals(Object object) {
return super.equals(object);
}
@Override
public int hashCode() {
if (throwException.get()) {
throw new RuntimeException();
}
return super.hashCode();
}
};
mockSPI.spiConfiguration = spiConfiguration;
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
SPIRegistryImpl.class.getName(), Level.WARNING)) {
// With log
List<LogRecord> logRecords = captureHandler.getLogRecords();
_spiRegistryImpl.registerSPI(mockSPI);
Assert.assertEquals(
_portletSPIs.toString(), 3, _portletSPIs.size());
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet1"));
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet3"));
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet4"));
Assert.assertSame(
mockSPI, _spiRegistryImpl.getServletContextSPI("portletApp1"));
Assert.assertSame(
mockSPI, _spiRegistryImpl.getServletContextSPI("portletApp2"));
Assert.assertNull(
_spiRegistryImpl.getServletContextSPI("portletApp3"));
_spiRegistryImpl.setSPIRegistryValidator(
new MockSPIRegistryValidator());
Assert.assertSame(
_spiRegistryImpl.getErrorSPI(),
_spiRegistryImpl.getServletContextSPI("portletApp1"));
Assert.assertSame(
_spiRegistryImpl.getErrorSPI(),
_spiRegistryImpl.getServletContextSPI("portletApp2"));
Assert.assertNull(
_spiRegistryImpl.getServletContextSPI("portletApp3"));
_spiRegistryImpl.setSPIRegistryValidator(null);
List<String> portletIds = Arrays.asList(
_portletIds.remove(mockSPI));
Assert.assertTrue(portletIds.contains("portlet1"));
Assert.assertTrue(portletIds.contains("portlet3"));
Assert.assertTrue(portletIds.contains("portlet4"));
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
LogRecord logRecord1 = logRecords.get(0);
Assert.assertEquals(
"Skip unknown portlet id portlet2", logRecord1.getMessage());
LogRecord logRecord2 = logRecords.get(1);
Assert.assertEquals(
"Skip unknown servlet context name portletApp2",
logRecord2.getMessage());
// Without log
logRecords = captureHandler.resetLogLevel(Level.OFF);
_spiRegistryImpl.registerSPI(mockSPI);
Assert.assertEquals(
_portletSPIs.toString(), 3, _portletSPIs.size());
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet1"));
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet3"));
Assert.assertEquals(mockSPI, _portletSPIs.remove("portlet4"));
portletIds = Arrays.asList(_portletIds.remove(mockSPI));
Assert.assertTrue(portletIds.contains("portlet1"));
Assert.assertTrue(portletIds.contains("portlet3"));
Assert.assertTrue(portletIds.contains("portlet4"));
Assert.assertTrue(logRecords.isEmpty());
// Hash failure
logRecords = captureHandler.resetLogLevel(Level.WARNING);
throwException.set(true);
try {
_spiRegistryImpl.registerSPI(mockSPI);
Assert.fail();
}
catch (RuntimeException re) {
}
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
logRecord1 = logRecords.get(0);
Assert.assertEquals(
"Skip unknown portlet id portlet2", logRecord1.getMessage());
logRecord2 = logRecords.get(1);
Assert.assertEquals(
"Skip unknown servlet context name portletApp2",
logRecord2.getMessage());
_portletSPIs.clear();
// Unregister, normal
logRecords = captureHandler.resetLogLevel(Level.WARNING);
throwException.set(false);
_spiRegistryImpl.registerSPI(mockSPI);
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
logRecord1 = logRecords.get(0);
Assert.assertEquals(
"Skip unknown portlet id portlet2", logRecord1.getMessage());
logRecord2 = logRecords.get(1);
Assert.assertEquals(
"Skip unknown servlet context name portletApp2",
logRecord2.getMessage());
}
_spiRegistryImpl.unregisterSPI(mockSPI);
Assert.assertTrue(_portletIds.isEmpty());
Assert.assertTrue(_portletSPIs.isEmpty());
// Unregister, again
_spiRegistryImpl.unregisterSPI(mockSPI);
Assert.assertTrue(_portletIds.isEmpty());
Assert.assertTrue(_portletSPIs.isEmpty());
// Hash failure
throwException.set(true);
try {
_spiRegistryImpl.unregisterSPI(mockSPI);
Assert.fail();
}
catch (RuntimeException re) {
}
}
@Aspect
public static class PortletLocalServiceUtilAdvice {
@Around(
"execution(public static com.liferay.portal.kernel.model.PortletApp " +
"com.liferay.portal.kernel.service.PortletLocalServiceUtil." +
"getPortletApp(String)) && args(servletContextName)"
)
public PortletApp getPortletApp(String servletContextName) {
if (servletContextName.equals("portletApp1")) {
return _createPortletAppProxy(_portletIds);
}
return null;
}
@Around(
"execution(public static com.liferay.portal.kernel.model.Portlet " +
"com.liferay.portal.kernel.service.PortletLocalServiceUtil." +
"getPortletById(String)) && args(portletId)"
)
public Portlet getPortletById(String portletId) {
if (portletId.equals("portlet1")) {
return _createPortletProxy(portletId);
}
return null;
}
private static List<String> _portletIds;
}
private static PortletApp _createPortletAppProxy(
final List<String> portletIds) {
return (PortletApp)ProxyUtil.newProxyInstance(
PortletApp.class.getClassLoader(),
new Class<?>[] {PortletApp.class},
new InvocationHandler() {
@Override
public Object invoke(
Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if (methodName.equals("getPortlets")) {
List<Portlet> portlets = new ArrayList<>(
portletIds.size());
for (String portletId : portletIds) {
portlets.add(_createPortletProxy(portletId));
}
return portlets;
}
throw new UnsupportedOperationException();
}
});
}
private static Portlet _createPortletProxy(final String portletId) {
return (Portlet)ProxyUtil.newProxyInstance(
Portlet.class.getClassLoader(), new Class<?>[] {Portlet.class},
new InvocationHandler() {
@Override
public Object invoke(
Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if (methodName.equals("getPortletId")) {
return portletId;
}
throw new UnsupportedOperationException();
}
});
}
private Set<String> _excludedPortletIds;
private Map<SPI, String[]> _portletIds;
private Map<String, SPI> _portletSPIs;
private SPIRegistryImpl _spiRegistryImpl;
}