/* * Copyright (C) 2012-2016 Facebook, Inc. * * 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 com.facebook.nifty.core; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TMessage; import org.apache.thrift.protocol.TMessageType; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.protocol.TStruct; import org.apache.thrift.transport.TIOStreamTransport; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import com.facebook.nifty.processor.NiftyProcessor; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.Uninterruptibles; public class AbstractLiveTest { protected AbstractLiveTest() { } protected FakeServer listen(NiftyProcessor processor) { // NiftyBootstrap.stop() will shutdown the threadpool for us return new FakeServer(processor, Executors.newCachedThreadPool(), new DefaultChannelGroup()); } protected FakeServer listen(NiftyProcessor processor, Executor taskExecutor, ChannelGroup group) { return new FakeServer(processor, taskExecutor, group); } protected FakeClient connect(FakeServer server) throws IOException { return new FakeClient(server); } protected NiftyProcessor mockProcessor( @Nullable final BlockingQueue<TProtocol> inQueue, @Nullable final BlockingQueue<TProtocol> outQueue, @Nullable final BlockingQueue<RequestContext> requestContextQueue, @Nonnull final BlockingQueue<SettableFuture<Boolean>> responseQueue ) { return new NiftyProcessor() { @Override public ListenableFuture<Boolean> process(TProtocol in, TProtocol out, RequestContext requestContext) throws TException { if (inQueue != null) { Uninterruptibles.putUninterruptibly(inQueue, in); } if (outQueue != null) { Uninterruptibles.putUninterruptibly(outQueue, out); } if (requestContextQueue != null) { Uninterruptibles.putUninterruptibly(requestContextQueue, requestContext); } SettableFuture<Boolean> resp = SettableFuture.create(); Uninterruptibles.putUninterruptibly(responseQueue, resp); return resp; } }; } protected static class FakeServer implements AutoCloseable { private final NiftyBootstrap nifty; private FakeServer(NiftyProcessor processor, Executor taskExecutor, ChannelGroup group) { ThriftServerDef thriftServerDef = new ThriftServerDefBuilder() .withProcessor(processor) .using(taskExecutor) .listen(0) .build(); this.nifty = new NiftyBootstrap( ImmutableSet.of(thriftServerDef), new NettyServerConfigBuilder().build(), group); nifty.start(); } public int getPort() { return Iterables.getOnlyElement(nifty.getBoundPorts().values()); } @Override public void close() { nifty.stop(); } } protected static class FakeClient implements AutoCloseable { private Socket socketToServer; private FakeClient(FakeServer server) throws IOException { socketToServer = new Socket(InetAddress.getLoopbackAddress(), server.getPort()); } public int getClientPort() { return socketToServer.getLocalPort(); } public void sendRequest() throws IOException, TException { TProtocol out = new TBinaryProtocol(new TIOStreamTransport(socketToServer.getOutputStream())); out.writeMessageBegin(new TMessage("dummy", TMessageType.CALL, 0)); out.writeStructBegin(new TStruct("dummy_args")); out.writeFieldStop(); out.writeStructEnd(); out.writeMessageEnd(); out.getTransport().flush(); } @Override public void close() throws IOException { socketToServer.close(); socketToServer = null; } } }