package com.github.phantomthief.failover.impl;

import static com.google.common.base.Throwables.throwIfUnchecked;
import static com.google.common.collect.ImmutableList.of;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static java.util.Collections.singleton;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableList;

/**
 * @author w.vela
 * Created on 2017-12-28.
 */
class ComboFailoverTest {

    private static final Logger logger = LoggerFactory.getLogger(ComboFailoverTest.class);

    @Test
    void test() {
        ComboFailover<String> combo = ComboFailover.<String> builder() //
                .add(WeightFailover.<String> newGenericBuilder() //
                        .checker(this::check) //
                        .checkDuration(1, SECONDS) //
                        .failReduceRate(0.1) //
                        .build(of("test1", "test2"))) //
                .add(WeightFailover.<String> newGenericBuilder() //
                        .checker(this::check) //
                        .checkDuration(1, SECONDS) //
                        .failReduceRate(0.1) //
                        .build(of("test3", "test4"))) //
                .build();
        ImmutableList<String> all = of("test1", "test2", "test3", "test4");
        assertTrue(all.containsAll(combo.getAll()));
        assertTrue(all.containsAll(combo.getAvailable()));
        assertTrue(all.contains(combo.getOneAvailable()));
        for (int i = 0; i < 10; i++) {
            assertTrue(of("test1", "test2")
                    .contains(combo.getOneAvailableExclude(of("test3", "test4"))));
            assertFalse(of("test3", "test4")
                    .contains(combo.getOneAvailableExclude(of("test3", "test4"))));
        }

        for (int i = 0; i < 10; i++) {
            combo.fail("test1");
        }
        assertEquals(singleton("test1"), combo.getFailed());
        for (int i = 0; i < 10; i++) {
            assertFalse(of("test3").contains(combo.getOneAvailable()));
        }
        sleepUninterruptibly(2, SECONDS);
        assertTrue(combo.getFailed().isEmpty());
        for (int i = 0; i < 10; i++) {
            assertTrue(of("test3")
                    .contains(combo.getOneAvailableExclude(of("test1", "test2", "test4"))));
        }

        for (int i = 0; i < 10; i++) {
            assertTrue(of("test1", "test2").contains(combo.getOneAvailable()));
            assertFalse(of("test3", "test4").contains(combo.getOneAvailable()));
        }
        combo.down("test1");
        combo.down("test2");
        for (int i = 0; i < 10; i++) {
            assertFalse(of("test1", "test2").contains(combo.getOneAvailable()));
            assertTrue(of("test3", "test4").contains(combo.getOneAvailable()));
        }
        sleepUninterruptibly(2, SECONDS);

        combo.forEach(failover -> {
            if (failover instanceof AutoCloseable) {
                try {
                    ((AutoCloseable) failover).close();
                } catch (Exception e) {
                    throwIfUnchecked(e);
                    throw new RuntimeException(e);
                }
            }
        });
    }

    private double check(String value) {
        logger.info("check:{}", value);
        return 0.5D;
    }
}
@@ -343,16 +343,21 @@
 imeUnit.
+MILLI
 SECONDS;
@@ -357,16 +357,16 @@
 ECONDS;%0A
-
 import s
@@ -631,16 +631,71 @@
 ctory;%0A%0A
+import com.github.phantomthief.util.ThrowableFunction;%0A
 import c
@@ -930,24 +930,290 @@
 id test() %7B%0A
+        boolean%5B%5D checkerSwitch = %7B true %7D;%0A        ThrowableFunction%3CString, Double, Throwable%3E checker = value -%3E %7B%0A            if (checkerSwitch%5B0%5D) %7B%0A                return check(value);%0A            %7D else %7B%0A                return 0.0D;%0A            %7D%0A        %7D;%0A
         Comb
@@ -1371,35 +1371,31 @@
    .checker(
-this::
 check
+er
 ) //%0A       
@@ -1419,34 +1419,40 @@
 .checkDuration(1
+0
 , 
+MILLI
 SECONDS) //%0A    
@@ -1657,19 +1657,15 @@
 ker(
-this::
 check
+er
 ) //
@@ -1705,18 +1705,24 @@
 ration(1
+0
 , 
+MILLI
 SECONDS)
@@ -1852,24 +1852,58 @@
   .build();%0A
+        checkerSwitch%5B0%5D = false;%0A
         Immu
@@ -2720,40 +2720,114 @@
     
-sleepUninterruptibly(2, SECONDS)
+checkerSwitch%5B0%5D = true;%0A        sleepUninterruptibly(100, MILLISECONDS);%0A        checkerSwitch%5B0%5D = false
 ;%0A  
@@ -3541,40 +3541,114 @@
     
-sleepUninterruptibly(2, SECONDS)
+checkerSwitch%5B0%5D = true;%0A        sleepUninterruptibly(100, MILLISECONDS);%0A        checkerSwitch%5B0%5D = false
 ;%0A%0A 

update combo test may failed.