on master help sign in
Added quickcheck
commit768c24ee12624551766db3f0420ff46d5d28c0d5 authoriko <ilyakooo0@gmail.com> dateMon 13 May 2019, 18:34 (7 years ago) parent4a67a77
6 files changed+197−11
denis/package.yaml+13 denis/src/Data/PostElement.hs+7−5 denis/src/Server/Auth.hs+4−2 denis/src/Server/Server.hs+13−4 denis/src/test/Orphans.hs+104 denis/src/test/Spec.hs+56
denis/package.yaml+13
@@ -63,6 +63,10 @@ dependencies:
6363- blaze-html
6464- servant-blaze
6565- random
66+- hspec
67+- generic-arbitrary
68+- quickcheck-instances
69+- http-client
6670
6771library:
6872 source-dirs: src
@@ -105,4 +109,13 @@ executables:
105109 - -rtsopts
106110 - -with-rtsopts=-N
107111 dependencies:
112+ - denis
113+ test:
114+ main: Spec.hs
115+ source-dirs: src/test
116+ ghc-options:
117+ - -threaded
118+ dependencies:
119+ - QuickCheck
120+ - servant-quickcheck
108121 - denis
denis/src/Data/PostElement.hs+7−5
@@ -15,7 +15,8 @@ module Data.PostElement (
1515 MkElementRow,
1616 PostElementRow(..),
1717 PostElement(..),
18− elementsToRows
18+ elementsToRows,
19+ PostQuote(..)
1920) where
2021
2122import Data.Int (Int64)
@@ -40,9 +41,9 @@ instance ToSample (PostElement p) where
4041data PostElement a = Markdown Text
4142 | Latex Text
4243 | Image Text
43− | Quote PostQuote
44+ | Quote ()
4445 | Attachment Text
45− deriving (Show)
46+ deriving (Show, GHC.Generic)
4647
4748instance ToJSON (PostElement t) where
4849 toJSON (Markdown m) = object ["markdown" .= m]
@@ -69,7 +70,8 @@ elemenToRow f el = case el of
6970 Markdown m -> f (Just m) Nothing Nothing Nothing Nothing
7071 Latex l -> f Nothing (Just l) Nothing Nothing Nothing
7172 Image i -> f Nothing Nothing (Just i) Nothing Nothing
72− Quote q -> f Nothing Nothing Nothing (Just $ quoteId q) Nothing
73+ -- Quote q -> f Nothing Nothing Nothing (Just $ (quoteId q)) Nothing
74+ Quote _ -> f Nothing Nothing Nothing Nothing Nothing
7375 Attachment a -> f Nothing Nothing Nothing Nothing (Just a)
7476
7577rowsToElement :: MkElementRow (Maybe (PostElement p))
@@ -105,7 +107,7 @@ data PostQuote = PostQuote {
105107 quoteId :: Int64,
106108 quoteBody :: [PostElement PostQuote],
107109 quotePostId :: Int64
108−} deriving (Show)
110+} deriving (Show, GHC.Generic)
109111
110112instance ToJSON PostQuote where
111113 toJSON (PostQuote qId pb pId) = object [
denis/src/Server/Auth.hs+4−2
@@ -11,6 +11,7 @@
1111 DeriveAnyClass,
1212 RecordWildCards #-}
1313{-# OPTIONS_GHC -Wno-orphans #-}
14+
1415module Server.Auth (
1516 checkToken,
1617 cookieTokenKey,
@@ -19,7 +20,8 @@ module Server.Auth (
1920 logIn,
2021 contextProxy,
2122 AuthenticationCredits(..),
22− authenticationAPI
23+ authenticationAPI,
24+ TokenActivationData
2325) where
2426
2527import Server.App
@@ -160,7 +162,7 @@ data AuthenticationCookieData = AuthenticationCookieData {
160162data TokenActivationData = TokenActivationData {
161163 tokenVerificationUserId :: UserId,
162164 tokenVerificationData :: BS.ByteString
163−} deriving (Show)
165+} deriving (Show, GHC.Generic)
164166
165167instance ToJSON TokenActivationData where
166168 toJSON (TokenActivationData uId vData) = object [
denis/src/Server/Server.hs+13−4
@@ -1,7 +1,12 @@
1−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE
2+ OverloadedStrings,
3+ TypeOperators,
4+ DataKinds #-}
25
36module Server.Server (
4− runServer
7+ runServer,
8+ hoistedServer,
9+ getConfig
510) where
611
712import Server.API
@@ -49,6 +54,11 @@ getConfig = do
4954 mail <- getMailConfig
5055 return $ Config conn crypto selfRoot mail
5156
57+hoistedServer :: Logger -> Config -> Server API
58+hoistedServer logger cfg =
59+ let serverAPI = mkServerAPI logger
60+ in hoistServerWithContext serverProxy contextProxy (flip runReaderT cfg) serverAPI
61+
5262runServer :: IO ()
5363runServer = do
5464 port <- getServerPort
@@ -57,8 +67,7 @@ runServer = do
5767 _ <- periodically (20 * minutes) $ runDbTask cfg pruneAuth
5868 let ctx = genAuthServerContext $ getPool cfg
5969 (middleLogger, logger) <- mkLogger 500
60− let serverAPI = mkServerAPI logger
61− let s = hoistServerWithContext serverProxy contextProxy (flip runReaderT cfg) serverAPI
70+ let s = hoistedServer logger cfg
6271 runSettings (settings port) $ cors (const $ Just policy) . middleLogger $ serveWithContext serverProxy ctx s
6372
6473policy :: CorsResourcePolicy
denis/src/test/Orphans.hsnew file+104
@@ -0,0 +1,104 @@
1+{-# LANGUAGE
2+ OverloadedStrings,
3+ TypeOperators,
4+ DataKinds,
5+ FlexibleInstances,
6+ UndecidableInstances #-}
7+
8+module Orphans where
9+
10+import Server.API
11+import Server.Server
12+import Test.QuickCheck
13+import Servant.QuickCheck
14+import Test.Hspec
15+import Server.App
16+import Servant.Server
17+import Data.User
18+import Servant.Server.Experimental.Auth
19+import Network.Wai
20+import Servant.QuickCheck.Internal.HasGenRequest
21+import Servant.API
22+import Server.Query.ComplexQuery
23+import Test.QuickCheck
24+import Server.Query.Pagination
25+import Test.QuickCheck.Arbitrary.Generic
26+import Data.Post
27+import Data.Channel.NamedChannel
28+import Test.QuickCheck.Instances
29+import Server.Auth
30+import Data.Query
31+import Data.User
32+import Data.PostElement
33+import Data.Channel.AnonymousChannel
34+import Data.Channel.NamedChannel
35+import Data.GroupChat
36+import Squeal.PostgreSQL.Schema
37+import Data.Message
38+
39+instance (Arbitrary i, Arbitrary r) => Arbitrary (PaginatingRequest i r) where
40+ arbitrary = genericArbitrary
41+ shrink = genericShrink
42+
43+instance Arbitrary PaginationDirection where
44+ arbitrary = elements [BackPagination, ForwardPagination]
45+
46+instance (Arbitrary u) => Arbitrary (NamedChannel u) where
47+ arbitrary = genericArbitrary
48+ shrink = genericShrink
49+
50+instance Arbitrary AuthenticationCredits where
51+ arbitrary = genericArbitrary
52+ shrink = genericShrink
53+
54+instance Arbitrary UserCreation where
55+ arbitrary = genericArbitrary
56+ shrink = genericShrink
57+
58+instance Arbitrary TokenActivationData where
59+ arbitrary = genericArbitrary
60+ shrink = genericShrink
61+
62+instance Arbitrary UserUpdate where
63+ arbitrary = genericArbitrary
64+ shrink = genericShrink
65+
66+instance Arbitrary PostCreation where
67+ arbitrary = genericArbitrary
68+ shrink = genericShrink
69+
70+instance Arbitrary (PostElement p) where
71+ arbitrary = genericArbitrary
72+ shrink = genericShrink
73+
74+instance Arbitrary PostQuote where
75+ arbitrary = genericArbitrary
76+ shrink = genericShrink
77+
78+instance Arbitrary AnonymousChannel where
79+ arbitrary = genericArbitrary
80+ shrink = genericShrink
81+
82+instance Arbitrary NamedChannelCreationRequest where
83+ arbitrary = genericArbitrary
84+ shrink = genericShrink
85+
86+instance Arbitrary GroupChat where
87+ arbitrary = genericArbitrary
88+ shrink = genericShrink
89+
90+instance Arbitrary GroupChatPermissions where
91+ arbitrary = genericArbitrary
92+ shrink = genericShrink
93+
94+instance Arbitrary GroupChatCreation where
95+ arbitrary = genericArbitrary
96+ shrink = genericShrink
97+
98+instance Arbitrary MessageCreation where
99+ arbitrary = genericArbitrary
100+ shrink = genericShrink
101+
102+instance (Arbitrary a) => Arbitrary (Jsonb a) where
103+ arbitrary = genericArbitrary
104+ shrink = genericShrink
denis/src/test/Spec.hsnew file+56
@@ -0,0 +1,56 @@
1+{-# LANGUAGE
2+ OverloadedStrings,
3+ TypeOperators,
4+ DataKinds,
5+ FlexibleInstances,
6+ UndecidableInstances,
7+ ScopedTypeVariables #-}
8+
9+import Server.API
10+import Server.Server
11+import Test.QuickCheck
12+import Servant.QuickCheck
13+import Test.Hspec
14+import Server.App
15+import Servant.Server
16+import Data.User
17+import Servant.Server.Experimental.Auth
18+import Network.Wai
19+import Servant.QuickCheck.Internal.HasGenRequest
20+import Servant.API
21+import Server.Query.ComplexQuery
22+import Orphans
23+import qualified Network.HTTP.Client as HTTP
24+import qualified Data.ByteString.Char8 as B
25+import qualified Data.ByteString.Lazy.Char8 as LB
26+
27+main :: IO ()
28+main = hspec goodAPISpec
29+
30+mockAuth :: Context (AuthHandler Request UserId ': '[])
31+mockAuth = mkAuthHandler (const $ return 3) :. EmptyContext
32+
33+goodAPISpec = describe "my server" $ do
34+
35+ it "follows best practices" $ do
36+ cfg' <- getConfig
37+ withServantServerAndContext serverProxy mockAuth (return $ hoistedServer (return "") cfg') $ \burl ->
38+ serverSatisfies serverProxy burl stdArgs{chatty=True} (
39+ printPredicate
40+ <%> not500
41+ <%> mempty)
42+
43+printPredicate = RequestPredicate $ \ req mgr -> do
44+ let url = HTTP.path req
45+ let (HTTP.RequestBodyLBS bs) = HTTP.requestBody req
46+ putStrLn . ("\t\t" <>) $ B.unpack url
47+ putStrLn $ LB.unpack bs
48+ putStrLn ""
49+ return []
50+
51+
52+instance (HasGenRequest a) => HasGenRequest (Authentication :> a) where
53+ genRequest (Proxy :: Proxy (Authentication :> a)) = genRequest (Proxy :: Proxy a)
54+
55+instance HasGenRequest api => HasGenRequest (ComplexQuery :> api) where
56+ genRequest (Proxy :: Proxy (ComplexQuery :> api)) = genRequest (Proxy :: Proxy api)