/**
* 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.agent;
import com.liferay.portal.fabric.OutputResource;
import com.liferay.portal.fabric.netty.NettyTestUtil;
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.status.FabricStatus;
import com.liferay.portal.fabric.status.RemoteFabricStatus;
import com.liferay.portal.fabric.worker.FabricWorker;
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.local.ReturnProcessCallable;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedChannel;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class NettyFabricAgentStubTest {
@ClassRule
public static final CodeCoverageAssertor codeCoverageAssertor =
CodeCoverageAssertor.INSTANCE;
@Test
public void testConstructor() {
try {
new NettyFabricAgentStub(null, null, null, 0, 0);
Assert.fail();
}
catch (NullPointerException npe) {
Assert.assertEquals("Channel is null", npe.getMessage());
}
try {
new NettyFabricAgentStub(_embeddedChannel, null, null, 0, 0);
Assert.fail();
}
catch (NullPointerException npe) {
Assert.assertEquals("Repository is null", npe.getMessage());
}
try {
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(), null, 0, 0);
Assert.fail();
}
catch (NullPointerException npe) {
Assert.assertEquals(
"Remote repository path is null", npe.getMessage());
}
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, 0);
}
@Test
public void testEquals() {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, 0);
Assert.assertTrue(nettyFabricAgentStub.equals(nettyFabricAgentStub));
Assert.assertFalse(nettyFabricAgentStub.equals(new Object()));
NettyFabricAgentStub anotherNettyFabricAgentStub =
new NettyFabricAgentStub(
NettyTestUtil.createEmptyEmbeddedChannel(),
new MockRepository<Channel>(),
Paths.get("AnotherRepositoryPath"), 0, 0);
Assert.assertFalse(
nettyFabricAgentStub.equals(anotherNettyFabricAgentStub));
anotherNettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("AnotherRepositoryPath"), 0, 0);
Assert.assertTrue(
nettyFabricAgentStub.equals(anotherNettyFabricAgentStub));
}
@Test
public void testExecute() throws Exception {
final NettyFabricAgentStub nettyFabricAgentStub =
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, Long.MAX_VALUE);
AtomicLong idGenerator = ReflectionTestUtil.getFieldValue(
nettyFabricAgentStub, "_idGenerator");
long id = idGenerator.get();
Builder builder = new Builder();
ProcessConfig processConfig = builder.build();
File testFile1 = new File("TestFile1");
File testFile2 = new File("TestFile2");
File testFile3 = new File("TestFile3");
ProcessCallable<String> processCallable = new TestProcessCallable(
testFile1, testFile2, testFile3);
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addLast(
new ChannelOutboundHandlerAdapter() {
@Override
public void write(
ChannelHandlerContext channelHandlerContext, Object obj,
ChannelPromise channelPromise)
throws Exception {
super.write(channelHandlerContext, obj, channelPromise);
if (!(obj instanceof NettyFabricWorkerConfig)) {
return;
}
NettyFabricWorkerConfig<?> nettyFabricWorkerConfig =
(NettyFabricWorkerConfig<?>)obj;
nettyFabricAgentStub.finishStartup(
nettyFabricWorkerConfig.getId());
}
});
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
processConfig, processCallable);
Queue<Object> messages = _embeddedChannel.outboundMessages();
Assert.assertEquals(1, messages.size());
NettyFabricWorkerConfig<String> nettyFabricWorkerConfig =
(NettyFabricWorkerConfig<String>)messages.poll();
Assert.assertEquals(id, nettyFabricWorkerConfig.getId());
Assert.assertSame(
processConfig, nettyFabricWorkerConfig.getProcessConfig());
ProcessCallable<String> nettyFabricWorkerProcessCallable =
nettyFabricWorkerConfig.getProcessCallable();
Assert.assertNotSame(processCallable, nettyFabricWorkerProcessCallable);
Assert.assertEquals(
processCallable.toString(),
nettyFabricWorkerProcessCallable.toString());
Assert.assertEquals(
processCallable.call(), nettyFabricWorkerProcessCallable.call());
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertEquals(fabricWorkers.toString(), 1, fabricWorkers.size());
Assert.assertTrue(fabricWorkers.contains(fabricWorker));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
Assert.assertFalse(noticeableFuture.isDone());
NettyFabricWorkerStub<String> nettyFabricWorkerStub =
(NettyFabricWorkerStub<String>)
nettyFabricAgentStub.takeNettyStubFabricWorker(id);
Assert.assertTrue(fabricWorkers.isEmpty());
Map<Path, Path> outputPathMap = ReflectionTestUtil.getFieldValue(
nettyFabricWorkerStub, "_outputPathMap");
Assert.assertEquals(outputPathMap.toString(), 2, outputPathMap.size());
Path path1 = testFile1.toPath();
File testOutput1 = ReflectionTestUtil.getFieldValue(
processCallable, "_testOutput1");
Assert.assertEquals(path1, outputPathMap.get(testOutput1.toPath()));
Path path3 = testFile3.toPath();
File testOutput3 = ReflectionTestUtil.getFieldValue(
processCallable, "_testOutput3");
Assert.assertEquals(path3, outputPathMap.get(testOutput3.toPath()));
nettyFabricWorkerStub.setResult(processCallable.call());
Assert.assertEquals(processCallable.call(), noticeableFuture.get());
// Ensure no side effect to finish an already finished startup
nettyFabricAgentStub.finishStartup(id);
}
@Test
public void testExecuteWithCancellation() {
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addFirst(
new ChannelOutboundHandlerAdapter() {
@Override
public void write(
ChannelHandlerContext channelHandlerContext, Object object,
ChannelPromise channelPromise) {
channelPromise.cancel(true);
}
});
try {
NettyFabricAgentStub nettyFabricAgentStub =
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, Long.MAX_VALUE);
Builder builder = new Builder();
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
builder.build(),
new ReturnProcessCallable<String>("Test result"));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
Assert.assertTrue(noticeableFuture.isCancelled());
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertTrue(fabricWorkers.isEmpty());
}
finally {
channelPipeline.removeFirst();
}
}
@Test
public void testExecuteWithClosedChannel() {
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addFirst(
new ChannelOutboundHandlerAdapter() {
@Override
public void write(
ChannelHandlerContext channelHandlerContext, Object object,
ChannelPromise channelPromise) {
_embeddedChannel.close();
}
});
try {
NettyFabricAgentStub nettyFabricAgentStub =
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, Long.MAX_VALUE);
Builder builder = new Builder();
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
builder.build(),
new ReturnProcessCallable<String>("Test result"));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
Assert.assertTrue(noticeableFuture.isCancelled());
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertTrue(fabricWorkers.isEmpty());
}
finally {
channelPipeline.removeFirst();
}
}
@Test
public void testExecuteWithFailure() throws Exception {
final Throwable throwable = new Throwable();
ChannelPipeline channelPipeline = _embeddedChannel.pipeline();
channelPipeline.addFirst(
new ChannelOutboundHandlerAdapter() {
@Override
public void write(
ChannelHandlerContext channelHandlerContext, Object object,
ChannelPromise channelPromise) {
channelPromise.setFailure(throwable);
}
});
try {
NettyFabricAgentStub nettyFabricAgentStub =
new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, Long.MAX_VALUE);
Builder builder = new Builder();
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
builder.build(),
new ReturnProcessCallable<String>("Test result"));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Assert.assertSame(throwable, ee.getCause());
}
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertTrue(fabricWorkers.isEmpty());
}
finally {
channelPipeline.removeFirst();
}
}
@Test
public void testExecuteWithInterruption() throws Exception {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, Long.MAX_VALUE);
Thread currentThread = Thread.currentThread();
currentThread.interrupt();
Builder builder = new Builder();
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
builder.build(), new ReturnProcessCallable<String>("Test result"));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Throwable throwable = ee.getCause();
Assert.assertSame(InterruptedException.class, throwable.getClass());
}
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertTrue(fabricWorkers.isEmpty());
}
@Test
public void testExecuteWithTimeout() throws InterruptedException {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, 0);
Builder builder = new Builder();
FabricWorker<String> fabricWorker = nettyFabricAgentStub.execute(
builder.build(), new ReturnProcessCallable<String>("Test result"));
NoticeableFuture<String> noticeableFuture =
fabricWorker.getProcessNoticeableFuture();
try {
noticeableFuture.get();
Assert.fail();
}
catch (ExecutionException ee) {
Throwable throwable = ee.getCause();
Assert.assertSame(TimeoutException.class, throwable.getClass());
}
Collection<? extends FabricWorker<?>> fabricWorkers =
nettyFabricAgentStub.getFabricWorkers();
Assert.assertTrue(fabricWorkers.isEmpty());
}
@Test
public void testGetFabricStatus() {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, 0);
FabricStatus fabricStatus = nettyFabricAgentStub.getFabricStatus();
Assert.assertSame(RemoteFabricStatus.class, fabricStatus.getClass());
}
@Test
public void testHashCode() {
NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub(
_embeddedChannel, new MockRepository<Channel>(),
Paths.get("RepositoryPath"), 0, 0);
Assert.assertEquals(
_embeddedChannel.hashCode(), nettyFabricAgentStub.hashCode());
}
private final EmbeddedChannel _embeddedChannel =
NettyTestUtil.createEmptyEmbeddedChannel();
private static class TestProcessCallable
implements ProcessCallable<String> {
public TestProcessCallable(
File testOutput1, File testOutput2, File testOutput3) {
_testOutput1 = testOutput1;
_testOutput2 = testOutput2;
_testOutput3 = testOutput3;
}
@Override
public String call() {
return "Test Result";
}
@OutputResource
private static final String _NOT_AFILE = "Not a File";
private static final long serialVersionUID = 1L;
@OutputResource
private final File _testOutput1;
@SuppressWarnings("unused")
private final File _testOutput2;
@OutputResource
private final File _testOutput3;
}
}