packages feed

rollbar-wai-1.0.0: test/Rollbar/WaiSpec.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

module Rollbar.WaiSpec
  ( spec
  ) where

import qualified Data.Aeson.KeyMap as KM
import qualified Data.Text as T
import qualified Network.Wai as W
import qualified Network.Wai.Handler.Warp as W

import Control.Concurrent (threadDelay)
import Control.Monad (join)
import Control.Monad.IO.Class
import Data.Aeson
import Data.IORef
import Network.HTTP.Req
import Network.HTTP.Types (status200, status404)
import Rollbar.Client
import Rollbar.Wai (rollbarOnExceptionWith)
import Test.Hspec

spec :: Spec
spec = before getSettingsAndItemRef $
  describe "rollbarOnExceptionWith" $ do
    context "when the response status code is 200" $
      it "does not trigger a call to Rollbar" $
        withApp $ \itemRef warpPort -> do
          let url = http "localhost" /: "success"
          response <- runReq
            defaultHttpConfig
            (req GET url NoReqBody bsResponse $ port warpPort)
          responseStatusCode response `shouldBe` 200
          responseBody response `shouldBe` "OK"
          threadDelay 500
          readIORef itemRef `shouldReturn` Nothing

    context "when the response status code is not 200" $
      it "triggers a call to Rollbar" $
        withApp $ \itemRef warpPort -> do
          let url = http "localhost" /: "error"
          response <- fmap responseBody $ runReq
            (defaultHttpConfig { httpConfigCheckResponse = \_ _ _ -> Nothing })
            (req GET url NoReqBody bsResponse $ port warpPort)
          response `shouldBe` "Something went wrong"
          threadDelay 500
          let portAsText = T.pack $ show warpPort
          join . fmap itemRequest <$> readIORef itemRef `shouldReturn` Just
            ( Request
                { requestUrl = "http://localhost:" <> portAsText <> "/error"
                , requestMethod = "GET"
                , requestHeaders = KM.fromList
                    [ ("Accept-Encoding", "gzip")
                    , ("Host", String $ "localhost:" <> portAsText)
                    ]
                , requestParams = mempty
                , requestGet = mempty
                , requestQueryStrings = ""
                , requestPost = mempty
                , requestBody = ""
                , requestUserIp = ""
                }
            )


getSettingsAndItemRef :: IO (Settings, IORef (Maybe Item))
getSettingsAndItemRef =
  (,) <$> readSettings "rollbar.yaml"
      <*> newIORef Nothing

withApp
  :: (IORef (Maybe Item) -> W.Port -> IO a)
  -> (Settings, IORef (Maybe Item))
  -> IO a
withApp f (settings, itemRef) = do
  let waiSettings = W.setOnException
        (rollbarOnExceptionWith (createItemFake itemRef) settings)
        W.defaultSettings
  W.withApplicationSettings waiSettings (return app) $ f itemRef

app :: W.Application
app wrequest respond =
  case W.rawPathInfo wrequest of
    "/error" -> error "Boom"
    "/success" -> respond $ W.responseLBS status200 [] "OK"
    _ -> respond $ W.responseLBS status404 [] "Not Found"

createItemFake :: IORef (Maybe Item) -> Item -> Rollbar ()
createItemFake itemRef item = do
  requestModifier <- getRequestModifier
  liftIO $ writeIORef itemRef $ Just $
    item { itemRequest = requestModifier <$> itemRequest item }