fix serverSatisfies

This commit is contained in:
Julian K. Arni 2016-04-23 19:24:49 +02:00
parent dbdb948934
commit d22576bc26
2 changed files with 35 additions and 18 deletions

View File

@ -3,9 +3,10 @@ module Servant.QuickCheck.Internal.Predicates where
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Control.Monad import Control.Monad
import Network.HTTP.Client (Request, Response, responseStatus) import Network.HTTP.Client (Request, Response, responseStatus, Manager, httpLbs)
import Network.HTTP.Types (status500) import Network.HTTP.Types (status500)
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
import Data.Bifunctor (Bifunctor(..))
import Data.Text (Text) import Data.Text (Text)
-- | @500 Internal Server Error@ should be avoided - it may represent some -- | @500 Internal Server Error@ should be avoided - it may represent some
@ -13,9 +14,8 @@ import Data.Text (Text)
-- indication of how to proceed or what went wrong. -- indication of how to proceed or what went wrong.
-- --
-- This function checks that the response code is not 500. -- This function checks that the response code is not 500.
not500 :: ResponsePredicate Text [Text] not500 :: ResponsePredicate Text Bool
not500 = ResponsePredicate "not500" (\resp -> not500 = ResponsePredicate "not500" (\resp -> not $ responseStatus resp == status500)
if responseStatus resp == status500 then ["not500"] else [])
{- {-
-- | Returning anything other than an object when returning JSON is considered -- | Returning anything other than an object when returning JSON is considered
@ -158,6 +158,10 @@ data ResponsePredicate n r = ResponsePredicate
, respPred :: Response LBS.ByteString -> r , respPred :: Response LBS.ByteString -> r
} deriving (Functor, Generic) } deriving (Functor, Generic)
instance Bifunctor ResponsePredicate where
first f (ResponsePredicate a b) = ResponsePredicate (f a) b
second = fmap
instance (Monoid n, Monoid r) => Monoid (ResponsePredicate n r) where instance (Monoid n, Monoid r) => Monoid (ResponsePredicate n r) where
mempty = ResponsePredicate mempty mempty mempty = ResponsePredicate mempty mempty
a `mappend` b = ResponsePredicate a `mappend` b = ResponsePredicate
@ -167,15 +171,20 @@ instance (Monoid n, Monoid r) => Monoid (ResponsePredicate n r) where
data RequestPredicate n r = RequestPredicate data RequestPredicate n r = RequestPredicate
{ reqPredName :: n { reqPredName :: n
, reqResps :: Request -> IO [Response LBS.ByteString] , reqResps :: Request -> Manager -> IO [Response LBS.ByteString]
, reqPred :: ResponsePredicate n r , reqPred :: ResponsePredicate n r
} deriving (Generic, Functor) } deriving (Generic, Functor)
instance Bifunctor RequestPredicate where
first f (RequestPredicate a b c) = RequestPredicate (f a) b (first f c)
second = fmap
-- TODO: This isn't actually a monoid
instance (Monoid n, Monoid r) => Monoid (RequestPredicate n r) where instance (Monoid n, Monoid r) => Monoid (RequestPredicate n r) where
mempty = RequestPredicate mempty (\_ -> return mempty) mempty mempty = RequestPredicate mempty (\r m -> return <$> httpLbs r m) mempty
a `mappend` b = RequestPredicate a `mappend` b = RequestPredicate
{ reqPredName = reqPredName a <> reqPredName b { reqPredName = reqPredName a <> reqPredName b
, reqResps = \x -> liftM2 (<>) (reqResps a x) (reqResps b x) , reqResps = \x m -> liftM2 (<>) (reqResps a x m) (reqResps b x m)
, reqPred = reqPred a <> reqPred b , reqPred = reqPred a <> reqPred b
} }
@ -194,17 +203,21 @@ class JoinPreds a where
joinPreds :: a -> Predicates [Text] [Text] -> Predicates [Text] [Text] joinPreds :: a -> Predicates [Text] [Text] -> Predicates [Text] [Text]
instance JoinPreds (RequestPredicate Text Bool) where instance JoinPreds (RequestPredicate Text Bool) where
joinPreds p (Predicates x y) = Predicates (p <> x) y joinPreds p (Predicates x y) = Predicates (go <> x) y
where go = let p' = first return p
in fmap (\z -> if z then [] else reqPredName p') p'
instance JoinPreds (ResponsePredicate Text Bool) where instance JoinPreds (ResponsePredicate Text Bool) where
joinPreds p (Predicates x y) = Predicates x (p <> y) joinPreds p (Predicates x y) = Predicates x (go <> y)
where go = let p' = first return p
in fmap (\z -> if z then [] else respPredName p') p'
infixr 6 <%> infixr 6 <%>
(<%>) :: JoinPreds a n b r => a -> Predicates n b r -> Predicates n b r (<%>) :: JoinPreds a => a -> Predicates [Text] [Text] -> Predicates [Text] [Text]
(<%>) = joinPreds (<%>) = joinPreds
finishPredicates :: Predicates [Text] [Text] -> Request -> IO [Text] finishPredicates :: Predicates [Text] [Text] -> Request -> Manager -> IO [Text]
finishPredicates p req = do finishPredicates p req mgr = do
resps <- reqResps (reqPreds p) req resps <- reqResps (reqPreds p) req mgr
let preds = reqPred (reqPreds p) <> respPreds p let preds = reqPred (reqPreds p) <> respPreds p
return $ mconcat [respPred preds r | r <- resps ] return $ mconcat [respPred preds r | r <- resps ]

View File

@ -3,7 +3,7 @@ module Servant.QuickCheck.Internal.QuickCheck where
import Data.Proxy (Proxy) import Data.Proxy (Proxy)
import Network.HTTP.Client (Manager, defaultManagerSettings, import Network.HTTP.Client (Manager, defaultManagerSettings,
newManager, httpLbs) newManager, httpLbs, checkStatus, Request)
import Network.Wai.Handler.Warp (withApplication) import Network.Wai.Handler.Warp (withApplication)
import Servant (HasServer, Server, serve) import Servant (HasServer, Server, serve)
import Servant.Client (BaseUrl (..), Scheme (..) ) import Servant.Client (BaseUrl (..), Scheme (..) )
@ -44,8 +44,8 @@ serversEqual :: HasGenRequest a =>
serversEqual api burl1 burl2 args req = do serversEqual api burl1 burl2 args req = do
let reqs = (\f -> (f burl1, f burl2)) <$> genRequest api let reqs = (\f -> (f burl1, f burl2)) <$> genRequest api
r <- quickCheckWithResult args $ monadicIO $ forAllM reqs $ \(req1, req2) -> do r <- quickCheckWithResult args $ monadicIO $ forAllM reqs $ \(req1, req2) -> do
resp1 <- run $ httpLbs req1 defManager resp1 <- run $ httpLbs (noCheckStatus req1) defManager
resp2 <- run $ httpLbs req2 defManager resp2 <- run $ httpLbs (noCheckStatus req2) defManager
assert $ getResponseEquality req resp1 resp2 assert $ getResponseEquality req resp1 resp2
case r of case r of
Success {} -> return () Success {} -> return ()
@ -55,11 +55,12 @@ serversEqual api burl1 burl2 args req = do
InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage" InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage"
serverSatisfies :: (HasGenRequest a) => serverSatisfies :: (HasGenRequest a) =>
Proxy a -> BaseUrl -> Args -> Predicates Text [Text] -> Expectation Proxy a -> BaseUrl -> Args -> Predicates [Text] [Text] -> Expectation
serverSatisfies api burl args preds = do serverSatisfies api burl args preds = do
let reqs = ($ burl) <$> genRequest api let reqs = ($ burl) <$> genRequest api
r <- quickCheckWithResult args $ monadicIO $ forAllM reqs $ \req -> do r <- quickCheckWithResult args $ monadicIO $ forAllM reqs $ \req -> do
v <- run $ finishPredicates preds req v <- run $ finishPredicates preds (noCheckStatus req) defManager
{-run $ print v-}
assert $ null v assert $ null v
case r of case r of
Success {} -> return () Success {} -> return ()
@ -69,6 +70,9 @@ serverSatisfies api burl args preds = do
InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage" InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage"
noCheckStatus :: Request -> Request
noCheckStatus r = r { checkStatus = \_ _ _ -> Nothing}
defManager :: Manager defManager :: Manager
defManager = unsafePerformIO $ newManager defaultManagerSettings defManager = unsafePerformIO $ newManager defaultManagerSettings
{-# NOINLINE defManager #-} {-# NOINLINE defManager #-}