/**
* 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 com.netflix.hystrix.contrib.javanica.util;
import com.google.common.base.Throwables;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException;
import com.netflix.hystrix.contrib.javanica.utils.FallbackMethod;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.Test;
import org.junit.runner.RunWith;
import rx.Observable;
import java.lang.reflect.Method;
import java.util.concurrent.Future;
/**
* Created by dmgcodevil.
*/
@RunWith(DataProviderRunner.class)
public class FallbackMethodValidationTest {
@DataProvider
public static Object[][] fail() {
// @formatter:off
return new Object[][]{
// sync execution
{getMethod("commandReturnPlainTypeLong"), getMethod("fallbackReturnPlainTypeString")},
{getMethod("commandReturnPlainTypeChild"), getMethod("fallbackReturnPlainTypeParent")},
{getMethod("commandReturnGenericTypeParent"), getMethod("fallbackReturnGenericTypeChild")},
{getMethod("commandReturnGenericTypeChild"), getMethod("fallbackReturnGenericTypeParent")},
{getMethod("commandReturnGenericTypeChildParent"), getMethod("fallbackReturnGenericTypeParentChild")},
{getMethod("commandReturnGenericTypeParentChild"), getMethod("fallbackReturnGenericTypeChildParent")},
{getMethod("commandReturnGenericNestedTypeParentChildParent"), getMethod("commandReturnGenericNestedTypeParentParentParent")},
// async execution
{getMethod("commandReturnFutureParent"), getMethod("fallbackCommandReturnFutureChild")},
{getMethod("commandReturnFutureParent"), getMethod("fallbackReturnFutureParent")},
{getMethod("commandReturnFutureParent"), getMethod("fallbackReturnChild")},
{getMethod("commandReturnParent"), getMethod("fallbackReturnFutureParent")},
{getMethod("commandReturnParent"), getMethod("fallbackCommandReturnFutureParent")},
// observable execution
{getMethod("fallbackReturnObservableParent"), getMethod("fallbackReturnObservableChild")},
{getMethod("fallbackReturnObservableParent"), getMethod("fallbackCommandReturnObservableChild")},
{getMethod("fallbackReturnObservableParent"), getMethod("fallbackReturnChild")},
{getMethod("commandReturnParent"), getMethod("fallbackReturnObservableParent")},
{getMethod("commandReturnParent"), getMethod("fallbackCommandReturnObservableParent")},
{getMethod("commandReturnParent"), getMethod("fallbackReturnObservableChild")},
{getMethod("commandReturnParent"), getMethod("fallbackCommandReturnObservableChild")},
};
// @formatter:on
}
@DataProvider
public static Object[][] success() {
// @formatter:off
return new Object[][]{
// sync execution
{getMethod("commandReturnPlainTypeLong"), getMethod("fallbackReturnPlainTypeLong")},
{getMethod("commandReturnPlainTypeParent"), getMethod("fallbackReturnPlainTypeChild")},
{getMethod("commandReturnPlainTypeParent"), getMethod("fallbackReturnPlainTypeParent")},
{getMethod("commandReturnGenericTypeChild"), getMethod("fallbackReturnGenericTypeChild")},
{getMethod("commandReturnGenericNestedTypeParentChildParent"), getMethod("fallbackReturnGenericNestedTypeParentChildParent")},
// async execution
{getMethod("commandReturnFutureParent"), getMethod("fallbackCommandReturnFutureParent")},
{getMethod("commandReturnFutureParent"), getMethod("fallbackCommandReturnParent")},
{getMethod("commandReturnFutureParent"), getMethod("fallbackReturnParent")},
// observable execution
{getMethod("commandReturnObservableParent"), getMethod("fallbackReturnObservableParent")},
{getMethod("commandReturnObservableParent"), getMethod("fallbackCommandReturnObservableParent")},
{getMethod("commandReturnObservableParent"), getMethod("fallbackReturnParent")},
};
// @formatter:on
}
@Test(expected = FallbackDefinitionException.class)
@UseDataProvider("fail")
public void testValidateBadFallbackReturnType(Method commandMethod, Method fallbackMethod) {
new FallbackMethod(fallbackMethod).validateReturnType(commandMethod);
}
@UseDataProvider("success")
public void testValidateCorrectFallbackReturnType(Method commandMethod, Method fallbackMethod) {
new FallbackMethod(fallbackMethod).validateReturnType(commandMethod);
}
private static Method getMethod(String name) {
try {
return Service.class.getDeclaredMethod(name);
} catch (NoSuchMethodException e) {
throw Throwables.propagate(e);
}
}
// @formatter:off
private static class Service {
// Sync execution
public Parent commandReturnPlainTypeParent() {return null;}
public Child commandReturnPlainTypeChild() {return null;}
public Parent fallbackReturnPlainTypeParent() {return null;}
public Child fallbackReturnPlainTypeChild() {return null;}
public Long commandReturnPlainTypeLong() {return null;}
public Long fallbackReturnPlainTypeLong() {return null;}
public String fallbackReturnPlainTypeString() {return null;}
public GType<Parent> commandReturnGenericTypeParent() {return null;}
public GType<Child> commandReturnGenericTypeChild() {return null;}
public GType<Parent> fallbackReturnGenericTypeParent() {return null;}
public GType<Child> fallbackReturnGenericTypeChild() {return null;}
public GDoubleType<Parent, Child> commandReturnGenericTypeParentChild() {return null;}
public GDoubleType<Child, Parent> commandReturnGenericTypeChildParent() {return null;}
public GDoubleType<Parent, Child> fallbackReturnGenericTypeParentChild() {return null;}
public GDoubleType<Child, Parent> fallbackReturnGenericTypeChildParent() {return null;}
public GType<GType<GDoubleType<GType<GDoubleType<Parent, Child>>, Parent>>> commandReturnGenericNestedTypeParentChildParent() {return null;}
public GType<GType<GDoubleType<GType<GDoubleType<Parent, Parent>>, Parent>>> commandReturnGenericNestedTypeParentParentParent() {return null;}
public GType<GType<GDoubleType<GType<GDoubleType<Parent, Child>>, Parent>>> fallbackReturnGenericNestedTypeParentChildParent() {return null;}
// Async execution
Future<Parent> commandReturnFutureParent() {return null;}
Parent commandReturnParent() {return null;}
Parent fallbackReturnParent() {return null;}
Child fallbackReturnChild() {return null;}
Future<Parent> fallbackReturnFutureParent() {return null;}
Future<Child> fallbackReturnFutureChild() {return null;}
@HystrixCommand Parent fallbackCommandReturnParent() {return null;}
@HystrixCommand Child fallbackCommandReturnChild() {return null;}
@HystrixCommand Future<Parent> fallbackCommandReturnFutureParent() {return null;}
@HystrixCommand Future<Child> fallbackCommandReturnFutureChild() {return null;}
// Observable execution
Observable<Parent> commandReturnObservableParent() {return null;}
Observable<Parent> fallbackReturnObservableParent() {return null;}
Observable<Child> fallbackReturnObservableChild() {return null;}
@HystrixCommand Observable<Parent> fallbackCommandReturnObservableParent() {return null;}
@HystrixCommand Observable<Child> fallbackCommandReturnObservableChild() {return null;}
}
// @formatter:on
private interface GType<T> {
}
private interface GDoubleType<T1, T2> {
}
private static class Parent {
}
private static class Child extends Parent {
}
}