package dev.coph.nextusweb.server.ratelimit; import org.junit.jupiter.api.Test; import java.util.List; import static org.junit.jupiter.api.Assertions.*; class RateLimitConfigTest { private RateLimiter alwaysAllow() { return (k, now) -> RateLimiter.Result.allow(1, 1); } private KeyResolver keyer() { return (req, remote) -> "x"; } @Test void emptyConfigReturnsEmptyList() { RateLimitConfig cfg = RateLimitConfig.builder().build(); assertTrue(cfg.rulesFor("/anything").isEmpty()); } @Test void globalOnlyReturnsOneRule() { RateLimitConfig cfg = RateLimitConfig.builder() .global(alwaysAllow(), keyer()) .build(); List rules = cfg.rulesFor("/x"); assertEquals(1, rules.size()); assertEquals("global", rules.getFirst().name()); } @Test void exactPathTrumpsPrefixRule() { RateLimitConfig cfg = RateLimitConfig.builder() .forPath("/a/b", alwaysAllow(), keyer()) .forPrefix("/a/", alwaysAllow(), keyer()) .build(); List rules = cfg.rulesFor("/a/b"); assertEquals(1, rules.size()); assertEquals("/a/b", rules.getFirst().name()); } @Test void prefixRuleMatchesWhenNoExact() { RateLimitConfig cfg = RateLimitConfig.builder() .forPrefix("/api/", alwaysAllow(), keyer()) .build(); List rules = cfg.rulesFor("/api/users"); assertEquals(1, rules.size()); assertEquals("/api/*", rules.getFirst().name()); } @Test void longerPrefixWinsOverShorter() { RateLimitConfig cfg = RateLimitConfig.builder() .forPrefix("/api/", alwaysAllow(), keyer()) .forPrefix("/api/v2/", alwaysAllow(), keyer()) .build(); List rules = cfg.rulesFor("/api/v2/users"); assertEquals(1, rules.size()); assertEquals("/api/v2/*", rules.getFirst().name()); } @Test void globalIsAlwaysIncludedAlongsideMatchedRule() { RateLimitConfig cfg = RateLimitConfig.builder() .global(alwaysAllow(), keyer()) .forPath("/x", alwaysAllow(), keyer()) .build(); List rules = cfg.rulesFor("/x"); assertEquals(2, rules.size()); assertEquals("global", rules.get(0).name()); assertEquals("/x", rules.get(1).name()); } }