package ru.shishmakov.core;

import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import ru.shishmakov.BaseTest;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;

/**
 * @author Dmitriy Shishmakov on 11.05.17
 */
public class RateAccessControllerTest extends BaseTest {

    private ExecutorService pool;

    @Before
    @Override
    public void setUp() {
        super.setUp();
        pool = buildExecutorService();
    }

    @After
    public void tearDown() {
        MoreExecutors.shutdownAndAwaitTermination(pool, 30, SECONDS);
    }

    @Test
    public void acquireAccessShouldHaveThresholdTaskCountPerSecond() throws Exception {
        final int ratePerSecond = 20;
        final int taskCount = 100;
        Map<Long, Integer> statistics = new ConcurrentHashMap<>();
        CountDownLatch awaitTasks = new CountDownLatch(taskCount);

        RateAccessController controller = new RateAccessController();
        controller.setUp();
        for (int i = 0; i < taskCount; i++) {
            pool.submit(() -> controller.acquireAccess(buildTask(statistics, awaitTasks)));
        }
        awaitTasks.await();
        controller.tearDown();
        logger.info("Result map: {}", statistics);

        statistics.forEach((second, tasks) -> assertEquals("Excess rate per second", ratePerSecond, tasks.intValue()));
    }

    private Runnable buildTask(Map<Long, Integer> statistics, CountDownLatch awaitTasks) {
        return () -> {
            long currentSec = System.currentTimeMillis() / 1000;
            statistics.merge(currentSec, 1, (old, inc) -> old + inc);
            awaitTasks.countDown();
        };
    }

    private static ExecutorService buildExecutorService() {
        return Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors() / 2),
                new BasicThreadFactory.Builder()
                        .namingPattern("request-worker %d")
                        .build());
    }

}

@@ -224,32 +224,263 @@
 ort 
-ru.shishmakov.BaseTest;%0A
+org.junit.runner.RunWith;%0Aimport org.springframework.test.context.ContextConfiguration;%0Aimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;%0Aimport ru.shishmakov.BaseTest;%0Aimport ru.shishmakov.config.Config;%0A%0Aimport javax.inject.Inject;
 %0Aimp
@@ -823,16 +823,102 @@
 .17%0A */%0A
+@RunWith(SpringJUnit4ClassRunner.class)%0A@ContextConfiguration(classes = Config.class)%0A
 public c
@@ -1002,16 +1002,74 @@
  pool;%0A%0A
+    @Inject%0A    private RateAccessController controller;%0A%0A
     @Bef
@@ -1608,106 +1608,8 @@
 );%0A%0A
-        RateAccessController controller = new RateAccessController();%0A        controller.setUp();%0A
     
@@ -1784,39 +1784,8 @@
 ();%0A
-        controller.tearDown();%0A
     

Use 'spring-test' for class 'RateAccessControllerTest'