package com.qmth.boot.test.core.rateLimit;

import com.qmth.boot.core.rateLimit.entity.RateLimitRule;
import com.qmth.boot.core.rateLimit.entity.RateLimitScope;
import com.qmth.boot.core.rateLimit.entity.RateLimitTarget;
import com.qmth.boot.core.rateLimit.service.RateLimiter;
import com.qmth.boot.core.rateLimit.service.impl.MemoryRateLimitService;
import org.apache.commons.lang3.RandomUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.time.Duration;

public class RateLimitTest {

    private static MemoryRateLimitService service;

    @BeforeClass
    public static void prepare() {
        service = new MemoryRateLimitService();
    }

    @Test
    public void testRuleExpression() {
        RateLimitRule rule = RateLimitRule.parse("1/1s");
        Assert.assertNotNull(rule);
        Assert.assertEquals(rule.getCount(), 1);
        Assert.assertEquals(rule.getPeriod(), Duration.ofSeconds(1));
        Assert.assertEquals(rule.getScope(), RateLimitScope.CLUSTER);
        Assert.assertEquals(rule.getTarget(), RateLimitTarget.ALL);

        rule = RateLimitRule.parse("10/id/500ms");
        Assert.assertNotNull(rule);
        Assert.assertEquals(rule.getCount(), 10);
        Assert.assertEquals(rule.getPeriod(), Duration.ofMillis(500));
        Assert.assertEquals(rule.getScope(), RateLimitScope.INSTANCE);
        Assert.assertEquals(rule.getTarget(), RateLimitTarget.DEVICE);
    }

    //@Test
    public void testSimpleRule() throws InterruptedException {
        RateLimitRule rule = RateLimitRule.parse("1/1s");
        String endpoint = "/api/test";
        String target = "test";
        RateLimiter limiter = service.getRateLimiter(endpoint, target, rule);

        int loop = 0;
        long time = 0;
        while (loop < 50) {
            long current = System.currentTimeMillis() / rule.getPeriod().toMillis();
            boolean result = limiter.acquire();
            System.out.println(current + "-" + time + "-" + result);
            if (current != time) {
                Assert.assertTrue(result);
            } else {
                Assert.assertFalse(result);
            }
            time = current;
            loop++;
            Thread.sleep(RandomUtils.nextInt(100, 200));
        }

    }

}
