module WaiMiddlewareThrottleSpec where import Prelude hiding (lookup) import Control.Concurrent (threadDelay) import Control.Monad (replicateM, void) import Data.Cache (lookup) import Data.Maybe (isJust, isNothing) import Network.HTTP.Types.Status (status200, status429) import Network.Wai (defaultRequest, responseLBS) import Network.Wai.Test (request, runSession, simpleStatus) import System.Clock (TimeSpec (TimeSpec)) import Test.Hspec (Spec, before, describe, it, shouldSatisfy) -- the modules being tested import Network.Wai.Middleware.Throttle import Network.Wai.Middleware.Throttle.Internal spec :: Spec spec = do let expirationSpec = TimeSpec 5 0 runBefore :: IO (Throttle Int) runBefore = initCustomThrottler (defaultThrottleSettings expirationSpec) (const $ Right 1) before runBefore $ describe "Network.Wai.Middleware.Throttle" $ do describe "Bucket Operations" $ do it "initializes bucket when missing" $ \ th -> do let throttleKey = 1 cache = throttleCache th void $ retrieveOrInitializeBucket th throttleKey lookup cache throttleKey >>= \ b -> b `shouldSatisfy` isJust it "retrieves bucket on subsequent calls" $ \ th -> do let throttleKey = 1 cache = throttleCache th void $ retrieveOrInitializeBucket th throttleKey void $ retrieveOrInitializeBucket th throttleKey lookup cache throttleKey >>= \ b -> b `shouldSatisfy` isJust it "expires buckets" $ \ th -> do let throttleKey = 1 cache = throttleCache th void $ retrieveOrInitializeBucket th throttleKey lookup cache throttleKey >>= \ b -> b `shouldSatisfy` isJust threadDelay 5000000 lookup cache throttleKey >>= \ b -> b `shouldSatisfy` isNothing describe "Throttling Behavior" $ do it "throttles requests" $ \ th -> do let appl = throttle th $ \ _ f -> f $ responseLBS status200 [] "ok" statuses <- flip runSession appl $ do responses <- replicateM 100 (request defaultRequest) pure $ simpleStatus <$> responses statuses `shouldSatisfy` elem status429