Skip to content
Snippets Groups Projects
Commit 28779449 authored by Jean-Paul Calderone's avatar Jean-Paul Calderone
Browse files

pursue this elsewhere

parent af7102a9
No related branches found
No related tags found
1 merge request!22Ristretto-flavored PrivacyPass
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module SpecStuff where
import Test.Tasty
( TestTree
, testGroup
)
import Test.Tasty.Wai
( assertBody
, assertStatus
, assertStatus'
, get
, post
, testWai
)
import Test.Tasty.QuickCheck
( testProperty
)
import PaymentServer.Persistence
( Voucher
)
import PaymentServer.Redemption
( RedemptionAPI
, Result(Failed, Succeeded)
)
import PaymentServer.Issuer
( BlindedToken
)
import Data.ByteString
( ByteString
)
import Text.Printf
( printf
)
import Data.Aeson
( decode
, encode
)
import Servant
( Application
, Proxy(Proxy)
, serve
)
import Test.Hspec
( Spec
, parallel
, describe
, it
, runIO
)
import Network.HTTP.Types
( Header
)
import Test.Hspec.Wai
( ResponseMatcher(matchBody, matchHeaders)
, (<:>)
, WaiExpectation
, Body
, MatchBody(MatchBody)
, with
, shouldRespondWith
, liftIO
)
import Test.QuickCheck
( ioProperty
)
import Test.Hspec.Wai.QuickCheck
( Testable(toProperty)
, WaiProperty(unWaiProperty)
, property
)
import Test.QuickCheck.Instances.Text ()
import Util.Spec
( wrongMethodNotAllowed
, nonJSONUnsupportedMediaType
, wrongJSONInvalidRequest
)
import Util.WAI
( postJSON
)
import PaymentServer.Issuer
( BlindedToken
, ChallengeBypass(ChallengeBypass)
, Issuer
, trivialIssue
)
import PaymentServer.Redemption
( RedemptionAPI
, Redeem(Redeem)
, Result(Failed, Succeeded)
, redemptionServer
)
import PaymentServer.Persistence
( RedeemError(NotPaid)
, Voucher
, VoucherDatabase(payForVoucher, redeemVoucher)
, memory
)
redemptionAPI :: Proxy RedemptionAPI
redemptionAPI = Proxy
app :: VoucherDatabase d => Issuer -> d -> Application
app issue = serve redemptionAPI . redemptionServer issue
path = "/"
propertyRedeem :: ByteString -> Voucher -> [BlindedToken] -> ResponseMatcher -> WaiExpectation
propertyRedeem path voucher tokens matcher =
postJSON path (encode $ Redeem voucher tokens) `shouldRespondWith` matcher
-- | A VoucherDatabaseTestDouble has a VoucherDatabase instance which provides
-- a number of different behaviors which are useful to be able to directly
-- test against.
data VoucherDatabaseTestDouble
-- | A RefuseRedemption database always refuses redemption with a given error.
= RefuseRedemption RedeemError
-- | A PermitRedemption database always permits redemption.
| PermitRedemption
deriving (Show)
instance VoucherDatabase VoucherDatabaseTestDouble where
payForVoucher _ voucher = return ()
redeemVoucher (RefuseRedemption err) _ _ = return $ Left err
redeemVoucher PermitRedemption _ _ = return $ Right ()
test_foo :: TestTree
test_foo = testGroup "Foo" redemption
redemption :: [TestTree]
redemption =
[ testProperty "fails when the voucher is not paid" $
\(voucher :: Voucher) (tokens :: [BlindedToken]) ->
propertyRedeem path voucher tokens 400
{ matchBody = matchJSONBody Failed
-- major/minor, fine. charset=utf-8... okay. but really this is
-- overspecified by encoding the exact byte sequence. I'd rather
-- assert semantic equality.
, matchHeaders = ["Content-Type" <:> "application/json;charset=utf-8"]
}
]
matchJSONBody :: Result -> MatchBody
matchJSONBody expected =
let
bodyMatcher :: [Header] -> Body -> Maybe String
bodyMatcher headers actualBody =
case decode actualBody of
Nothing ->
Just $ "failed to decode body as value of expected type: " ++ show actualBody
Just actual ->
if actual == expected then
Nothing
else
Just $ "decoded body does not equal expected value: " ++ show actual ++ show expected
in
MatchBody bodyMatcher
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment