/**
* 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.kernel.resiliency.spi.remote;
import com.liferay.portal.kernel.io.Serializer;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
import com.liferay.portal.kernel.nio.intraband.Datagram;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.blocking.ExecutorIntraband;
import com.liferay.portal.kernel.nio.intraband.rpc.RPCResponse;
import com.liferay.portal.kernel.nio.intraband.test.MockIntraband;
import com.liferay.portal.kernel.nio.intraband.test.MockRegistrationReference;
import com.liferay.portal.kernel.nio.intraband.welder.Welder;
import com.liferay.portal.kernel.process.ProcessCallable;
import com.liferay.portal.kernel.process.ProcessException;
import com.liferay.portal.kernel.process.local.LocalProcessLauncher.ProcessContext;
import com.liferay.portal.kernel.process.log.ProcessOutputStream;
import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtil;
import com.liferay.portal.kernel.resiliency.mpi.MPIHelperUtilTestUtil;
import com.liferay.portal.kernel.resiliency.spi.MockRemoteSPI;
import com.liferay.portal.kernel.resiliency.spi.MockSPI;
import com.liferay.portal.kernel.resiliency.spi.MockSPIProvider;
import com.liferay.portal.kernel.resiliency.spi.MockWelder;
import com.liferay.portal.kernel.resiliency.spi.SPI;
import com.liferay.portal.kernel.resiliency.spi.SPIConfiguration;
import com.liferay.portal.kernel.resiliency.spi.SPIRegistry;
import com.liferay.portal.kernel.resiliency.spi.SPIRegistryUtil;
import com.liferay.portal.kernel.resiliency.spi.agent.MockSPIAgent;
import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgent;
import com.liferay.portal.kernel.resiliency.spi.agent.SPIAgentFactoryUtil;
import com.liferay.portal.kernel.resiliency.spi.provider.SPIProvider;
import com.liferay.portal.kernel.resiliency.spi.provider.SPISynchronousQueueUtil;
import com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPI.RegisterCallback;
import com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPI.SPIShutdownHook;
import com.liferay.portal.kernel.resiliency.spi.remote.RemoteSPI.UnregisterSPIProcessCallable;
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.CodeCoverageAssertor;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.ProxyUtil;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.server.ExportException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class RemoteSPITest {
@ClassRule
public static final CodeCoverageAssertor codeCoverageAssertor =
CodeCoverageAssertor.INSTANCE;
@BeforeClass
public static void setUpClass() {
System.setProperty(
PropsKeys.INTRABAND_IMPL, ExecutorIntraband.class.getName());
System.setProperty(PropsKeys.INTRABAND_TIMEOUT_DEFAULT, "10000");
System.setProperty(
PropsKeys.INTRABAND_WELDER_IMPL, MockWelder.class.getName());
System.setProperty(
PropsKeys.LIFERAY_HOME, System.getProperty("user.dir"));
SPIAgentFactoryUtil.registerSPIAgentClass(MockSPIAgent.class);
}
@Before
public void setUp() {
_spiConfiguration = new SPIConfiguration(
"spiId", null, null, MockSPIAgent.class.getName(), 8081, null,
new String[0], new String[0], 5000, 0, 0, null);
_mockRemoteSPI = new MockRemoteSPI(_spiConfiguration);
_mockRemoteSPI.countDownLatch = new CountDownLatch(1);
SPIRegistryUtil spiRegistryUtil = new SPIRegistryUtil();
spiRegistryUtil.setSPIRegistry(
(SPIRegistry)ProxyUtil.newProxyInstance(
RemoteSPITest.class.getClassLoader(),
new Class<?>[] {SPIRegistry.class},
new InvocationHandler() {
@Override
public Object invoke(
Object proxy, Method method, Object[] args) {
return null;
}
}));
}
@After
public void tearDown() {
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
MPIHelperUtil.class.getName(), Level.OFF)) {
for (SPIProvider spiProvider : MPIHelperUtil.getSPIProviders()) {
MPIHelperUtil.unregisterSPIProvider(spiProvider);
}
}
}
@Test
public void testCall() throws Exception {
final AtomicBoolean throwIOException = new AtomicBoolean();
// Success
ProcessOutputStream processOutputStream = new ProcessOutputStream(
new ObjectOutputStream(new UnsyncByteArrayOutputStream())) {
@Override
public void writeProcessCallable(ProcessCallable<?> processCallable)
throws IOException {
if (throwIOException.get()) {
throw new IOException();
}
super.writeProcessCallable(processCallable);
}
};
ReflectionTestUtil.setFieldValue(
ProcessContext.class, "_processOutputStream", processOutputStream);
ConcurrentMap<String, Object> attributes =
ProcessContext.getAttributes();
SPI spi = _mockRemoteSPI.call();
Assert.assertSame(spi, UnicastRemoteObject.toStub(_mockRemoteSPI));
Assert.assertTrue(ProcessContext.isAttached());
ProcessContext.detach();
Assert.assertSame(
_mockRemoteSPI,
attributes.remove(SPI.SPI_INSTANCE_PUBLICATION_KEY));
// Duplicate export
try {
_mockRemoteSPI.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(ExportException.class, throwable.getClass());
}
Assert.assertTrue(ProcessContext.isAttached());
ProcessContext.detach();
Assert.assertNull(attributes.remove(SPI.SPI_INSTANCE_PUBLICATION_KEY));
// Unable to write process callable
UnicastRemoteObject.unexportObject(_mockRemoteSPI, true);
throwIOException.set(true);
try {
_mockRemoteSPI.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(IOException.class, throwable.getClass());
}
Assert.assertTrue(ProcessContext.isAttached());
ProcessContext.detach();
Assert.assertNull(attributes.remove(SPI.SPI_INSTANCE_PUBLICATION_KEY));
UnicastRemoteObject.unexportObject(_mockRemoteSPI, true);
}
@Test
public void testConstructor() {
Assert.assertSame(
_spiConfiguration, _mockRemoteSPI.getSPIConfiguration());
Assert.assertSame(MPIHelperUtil.getMPI(), _mockRemoteSPI.getMPI());
Welder welder = _mockRemoteSPI.getWelder();
Assert.assertSame(MockWelder.class, welder.getClass());
Assert.assertNotNull(_mockRemoteSPI.getUUID());
Assert.assertNull(_mockRemoteSPI.getRegistrationReference());
Assert.assertTrue(_mockRemoteSPI.isAlive());
SPIAgent spiAgent = _mockRemoteSPI.getSPIAgent();
Assert.assertSame(MockSPIAgent.class, spiAgent.getClass());
Assert.assertSame(spiAgent, _mockRemoteSPI.getSPIAgent());
}
@Test
public void testDestroy() throws RemoteException {
// Unable to unexport
try {
_mockRemoteSPI.destroy();
Assert.fail();
}
catch (RemoteException re) {
Assert.assertSame(NoSuchObjectException.class, re.getClass());
}
CountDownLatch countDownLatch = _mockRemoteSPI.countDownLatch;
Assert.assertEquals(0, countDownLatch.getCount());
// Unable to destroy
_mockRemoteSPI.setFailOnDestroy(true);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
try {
_mockRemoteSPI.destroy();
Assert.fail();
}
catch (RemoteException re) {
Assert.assertSame(RemoteException.class, re.getClass());
}
unexported();
// Successfully destroy
_mockRemoteSPI.countDownLatch = null;
_mockRemoteSPI.setFailOnDestroy(false);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
_mockRemoteSPI.destroy();
unexported();
}
@Test
public void testRegisterCallback() throws Exception {
// Successfully register callback
String uuid = "uuid";
final SynchronousQueue<SPI> synchronousQueue =
SPISynchronousQueueUtil.createSynchronousQueue(uuid);
FutureTask<SPI> takeSPIFutureTask = new FutureTask<>(
new Callable<SPI>() {
@Override
public SPI call() throws InterruptedException {
return synchronousQueue.take();
}
});
Thread takeSPIThread = new Thread(takeSPIFutureTask);
takeSPIThread.start();
RegisterCallback registerCallback = new RegisterCallback(
uuid, _mockRemoteSPI);
Assert.assertSame(_mockRemoteSPI, registerCallback.call());
Assert.assertSame(_mockRemoteSPI, takeSPIFutureTask.get());
// Interrupted on notify waiting
SPISynchronousQueueUtil.createSynchronousQueue(uuid);
registerCallback = new RegisterCallback(uuid, _mockRemoteSPI);
Thread currentThread = Thread.currentThread();
currentThread.interrupt();
try {
registerCallback.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(InterruptedException.class, throwable.getClass());
}
}
@Test
public void testSerialization() throws Exception {
UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
new UnsyncByteArrayOutputStream();
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(
unsyncByteArrayOutputStream)) {
objectOutputStream.writeObject(_mockRemoteSPI);
}
byte[] data = unsyncByteArrayOutputStream.toByteArray();
System.clearProperty(PropsKeys.INTRABAND_IMPL);
System.clearProperty(PropsKeys.INTRABAND_TIMEOUT_DEFAULT);
System.clearProperty(PropsKeys.INTRABAND_WELDER_IMPL);
System.clearProperty(PropsKeys.LIFERAY_HOME);
ObjectInputStream objectInputStream = new ObjectInputStream(
new UnsyncByteArrayInputStream(data));
Object object = objectInputStream.readObject();
Assert.assertSame(MockRemoteSPI.class, object.getClass());
Assert.assertEquals(
ExecutorIntraband.class.getName(),
System.getProperty(PropsKeys.INTRABAND_IMPL));
Assert.assertEquals(
"10000", System.getProperty(PropsKeys.INTRABAND_TIMEOUT_DEFAULT));
Assert.assertEquals(
MockWelder.class.getName(),
System.getProperty(PropsKeys.INTRABAND_WELDER_IMPL));
Assert.assertEquals(
System.getProperty("user.dir"),
System.getProperty("portal:" + PropsKeys.LIFERAY_HOME));
Assert.assertEquals(
"-".concat(_spiConfiguration.getSPIId()),
System.getProperty("spi.id"));
Assert.assertEquals(
"false",
System.getProperty("portal:" + PropsKeys.AUTO_DEPLOY_ENABLED));
Assert.assertEquals(
"false",
System.getProperty("portal:" + PropsKeys.CLUSTER_LINK_ENABLED));
Assert.assertEquals(
"false",
System.getProperty(
"portal:" +
PropsKeys.HOT_DEPLOY_DEPENDENCY_MANAGEMENT_ENABLED));
}
@Test
public void testSerializationSignature() throws Exception {
// Read object
Method readObjectMethod = RemoteSPI.class.getDeclaredMethod(
"readObject", ObjectInputStream.class);
Assert.assertNotNull(readObjectMethod);
Assert.assertEquals(Modifier.PRIVATE, readObjectMethod.getModifiers());
Assert.assertSame(void.class, readObjectMethod.getReturnType());
Class<?>[] parameterTypes = readObjectMethod.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 1, parameterTypes.length);
Assert.assertSame(ObjectInputStream.class, parameterTypes[0]);
List<Class<?>> exceptionTypes = Arrays.asList(
readObjectMethod.getExceptionTypes());
Assert.assertEquals(
exceptionTypes.toString(), 2, exceptionTypes.size());
Assert.assertTrue(
exceptionTypes.contains(ClassNotFoundException.class));
Assert.assertTrue(exceptionTypes.contains(IOException.class));
// Write object
Method writeObjectMethod = RemoteSPI.class.getDeclaredMethod(
"writeObject", ObjectOutputStream.class);
Assert.assertNotNull(writeObjectMethod);
Assert.assertEquals(Modifier.PRIVATE, writeObjectMethod.getModifiers());
Assert.assertSame(void.class, writeObjectMethod.getReturnType());
parameterTypes = writeObjectMethod.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 1, parameterTypes.length);
Assert.assertSame(ObjectOutputStream.class, parameterTypes[0]);
Class<?>[] exceptionTypeArray = writeObjectMethod.getExceptionTypes();
Assert.assertEquals(
Arrays.toString(exceptionTypeArray), 1, exceptionTypeArray.length);
Assert.assertSame(IOException.class, exceptionTypeArray[0]);
}
@Test
public void testSPIShutdownHookRun1() {
// Shortcut
_mockRemoteSPI.countDownLatch = new CountDownLatch(0);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
}
@Test
public void testSPIShutdownHookRun2() throws RemoteException {
// Unable to unregister, MPI waiting timed out, with log
String spiProviderName = "spiProviderName";
MockSPIProvider mockSPIProvider = new MockSPIProvider(spiProviderName);
MPIHelperUtil.registerSPIProvider(mockSPIProvider);
_mockRemoteSPI.setFailOnStop(false);
_mockRemoteSPI.setSpiProviderName(spiProviderName);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
MPIHelperUtil.registerSPI(_mockRemoteSPI);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 3, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Unable to unregister SPI from MPI", logRecord.getMessage());
Throwable throwable = logRecord.getThrown();
Assert.assertSame(NullPointerException.class, throwable.getClass());
logRecord = logRecords.get(1);
Assert.assertEquals(
"Wait up to " + _spiConfiguration.getShutdownTimeout() +
" ms for MPI shutdown request",
logRecord.getMessage());
logRecord = logRecords.get(2);
Assert.assertEquals(
"Proceed with SPI shutdown", logRecord.getMessage());
}
unexported();
}
@Test
public void testSPIShutdownHookRun3() throws RemoteException {
// Unable to unregister, MPI waiting timed out, without log
String spiProviderName = "spiProviderName";
MockSPIProvider mockSPIProvider = new MockSPIProvider(spiProviderName);
MPIHelperUtil.registerSPIProvider(mockSPIProvider);
_mockRemoteSPI.setFailOnStop(false);
_mockRemoteSPI.setSpiProviderName(spiProviderName);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
MPIHelperUtil.registerSPI(_mockRemoteSPI);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.OFF)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
unexported();
}
@Test
public void testSPIShutdownHookRun4() throws Exception {
// Unable to unregister, MPI shutdown request received, without log
String spiProviderName = "spiProviderName";
MockSPIProvider mockSPIProvider = new MockSPIProvider(spiProviderName);
MPIHelperUtil.registerSPIProvider(mockSPIProvider);
_mockRemoteSPI = new MockRemoteSPI(
new SPIConfiguration(
"spiId", null, null, MockSPIAgent.class.getName(), 8081, null,
new String[0], new String[0], 5000, 0, Long.MAX_VALUE, null));
_mockRemoteSPI.countDownLatch = new CountDownLatch(1);
_mockRemoteSPI.setFailOnStop(false);
_mockRemoteSPI.setSpiProviderName(spiProviderName);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
MPIHelperUtil.registerSPI(_mockRemoteSPI);
Future<?> future = actionOnMPIWaiting(true);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.OFF)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
Assert.assertNull(future.get());
unexported();
}
@Test
public void testSPIShutdownHookRun5() throws Exception {
// Unregister returns false, MPI waiting interrupts, with log
_mockRemoteSPI = new MockRemoteSPI(
new SPIConfiguration(
"spiId", null, null, MockSPIAgent.class.getName(), 8081, null,
new String[0], new String[0], 5000, 0, Long.MAX_VALUE, null));
_mockRemoteSPI.countDownLatch = new CountDownLatch(1);
_mockRemoteSPI.registrationReference = mockRegistrationReference(false);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
Future<?> future = actionOnMPIWaiting(false);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Wait up to " + Long.MAX_VALUE + " ms for MPI shutdown request",
logRecord.getMessage());
logRecord = logRecords.get(1);
Assert.assertEquals(
"Proceed with SPI shutdown", logRecord.getMessage());
}
Assert.assertNull(future.get());
unexported();
}
@Test
public void testSPIShutdownHookRun6() throws Exception {
// Unregister returns true, MPI shutdown request received, with log
_mockRemoteSPI = new MockRemoteSPI(
new SPIConfiguration(
"spiId", null, null, MockSPIAgent.class.getName(), 8081, null,
new String[0], new String[0], 5000, 0, Long.MAX_VALUE, null));
_mockRemoteSPI.countDownLatch = new CountDownLatch(1);
_mockRemoteSPI.registrationReference = mockRegistrationReference(false);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
Future<?> future = actionOnMPIWaiting(true);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Wait up to " + Long.MAX_VALUE + " ms for MPI shutdown request",
logRecord.getMessage());
logRecord = logRecords.get(1);
Assert.assertEquals(
"MPI shutdown request received", logRecord.getMessage());
}
Assert.assertNull(future.get());
unexported();
}
@Test
public void testSPIShutdownHookRun7() throws RemoteException {
// Unregister returns true, MPI waiting timed out, with log
_mockRemoteSPI.registrationReference = mockRegistrationReference(true);
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
spiShutdownHook.run();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
unexported();
}
@Test
public void testSPIShutdownHookShutdown1() throws RemoteException {
// Peacefully
UnicastRemoteObject.exportObject(_mockRemoteSPI, 0);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.ALL)) {
Assert.assertTrue(spiShutdownHook.shutdown(0, null));
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
unexported();
}
@Test
public void testSPIShutdownHookShutdown2() {
// Unable to stop and destroy, with log
_mockRemoteSPI.setFailOnStop(true);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.SEVERE)) {
Assert.assertTrue(spiShutdownHook.shutdown(0, null));
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals("Unable to stop SPI", logRecord.getMessage());
Throwable throwable = logRecord.getThrown();
Assert.assertSame(RemoteException.class, throwable.getClass());
logRecord = logRecords.get(1);
Assert.assertEquals(
"Unable to destroy SPI", logRecord.getMessage());
throwable = logRecord.getThrown();
Assert.assertSame(
NoSuchObjectException.class, throwable.getClass());
}
}
@Test
public void testSPIShutdownHookShutdown3() {
// Unable to stop and destroy, without log
_mockRemoteSPI.setFailOnStop(true);
SPIShutdownHook spiShutdownHook = _mockRemoteSPI.new SPIShutdownHook();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
RemoteSPI.class.getName(), Level.OFF)) {
Assert.assertTrue(spiShutdownHook.shutdown(0, null));
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
}
}
@Test
public void testUnregisterSPIProcessCallable() throws Exception {
// No such SPI
String spiProviderName = "spiProviderName";
String spiId = "spiId";
ProcessCallable<Boolean> processCallable =
new UnregisterSPIProcessCallable(spiProviderName, spiId);
Assert.assertFalse(processCallable.call());
// Unable to unregister SPI due to MPI mismatch
MPIHelperUtil.registerSPIProvider(new MockSPIProvider(spiProviderName));
MockSPI mockSPI = new MockSPI();
mockSPI.spiProviderName = spiProviderName;
MPIHelperUtilTestUtil.directResigterSPI(spiId, mockSPI);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
MPIHelperUtil.class.getName(), Level.WARNING)) {
Assert.assertFalse(processCallable.call());
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Not unregistering SPI " + mockSPI + " with foreign MPI null " +
"versus " + MPIHelperUtil.getMPI(),
logRecord.getMessage());
}
// Successfully unregister SPI
mockSPI.mpi = MPIHelperUtil.getMPI();
mockSPI.spiConfiguration = new SPIConfiguration(
spiId, null, 0, null, null, new String[0], null);
Assert.assertTrue(processCallable.call());
}
protected Future<?> actionOnMPIWaiting(final boolean countDownOrInterrupt) {
final Thread currentThread = Thread.currentThread();
FutureTask<?> futureTask = new FutureTask<>(
new Callable<Object>() {
@Override
public Object call() {
AbstractQueuedSynchronizer abstractQueuedSynchronizer =
ReflectionTestUtil.getFieldValue(
_mockRemoteSPI.countDownLatch, "sync");
while (true) {
Collection<Thread> threads =
abstractQueuedSynchronizer.getQueuedThreads();
if (threads.contains(currentThread)) {
if (countDownOrInterrupt) {
CountDownLatch countDownLatch =
_mockRemoteSPI.countDownLatch;
countDownLatch.countDown();
}
else {
currentThread.interrupt();
}
break;
}
}
return null;
}
});
Thread thread = new Thread(futureTask);
thread.start();
return futureTask;
}
protected RegistrationReference mockRegistrationReference(
final boolean unregistered) {
MockIntraband mockIntraband = new MockIntraband() {
@Override
protected Datagram processDatagram(Datagram datagram) {
try {
Serializer serializer = new Serializer();
serializer.writeObject(new RPCResponse(unregistered));
return Datagram.createResponseDatagram(
datagram, serializer.toByteBuffer());
}
catch (Exception e) {
throw new RuntimeException();
}
}
};
return new MockRegistrationReference(mockIntraband);
}
protected void unexported() {
try {
UnicastRemoteObject.unexportObject(_mockRemoteSPI, true);
}
catch (NoSuchObjectException nsoe) {
}
}
private MockRemoteSPI _mockRemoteSPI;
private SPIConfiguration _spiConfiguration;
}