/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package oz.hadoop.yarn.api.net;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author Oleg Zhurakousky
*
*/
public class ClientServerTests {
@Test
@Ignore // need to fix to adjust for API changes
public void validateNetworkStackShutdownAndOnDisconnectListenerInvocationByClosingServer() throws Exception {
int expectedClients = 2;
Runnable onDisconnectTaskServer = mock(Runnable.class);
Runnable onDisconnectTaskClient = mock(Runnable.class);
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(expectedClients, false, onDisconnectTaskServer);
InetSocketAddress address = clientServer.start();
assertTrue(clientServer.isRunning());
ApplicationContainerClientImpl containerClientOne = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), onDisconnectTaskClient);
containerClientOne.start();
assertTrue(containerClientOne.isRunning());
ApplicationContainerClientImpl containerClientTwo = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), onDisconnectTaskClient);
containerClientTwo.start();
assertTrue(containerClientTwo.isRunning());
clientServer.awaitAllClients(2);
verify(onDisconnectTaskClient, times(0)).run();
verify(onDisconnectTaskServer, times(0)).run();
clientServer.stop(false);
clientServer.awaitShutdown();
assertFalse(clientServer.isRunning());
assertFalse(containerClientOne.isRunning());
assertFalse(containerClientTwo.isRunning());
verify(onDisconnectTaskClient, times(2)).run();
verify(onDisconnectTaskServer, times(1)).run();
}
@Test
@Ignore // need to fix to adjust for API changes
public void validateNetworkStackShutdownAndOnDisconnectListenerInvocationByClosingClients() throws Exception {
int expectedClients = 2;
Runnable onDisconnectTaskServer = mock(Runnable.class);
Runnable onDisconnectTaskClient = mock(Runnable.class);
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(expectedClients, false, onDisconnectTaskServer);
InetSocketAddress address = clientServer.start();
assertTrue(clientServer.isRunning());
ApplicationContainerClientImpl containerClientOne = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), onDisconnectTaskClient);
containerClientOne.start();
assertTrue(containerClientOne.isRunning());
ApplicationContainerClientImpl containerClientTwo = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), onDisconnectTaskClient);
containerClientTwo.start();
assertTrue(containerClientTwo.isRunning());
clientServer.awaitAllClients(2);
verify(onDisconnectTaskClient, times(0)).run();
verify(onDisconnectTaskServer, times(0)).run();
containerClientOne.stop(false);
assertTrue(clientServer.isRunning());
assertFalse(containerClientOne.isRunning());
verify(onDisconnectTaskClient, times(1)).run();
verify(onDisconnectTaskServer, times(0)).run();
containerClientTwo.stop(false);
clientServer.awaitShutdown();
assertFalse(clientServer.isRunning());
assertFalse(containerClientTwo.isRunning());
verify(onDisconnectTaskClient, times(2)).run();
verify(onDisconnectTaskServer, times(1)).run();
}
@Test
public void validateForcedShutdown() throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
int expectedClients = 2;
final ApplicationContainerServer clientServer = new ApplicationContainerServerImpl(expectedClients, false, mock(Runnable.class));
InetSocketAddress address = clientServer.start();
final AtomicInteger containerExitCount = new AtomicInteger();
final ApplicationContainerClient applicationMasterClient = new ApplicationContainerClientImpl(address, new BlockingMessageHandler(), mock(Runnable.class));
applicationMasterClient.start();
ApplicationContainerClient containerClientOne = new ApplicationContainerClientImpl(address, new BlockingMessageHandler(), new Runnable() {
@Override
public void run() {
containerExitCount.incrementAndGet();
if (containerExitCount.get() == 2){
applicationMasterClient.stop(true);
}
}
});
containerClientOne.start();
ApplicationContainerClient containerClientTwo = new ApplicationContainerClientImpl(address, new BlockingMessageHandler(), new Runnable() {
@Override
public void run() {
containerExitCount.incrementAndGet();
if (containerExitCount.get() == 2){
applicationMasterClient.stop(true);
}
}
});
containerClientTwo.start();
clientServer.awaitAllClients(1);
ContainerDelegate[] containerDelegates = clientServer.getContainerDelegates();
for (ContainerDelegate containerDelegate : containerDelegates) {
containerDelegate.process(ByteBuffer.wrap("foo".getBytes()), mock(ReplyPostProcessor.class));
}
// attempt to shutdown without force. it will block without success since the container tasks are infinite
executor.execute(new Runnable() {
@Override
public void run() {
clientServer.stop(false);
}
});
Thread.sleep(2000);
assertTrue(clientServer.isRunning());
clientServer.stop(true);
clientServer.awaitShutdown();
assertFalse(clientServer.isRunning());
}
@Test
@Ignore // need to fix to adjust for API changes
public void validateMoreThenExpectedClients() throws Exception {
for (int y = 0; y < 10; y++) {
int expectedClients = 2;
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(expectedClients, false, mock(Runnable.class));
InetSocketAddress address = clientServer.start();
for (int i = 0; i < 40; i++) {
ApplicationContainerClientImpl containerClientOne = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), mock(Runnable.class));
containerClientOne.start();
}
clientServer.awaitAllClients(2);
ContainerDelegate[] containerDelegates = clientServer.getContainerDelegates();
assertEquals(expectedClients, containerDelegates.length);
clientServer.stop(false);
}
}
@Test(timeout=5000)
@Ignore // need to fix to adjust for API changes
public void validateSimpleInterruction() throws Exception {
int expectedClients = 2;
InetSocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), 0);
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(sa, expectedClients, false, mock(Runnable.class));
InetSocketAddress address = clientServer.start();
for (int i = 0; i < expectedClients; i++) {
ApplicationContainerClientImpl containerClientOne = new ApplicationContainerClientImpl(address, new EchoMessageHandler(), mock(Runnable.class));
containerClientOne.start();
}
clientServer.awaitAllClients(2);
ContainerDelegate[] containerDelegates = clientServer.getContainerDelegates();
assertEquals(expectedClients, containerDelegates.length);
for (int i = 0; i < 2; i++) {
final int I = i;
for (final ContainerDelegate containerDelegate : containerDelegates) {
containerDelegate.process(ByteBuffer.wrap(new String("Hello" + i).getBytes()), new ReplyPostProcessor() {
@Override
public void doProcess(ByteBuffer reply) {
String replyString = new String(reply.array()).trim();
assertEquals("Hello" + I, replyString);
}
});
}
}
clientServer.stop(false);
clientServer.awaitShutdown();
}
@Test(timeout=5000)
@Ignore // need to fix to adjust for API changes
public void validateMixedMessageSizeExchange() throws Exception {
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(1, false, mock(Runnable.class));
InetSocketAddress address = clientServer.start();
StringBuffer buffer = new StringBuffer();
String s = "Hello World";
int size = 0;
while (size < 16384){
buffer.append(s);
size += s.length();
}
buffer.append("\r\n");
String message = buffer.toString().substring(0, 16384);
ApplicationContainerClientImpl containerClient = new ApplicationContainerClientImpl(address, new SampleMessageHandler(), mock(Runnable.class));
containerClient.start();
final ByteBuffer b1 = ByteBuffer.wrap(message.getBytes());
ContainerDelegate[] containerDelegates = clientServer.getContainerDelegates();
// Large message
containerDelegates[0].process(b1, new ReplyPostProcessor() {
@Override
public void doProcess(ByteBuffer reply) {
int reportedMessageSize = reply.getInt(0);
assertEquals(b1.limit(), reportedMessageSize);
}
});
// Small Message
final ByteBuffer b2 = ByteBuffer.wrap("Hello NIO\r\n".getBytes());
containerDelegates[0].process(b2, new ReplyPostProcessor() {
@Override
public void doProcess(ByteBuffer reply) {
int reportedMessageSize = reply.getInt(0);
assertEquals(b2.limit(), reportedMessageSize);
}
});
}
@Test(timeout=30000)
@Ignore // need to fix to adjust for API changes
public void validateWithMixedMessageSizesAndCorrectResultMultiClient() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(20);
final int expectedClients = 40;
InetSocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), 0);
ApplicationContainerServerImpl clientServer = new ApplicationContainerServerImpl(sa, expectedClients, false, mock(Runnable.class));
InetSocketAddress actualServerAddress = clientServer.start();
for (int i = 0; i < expectedClients; i++) {
ApplicationContainerClientImpl containerClient = new ApplicationContainerClientImpl(actualServerAddress, new EchoMessageHandler(), mock(Runnable.class));
containerClient.start();
}
ContainerDelegate[] containerDelegates = clientServer.getContainerDelegates();
int iterations = 100;
final CountDownLatch latch = new CountDownLatch(containerDelegates.length * iterations);
final AtomicReference<Exception> error = new AtomicReference<>();
for (int i = 0; i < iterations; i++) {
for (final ContainerDelegate containerDelegate : containerDelegates) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
int loopCount = new Random().nextInt(1000);
StringBuffer buffer = new StringBuffer();
for (int y = 0; y < loopCount; y++) {
buffer.append(UUID.randomUUID().toString());
}
final String inputMessage = buffer.toString();
inputMessage.length();
ByteBuffer inputBuffer = ByteBuffer.wrap(inputMessage.getBytes());
containerDelegate.process(inputBuffer, new ReplyPostProcessor() {
@Override
public void doProcess(ByteBuffer reply) {
assertEquals(inputMessage.length(), reply.limit());
}
});
}
catch (Exception e) {
e.printStackTrace();
error.set(e);
}
finally {
latch.countDown();
}
}
});
}
}
latch.await();
assertNull(error.get());
clientServer.stop(false);
executor.shutdown();
}
private static class EchoMessageHandler implements ApplicationContainerMessageHandler {
@Override
public ByteBuffer handle(ByteBuffer messageBuffer) {
return messageBuffer;
}
@Override
public void onDisconnect() {
}
}
private static class BlockingMessageHandler implements ApplicationContainerMessageHandler {
@Override
public ByteBuffer handle(ByteBuffer messageBuffer) {
for (int i = 0; i < 1000000; i++) {
LockSupport.parkNanos(1000000000);
boolean interrupted = Thread.interrupted();
System.out.println(this + " - running: " + interrupted);
if (interrupted){
break;
}
}
return messageBuffer;
}
@Override
public void onDisconnect() {
}
}
private static class SampleMessageHandler implements ApplicationContainerMessageHandler {
@Override
public ByteBuffer handle(ByteBuffer messageBuffer) {
ByteBuffer replyBuffer = ByteBuffer.allocate(6).putInt(messageBuffer.limit());
replyBuffer.flip();
return replyBuffer;
}
@Override
public void onDisconnect() {
// TODO Auto-generated method stub
}
}
}