dormouse-client-0.2.0.0: src/Dormouse/Client/Test/Class.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- This module is useful for testing by providing a concrete ByteString typed version of 'MonadDormouseClient' called `MonadDormouseTestClient`.
--
-- The assumption is that, in most test cases, you probably want to verify the byte payload of the request (which you simply extract
-- from the request here as a @ByteString@) and provide a byte payload (also as a @ByteString@) in the response so that you can verify
-- your repsonse payload can be decoded directly.
--
-- An implementation of `MonadDormouseTestClient` can be written in terms of either Strict or Lazy Bytestrings at your convenient and the other
-- will be automatically provided for you.
--
-- The machinery in here uses orphan instances of 'MonadDormouseClient' so you should use this carefully and restrict this module to test
-- cases only.
module Dormouse.Client.Test.Class
( MonadDormouseTestClient(..)
) where
import Control.Monad.IO.Class ( MonadIO(..) )
import qualified Data.ByteString as SB
import qualified Data.ByteString.Lazy as LB
import Data.Word ( Word8 )
import Dormouse.Client.Class ( MonadDormouseClient(..) )
import Dormouse.Client.Payload ( RawRequestPayload(..) )
import Dormouse.Client.Types ( HttpRequest(..), HttpResponse(..) )
import Dormouse.Url ( IsUrl )
import Streamly ( SerialT )
import qualified Streamly.Prelude as S
import qualified Streamly.External.ByteString as SEB
import qualified Streamly.External.ByteString.Lazy as SEBL
-- | MonadDormouseTestClient describes the capability to send and receive specifically ByteString typed HTTP Requests and Responses
class Monad m => MonadDormouseTestClient m where
-- | Make the supplied HTTP request, expecting an HTTP response with a Lazy ByteString body to be delivered in some @MonadDormouseTest m@
expectLbs :: IsUrl url => HttpRequest url method LB.ByteString contentTag acceptTag -> m (HttpResponse LB.ByteString)
expectLbs req = do
resp <- expectBs $ req {requestBody = LB.toStrict $ requestBody req}
return $ resp {responseBody = LB.fromStrict $ responseBody resp}
-- | Make the supplied HTTP request, expecting an HTTP response with a Strict ByteString body to be delivered in some @MonadDormouseTest m@
expectBs :: IsUrl url => HttpRequest url method SB.ByteString contentTag acceptTag -> m (HttpResponse SB.ByteString)
expectBs req = do
resp <- expectLbs $ req {requestBody = LB.fromStrict $ requestBody req}
return $ resp {responseBody = LB.toStrict $ responseBody resp}
{-# MINIMAL expectLbs | expectBs #-}
instance (Monad m, MonadIO m, MonadDormouseTestClient m) => MonadDormouseClient m where
send req deserialiseResp = do
reqBody <- liftIO . S.fold SEB.write . extricateRequestStream . requestBody $ req
let reqBs = req {requestBody = reqBody}
respBs <- expectBs reqBs
let respStream = S.unfold SEBL.read . LB.fromStrict $ responseBody respBs
liftIO $ deserialiseResp $ respBs { responseBody = respStream }
where
extricateRequestStream :: RawRequestPayload -> SerialT IO Word8
extricateRequestStream (DefinedContentLength _ s) = s
extricateRequestStream (ChunkedTransfer s) = s