package com.yammer.tenacity.testing;

import com.google.common.base.Throwables;
import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.Hystrix;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class TenacityTestRule implements TestRule {
    private void setup() {
        resetHystrixPlugins();
        ConfigurationManager
                .getConfigInstance()
                .setProperty("hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds", "1");
    }

    public void teardown() {
        Hystrix.reset(1, TimeUnit.SECONDS);
        ConfigurationManager.getConfigInstance().clear();
        resetHystrixPlugins();
    }

    private static void resetHystrixPlugins() {
        Hystrix.reset();
        resetCommandExecutionHook();
    }

    /**
     * There is a bug in {@link com.netflix.hystrix.strategy.HystrixPlugins.UnitTest#reset()} whereby the reset method
     * used to reset the test environment fails to reset commandExecutionHook field and thus prevents multiple tests from running.
     * <p/>
     * This class fixes this in a very hacky way and should be abandoned as tenacity is migrated to new hystrix that fixes it.
     * Pull request has been merged, but new version has not been released yet:
     * https://github.com/Netflix/Hystrix/pull/240
     */
    private static void resetCommandExecutionHook() {
        try {
            Field commandExecutionHookField = HystrixPlugins.class.getDeclaredField("commandExecutionHook");
            commandExecutionHookField.setAccessible(true);
            HystrixPlugins jvmInstance = HystrixPlugins.getInstance();
            AtomicReference<HystrixCommandExecutionHook> commandExecutionHookRef =
                    (AtomicReference<HystrixCommandExecutionHook>) commandExecutionHookField.get(jvmInstance);
            commandExecutionHookRef.set(null);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            throw Throwables.propagate(e);
        }
    }

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                try {
                    setup();
                    base.evaluate();
                } finally {
                    teardown();
                }
            }
        };
    }
}
@@ -35,50 +35,8 @@
 g;%0A%0A
-import com.google.common.base.Throwables;%0A
 impo
@@ -119,139 +119,8 @@
 ix;%0A
-import com.netflix.hystrix.strategy.HystrixPlugins;%0Aimport com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;%0A
 impo
@@ -232,40 +232,8 @@
 t;%0A%0A
-import java.lang.reflect.Field;%0A
 impo
@@ -269,60 +269,8 @@
 nit;
-%0Aimport java.util.concurrent.atomic.AtomicReference;
 %0A%0Apu
@@ -354,35 +354,29 @@
         
-reset
 Hystrix
-Plugins
+.reset
 ();%0A    
@@ -687,1368 +687,8 @@
 ();%0A
-        resetHystrixPlugins();%0A    %7D%0A%0A    private static void resetHystrixPlugins() %7B%0A        Hystrix.reset();%0A        resetCommandExecutionHook();%0A    %7D%0A%0A    /**%0A     * There is a bug in %7B@link com.netflix.hystrix.strategy.HystrixPlugins.UnitTest#reset()%7D whereby the reset method%0A     * used to reset the test environment fails to reset commandExecutionHook field and thus prevents multiple tests from running.%0A     * %3Cp/%3E%0A     * This class fixes this in a very hacky way and should be abandoned as tenacity is migrated to new hystrix that fixes it.%0A     * Pull request has been merged, but new version has not been released yet:%0A     * https://github.com/Netflix/Hystrix/pull/240%0A     */%0A    private static void resetCommandExecutionHook() %7B%0A        try %7B%0A            Field commandExecutionHookField = HystrixPlugins.class.getDeclaredField(%22commandExecutionHook%22);%0A            commandExecutionHookField.setAccessible(true);%0A            HystrixPlugins jvmInstance = HystrixPlugins.getInstance();%0A            AtomicReference%3CHystrixCommandExecutionHook%3E commandExecutionHookRef =%0A                    (AtomicReference%3CHystrixCommandExecutionHook%3E) commandExecutionHookField.get(jvmInstance);%0A            commandExecutionHookRef.set(null);%0A        %7D catch (IllegalAccessException %7C NoSuchFieldException e) %7B%0A            throw Throwables.propagate(e);%0A        %7D%0A
     

Drop explicit reset of HystrixPlugins. The main Hystrix.reset covers this functionality now. Also remove the now unnecessary reflection resetting of the command hooks