/*
* Copyright 2016 Netflix, 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 io.reactivex.netty.protocol.http.client.internal;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.EventExecutorGroup;
import io.reactivex.netty.channel.Connection;
import io.reactivex.netty.channel.ConnectionImpl;
import io.reactivex.netty.channel.ConnectionInputSubscriberEvent;
import io.reactivex.netty.events.EventAttributeKeys;
import io.reactivex.netty.protocol.http.TrailingHeaders;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import io.reactivex.netty.protocol.tcp.client.TcpClient;
import io.reactivex.netty.protocol.tcp.client.events.TcpClientEventPublisher;
import io.reactivex.netty.test.util.MockEventPublisher;
import io.reactivex.netty.test.util.FlushSelector;
import io.reactivex.netty.test.util.TcpConnectionRequestMock;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.observers.TestSubscriber;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpHeaderValues.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.*;
import static org.mockito.Matchers.*;
public class HttpClientRequestImplTest {
@Rule
public final RequestRule requestRule = new RequestRule();
@Test(timeout = 60000)
public void testWriteContent() throws Exception {
Observable<Object> content = Observable.<Object>just("Hello");
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeContent(content);
requestRule.assertContentWrite(content, newReq);
}
@Test(timeout = 60000)
public void testWriteContentAndFlushOnEach() throws Exception {
Observable<Object> content = Observable.<Object>just("Hello");
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeContentAndFlushOnEach(content);
requestRule.assertContentWriteAndFlushOnEach(content, newReq);
}
@Test(timeout = 60000)
public void testWriteStringContent() throws Exception {
Observable<String> content = Observable.just("Hello");
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeStringContent(content);
requestRule.assertContentWrite(content, newReq);
}
@Test(timeout = 60000)
public void testWriteBytesContent() throws Exception {
Observable<byte[]> content = Observable.just("Hello".getBytes());
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeBytesContent(content);
requestRule.assertContentWrite(content, newReq);
}
@Test(timeout = 60000)
public void testWriteContentWithFlushSelector() throws Exception {
Observable<Object> content = Observable.<Object>just("Hello");
FlushSelector<Object> flushSelector = new FlushSelector<>(5);
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeContent(content, flushSelector);
requestRule.assertContentWrite(content, newReq, flushSelector);
}
@Test(timeout = 60000)
public void testWriteStringContentWithFlushSelector() throws Exception {
Observable<String> content = Observable.just("Hello");
FlushSelector<String> flushSelector = new FlushSelector<>(5);
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeStringContent(content, flushSelector);
requestRule.assertContentWrite(content, newReq, flushSelector);
}
@Test(timeout = 60000)
public void testWriteBytesContentWithFlushSelector() throws Exception {
Observable<byte[]> content = Observable.just("Hello".getBytes());
FlushSelector<byte[]> flushSelector = new FlushSelector<>(5);
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeBytesContent(content, flushSelector);
requestRule.assertContentWrite(content, newReq, flushSelector);
}
@Test(timeout = 60000)
public void testWriteContentWithTrailer() throws Exception {
Observable<Object> content = Observable.<Object>just("Hello");
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<Object> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeContent(content, tFactory, tMutator);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator);
}
@Test(timeout = 60000)
public void testWriteStringContentWithTrailer() throws Exception {
Observable<String> content = Observable.just("Hello");
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<String> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeStringContent(content, tFactory,
tMutator);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator);
}
@Test(timeout = 60000)
public void testWriteBytesContentWithTrailer() throws Exception {
Observable<byte[]> content = Observable.just("Hello".getBytes());
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<byte[]> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeBytesContent(content, tFactory,
tMutator);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator);
}
@Test(timeout = 60000)
public void testWriteContentWithTrailerAndSelector() throws Exception {
Observable<Object> content = Observable.<Object>just("Hello".getBytes());
FlushSelector<Object> selector = new FlushSelector<>(1);
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<Object> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeContent(content, tFactory, tMutator,
selector);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator, 2/*One for content & one for trailer*/);
}
@Test(timeout = 60000)
public void testWriteStringContentWithTrailerAndSelector() throws Exception {
Observable<String> content = Observable.just("Hello");
FlushSelector<String> selector = new FlushSelector<>(1);
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<String> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeStringContent(content, tFactory,
tMutator, selector);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator, 2/*One for content & one for trailer*/);
}
@Test(timeout = 60000)
public void testWriteBytesContentWithTrailerAndSelector() throws Exception {
Observable<byte[]> content = Observable.just("Hello".getBytes());
FlushSelector<byte[]> selector = new FlushSelector<>(1);
TestTrailerFactory tFactory = requestRule.newTrailerFactory();
TestTrailerMutator<byte[]> tMutator = requestRule.newTrailerMutator();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeBytesContent(content, tFactory,
tMutator, selector);
requestRule.assertContentWrite(content, newReq, tFactory, tMutator, 2/*One for content & one for trailer*/);
}
@Test(timeout = 60000)
public void testAddHeader() throws Exception {
final String headerName = "Foo";
final String headerVal = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq =
requestRule.request.addHeader(headerName, headerVal);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, headerVal);
}
@Test(timeout = 60000)
public void testAddCookie() throws Exception {
DefaultCookie cookie = new DefaultCookie("cookie", "cook");
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addCookie(cookie);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, COOKIE.toString(), ClientCookieEncoder.STRICT.encode(cookie));
}
@Test(timeout = 60000)
public void testAddDateHeader() throws Exception {
String headerName = "date";
Date date = new Date();
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addDateHeader(headerName, date);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, date);
}
@Test(timeout = 60000)
public void testAddDateHeaderMulti() throws Exception {
String headerName = "date";
Date date1 = new Date();
Date date2 = new Date();
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addDateHeader(headerName,
Arrays.asList(date1, date2));
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, date1, date2);
}
@Test(timeout = 60000)
public void testAddDateHeaderIncrementally() throws Exception {
String headerName = "foo";
Date date1 = new Date();
Date date2 = new Date();
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, date1);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, date1);
HttpClientRequestImpl<Object, ByteBuf> newReq2 = newReq.addHeader(headerName, date2);
requestRule.assertCopy(newReq, newReq2);
requestRule.assertHeaderAdded(newReq2, headerName, date1, date2);
}
@Test(timeout = 60000)
public void testAddHeaderMulti() throws Exception {
String headerName = "foo";
String val1 = "val1";
String val2 = "val2";
HttpClientRequestImpl<Object, ByteBuf> newReq =
requestRule.request.addHeaderValues(headerName, Arrays.<Object>asList(val1, val2));
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, val1, val2);
}
@Test(timeout = 60000)
public void testAddHeaderIncrementally() throws Exception {
String headerName = "foo";
String val1 = "val1";
String val2 = "val2";
HttpClientRequestImpl<Object, ByteBuf> newReq =
requestRule.request.addHeader(headerName, val1);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, val1);
HttpClientRequestImpl<Object, ByteBuf> newReq2 = newReq.addHeader(headerName, val2);
requestRule.assertCopy(newReq, newReq2);
requestRule.assertHeaderAdded(newReq2, headerName, val1, val2);
}
@Test(timeout = 60000)
public void testSetDateHeader() throws Exception {
String headerName = "date";
Date date1 = new Date();
HttpClientRequestImpl<Object, ByteBuf> addReq = requestRule.request.addDateHeader(headerName, date1);
requestRule.assertCopy(addReq);
requestRule.assertHeaderAdded(addReq, headerName, date1);
Date date2 = new Date(100);
HttpClientRequestImpl<Object, ByteBuf> setReq = requestRule.request.setDateHeader(headerName, date2);
requestRule.assertCopy(setReq);
requestRule.assertHeaderAdded(setReq, headerName, date2);
}
@Test(timeout = 60000)
public void testSetHeader() throws Exception {
String headerName = "foo";
String val1 = "bar";
HttpClientRequestImpl<Object, ByteBuf> addReq = requestRule.request.addHeader(headerName, val1);
requestRule.assertCopy(addReq);
requestRule.assertHeaderAdded(addReq, headerName, val1);
String val2 = "bar2";
HttpClientRequestImpl<Object, ByteBuf> setReq = requestRule.request.setHeader(headerName, val2);
requestRule.assertCopy(setReq);
requestRule.assertHeaderAdded(setReq, headerName, val2);
}
@Test(timeout = 60000)
public void testSetDateHeaderMulti() throws Exception {
String headerName = "date";
Date date1 = new Date();
HttpClientRequestImpl<Object, ByteBuf> addReq = requestRule.request.addDateHeader(headerName, date1);
requestRule.assertCopy(addReq);
requestRule.assertHeaderAdded(addReq, headerName, date1);
Date date2 = new Date(100);
Date date3 = new Date(500);
HttpClientRequestImpl<Object, ByteBuf> setReq = requestRule.request.setDateHeader(headerName,
Arrays.asList(date2, date3));
requestRule.assertCopy(setReq);
requestRule.assertHeaderAdded(setReq, headerName, date2, date3);
}
@Test(timeout = 60000)
public void testSetHeaderMulti() throws Exception {
String headerName = "date";
Date date1 = new Date();
HttpClientRequestImpl<Object, ByteBuf> addReq = requestRule.request.addDateHeader(headerName, date1);
requestRule.assertCopy(addReq);
requestRule.assertHeaderAdded(addReq, headerName, date1);
String val2 = "bar2";
String val3 = "bar3";
HttpClientRequestImpl<Object, ByteBuf> setReq = requestRule.request.setHeaderValues(headerName,
Arrays.<Object>asList(val2, val3));
requestRule.assertCopy(setReq);
requestRule.assertHeaderAdded(setReq, headerName, val2, val3);
}
@Test(timeout = 60000)
public void testRemoveHeader() throws Exception {
final String headerName = "Foo";
final String headerVal = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, headerVal);
requestRule.assertCopy(newReq);
requestRule.assertHeaderAdded(newReq, headerName, headerVal);
HttpClientRequestImpl<Object, ByteBuf> newReq2 = newReq.removeHeader(headerName);
requestRule.assertCopy(newReq2, newReq);
HttpRequest newReqHeaders = newReq2.unsafeRawRequest().getHeaders();
HttpRequest origReqHeaders = newReq.unsafeRawRequest().getHeaders();
assertThat("Header not removed.", newReqHeaders.headers().contains(headerName), is(false));
assertThat("Header removed from original request.", origReqHeaders.headers().contains(headerName),
is(true));
}
@Test(timeout = 60000)
public void testSetKeepAlive() throws Exception {
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.setKeepAlive(false);
requestRule.assertHeaderAdded(newReq, CONNECTION.toString(), CLOSE.toString());
}
@Test(timeout = 60000)
public void testSetTransferEncodingChunked() throws Exception {
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.setTransferEncodingChunked();
requestRule.assertHeaderAdded(newReq, TRANSFER_ENCODING.toString(), CHUNKED.toString());
}
@Test(timeout = 60000)
public void testContainsHeader() throws Exception {
final String headerName = "Foo";
final String headerVal = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, headerVal);
requestRule.assertHeaderAdded(newReq, headerName, headerVal);
assertThat("Added header not retrievable.", newReq.containsHeader(headerName), is(true));
}
@Test(timeout = 60000)
public void testContainsHeaderWithValue() throws Exception {
final String headerName = "Foo";
final String headerVal1 = "bar";
final String headerVal2 = "bar2";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request
.addHeaderValues(headerName, Arrays.<Object>asList(headerVal1, headerVal2));
requestRule.assertHeaderAdded(newReq, headerName, headerVal1, headerVal2);
assertThat("Added header not retrievable.", newReq.containsHeaderWithValue(headerName, headerVal1, false),
is(true));
}
@Test(timeout = 60000)
public void testContainsHeaderWithValueCaseInsensitive() throws Exception {
final String headerName = "Foo";
final String headerVal = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, headerVal);
requestRule.assertHeaderAdded(newReq, headerName, headerVal);
assertThat("Added header not retrievable.", newReq.containsHeaderWithValue(headerName, "BaR", true),
is(true));
}
@Test(timeout = 60000)
public void testGetHeader() throws Exception {
final String headerName = "Foo";
final String headerVal = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, headerVal);
requestRule.assertHeaderAdded(newReq, headerName, headerVal);
assertThat("Added header not retrievable.", newReq.getHeader(headerName), is(headerVal));
}
@Test(timeout = 60000)
public void testGetAllHeaders() throws Exception {
final String headerName = "Foo";
final String headerVal1 = "bar";
final String headerVal2 = "bar2";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request
.addHeaderValues(headerName, Arrays.<Object>asList(headerVal1, headerVal2));
requestRule.assertHeaderAdded(newReq, headerName, headerVal1, headerVal2);
assertThat("Added header not retrievable.", newReq.getAllHeaders(headerName),
hasSize(2));
assertThat("Added header not retrievable.", newReq.getAllHeaders(headerName),
contains(headerVal1, headerVal2));
}
@Test(timeout = 60000)
public void testGetHttpVersion() throws Exception {
assertThat("Unexpected http version", requestRule.request.getHttpVersion(), is(HttpVersion.HTTP_1_1));
}
@Test(timeout = 60000)
public void testGetMethod() throws Exception {
assertThat("Unexpected http version", requestRule.request.getMethod(), is(HttpMethod.GET));
}
@Test(timeout = 60000)
public void testGetUri() throws Exception {
assertThat("Unexpected http version", requestRule.request.getUri(), is("/"));
}
@Test(timeout = 60000)
public void testHeaderIterator() throws Exception {
final String headerName = "Foo";
final String headerVal1 = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq =
requestRule.request.addHeader(headerName, headerVal1);
requestRule.assertHeaderAdded(newReq, headerName, headerVal1);
Iterator<Entry<CharSequence, CharSequence>> headerIter = newReq.headerIterator();
List<Entry<CharSequence, CharSequence>> allHeaders = new ArrayList<>();
while (headerIter.hasNext()) {
Entry<CharSequence, CharSequence> next = headerIter.next();
allHeaders.add(next);
}
assertThat("Added header not retrievable.", allHeaders, hasSize(1));
assertThat("Unexpected header name.", allHeaders.get(0).getKey(), equalTo((CharSequence)headerName));
assertThat("Unexpected header value.", allHeaders.get(0).getValue(), equalTo((CharSequence)headerVal1));
}
@Test(timeout = 60000)
public void testGetHeaderNames() throws Exception {
final String headerName = "Foo";
final String headerVal1 = "bar";
HttpClientRequestImpl<Object, ByteBuf> newReq = requestRule.request.addHeader(headerName, headerVal1);
requestRule.assertHeaderAdded(newReq, headerName, headerVal1);
assertThat("Added header not retrievable.", newReq.getHeaderNames(), hasSize(1));
assertThat("Unexpected header name.", newReq.getHeaderNames(), contains(headerName));
}
@Test(timeout = 60000)
public void testSubscribe() throws Exception {
TestSubscriber<Object> subscriber = new TestSubscriber<>();
Observable<HttpClientResponse<ByteBuf>> newReq = requestRule.request.writeStringContent(Observable.just("Hello"));
RawRequest<Object, ByteBuf> rawReq = RequestRule.getRawRequest(newReq);
newReq.subscribe(subscriber);
subscriber.assertNoErrors();
requestRule.channel.flush(); /*Since nobody subscribes to the observable.*/
assertThat("Unexpected number of items written on the channel.", requestRule.channel.outboundMessages(),
hasSize(1));
Object outboundMsg = requestRule.channel.readOutbound();
assertThat("Unexpected item written on the channel.", outboundMsg, instanceOf(Observable.class));
@SuppressWarnings("unchecked")
Observable<Object> writtenO = (Observable<Object>) outboundMsg;
TestSubscriber<Object> writtenOSub = new TestSubscriber<>();
writtenO.subscribe(writtenOSub);
writtenOSub.assertTerminalEvent();
writtenOSub.assertNoErrors();
@SuppressWarnings("unchecked")
Observable<Object> rawReqO = (Observable<Object>) rawReq.asObservable(requestRule.connMock);
TestSubscriber<Object> rawReqOSub = new TestSubscriber<>();
rawReqO.subscribe(rawReqOSub);
rawReqOSub.assertTerminalEvent();
rawReqOSub.assertNoErrors();
assertThat("Unexpected items count in Observable written on channel.", writtenOSub.getOnNextEvents(),
hasSize(rawReqOSub.getOnNextEvents().size()));
assertThat("Unexpected items in Observable written on channel.", writtenOSub.getOnNextEvents(),
contains(rawReqOSub.getOnNextEvents().toArray()));
DefaultFullHttpResponse nettyResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.ACCEPTED);
HttpClientResponse<Object> response = HttpClientResponseImpl.newInstance(nettyResponse, requestRule.connMock);
requestRule.addToConnectionInput(response);
subscriber.assertTerminalEvent();
subscriber.assertNoErrors();
assertThat("Unexpected response count received.", subscriber.getOnNextEvents(), hasSize(1));
assertThat("Unexpected response received.", subscriber.getOnNextEvents().get(0),
instanceOf(HttpClientResponse.class));
@SuppressWarnings("unchecked")
HttpClientResponse<Object> actual = (HttpClientResponse<Object>) subscriber.getOnNextEvents().get(0);
assertThat("Unexpected response received.", actual.getStatus(), is(HttpResponseStatus.ACCEPTED));
assertThat("Unexpected response received.", actual.getHttpVersion(), is(HttpVersion.HTTP_1_1));
}
public static class RequestRule extends ExternalResource {
private HttpClientRequestImpl<Object, ByteBuf> request;
private TcpClient<ByteBuf, HttpClientResponse<ByteBuf>> clientMock;
private Connection<ByteBuf, HttpClientResponse<ByteBuf>> connMock;
private EmbeddedChannel channel;
@SuppressWarnings("rawtypes")
private Subscriber cis;
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
@SuppressWarnings("unchecked")
TcpClient<ByteBuf, HttpClientResponse<ByteBuf>> clientMock =
(TcpClient<ByteBuf, HttpClientResponse<ByteBuf>>) Mockito.mock(TcpClient.class);
channel = new EmbeddedChannel(new ChannelDuplexHandler() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof ConnectionInputSubscriberEvent) {
@SuppressWarnings({"rawtypes", "unchecked"})
ConnectionInputSubscriberEvent cise = (ConnectionInputSubscriberEvent) evt;
cis = cise.getSubscriber();
}
super.userEventTriggered(ctx, evt);
}
});
TcpClientEventPublisher eventPublisher = new TcpClientEventPublisher();
channel.attr(EventAttributeKeys.EVENT_PUBLISHER).set(eventPublisher);
channel.attr(EventAttributeKeys.CLIENT_EVENT_LISTENER).set(eventPublisher);
channel.attr(EventAttributeKeys.CONNECTION_EVENT_LISTENER).set(eventPublisher);
connMock = ConnectionImpl.fromChannel(channel);
@SuppressWarnings("unchecked")
final
TcpConnectionRequestMock<ByteBuf, HttpClientResponse<ByteBuf>> connReqMock =
new TcpConnectionRequestMock(Observable.just(connMock));
Mockito.when(clientMock.createConnectionRequest())
.thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return connReqMock;
}
});
Answer<Object> returnThisMock = new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return invocation.getMock();
}
};
Mockito.when(clientMock.addChannelHandlerFirst(anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerFirst(Matchers.<EventExecutorGroup>anyObject(),
anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerLast(anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerLast(Matchers.<EventExecutorGroup>anyObject(),
anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerBefore(anyString(), anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerBefore(Matchers.<EventExecutorGroup>anyObject(),
anyString(), anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerAfter(anyString(), anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.addChannelHandlerAfter(Matchers.<EventExecutorGroup>anyObject(),
anyString(), anyString(),
Matchers.<Func0<ChannelHandler>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.pipelineConfigurator(Matchers.<Action1<ChannelPipeline>>anyObject()))
.thenAnswer(returnThisMock);
Mockito.when(clientMock.enableWireLogging(anyString(), Matchers.<LogLevel>anyObject()))
.thenAnswer(returnThisMock);
RequestRule.this.clientMock = clientMock;
request = HttpClientRequestImpl.create(HttpVersion.HTTP_1_1,
HttpMethod.GET, "/",
RequestRule.this.clientMock
);
base.evaluate();
}
};
}
public void assertCopy(HttpClientRequestImpl<Object, ByteBuf> newReq) {
assertCopy(request, newReq);
}
public void assertCopy(HttpClientRequestImpl<Object, ByteBuf> oldReq,
HttpClientRequestImpl<Object, ByteBuf> newReq) {
assertThat("Request not copied.", newReq, not(equalTo(oldReq)));
assertThat("Underlying raw request not copied.", newReq.unsafeRawRequest(),
not(equalTo(oldReq.unsafeRawRequest())));
assertThat("Underlying raw request headers not copied.", newReq.unsafeRawRequest().getHeaders(),
not(equalTo(oldReq.unsafeRawRequest().getHeaders())));
}
public void assertHeaderAdded(HttpClientRequestImpl<Object, ByteBuf> newReq, String headerName,
String... headerVals) {
assertHeaderAdded(request, newReq, headerName, headerVals);
}
public void assertHeaderAdded(HttpClientRequestImpl<Object, ByteBuf> oldReq,
HttpClientRequestImpl<Object, ByteBuf> newReq, String headerName,
String... headerVals) {
HttpRequest newReqHeaders = newReq.unsafeRawRequest().getHeaders();
HttpRequest origReqHeaders = oldReq.unsafeRawRequest().getHeaders();
assertThat("New header not added.", newReqHeaders.headers().contains(headerName), is(true));
assertThat("Unexpected header value.", newReqHeaders.headers().getAll(headerName), contains(headerVals));
assertThat("More than one header added.", newReqHeaders.headers().names(), hasSize(1));
assertThat("New header added to original request.", origReqHeaders.headers().names(), is(empty()));
}
public void assertHeaderAdded(HttpClientRequestImpl<Object, ByteBuf> newReq, String headerName,
Date... dates) {
SimpleDateFormat sdf = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String[] expectedValues = new String[dates.length];
for (int i = 0; i < dates.length; i++) {
Date date = dates[i];
expectedValues[i] = sdf.format(date);
}
assertHeaderAdded(newReq, headerName, expectedValues);
}
RawRequest<Object, ByteBuf> assertContentWrite(@SuppressWarnings("rawtypes") Observable contentWritten,
Observable<HttpClientResponse<ByteBuf>> newReq) {
RawRequest<Object, ByteBuf> rawRequest = _assertContentWriteContentOnly(contentWritten, newReq);
assertThat("Unexpected flush selector in the created raw request.", rawRequest.getFlushSelector(),
is(nullValue()));
assertThat("Unexpected trailers flag in the created raw request.", rawRequest.hasTrailers(),
is(false));
return rawRequest;
}
RawRequest<Object, ByteBuf> assertContentWriteAndFlushOnEach(@SuppressWarnings("rawtypes") Observable contentWritten,
Observable<HttpClientResponse<ByteBuf>> newReq) {
RawRequest<Object, ByteBuf> rawRequest = _assertContentWriteContentOnly(contentWritten, newReq);
assertThat("Unexpected flush selector in the created raw request.", rawRequest.getFlushSelector(),
is(notNullValue()));
/*Just a way to assert that it is an unconditional flush on each*/
assertThat("Unexpected flush selector implementation in the created raw request.",
rawRequest.getFlushSelector().call(null), is(true));
assertThat("Unexpected trailers flag in the created raw request.", rawRequest.hasTrailers(),
is(false));
return rawRequest;
}
RawRequest<Object, ByteBuf> assertContentWrite(@SuppressWarnings("rawtypes") Observable contentWritten,
Observable<HttpClientResponse<ByteBuf>> newReq,
@SuppressWarnings("rawtypes") Func1 selector) {
RawRequest<Object, ByteBuf> rawRequest = _assertContentWriteContentOnly(contentWritten, newReq);
@SuppressWarnings({"unchecked", "rawtypes"})
Func1 selectorFound = rawRequest.getFlushSelector();
assertThat("Unexpected flush selector in the created raw request.", selectorFound,
is(notNullValue()));
assertThat("Unexpected flush selector implementation in the created raw request.",
selectorFound, equalTo(selector));
assertThat("Unexpected trailers flag in the created raw request.", rawRequest.hasTrailers(),
is(false));
return rawRequest;
}
public <T> int assertContentWrite(Observable<T> content, Observable<HttpClientResponse<ByteBuf>> newReq,
TestTrailerFactory tFactory, TestTrailerMutator<T> tMutator) {
RawRequest<Object, ByteBuf> rawReq = getRawRequest(newReq);
final AtomicInteger flushCount = new AtomicInteger();
EmbeddedChannel channel = new EmbeddedChannel(new LoggingHandler()) {
@Override
public Channel flush() {
flushCount.incrementAndGet();
return super.flush();
}
};
channel.attr(EventAttributeKeys.EVENT_PUBLISHER).set(MockEventPublisher.disabled());
ConnectionImpl<Object, Object> conn = ConnectionImpl.fromChannel(channel);
Observable<?> reqAsO = rawReq.asObservable(conn);
TestSubscriber<T> writtenContentSub = new TestSubscriber<>();
content.subscribe(writtenContentSub);
writtenContentSub.assertTerminalEvent();
writtenContentSub.assertNoErrors();
TestSubscriber<Object> reqSubscriber = new TestSubscriber<>();
reqAsO.subscribe((Observer<Object>)reqSubscriber);
reqSubscriber.awaitTerminalEvent();
reqSubscriber.assertNoErrors();
@SuppressWarnings("unchecked")
List<Object> writtenOnNextEvents = (List<Object>) writtenContentSub.getOnNextEvents();
List<Object> reqOnNextEvents = reqSubscriber.getOnNextEvents();
assertThat("Unexpected items in raw request as Observable.", reqOnNextEvents,
hasSize(writtenOnNextEvents.size() + 2));
assertThat("Unexpected type of first item in raw request Observable.", reqOnNextEvents.get(0),
instanceOf(HttpRequest.class));
HttpRequest headers = (HttpRequest) reqOnNextEvents.get(0);
assertThat("Unexpected headers in the created raw request.", headers,
is(request.unsafeRawRequest().getHeaders()));
assertThat("Unexpected type of last item in raw request Observable.",
reqOnNextEvents.get(reqOnNextEvents.size() - 1),
instanceOf(TrailingHeaders.class));
TrailingHeaders trailers = (TrailingHeaders) reqOnNextEvents.get(reqOnNextEvents.size() - 1);
assertThat("Unexpected trailing headers in the created raw request.", trailers,
is(tFactory.lastReturned));
assertThat("Unexpected trailer mutator invocation count.", tMutator.callCount,
is(writtenOnNextEvents.size()));
List<Object> contentItems = reqOnNextEvents.subList(1, reqOnNextEvents.size() - 1);
assertThat("Unexpected content items count in raw request as Observable.", contentItems,
hasSize(writtenOnNextEvents.size()));
assertThat("Unexpected content items in raw request as Observable.", contentItems,
contains(writtenOnNextEvents.toArray()));
return flushCount.get();
}
public <T> void assertContentWrite(Observable<T> content, Observable<HttpClientResponse<ByteBuf>> newReq,
TestTrailerFactory tFactory, TestTrailerMutator<T> tMutator,
int expectedFlushCounts) {
int flushCount = assertContentWrite(content, newReq, tFactory, tMutator);
assertThat("Unexpected flush counts", flushCount, is(expectedFlushCounts));
}
private RawRequest<Object, ByteBuf> _assertContentWriteContentOnly(@SuppressWarnings("rawtypes") Observable contentWritten,
Observable<HttpClientResponse<ByteBuf>> newReq) {
RawRequest<Object, ByteBuf> rawRequest = getRawRequest(newReq);
assertThat("Unexpected headers in the created raw request.", rawRequest.getHeaders(),
is(request.unsafeRawRequest().getHeaders()));
assertThat("Unexpected content in the created raw request.", rawRequest.getContent(), is(contentWritten));
return rawRequest;
}
static RawRequest<Object, ByteBuf> getRawRequest(Observable<HttpClientResponse<ByteBuf>> newReq) {
assertThat("Unexpected request.", newReq, instanceOf(HttpClientRequestImpl.class));
HttpClientRequestImpl<Object, ByteBuf> asClientReq = (HttpClientRequestImpl<Object, ByteBuf>) newReq;
return asClientReq.unsafeRawRequest();
}
public TestTrailerFactory newTrailerFactory() {
return new TestTrailerFactory();
}
public <T> TestTrailerMutator<T> newTrailerMutator() {
return new TestTrailerMutator<>();
}
@SuppressWarnings("unchecked")
public void addToConnectionInput(Object msg) {
if (null != cis) {
cis.onNext(msg);
} else {
throw new AssertionError("Connection input subscriber not found");
}
}
}
public static class TestTrailerFactory implements Func0<TrailingHeaders> {
private volatile TrailingHeaders lastReturned;
@Override
public TrailingHeaders call() {
lastReturned = new TrailingHeaders();
return lastReturned;
}
}
public static class TestTrailerMutator<T> implements Func2<TrailingHeaders, T, TrailingHeaders> {
private volatile int callCount;
@Override
public TrailingHeaders call(TrailingHeaders trailingHeaders,T content) {
callCount++;
return trailingHeaders;
}
}
}