/*
* Copyright (c) 2010 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package org.asynchttpclient.handler.resumable;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static org.asynchttpclient.Dsl.get;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.testng.Assert.*;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.asynchttpclient.AsyncHandler;
import org.asynchttpclient.AsyncHandler.State;
import org.asynchttpclient.HttpResponseBodyPart;
import org.asynchttpclient.HttpResponseStatus;
import org.asynchttpclient.Request;
import org.asynchttpclient.Response;
import org.asynchttpclient.uri.Uri;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.annotations.Test;
/**
* @author Benjamin Hanzelmann
*/
@PrepareForTest({ HttpResponseStatus.class, State.class })
public class ResumableAsyncHandlerTest extends PowerMockTestCase {
@Test
public void testAdjustRange() {
MapResumableProcessor proc = new MapResumableProcessor();
ResumableAsyncHandler handler = new ResumableAsyncHandler(proc);
Request request = get("http://test/url").build();
Request newRequest = handler.adjustRequestRange(request);
assertEquals(newRequest.getUri(), request.getUri());
String rangeHeader = newRequest.getHeaders().get(RANGE);
assertNull(rangeHeader);
proc.put("http://test/url", 5000);
newRequest = handler.adjustRequestRange(request);
assertEquals(newRequest.getUri(), request.getUri());
rangeHeader = newRequest.getHeaders().get(RANGE);
assertEquals(rangeHeader, "bytes=5000-");
}
@Test
public void testOnStatusReceivedOkStatus() throws Exception {
MapResumableProcessor processor = new MapResumableProcessor();
ResumableAsyncHandler handler = new ResumableAsyncHandler(processor);
HttpResponseStatus responseStatus200 = mock(HttpResponseStatus.class);
when(responseStatus200.getStatusCode()).thenReturn(200);
when(responseStatus200.getUri()).thenReturn(mock(Uri.class));
State state = handler.onStatusReceived(responseStatus200);
assertEquals(state, AsyncHandler.State.CONTINUE, "Status should be CONTINUE for a OK response");
}
@Test
public void testOnStatusReceived206Status() throws Exception {
MapResumableProcessor processor = new MapResumableProcessor();
ResumableAsyncHandler handler = new ResumableAsyncHandler(processor);
HttpResponseStatus responseStatus206 = mock(HttpResponseStatus.class);
when(responseStatus206.getStatusCode()).thenReturn(206);
when(responseStatus206.getUri()).thenReturn(mock(Uri.class));
State state = handler.onStatusReceived(responseStatus206);
assertEquals(state, AsyncHandler.State.CONTINUE, "Status should be CONTINUE for a 'Partial Content' response");
}
@Test
public void testOnStatusReceivedOkStatusWithDecoratedAsyncHandler() throws Exception {
HttpResponseStatus mockResponseStatus = mock(HttpResponseStatus.class);
when(mockResponseStatus.getStatusCode()).thenReturn(200);
when(mockResponseStatus.getUri()).thenReturn(mock(Uri.class));
@SuppressWarnings("unchecked")
AsyncHandler<Response> decoratedAsyncHandler = mock(AsyncHandler.class);
State mockState = mock(State.class);
when(decoratedAsyncHandler.onStatusReceived(mockResponseStatus)).thenReturn(mockState);
ResumableAsyncHandler handler = new ResumableAsyncHandler(decoratedAsyncHandler);
State state = handler.onStatusReceived(mockResponseStatus);
verify(decoratedAsyncHandler).onStatusReceived(mockResponseStatus);
assertEquals(state, mockState, "State returned should be equal to the one returned from decoratedAsyncHandler");
}
@Test
public void testOnStatusReceived500Status() throws Exception{
MapResumableProcessor processor = new MapResumableProcessor();
ResumableAsyncHandler handler = new ResumableAsyncHandler(processor);
HttpResponseStatus mockResponseStatus = mock(HttpResponseStatus.class);
when(mockResponseStatus.getStatusCode()).thenReturn(500);
when(mockResponseStatus.getUri()).thenReturn(mock(Uri.class));
State state = handler.onStatusReceived(mockResponseStatus);
assertEquals(state, AsyncHandler.State.ABORT, "State should be ABORT for Internal Server Error status");
}
@Test
public void testOnBodyPartReceived() throws Exception {
ResumableAsyncHandler handler = new ResumableAsyncHandler();
HttpResponseBodyPart bodyPart = PowerMockito.mock(HttpResponseBodyPart.class);
when(bodyPart.getBodyPartBytes()).thenReturn(new byte[0]);
ByteBuffer buffer = ByteBuffer.allocate(0);
when(bodyPart.getBodyByteBuffer()).thenReturn(buffer);
State state = handler.onBodyPartReceived(bodyPart);
assertEquals(state, AsyncHandler.State.CONTINUE, "State should be CONTINUE for a successful onBodyPartReceived");
}
@Test
public void testOnBodyPartReceivedWithResumableListenerThrowsException() throws Exception {
ResumableAsyncHandler handler = new ResumableAsyncHandler();
ResumableListener resumableListener = PowerMockito.mock(ResumableListener.class);
doThrow(new IOException()).when(resumableListener).onBytesReceived(anyObject());
handler.setResumableListener(resumableListener);
HttpResponseBodyPart bodyPart = PowerMockito.mock(HttpResponseBodyPart.class);
State state = handler.onBodyPartReceived(bodyPart);
assertEquals(state, AsyncHandler.State.ABORT,
"State should be ABORT if the resumableListener threw an exception in onBodyPartReceived");
}
@Test
public void testOnBodyPartReceivedWithDecoratedAsyncHandler() throws Exception {
HttpResponseBodyPart bodyPart = PowerMockito.mock(HttpResponseBodyPart.class);
when(bodyPart.getBodyPartBytes()).thenReturn(new byte[0]);
ByteBuffer buffer = ByteBuffer.allocate(0);
when(bodyPart.getBodyByteBuffer()).thenReturn(buffer);
@SuppressWarnings("unchecked")
AsyncHandler<Response> decoratedAsyncHandler = mock(AsyncHandler.class);
State mockState = mock(State.class);
when(decoratedAsyncHandler.onBodyPartReceived(bodyPart)).thenReturn(mockState);
// following is needed to set the url variable
HttpResponseStatus mockResponseStatus = mock(HttpResponseStatus.class);
when(mockResponseStatus.getStatusCode()).thenReturn(200);
Uri mockUri = mock(Uri.class);
when(mockUri.toUrl()).thenReturn("http://non.null");
when(mockResponseStatus.getUri()).thenReturn(mockUri);
ResumableAsyncHandler handler = new ResumableAsyncHandler(decoratedAsyncHandler);
handler.onStatusReceived(mockResponseStatus);
State state = handler.onBodyPartReceived(bodyPart);
assertEquals(state, mockState, "State should be equal to the state returned from decoratedAsyncHandler");
}
@Test
public void testOnHeadersReceived() throws Exception {
ResumableAsyncHandler handler = new ResumableAsyncHandler();
HttpHeaders responseHeaders = new DefaultHttpHeaders();
State status = handler.onHeadersReceived(responseHeaders);
assertEquals(status, AsyncHandler.State.CONTINUE, "State should be CONTINUE for a successful onHeadersReceived");
}
@Test
public void testOnHeadersReceivedWithDecoratedAsyncHandler() throws Exception {
HttpHeaders responseHeaders = new DefaultHttpHeaders();
@SuppressWarnings("unchecked")
AsyncHandler<Response> decoratedAsyncHandler = mock(AsyncHandler.class);
State mockState = mock(State.class);
when(decoratedAsyncHandler.onHeadersReceived(responseHeaders)).thenReturn(mockState);
ResumableAsyncHandler handler = new ResumableAsyncHandler(decoratedAsyncHandler);
State status = handler.onHeadersReceived(responseHeaders);
assertEquals(status, mockState, "State should be equal to the state returned from decoratedAsyncHandler");
}
@Test
public void testOnHeadersReceivedContentLengthMinus() throws Exception {
ResumableAsyncHandler handler = new ResumableAsyncHandler();
HttpHeaders responseHeaders = new DefaultHttpHeaders();
responseHeaders.add(CONTENT_LENGTH, -1);
State status = handler.onHeadersReceived(responseHeaders);
assertEquals(status, AsyncHandler.State.ABORT, "State should be ABORT for content length -1");
}
}