/*
* Copyright 2014 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 com.netflix.ribbon.proxy;
import com.netflix.ribbon.CacheProvider;
import com.netflix.ribbon.RibbonRequest;
import com.netflix.ribbon.http.HttpRequestBuilder;
import com.netflix.ribbon.http.HttpRequestTemplate;
import com.netflix.ribbon.http.HttpRequestTemplate.Builder;
import com.netflix.ribbon.http.HttpResourceGroup;
import com.netflix.ribbon.proxy.processor.AnnotationProcessorsProvider;
import com.netflix.ribbon.proxy.sample.HystrixHandlers.MovieFallbackHandler;
import com.netflix.ribbon.proxy.sample.HystrixHandlers.SampleHttpResponseValidator;
import com.netflix.ribbon.proxy.sample.Movie;
import com.netflix.ribbon.proxy.sample.MovieServiceInterfaces.SampleMovieService;
import com.netflix.ribbon.proxy.sample.MovieServiceInterfaces.ShortMovieService;
import io.netty.buffer.ByteBuf;
import io.reactivex.netty.channel.ContentTransformer;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.annotation.Mock;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import rx.Observable;
import java.lang.reflect.Method;
import java.util.Map;
import static com.netflix.ribbon.proxy.Utils.methodByName;
import static junit.framework.Assert.assertEquals;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.powermock.api.easymock.PowerMock.*;
/**
* @author Tomasz Bak
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({MethodTemplateExecutor.class})
@PowerMockIgnore("javax.management.*")
public class MethodTemplateExecutorTest {
@Mock
private RibbonRequest ribbonRequestMock = createMock(RibbonRequest.class);
@Mock
private HttpRequestBuilder requestBuilderMock = createMock(HttpRequestBuilder.class);
@Mock
private Builder httpRequestTemplateBuilderMock = createMock(Builder.class);
@Mock
private HttpRequestTemplate httpRequestTemplateMock = createMock(HttpRequestTemplate.class);
@Mock
private HttpResourceGroup httpResourceGroupMock = createMock(HttpResourceGroup.class);
@BeforeClass
public static void setup() {
RibbonDynamicProxy.registerAnnotationProcessors(AnnotationProcessorsProvider.DEFAULT);
}
@Before
public void setUp() throws Exception {
expect(requestBuilderMock.build()).andReturn(ribbonRequestMock);
expect(httpRequestTemplateBuilderMock.build()).andReturn(httpRequestTemplateMock);
expect(httpRequestTemplateMock.requestBuilder()).andReturn(requestBuilderMock);
}
@Test
public void testGetQueryWithDomainObjectResult() throws Exception {
expectUrlBase("GET", "/movies/{id}");
expect(requestBuilderMock.withRequestProperty("id", "id123")).andReturn(requestBuilderMock);
expect(httpResourceGroupMock.newTemplateBuilder("findMovieById")).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withHeader("X-MyHeader1", "value1.1")).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withHeader("X-MyHeader1", "value1.2")).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withHeader("X-MyHeader2", "value2")).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withRequestCacheKey("findMovieById/{id}")).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withFallbackProvider(anyObject(MovieFallbackHandler.class))).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withResponseValidator(anyObject(SampleHttpResponseValidator.class))).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withCacheProvider(anyObject(String.class), anyObject(CacheProvider.class))).andReturn(httpRequestTemplateBuilderMock);
replayAll();
MethodTemplateExecutor executor = createExecutor(SampleMovieService.class, "findMovieById");
RibbonRequest ribbonRequest = executor.executeFromTemplate(new Object[]{"id123"});
verifyAll();
assertEquals(ribbonRequestMock, ribbonRequest);
}
@Test
public void testGetQueryWithByteBufResult() throws Exception {
expectUrlBase("GET", "/rawMovies/{id}");
expect(requestBuilderMock.withRequestProperty("id", "id123")).andReturn(requestBuilderMock);
expect(httpResourceGroupMock.newTemplateBuilder("findRawMovieById")).andReturn(httpRequestTemplateBuilderMock);
replayAll();
MethodTemplateExecutor executor = createExecutor(SampleMovieService.class, "findRawMovieById");
RibbonRequest ribbonRequest = executor.executeFromTemplate(new Object[]{"id123"});
verifyAll();
assertEquals(ribbonRequestMock, ribbonRequest);
}
@Test
public void testPostWithDomainObjectAndTransformer() throws Exception {
doTestPostWith("/movies", "registerMovie", new Movie());
}
@Test
public void testPostWithString() throws Exception {
doTestPostWith("/titles", "registerTitle", "some title");
}
@Test
public void testPostWithByteBuf() throws Exception {
doTestPostWith("/binaries/byteBuf", "registerByteBufBinary", createMock(ByteBuf.class));
}
@Test
public void testPostWithByteArray() throws Exception {
doTestPostWith("/binaries/byteArray", "registerByteArrayBinary", new byte[]{1});
}
private void doTestPostWith(String uriTemplate, String methodName, Object contentObject) {
expectUrlBase("POST", uriTemplate);
expect(httpResourceGroupMock.newTemplateBuilder(methodName)).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withRequestCacheKey(methodName)).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withFallbackProvider(anyObject(MovieFallbackHandler.class))).andReturn(httpRequestTemplateBuilderMock);
expect(requestBuilderMock.withRawContentSource(anyObject(Observable.class), anyObject(ContentTransformer.class))).andReturn(requestBuilderMock);
replayAll();
MethodTemplateExecutor executor = createExecutor(SampleMovieService.class, methodName);
RibbonRequest ribbonRequest = executor.executeFromTemplate(new Object[]{contentObject});
verifyAll();
assertEquals(ribbonRequestMock, ribbonRequest);
}
@Test
public void testFromFactory() throws Exception {
expect(httpResourceGroupMock.newTemplateBuilder(anyObject(String.class))).andReturn(httpRequestTemplateBuilderMock).anyTimes();
expect(httpRequestTemplateBuilderMock.withMethod(anyObject(String.class))).andReturn(httpRequestTemplateBuilderMock).anyTimes();
expect(httpRequestTemplateBuilderMock.withUriTemplate(anyObject(String.class))).andReturn(httpRequestTemplateBuilderMock).anyTimes();
replayAll();
Map<Method, MethodTemplateExecutor> executorMap = MethodTemplateExecutor.from(httpResourceGroupMock, ShortMovieService.class, AnnotationProcessorsProvider.DEFAULT);
assertEquals(ShortMovieService.class.getMethods().length, executorMap.size());
}
private void expectUrlBase(String method, String path) {
expect(httpRequestTemplateBuilderMock.withMethod(method)).andReturn(httpRequestTemplateBuilderMock);
expect(httpRequestTemplateBuilderMock.withUriTemplate(path)).andReturn(httpRequestTemplateBuilderMock);
}
private MethodTemplateExecutor createExecutor(Class<?> clientInterface, String methodName) {
MethodTemplate methodTemplate = new MethodTemplate(methodByName(clientInterface, methodName));
return new MethodTemplateExecutor(httpResourceGroupMock, methodTemplate, AnnotationProcessorsProvider.DEFAULT);
}
}