Merge pull request #410 from meteficha/runFakeHandler

New function runFakeHandler.
This commit is contained in:
Michael Snoyman 2012-08-21 21:06:55 -07:00
commit a9b10ce0bc
2 changed files with 83 additions and 0 deletions

View File

@ -40,6 +40,7 @@ module Yesod.Core
-- * Misc -- * Misc
, yesodVersion , yesodVersion
, yesodRender , yesodRender
, runFakeHandler
-- * Re-exports -- * Re-exports
, module Yesod.Content , module Yesod.Content
, module Yesod.Dispatch , module Yesod.Dispatch

View File

@ -36,6 +36,7 @@ module Yesod.Internal.Core
, resolveApproot , resolveApproot
, Approot (..) , Approot (..)
, FileUpload (..) , FileUpload (..)
, runFakeHandler
) where ) where
import Yesod.Content import Yesod.Content
@ -55,6 +56,7 @@ import Yesod.Internal.Request
import qualified Web.ClientSession as CS import qualified Web.ClientSession as CS
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.IORef as I
import Data.Monoid import Data.Monoid
import Text.Hamlet import Text.Hamlet
import Text.Julius import Text.Julius
@ -64,6 +66,7 @@ import Data.Text.Lazy.Builder (toLazyText)
import Data.Text.Lazy.Encoding (encodeUtf8) import Data.Text.Lazy.Encoding (encodeUtf8)
import Data.Maybe (fromMaybe, isJust) import Data.Maybe (fromMaybe, isJust)
import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Trans.Resource (runResourceT)
import Web.Cookie (parseCookies) import Web.Cookie (parseCookies)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Time import Data.Time
@ -752,3 +755,82 @@ loadClientSession key timeout sessionName master req now = return (sess, save)
expires = fromIntegral (timeout * 60) `addUTCTime` now' expires = fromIntegral (timeout * 60) `addUTCTime` now'
sessionVal iv = encodeClientSession key iv expires host sess' sessionVal iv = encodeClientSession key iv expires host sess'
-- | Run a 'GHandler' completely outside of Yesod. This
-- function comes with many caveats and you shouldn't use it
-- unless you fully understand what it's doing and how it works.
--
-- As of now, there's only one reason to use this function at
-- all: in order to run unit tests of functions inside 'GHandler'
-- but that aren't easily testable with a full HTTP request.
-- Even so, it's better to use @wai-test@ or @yesod-test@ instead
-- of using this function.
--
-- This function will create a fake HTTP request (both @wai@'s
-- 'W.Request' and @yesod@'s 'Request') and feed it to the
-- @GHandler@. The only useful information the @GHandler@ may
-- get from the request is the session map, which you must supply
-- as argument to @runFakeHandler@. All other fields contain
-- fake information, which means that they can be accessed but
-- won't have any useful information. The response of the
-- @GHandler@ is completely ignored, including changes to the
-- session, cookies or headers. We only return you the
-- @GHandler@'s return value.
runFakeHandler :: (Yesod master, MonadIO m) =>
SessionMap
-> (master -> Logger)
-> master
-> GHandler master master a
-> m (Either ErrorResponse a)
runFakeHandler fakeSessionMap logger master handler = liftIO $ do
ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")
let handler' = do liftIO . I.writeIORef ret . Right =<< handler
return ()
let YesodApp yapp =
runHandler
handler'
(yesodRender master "")
Nothing
id
master
master
(fileUpload master)
(messageLogger master $ logger master)
errHandler err =
YesodApp $ \_ _ _ session -> do
liftIO $ I.writeIORef ret (Left err)
return $ YARPlain
H.status500
[]
typePlain
(toContent ("runFakeHandler: errHandler" :: S8.ByteString))
session
fakeWaiRequest =
W.Request
{ W.requestMethod = "POST"
, W.httpVersion = H.http11
, W.rawPathInfo = "/runFakeHandler/pathInfo"
, W.rawQueryString = ""
, W.serverName = "runFakeHandler-serverName"
, W.serverPort = 80
, W.requestHeaders = []
, W.isSecure = False
, W.remoteHost = error "runFakeHandler-remoteHost"
, W.pathInfo = ["runFakeHandler", "pathInfo"]
, W.queryString = []
, W.requestBody = mempty
, W.vault = mempty
}
fakeRequest =
Request
{ reqGetParams = []
, reqCookies = []
, reqWaiRequest = fakeWaiRequest
, reqLangs = []
, reqToken = Just "NaN" -- not a nonce =)
, reqBodySize = 0
}
fakeContentType = []
_ <- runResourceT $ yapp errHandler fakeRequest fakeContentType fakeSessionMap
I.readIORef ret
{-# WARNING runFakeHandler "Usually you should *not* use runFakeHandler unless you really understand how it works and why you need it." #-}