/**
* 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.fabric.netty.handlers;
import com.liferay.portal.fabric.FabricPathMappingVisitor;
import com.liferay.portal.fabric.InputResource;
import com.liferay.portal.fabric.agent.FabricAgent;
import com.liferay.portal.fabric.local.agent.EmbeddedProcessExecutor;
import com.liferay.portal.fabric.local.agent.LocalFabricAgent;
import com.liferay.portal.fabric.local.worker.EmbeddedProcessChannel;
import com.liferay.portal.fabric.local.worker.LocalFabricWorker;
import com.liferay.portal.fabric.netty.NettyTestUtil;
import com.liferay.portal.fabric.netty.agent.NettyFabricAgentStub;
import com.liferay.portal.fabric.netty.fileserver.handlers.FileServerTestUtil;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.FabricAgentFinishStartupProcessCallable;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.FabricWorkerResultProcessCallable;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.LoadedPaths;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.PostFabricWorkerExecutionFutureListener;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.PostFabricWorkerFinishFutureListener;
import com.liferay.portal.fabric.netty.handlers.NettyFabricWorkerExecutionChannelHandler.PostLoadPathsFutureListener;
import com.liferay.portal.fabric.netty.rpc.ChannelThreadLocal;
import com.liferay.portal.fabric.netty.rpc.RPCSerializable;
import com.liferay.portal.fabric.netty.util.NettyUtilAdvice;
import com.liferay.portal.fabric.netty.worker.NettyFabricWorkerConfig;
import com.liferay.portal.fabric.netty.worker.NettyFabricWorkerStub;
import com.liferay.portal.fabric.repository.MockRepository;
import com.liferay.portal.fabric.worker.FabricWorker;
import com.liferay.portal.kernel.concurrent.DefaultNoticeableFuture;
import com.liferay.portal.kernel.concurrent.FutureListener;
import com.liferay.portal.kernel.concurrent.NoticeableFuture;
import com.liferay.portal.kernel.process.ProcessCallable;
import com.liferay.portal.kernel.process.ProcessConfig;
import com.liferay.portal.kernel.process.ProcessConfig.Builder;
import com.liferay.portal.kernel.process.ProcessException;
import com.liferay.portal.kernel.process.local.ReturnProcessCallable;
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.ObjectGraphUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.test.rule.AdviseWith;
import com.liferay.portal.test.rule.AspectJNewEnvTestRule;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.concurrent.DefaultPromise;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ExecutionException;
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.ClassRule;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class NettyFabricWorkerExecutionChannelHandlerTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new AggregateTestRule(
CodeCoverageAssertor.INSTANCE, AspectJNewEnvTestRule.INSTANCE);
@Before
public void setUp() {
ChannelThreadLocal.setChannel(_embeddedChannel);
}
@After
public void tearDown() {
FileServerTestUtil.cleanUp();
ChannelThreadLocal.removeChannel();
}
@Test
public void testConstructor() {
try {
new NettyFabricWorkerExecutionChannelHandler(null, null, 0);
Assert.fail();
}
catch (NullPointerException npe) {
Assert.assertEquals("Repository is null", npe.getMessage());
}
try {
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(), null, 0);
Assert.fail();
}
catch (NullPointerException npe) {
Assert.assertEquals("Fabric agent is null", npe.getMessage());
}
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()), 0);
}
@Test
public void testExceptionCaught() {
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addFirst(nettyFabricWorkerExecutionChannelHandler);
NettyFabricWorkerConfig<Serializable> nettyFabricWorkerConfig =
createNettyFabricWorkerConfig();
ReflectionTestUtil.setFieldValue(
nettyFabricWorkerConfig, "_processConfig", null);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.INFO)) {
String embeddedChannelToString = _embeddedChannel.toString();
_embeddedChannel.writeInbound(nettyFabricWorkerConfig);
Assert.assertFalse(_embeddedChannel.isOpen());
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 2, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Closing " + embeddedChannelToString + " due to:",
logRecord.getMessage());
Throwable throwable = logRecord.getThrown();
Assert.assertSame(NullPointerException.class, throwable.getClass());
logRecord = logRecords.get(1);
Assert.assertEquals(
_embeddedChannel + " is closed", logRecord.getMessage());
}
}
@Test
public void testFabricAgentFinishStartupProcessCallable()
throws ProcessException {
FabricAgentFinishStartupProcessCallable
fabricWorkerFinishStartupProcessCallable =
new FabricAgentFinishStartupProcessCallable(0);
try {
fabricWorkerFinishStartupProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Assert.assertEquals(
"Unable to locate fabric agent on channel " + _embeddedChannel,
pe.getMessage());
}
NettyFabricAgentStub nettyFabricAgentStub =
installNettyFabricAgentStub();
Map<Long, DefaultNoticeableFuture<?>> startupNoticeableFutures =
ReflectionTestUtil.getFieldValue(
nettyFabricAgentStub, "_startupNoticeableFutures");
DefaultNoticeableFuture<?> defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
startupNoticeableFutures.put(0L, defaultNoticeableFuture);
Assert.assertFalse(defaultNoticeableFuture.isDone());
Assert.assertNull(fabricWorkerFinishStartupProcessCallable.call());
Assert.assertTrue(defaultNoticeableFuture.isDone());
}
@Test
public void testFabricWorkerResultProcessCallable() throws Exception {
// Unable to locate fabric agent
FabricWorkerResultProcessCallable fabricWorkerResultProcessCallable =
new FabricWorkerResultProcessCallable(0, StringPool.BLANK, null);
try {
fabricWorkerResultProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Assert.assertEquals(
"Unable to locate fabric agent on channel " + _embeddedChannel,
pe.getMessage());
}
// Unable to locate fabric worker
installNettyFabricAgentStub();
try {
fabricWorkerResultProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Assert.assertEquals(
"Unable to locate fabric worker on channel " +
_embeddedChannel + ", with fabric worker id 0",
pe.getMessage());
}
// Finish with result
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
installNettyFabricWorkerStub();
NoticeableFuture<Serializable> noticeableFuture =
nettyFabricWorkerStub.getProcessNoticeableFuture();
Assert.assertNull(fabricWorkerResultProcessCallable.call());
Assert.assertEquals(StringPool.BLANK, noticeableFuture.get());
// Finish with exception
Throwable throwable = new Throwable();
fabricWorkerResultProcessCallable =
new FabricWorkerResultProcessCallable(0, null, throwable);
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
Assert.assertNull(fabricWorkerResultProcessCallable.call());
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertSame(throwable, ee.getCause());
}
}
@AdviseWith(adviceClasses = NettyUtilAdvice.class)
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testIntegration() {
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addFirst(nettyFabricWorkerExecutionChannelHandler);
_embeddedChannel.writeInbound(createNettyFabricWorkerConfig());
FabricWorker<Serializable> fabricWorker =
NettyChannelAttributes.getFabricWorker(_embeddedChannel, 0);
DefaultNoticeableFuture<?> defaultNoticeableFuture =
(DefaultNoticeableFuture<?>)
fabricWorker.getProcessNoticeableFuture();
defaultNoticeableFuture.run();
Assert.assertNull(
NettyChannelAttributes.getFabricWorker(_embeddedChannel, 0));
}
@Test
public void testLoadedPaths() throws Exception {
// Good classpath
Map<Path, Path> inputPaths = Collections.emptyMap();
String newBootstrapClassPath = "newBootstrapClassPath";
String newRuntimeClassPath = "newRuntimeClassPath";
LoadedPaths loadedPaths = new LoadedPaths(
inputPaths, newBootstrapClassPath, newRuntimeClassPath);
Assert.assertSame(inputPaths, loadedPaths.getInputPaths());
List<String> arguments = Collections.emptyList();
Builder builder = new Builder();
builder.setArguments(arguments);
builder.setBootstrapClassPath("oldBootstrapClassPath");
builder.setRuntimeClassPath("oldRuntimeClassPath");
ProcessConfig processConfig = loadedPaths.toProcessConfig(
builder.build());
Assert.assertSame(arguments, processConfig.getArguments());
Assert.assertEquals(
newBootstrapClassPath, processConfig.getBootstrapClassPath());
Assert.assertEquals(
newRuntimeClassPath, processConfig.getRuntimeClassPath());
ClassLoader classLoader = processConfig.getReactClassLoader();
Assert.assertSame(URLClassLoader.class, classLoader.getClass());
URLClassLoader urlClassLoader = (URLClassLoader)classLoader;
URL[] urls = urlClassLoader.getURLs();
Assert.assertEquals(Arrays.toString(urls), 2, urls.length);
File file = new File(newBootstrapClassPath);
URI uri = file.toURI();
Assert.assertEquals(urls[0], uri.toURL());
file = new File(newRuntimeClassPath);
uri = file.toURI();
Assert.assertEquals(urls[1], uri.toURL());
// Broken classpath
final MalformedURLException malformedURLException =
new MalformedURLException();
Map<Object, Object> handlers = ReflectionTestUtil.getFieldValue(
URL.class, "handlers");
handlers.put(
"file",
new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL url) {
throw new UnsupportedOperationException();
}
@Override
protected void parseURL(
URL url, String spec, int start, int limit) {
ReflectionUtil.throwException(malformedURLException);
}
});
try {
loadedPaths.toProcessConfig(builder.build());
Assert.fail();
}
catch (ProcessException pe) {
Assert.assertSame(malformedURLException, pe.getCause());
}
finally {
handlers.clear();
}
}
@Test
public void testLoadPaths() throws Exception {
final Map<Path, Path> mergedPaths = new HashMap<>();
Path inputPath1 = Paths.get("inputPaths1");
Path mappedInputPath1 = Paths.get("mappedInputPath1");
Path inputPath2 = Paths.get("inputPaths2");
Path mappedInputPath2 = Paths.get("mappedInputPath2");
mergedPaths.put(inputPath1, mappedInputPath1);
mergedPaths.put(inputPath2, mappedInputPath2);
Path bootstrapPath1 = Paths.get("bootstrapPath1");
Path mappedBootstrapPath1 = Paths.get("mappedBootstrapPath1");
Path bootstrapPath2 = Paths.get("bootstrapPath2");
Path mappedBootstrapPath2 = Paths.get("mappedBootstrapPath2");
Path bootstrapPath3 = Paths.get("bootstrapPath3");
Path mappedBootstrapPath3 = Paths.get("mappedBootstrapPath3");
mergedPaths.put(bootstrapPath1, mappedBootstrapPath1);
mergedPaths.put(bootstrapPath2, mappedBootstrapPath2);
mergedPaths.put(bootstrapPath3, mappedBootstrapPath3);
Path runtimePath1 = Paths.get("runtimePath1");
Path mappedRuntimePath1 = Paths.get("mappedRuntimePath1");
Path runtimePath2 = Paths.get("runtimePath2");
Path mappedRuntimePath2 = Paths.get("mappedRuntimePath2");
Path runtimePath3 = Paths.get("runtimePath3");
Path mappedRuntimePath3 = Paths.get("mappedRuntimePath3");
mergedPaths.put(runtimePath1, mappedRuntimePath1);
mergedPaths.put(runtimePath2, mappedRuntimePath2);
mergedPaths.put(runtimePath3, mappedRuntimePath3);
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>("repository") {
@Override
public NoticeableFuture<Map<Path, Path>> getFiles(
Channel channel, Map<Path, Path> pathMap,
boolean deleteAfterFetch) {
DefaultNoticeableFuture<Map<Path, Path>>
defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(mergedPaths);
return defaultNoticeableFuture;
}
},
new LocalFabricAgent(new EmbeddedProcessExecutor()), 0);
Builder builder = new Builder();
builder.setBootstrapClassPath(
bootstrapPath1 + File.pathSeparator + bootstrapPath2 +
File.pathSeparator + bootstrapPath3);
builder.setRuntimeClassPath(
runtimePath1 + File.pathSeparator + runtimePath2 +
File.pathSeparator + runtimePath3);
ProcessConfig processConfig = builder.build();
ProcessCallable<Serializable> processCallable =
new LoadPathProcessCallable(
inputPath1.toFile(), inputPath2.toFile());
FabricPathMappingVisitor fabricPathMappingVisitor =
new FabricPathMappingVisitor(
InputResource.class, Paths.get("repository"));
ObjectGraphUtil.walkObjectGraph(
processCallable, fabricPathMappingVisitor);
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
LoadedPaths loadedPaths = noticeableFuture.get();
Map<Path, Path> loadedInputPaths = loadedPaths.getInputPaths();
Assert.assertEquals(
loadedInputPaths.toString(), 2, loadedInputPaths.size());
Assert.assertEquals(mappedInputPath1, loadedInputPaths.get(inputPath1));
Assert.assertEquals(mappedInputPath2, loadedInputPaths.get(inputPath2));
processConfig = loadedPaths.toProcessConfig(processConfig);
Assert.assertEquals(
mappedBootstrapPath1 + File.pathSeparator + mappedBootstrapPath2 +
File.pathSeparator +
mappedBootstrapPath3,
processConfig.getBootstrapClassPath());
Assert.assertEquals(
mappedRuntimePath1 + File.pathSeparator + mappedRuntimePath2 +
File.pathSeparator +
mappedRuntimePath3,
processConfig.getRuntimeClassPath());
}
@Test
public void testLoadPathsMissedBootstrapPaths() throws Exception {
// With log
final Map<Path, Path> mergedPaths = new HashMap<>();
Path bootstrapPath1 = Paths.get("bootstrapPath1");
Path mappedBootstrapPath1 = Paths.get("mappedBootstrapPath1");
Path bootstrapPath2 = Paths.get("bootstrapPath2");
Path bootstrapPath3 = Paths.get("bootstrapPath3");
mergedPaths.put(bootstrapPath1, mappedBootstrapPath1);
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>("repository") {
@Override
public NoticeableFuture<Map<Path, Path>> getFiles(
Channel channel, Map<Path, Path> pathMap,
boolean deleteAfterFetch) {
DefaultNoticeableFuture<Map<Path, Path>>
defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(mergedPaths);
return defaultNoticeableFuture;
}
},
new LocalFabricAgent(new EmbeddedProcessExecutor()), 0);
Builder builder = new Builder();
builder.setBootstrapClassPath(
bootstrapPath1 + File.pathSeparator + bootstrapPath2 +
File.pathSeparator + bootstrapPath3);
builder.setRuntimeClassPath(StringPool.BLANK);
ProcessConfig processConfig = builder.build();
ProcessCallable<Serializable> processCallable =
new ReturnProcessCallable<>(null);
FabricPathMappingVisitor fabricPathMappingVisitor =
new FabricPathMappingVisitor(
InputResource.class, Paths.get("repository"));
ObjectGraphUtil.walkObjectGraph(
processCallable, fabricPathMappingVisitor);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.WARNING)) {
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
LoadedPaths loadedPaths = noticeableFuture.get();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Incomplete bootstrap classpath loaded, missed: " +
Arrays.asList(bootstrapPath2, bootstrapPath3),
logRecord.getMessage());
Map<Path, Path> loadedInputPaths = loadedPaths.getInputPaths();
Assert.assertTrue(loadedInputPaths.isEmpty());
ProcessConfig loadedProcessConfig = loadedPaths.toProcessConfig(
processConfig);
Assert.assertEquals(
mappedBootstrapPath1.toString(),
loadedProcessConfig.getBootstrapClassPath());
Assert.assertEquals(
StringPool.BLANK, loadedProcessConfig.getRuntimeClassPath());
}
// Without log
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.OFF)) {
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
LoadedPaths loadedPaths = noticeableFuture.get();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
Map<Path, Path> loadedInputPaths = loadedPaths.getInputPaths();
Assert.assertTrue(loadedInputPaths.isEmpty());
ProcessConfig loadedProcessConfig = loadedPaths.toProcessConfig(
processConfig);
Assert.assertEquals(
mappedBootstrapPath1.toString(),
loadedProcessConfig.getBootstrapClassPath());
Assert.assertEquals(
StringPool.BLANK, loadedProcessConfig.getRuntimeClassPath());
}
}
@Test
public void testLoadPathsMissedInputPaths() throws InterruptedException {
final Map<Path, Path> mergedPaths = new HashMap<>();
Path inputPath1 = Paths.get("inputPaths1");
Path mappedInputPath1 = Paths.get("mappedInputPath1");
Path inputPath2 = Paths.get("inputPaths2");
mergedPaths.put(inputPath1, mappedInputPath1);
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>("repository") {
@Override
public NoticeableFuture<Map<Path, Path>> getFiles(
Channel channel, Map<Path, Path> pathMap,
boolean deleteAfterFetch) {
DefaultNoticeableFuture<Map<Path, Path>>
defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(mergedPaths);
return defaultNoticeableFuture;
}
},
new LocalFabricAgent(new EmbeddedProcessExecutor()), 0);
Builder builder = new Builder();
builder.setBootstrapClassPath(StringPool.BLANK);
builder.setRuntimeClassPath(StringPool.BLANK);
ProcessConfig processConfig = builder.build();
ProcessCallable<Serializable> processCallable =
new LoadPathProcessCallable(
inputPath1.toFile(), inputPath2.toFile());
FabricPathMappingVisitor fabricPathMappingVisitor =
new FabricPathMappingVisitor(
InputResource.class, Paths.get("repository"));
ObjectGraphUtil.walkObjectGraph(
processCallable, fabricPathMappingVisitor);
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
try {
noticeableFuture.get();
}
catch (ExecutionException ee) {
Throwable throwable = ee.getCause();
Assert.assertSame(IOException.class, throwable.getClass());
Assert.assertEquals(
"Unable to get input paths: " +
Arrays.asList(inputPath2),
throwable.getMessage());
}
}
@Test
public void testLoadPathsMissedRuntimePaths() throws Exception {
// With log
final Map<Path, Path> mergedPaths = new HashMap<>();
Path runtimePath1 = Paths.get("runtimePath1");
Path mappedRuntimePath1 = Paths.get("mappedRuntimePath1");
Path runtimePath2 = Paths.get("runtimePath2");
Path runtimePath3 = Paths.get("runtimePath3");
Path mappedRuntimePath3 = Paths.get("mappedRuntimePath3");
mergedPaths.put(runtimePath1, mappedRuntimePath1);
mergedPaths.put(runtimePath3, mappedRuntimePath3);
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>("repository") {
@Override
public NoticeableFuture<Map<Path, Path>> getFiles(
Channel channel, Map<Path, Path> pathMap,
boolean deleteAfterFetch) {
DefaultNoticeableFuture<Map<Path, Path>>
defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(mergedPaths);
return defaultNoticeableFuture;
}
},
new LocalFabricAgent(new EmbeddedProcessExecutor()), 0);
Builder builder = new Builder();
builder.setBootstrapClassPath(StringPool.BLANK);
builder.setRuntimeClassPath(
runtimePath1 + File.pathSeparator + runtimePath2 +
File.pathSeparator + runtimePath3);
ProcessConfig processConfig = builder.build();
ProcessCallable<Serializable> processCallable =
new ReturnProcessCallable<>(null);
FabricPathMappingVisitor fabricPathMappingVisitor =
new FabricPathMappingVisitor(
InputResource.class, Paths.get("repository"));
ObjectGraphUtil.walkObjectGraph(
processCallable, fabricPathMappingVisitor);
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.WARNING)) {
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
LoadedPaths loadedPaths = noticeableFuture.get();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Incomplete runtime classpath loaded, missed: " +
Arrays.asList(runtimePath2),
logRecord.getMessage());
Map<Path, Path> loadedInputPaths = loadedPaths.getInputPaths();
Assert.assertTrue(loadedInputPaths.isEmpty());
ProcessConfig loadedProcessConfig = loadedPaths.toProcessConfig(
processConfig);
Assert.assertEquals(
StringPool.BLANK, loadedProcessConfig.getBootstrapClassPath());
Assert.assertEquals(
mappedRuntimePath1 + File.pathSeparator +
mappedRuntimePath3,
loadedProcessConfig.getRuntimeClassPath());
}
// Without log
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.OFF)) {
NoticeableFuture<LoadedPaths> noticeableFuture =
nettyFabricWorkerExecutionChannelHandler.loadPaths(
_embeddedChannel,
new NettyFabricWorkerConfig<Serializable>(
0, processConfig, processCallable,
fabricPathMappingVisitor.getPathMap()));
LoadedPaths loadedPaths = noticeableFuture.get();
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertTrue(logRecords.isEmpty());
Map<Path, Path> loadedInputPaths = loadedPaths.getInputPaths();
Assert.assertTrue(loadedInputPaths.isEmpty());
ProcessConfig loadedProcessConfig = loadedPaths.toProcessConfig(
processConfig);
Assert.assertEquals(
StringPool.BLANK, loadedProcessConfig.getBootstrapClassPath());
Assert.assertEquals(
mappedRuntimePath1 + File.pathSeparator +
mappedRuntimePath3,
loadedProcessConfig.getRuntimeClassPath());
}
}
@AdviseWith(adviceClasses = NettyUtilAdvice.class)
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testPostFabricWorkerExecutionFutureListener() throws Exception {
// Execution failure
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
PostFabricWorkerExecutionFutureListener
postFabricWorkerExecutionFutureListener =
nettyFabricWorkerExecutionChannelHandler.
new PostFabricWorkerExecutionFutureListener(
_embeddedChannel, null,
createNettyFabricWorkerConfig());
DefaultPromise<FabricWorker<Serializable>> defaultPromise =
new DefaultPromise<>(_embeddedChannel.eventLoop());
Throwable throwable = new Throwable();
defaultPromise.setFailure(throwable);
installNettyFabricAgentStub();
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
installNettyFabricWorkerStub();
NoticeableFuture<Serializable> noticeableFuture =
nettyFabricWorkerStub.getProcessNoticeableFuture();
defaultPromise.addListener(postFabricWorkerExecutionFutureListener);
invokeRPC();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertEquals(throwable, ee.getCause());
}
// Finish startup failure
_embeddedChannel.close();
postFabricWorkerExecutionFutureListener =
nettyFabricWorkerExecutionChannelHandler.
new PostFabricWorkerExecutionFutureListener(
_embeddedChannel, null, createNettyFabricWorkerConfig());
defaultPromise = new DefaultPromise<>(_embeddedChannel.eventLoop());
DefaultNoticeableFuture<Serializable> processNoticeableFuture =
new DefaultNoticeableFuture<>();
FabricWorker<Serializable> fabricWorker = new LocalFabricWorker<>(
new EmbeddedProcessChannel<Serializable>(processNoticeableFuture));
defaultPromise.setSuccess(fabricWorker);
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.SEVERE)) {
defaultPromise.addListener(postFabricWorkerExecutionFutureListener);
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Unable to finish fabric worker startup",
logRecord.getMessage());
}
Assert.assertSame(
fabricWorker,
NettyChannelAttributes.getFabricWorker(_embeddedChannel, 0));
Set<FutureListener<Serializable>> futureListeners =
ReflectionTestUtil.getFieldValue(
processNoticeableFuture, "_futureListeners");
Assert.assertEquals(
futureListeners.toString(), 2, futureListeners.size());
Iterator<FutureListener<Serializable>> iterator =
futureListeners.iterator();
iterator.next();
FutureListener<Serializable> futureListener = iterator.next();
futureListener = ReflectionTestUtil.getFieldValue(
futureListener, "_futureListener");
Assert.assertSame(
PostFabricWorkerFinishFutureListener.class,
futureListener.getClass());
}
@AdviseWith(adviceClasses = NettyUtilAdvice.class)
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testPostFabricWorkerFinishFutureListener() throws Exception {
// Finish with execution exception
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
Path inputPath1 = FileServerTestUtil.createEmptyFile(
Paths.get("inputPath1"));
Path inputPath2 = FileServerTestUtil.createEmptyFile(
Paths.get("inputPath2"));
Map<Path, Path> inputPaths = new HashMap<>();
inputPaths.put(inputPath1, inputPath1);
inputPaths.put(inputPath2, inputPath2);
PostFabricWorkerFinishFutureListener
postFabricWorkerFinishFutureListener =
nettyFabricWorkerExecutionChannelHandler.
new PostFabricWorkerFinishFutureListener(
_embeddedChannel, createNettyFabricWorkerConfig(),
new LoadedPaths(inputPaths, null, null));
DefaultNoticeableFuture<Serializable> defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
Throwable throwable = new Throwable();
defaultNoticeableFuture.setException(throwable);
installNettyFabricAgentStub();
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
installNettyFabricWorkerStub();
NoticeableFuture<?> noticeableFuture =
nettyFabricWorkerStub.getProcessNoticeableFuture();
defaultNoticeableFuture.addFutureListener(
postFabricWorkerFinishFutureListener);
Assert.assertTrue(Files.notExists(inputPath1));
Assert.assertTrue(Files.notExists(inputPath2));
invokeRPC();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertEquals(throwable, ee.getCause());
}
// Finish with null pointer exception
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
postFabricWorkerFinishFutureListener.complete(null);
invokeRPC();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Throwable t = ee.getCause();
Assert.assertSame(NullPointerException.class, t.getClass());
}
// Finish with result
inputPath1 = FileServerTestUtil.createEmptyFile(
Paths.get("inputPath1"));
inputPath2 = FileServerTestUtil.createEmptyFile(
Paths.get("inputPath2"));
inputPaths = new HashMap<>();
inputPaths.put(inputPath1, inputPath1);
inputPaths.put(inputPath2, inputPath2);
postFabricWorkerFinishFutureListener =
nettyFabricWorkerExecutionChannelHandler.
new PostFabricWorkerFinishFutureListener(
_embeddedChannel, createNettyFabricWorkerConfig(),
new LoadedPaths(inputPaths, null, null));
defaultNoticeableFuture = new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(StringPool.BLANK);
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
defaultNoticeableFuture.addFutureListener(
postFabricWorkerFinishFutureListener);
Assert.assertTrue(Files.notExists(inputPath1));
Assert.assertTrue(Files.notExists(inputPath2));
invokeRPC();
Assert.assertEquals(StringPool.BLANK, noticeableFuture.get());
}
@AdviseWith(adviceClasses = NettyUtilAdvice.class)
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testPostLoadPathsFutureListener() throws Exception {
// Load paths failure
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
channelPipeline.addLast(nettyFabricWorkerExecutionChannelHandler);
ChannelHandlerContext channelHandlerContext =
channelPipeline.lastContext();
PostLoadPathsFutureListener postLoadPathsFutureListener =
nettyFabricWorkerExecutionChannelHandler.
new PostLoadPathsFutureListener(
channelHandlerContext, createNettyFabricWorkerConfig());
DefaultNoticeableFuture<LoadedPaths> defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
Throwable throwable = new Throwable();
defaultNoticeableFuture.setException(throwable);
installNettyFabricAgentStub();
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
installNettyFabricWorkerStub();
NoticeableFuture<Serializable> noticeableFuture =
nettyFabricWorkerStub.getProcessNoticeableFuture();
defaultNoticeableFuture.addFutureListener(postLoadPathsFutureListener);
invokeRPC();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertSame(throwable, ee.getCause());
}
// Loaded paths
defaultNoticeableFuture = new DefaultNoticeableFuture<>();
defaultNoticeableFuture.set(
new LoadedPaths(Collections.<Path, Path>emptyMap(), null, null));
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
defaultNoticeableFuture.addFutureListener(postLoadPathsFutureListener);
_embeddedChannel.runPendingTasks();
FabricAgent fabricAgent = ReflectionTestUtil.getFieldValue(
nettyFabricWorkerExecutionChannelHandler, "_fabricAgent");
Collection<? extends FabricWorker<?>> fabricWorkers =
fabricAgent.getFabricWorkers();
Assert.assertEquals(fabricWorkers.toString(), 1, fabricWorkers.size());
Assert.assertFalse(noticeableFuture.isDone());
}
@AdviseWith(adviceClasses = NettyUtilAdvice.class)
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testSendResult() throws Exception {
// Unable to send back fabric worker result
NettyFabricWorkerExecutionChannelHandler
nettyFabricWorkerExecutionChannelHandler =
new NettyFabricWorkerExecutionChannelHandler(
new MockRepository<Channel>(),
new LocalFabricAgent(new EmbeddedProcessExecutor()),
Long.MAX_VALUE);
Channel channel = NettyTestUtil.createEmptyEmbeddedChannel();
channel.close();
try (CaptureHandler captureHandler =
JDKLoggerTestUtil.configureJDKLogger(
NettyFabricWorkerExecutionChannelHandler.class.getName(),
Level.SEVERE)) {
nettyFabricWorkerExecutionChannelHandler.sendResult(
channel, 0, StringPool.BLANK, null);
List<LogRecord> logRecords = captureHandler.getLogRecords();
Assert.assertEquals(logRecords.toString(), 1, logRecords.size());
LogRecord logRecord = logRecords.get(0);
Assert.assertEquals(
"Unable to send back fabric worker result {id=0, result=, " +
"throwable=null}",
logRecord.getMessage());
}
// Send back result
installNettyFabricAgentStub();
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
installNettyFabricWorkerStub();
NoticeableFuture<Serializable> noticeableFuture =
nettyFabricWorkerStub.getProcessNoticeableFuture();
nettyFabricWorkerExecutionChannelHandler.sendResult(
_embeddedChannel, 0, StringPool.BLANK, null);
invokeRPC();
Assert.assertEquals(StringPool.BLANK, noticeableFuture.get());
// Send back exception
nettyFabricWorkerStub = installNettyFabricWorkerStub();
noticeableFuture = nettyFabricWorkerStub.getProcessNoticeableFuture();
Throwable throwable = new Throwable();
nettyFabricWorkerExecutionChannelHandler.sendResult(
_embeddedChannel, 0, null, throwable);
invokeRPC();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertSame(throwable, ee.getCause());
}
}
protected NettyFabricWorkerConfig<Serializable>
createNettyFabricWorkerConfig() {
Builder builder = new Builder();
builder.setBootstrapClassPath(StringPool.BLANK);
builder.setRuntimeClassPath(StringPool.BLANK);
return new NettyFabricWorkerConfig<>(
0, builder.build(), new ReturnProcessCallable<Serializable>(null),
Collections.<Path, Path>emptyMap());
}
protected NettyFabricAgentStub installNettyFabricAgentStub() {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("remoteRepositoryPath"), 0, Long.MAX_VALUE);
NettyChannelAttributes.setNettyFabricAgentStub(
_embeddedChannel, nettyFabricAgentStub);
return nettyFabricAgentStub;
}
protected NettyFabricWorkerStub<Serializable>
installNettyFabricWorkerStub() {
NettyFabricAgentStub nettyFabricAgentStub =
NettyChannelAttributes.getNettyFabricAgentStub(_embeddedChannel);
Map<Long, NettyFabricWorkerStub<?>> nettyFabricWorkerStubs =
ReflectionTestUtil.getFieldValue(
nettyFabricAgentStub, "_nettyFabricWorkerStubs");
NettyFabricWorkerStub<Serializable> nettyFabricWorkerStub =
new NettyFabricWorkerStub<>(
0, _embeddedChannel, new MockRepository<Channel>(),
Collections.<Path, Path>emptyMap(), 0);
nettyFabricWorkerStubs.put(0L, nettyFabricWorkerStub);
return nettyFabricWorkerStub;
}
protected void invokeRPC() {
RPCSerializable rpcSerializable =
(RPCSerializable)_embeddedChannel.readOutbound();
rpcSerializable.execute(_embeddedChannel);
Queue<Object> messages = _embeddedChannel.outboundMessages();
messages.clear();
}
private final EmbeddedChannel _embeddedChannel =
NettyTestUtil.createEmptyEmbeddedChannel();
private static class LoadPathProcessCallable
implements ProcessCallable<Serializable> {
public LoadPathProcessCallable(File inputFile1, File inputFile2) {
_inputFile1 = inputFile1;
_inputFile2 = inputFile2;
}
@Override
public Serializable call() {
return null;
}
private static final long serialVersionUID = 1L;
@InputResource
private final File _inputFile1;
@InputResource
private final File _inputFile2;
}
}