package com.netflix.hystrix.contrib.javanica.test.common.fallback; import com.netflix.hystrix.HystrixEventType; import com.netflix.hystrix.HystrixInvokableInfo; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException; import com.netflix.hystrix.contrib.javanica.test.common.BasicHystrixTest; import junitparams.JUnitParamsRunner; import junitparams.Parameters; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.helpers.MessageFormatter; import org.springframework.test.context.junit4.rules.SpringClassRule; import org.springframework.test.context.junit4.rules.SpringMethodRule; import rx.Completable; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Set; import static com.netflix.hystrix.contrib.javanica.test.common.CommonUtils.getHystrixCommandByKey; import static org.junit.Assert.assertTrue; /** * Created by dmgcodevil. */ @RunWith(JUnitParamsRunner.class) public abstract class BasicGenericFallbackTest extends BasicHystrixTest { @ClassRule public static final SpringClassRule SCR = new SpringClassRule(); @Rule public final SpringMethodRule springMethodRule = new SpringMethodRule(); protected abstract <T> T createProxy(Class<T> t); public Object[] methodGenericDefinitionSuccess() { return new Object[]{ new Object[]{MethodGenericDefinitionSuccessCase0.class}, new Object[]{MethodGenericDefinitionSuccessCase1.class}, new Object[]{MethodGenericDefinitionSuccessCase2.class}, new Object[]{MethodGenericDefinitionSuccessCase3.class}, new Object[]{MethodGenericDefinitionSuccessCase4.class}, new Object[]{MethodGenericDefinitionSuccessCase5.class}, new Object[]{MethodGenericDefinitionSuccessCase6.class}, new Object[]{MethodGenericDefinitionSuccessCase7.class}, }; } public Object[] methodGenericDefinitionFailure() { return new Object[]{ new Object[]{MethodGenericDefinitionFailureCase0.class}, new Object[]{MethodGenericDefinitionFailureCase1.class}, new Object[]{MethodGenericDefinitionFailureCase2.class}, new Object[]{MethodGenericDefinitionFailureCase3.class}, new Object[]{MethodGenericDefinitionFailureCase4.class}, new Object[]{MethodGenericDefinitionFailureCase5.class}, new Object[]{MethodGenericDefinitionFailureCase6.class}, new Object[]{MethodGenericDefinitionFailureCase7.class}, new Object[]{MethodGenericDefinitionFailureCase8.class}, new Object[]{MethodGenericDefinitionFailureCase9.class}, new Object[]{MethodGenericDefinitionFailureCase10.class}, new Object[]{MethodGenericDefinitionFailureCase11.class}, }; } public Object[] classGenericDefinitionSuccess() { return new Object[]{ new Object[]{ClassGenericDefinitionSuccessCase0.class}, new Object[]{ClassGenericDefinitionSuccessCase1.class}, }; } public Object[] classGenericDefinitionFailure() { return new Object[]{ new Object[]{ClassGenericDefinitionFailureCase0.class}, new Object[]{ClassGenericDefinitionFailureCase1.class}, }; } @Test @Parameters(method = "methodGenericDefinitionSuccess") public void testMethodGenericDefinitionSuccess(Class<?> type) { testXKindGenericDefinitionSuccess(type); } @Test(expected = FallbackDefinitionException.class) @Parameters(method = "methodGenericDefinitionFailure") public void testMethodGenericDefinitionFailure(Class<?> type) { Object p = createProxy(type); executeCommand(p); } @Test @Parameters(method = "classGenericDefinitionSuccess") public void testClassGenericDefinitionSuccess(Class<?> type) { testXKindGenericDefinitionSuccess(type); } @Test(expected = FallbackDefinitionException.class) @Parameters(method = "classGenericDefinitionFailure") public void testClassGenericDefinitionFailure(Class<?> type) { Object p = createProxy(type); executeCommand(p); } private void testXKindGenericDefinitionSuccess(Class<?> type) { Object p = createProxy(type); try { executeCommand(p); HystrixInvokableInfo<?> command = getHystrixCommandByKey("command"); assertTrue(command.getExecutionEvents().contains(HystrixEventType.FAILURE)); assertTrue(command.getExecutionEvents().contains(HystrixEventType.FALLBACK_SUCCESS)); } catch (FallbackDefinitionException e) { throw new AssertionError(MessageFormatter.format("Case class '{}' has failed. Reason:\n{}", type.getCanonicalName(), e).getMessage()); } } /* ====================================================================== */ /* ===================== GENERIC METHOD DEFINITIONS ===================== */ /* =========================== SUCCESS CASES ============================ */ public static class MethodGenericDefinitionSuccessCase0 { @HystrixCommand(fallbackMethod = "fallback") public <T> T command() { throw new IllegalStateException(); } private <T> T fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase1 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable> T command() { throw new IllegalStateException(); } private <T extends Serializable> T fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase2 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable, T1 extends T> T1 command() { throw new IllegalStateException(); } private <T extends Serializable, T1 extends T> T1 fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase3 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); } private <T extends Serializable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase4 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); } private <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase5 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> command() { throw new IllegalStateException(); } private <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> fallback() { return null; } } public static class MethodGenericDefinitionSuccessCase6 { @HystrixCommand(fallbackMethod = "fallback") public <T> GenericEntity<T> command() { throw new IllegalStateException(); } private <T> GenericEntity<T> fallback() { return new GenericEntity<T>(); } } public static class MethodGenericDefinitionSuccessCase7 { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<? super Serializable> command() { throw new IllegalStateException(); } private GenericEntity<? super Serializable> fallback() { return null; } } /* ====================================================================== */ /* ===================== GENERIC METHOD DEFINITIONS ===================== */ /* =========================== FAILURE CASES ============================ */ public static class MethodGenericDefinitionFailureCase0 { @HystrixCommand(fallbackMethod = "fallback") public <T> T command() { throw new IllegalStateException(); } private String fallback() { return null; } } public static class MethodGenericDefinitionFailureCase1 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable> T command() { throw new IllegalStateException(); } private <T> T fallback() { return null; } } public static class MethodGenericDefinitionFailureCase2 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable> T command() { throw new IllegalStateException(); } private <T extends Comparable> T fallback() { return null; } } public static class MethodGenericDefinitionFailureCase3 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); } private <T extends Serializable, T1 extends T> GenericEntity<T1> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase4 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable & Comparable, T1 extends T> GenericEntity<? extends T1> command() { throw new IllegalStateException(); } private <T extends Serializable, T1 extends T> GenericEntity<? extends T1> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase5 { @HystrixCommand(fallbackMethod = "fallback") public <T extends Serializable & Comparable, T1 extends GenericEntity<T>> GenericEntity<T1> command() { throw new IllegalStateException(); } private <T extends Serializable & Comparable, T1 extends GenericEntity<String>> GenericEntity<T1> fallback() { return null;} } public static class MethodGenericDefinitionFailureCase6 { @HystrixCommand(fallbackMethod = "fallback") public <T> GenericEntity<T> command() { throw new IllegalStateException(); } private GenericEntity<String> fallback() { return new GenericEntity<String>(); } } public static class MethodGenericDefinitionFailureCase7 { @HystrixCommand(fallbackMethod = "fallback") public <T> Set<T> command() { throw new IllegalStateException(); } private <T> List<T> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase8 { @HystrixCommand(fallbackMethod = "fallback") public <T> GenericEntity<Set<T>> command() { throw new IllegalStateException(); } private <T> GenericEntity<List<T>> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase9 { @HystrixCommand(fallbackMethod = "fallback") public <T> GenericEntity<List<Set<T>>> command() { throw new IllegalStateException(); } private <T> GenericEntity<List<List<T>>> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase10 { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<? super Serializable> command() { throw new IllegalStateException(); } private GenericEntity<? super Comparable> fallback() { return null; } } public static class MethodGenericDefinitionFailureCase11 { @HystrixCommand(fallbackMethod = "fallback") public Completable command() { throw new IllegalStateException(); } private void fallback() { return; } } /* ====================================================================== */ /* ===================== GENERIC CLASS DEFINITIONS =====+================ */ /* =========================== SUCCESS CASES ============================ */ public static class ClassGenericDefinitionSuccessCase0<T> { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<T> command() { throw new IllegalStateException(); } private GenericEntity<T> fallback() { return new GenericEntity<T>(); } } public static class ClassGenericDefinitionSuccessCase1<T extends Serializable> { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<T> command() { throw new IllegalStateException(); } private GenericEntity<T> fallback() { return new GenericEntity<T>(); } } /* ====================================================================== */ /* ===================== GENERIC CLASS DEFINITIONS =====+================ */ /* =========================== FAILURE CASES ============================ */ public static class ClassGenericDefinitionFailureCase0<T> { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<T> command() { throw new IllegalStateException(); } private <T> GenericEntity<T> fallback() { return new GenericEntity<T>(); } } public static class ClassGenericDefinitionFailureCase1<T extends Serializable> { @HystrixCommand(fallbackMethod = "fallback") public GenericEntity<T> command() { throw new IllegalStateException(); } private <T extends Serializable> GenericEntity<T> fallback() { return new GenericEntity<T>(); } } public static class GenericEntity<T> { } private static Object executeCommand(Object proxy) { try { Method method = proxy.getClass().getDeclaredMethod("command"); return method.invoke(proxy); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof FallbackDefinitionException) { throw (FallbackDefinitionException) t; } else throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } } }