packages feed

tower-hs-0.2.0.0: test/Tower/Middleware/LoggingSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Tower.Middleware.LoggingSpec (spec) where

import Data.IORef
import qualified Data.Text
import Data.Text (Text, isInfixOf)
import Test.Hspec

import Tower.Service
import Tower.Error
import Tower.Error.Testing ()
import Data.Function ((&))
import Tower.Middleware.Logging

spec :: Spec
spec = describe "Logging middleware (generic)" $ do
  it "logs successful requests" $ do
    logRef <- newIORef ([] :: [Text])
    let logger msg = modifyIORef' logRef (msg :)
        formatter _ result duration = case result of
          Right res -> "OK: " <> res <> " (" <> showMs duration <> ")"
          Left err  -> "ERR: " <> displayError err
        svc :: Service () Text
        svc = Service $ \_ -> pure (Right "done")
        logged = svc & withLogging formatter logger
    _ <- runService logged ()
    logs <- readIORef logRef
    length logs `shouldBe` 1
    isInfixOf "OK: done" (head logs) `shouldBe` True

  it "logs failed requests" $ do
    logRef <- newIORef ([] :: [Text])
    let logger msg = modifyIORef' logRef (msg :)
        formatter _ result _ = case result of
          Right _  -> "OK"
          Left err -> "ERR: " <> displayError err
        svc :: Service () Text
        svc = Service $ \_ -> pure (Left TimeoutError)
        logged = svc & withLogging formatter logger
    _ <- runService logged ()
    logs <- readIORef logRef
    length logs `shouldBe` 1
    isInfixOf "ERR" (head logs) `shouldBe` True

  it "does not alter the result" $ do
    let logger _ = pure ()
        formatter _ _ _ = "ignored"
        svc :: Service () Text
        svc = Service $ \_ -> pure (Right "original")
        logged = svc & withLogging formatter logger
    result <- runService logged ()
    result `shouldBe` Right "original"

  it "passes the request to the formatter" $ do
    logRef <- newIORef ([] :: [Text])
    let logger msg = modifyIORef' logRef (msg :)
        formatter req _ _ = "request=" <> req
        svc :: Service Text Text
        svc = Service $ \_ -> pure (Right "ok")
        logged = svc & withLogging formatter logger
    _ <- runService logged "my-request"
    logs <- readIORef logRef
    head logs `shouldBe` "request=my-request"

showMs :: Double -> Text
showMs d = let ms = round (d * 1000) :: Int
           in Data.Text.pack (show ms) <> "ms"