@@ -38,8 +38,8 @@ import Network.Wai.Internal (Response (ResponseBuilder))
38import Network.Wai.Test (defaultRequest, request,
38import Network.Wai.Test (defaultRequest, request,
39 runSession, simpleBody,
39 runSession, simpleBody,
40 simpleHeaders, simpleStatus)
40 simpleHeaders, simpleStatus)
41−import Servant.API ((:<|>) (..), (:>), Capture, Delete,
41+import Servant.API ((:<|>) (..), (:>), BasicAuth, BasicAuthData(BasicAuthData),
42− Get, Header (..),
42+ Capture, Delete, Get, Header (..),
43 Headers, HttpVersion,
43 Headers, HttpVersion,
44 IsSecure (..), JSON,
44 IsSecure (..), JSON,
45 NoContent (..), Patch, PlainText,
45 NoContent (..), Patch, PlainText,
@@ -49,13 +49,16 @@ import Servant.API ((:<|>) (..), (:>), Capture, Delete,
49 StdMethod (..), Verb, addHeader)
49 StdMethod (..), Verb, addHeader)
50import Servant.API.Internal.Test.ComprehensiveAPI
50import Servant.API.Internal.Test.ComprehensiveAPI
51import Servant.Server (ServantErr (..), Server, err404,
51import Servant.Server (ServantErr (..), Server, err404,
52− serve, serveWithContext, Context(EmptyContext))
52+ serve, serveWithContext, Context((:.), EmptyContext))
53import Test.Hspec (Spec, context, describe, it,
53import Test.Hspec (Spec, context, describe, it,
54 shouldBe, shouldContain)
54 shouldBe, shouldContain)
55+import qualified Test.Hspec.Wai as THW
55import Test.Hspec.Wai (get, liftIO, matchHeaders,
56import Test.Hspec.Wai (get, liftIO, matchHeaders,
56− matchStatus, request,
57− shouldRespondWith, with, (<:>))
57+ matchStatus, shouldRespondWith,
60+import Servant.Server.Internal.BasicAuth (BasicAuthCheck(BasicAuthCheck),
61+ BasicAuthResult(Authorized,Unauthorized))
59import Servant.Server.Internal.RoutingApplication
62import Servant.Server.Internal.RoutingApplication
60 (toApplication, RouteResult(..))
63 (toApplication, RouteResult(..))
61import Servant.Server.Internal.Router
64import Servant.Server.Internal.Router
@@ -86,6 +89,7 @@ spec = do
86 responseHeadersSpec
89 responseHeadersSpec
87 routerSpec
90 routerSpec
88 miscCombinatorSpec
91 miscCombinatorSpec
90------------------------------------------------------------------------------
94------------------------------------------------------------------------------
91-- * verbSpec {{{
95-- * verbSpec {{{
@@ -117,49 +121,49 @@ verbSpec = describe "Servant.API.Verb" $ do
117 -- HEAD and 214/215 need not return bodies
121 -- HEAD and 214/215 need not return bodies
118 unless (status `elem` [214, 215] || method == methodHead) $
122 unless (status `elem` [214, 215] || method == methodHead) $
119 it "returns the person" $ do
123 it "returns the person" $ do
120− response <- Test.Hspec.Wai.request method "/" [] ""
124+ response <- THW.request method "/" [] ""
121 liftIO $ statusCode (simpleStatus response) `shouldBe` status
125 liftIO $ statusCode (simpleStatus response) `shouldBe` status
122 liftIO $ decode' (simpleBody response) `shouldBe` Just alice
126 liftIO $ decode' (simpleBody response) `shouldBe` Just alice
124 it "returns no content on NoContent" $ do
128 it "returns no content on NoContent" $ do
125− response <- Test.Hspec.Wai.request method "/noContent" [] ""
129+ response <- THW.request method "/noContent" [] ""
126 liftIO $ statusCode (simpleStatus response) `shouldBe` status
130 liftIO $ statusCode (simpleStatus response) `shouldBe` status
127 liftIO $ simpleBody response `shouldBe` ""
131 liftIO $ simpleBody response `shouldBe` ""
129 -- HEAD should not return body
133 -- HEAD should not return body
130 when (method == methodHead) $
134 when (method == methodHead) $
131 it "HEAD returns no content body" $ do
135 it "HEAD returns no content body" $ do
132− response <- Test.Hspec.Wai.request method "/" [] ""
136+ response <- THW.request method "/" [] ""
133 liftIO $ simpleBody response `shouldBe` ""
137 liftIO $ simpleBody response `shouldBe` ""
135 it "throws 405 on wrong method " $ do
139 it "throws 405 on wrong method " $ do
136− Test.Hspec.Wai.request (wrongMethod method) "/" [] ""
140+ THW.request (wrongMethod method) "/" [] ""
137 `shouldRespondWith` 405
141 `shouldRespondWith` 405
139 it "returns headers" $ do
143 it "returns headers" $ do
140− response1 <- Test.Hspec.Wai.request method "/header" [] ""
144+ response1 <- THW.request method "/header" [] ""
141 liftIO $ statusCode (simpleStatus response1) `shouldBe` status
145 liftIO $ statusCode (simpleStatus response1) `shouldBe` status
142 liftIO $ simpleHeaders response1 `shouldContain` [("H", "5")]
146 liftIO $ simpleHeaders response1 `shouldContain` [("H", "5")]
144− response2 <- Test.Hspec.Wai.request method "/header" [] ""
148+ response2 <- THW.request method "/header" [] ""
145 liftIO $ statusCode (simpleStatus response2) `shouldBe` status
149 liftIO $ statusCode (simpleStatus response2) `shouldBe` status
146 liftIO $ simpleHeaders response2 `shouldContain` [("H", "5")]
150 liftIO $ simpleHeaders response2 `shouldContain` [("H", "5")]
148 it "handles trailing '/' gracefully" $ do
152 it "handles trailing '/' gracefully" $ do
149− response <- Test.Hspec.Wai.request method "/headerNC/" [] ""
153+ response <- THW.request method "/headerNC/" [] ""
150 liftIO $ statusCode (simpleStatus response) `shouldBe` status
154 liftIO $ statusCode (simpleStatus response) `shouldBe` status
152 it "returns 406 if the Accept header is not supported" $ do
156 it "returns 406 if the Accept header is not supported" $ do
153− Test.Hspec.Wai.request method "" [(hAccept, "crazy/mime")] ""
157+ THW.request method "" [(hAccept, "crazy/mime")] ""
154 `shouldRespondWith` 406
158 `shouldRespondWith` 406
156 it "responds if the Accept header is supported" $ do
160 it "responds if the Accept header is supported" $ do
157− response <- Test.Hspec.Wai.request method ""
161+ response <- THW.request method ""
158 [(hAccept, "application/json")] ""
162 [(hAccept, "application/json")] ""
159 liftIO $ statusCode (simpleStatus response) `shouldBe` status
163 liftIO $ statusCode (simpleStatus response) `shouldBe` status
161 it "sets the Content-Type header" $ do
165 it "sets the Content-Type header" $ do
162− response <- Test.Hspec.Wai.request method "" [] ""
166+ response <- THW.request method "" [] ""
163 liftIO $ simpleHeaders response `shouldContain`
167 liftIO $ simpleHeaders response `shouldContain`
164 [("Content-Type", "application/json")]
168 [("Content-Type", "application/json")]
@@ -306,7 +310,7 @@ reqBodySpec = describe "Servant.API.ReqBody" $ do
307 let server :: Server ReqBodyApi
311 let server :: Server ReqBodyApi
308 server = return :<|> return . age
312 server = return :<|> return . age
309− mkReq method x = Test.Hspec.Wai.request method x
313+ mkReq method x = THW.request method x
310 [(hContentType, "application/json;charset=utf-8")]
314 [(hContentType, "application/json;charset=utf-8")]
312 with (return $ serve reqBodyApi server) $ do
316 with (return $ serve reqBodyApi server) $ do
@@ -319,7 +323,7 @@ reqBodySpec = describe "Servant.API.ReqBody" $ do
319 mkReq methodPut "/blah" "some invalid body" `shouldRespondWith` 400
323 mkReq methodPut "/blah" "some invalid body" `shouldRespondWith` 400
321 it "responds with 415 if the request body media type is unsupported" $ do
325 it "responds with 415 if the request body media type is unsupported" $ do
322− Test.Hspec.Wai.request methodPost "/"
326+ THW.request methodPost "/"
323 [(hContentType, "application/nonsense")] "" `shouldRespondWith` 415
327 [(hContentType, "application/nonsense")] "" `shouldRespondWith` 415
@@ -455,19 +459,19 @@ responseHeadersSpec = describe "ResponseHeaders" $ do
456 it "includes the headers in the response" $
460 it "includes the headers in the response" $
457 forM_ methods $ \method ->
461 forM_ methods $ \method ->
458− Test.Hspec.Wai.request method "/" [] ""
462+ THW.request method "/" [] ""
459 `shouldRespondWith` "\"hi\""{ matchHeaders = ["H1" <:> "5", "H2" <:> "kilroy"]
463 `shouldRespondWith` "\"hi\""{ matchHeaders = ["H1" <:> "5", "H2" <:> "kilroy"]
460 , matchStatus = 200
464 , matchStatus = 200
463 it "responds with not found for non-existent endpoints" $
467 it "responds with not found for non-existent endpoints" $
464 forM_ methods $ \method ->
468 forM_ methods $ \method ->
465− Test.Hspec.Wai.request method "blahblah" [] ""
469+ THW.request method "blahblah" [] ""
466 `shouldRespondWith` 404
470 `shouldRespondWith` 404
468 it "returns 406 if the Accept header is not supported" $
472 it "returns 406 if the Accept header is not supported" $
469 forM_ methods $ \method ->
473 forM_ methods $ \method ->
470− Test.Hspec.Wai.request method "" [(hAccept, "crazy/mime")] ""
474+ THW.request method "" [(hAccept, "crazy/mime")] ""
471 `shouldRespondWith` 406
475 `shouldRespondWith` 406
@@ -527,6 +531,39 @@ miscCombinatorSpec = with (return $ serve miscApi miscServ) $
527 go "/host" "\"0.0.0.0:0\""
531 go "/host" "\"0.0.0.0:0\""
529 where go path res = Test.Hspec.Wai.get path `shouldRespondWith` res
533 where go path res = Test.Hspec.Wai.get path `shouldRespondWith` res
536+------------------------------------------------------------------------------
537+-- * Authentication {{{
538+------------------------------------------------------------------------------
540+type BasicAuthAPI = BasicAuth "foo" () :> "basic" :> Get '[JSON] Animal
542+basicAuthApi :: Proxy BasicAuthAPI
544+basicAuthServer :: Server BasicAuthAPI
545+basicAuthServer = const (return jerry)
547+basicAuthContext :: Context '[ BasicAuthCheck () ]
549+ let basicHandler = BasicAuthCheck $ (\(BasicAuthData usr pass) ->
550+ if usr == "servant" && pass == "server"
551+ then return (Authorized ())
552+ else return Unauthorized
554+ in basicHandler :. EmptyContext
556+basicAuthSpec :: Spec
558+ describe "Servant.API.BasicAuth" $ do
559+ with (return (serveWithContext basicAuthApi basicAuthContext basicAuthServer)) $ do
561+ context "Basic Authentication" $ do
562+ it "returns with 401 with bad password" $ do
563+ get "/basic" `shouldRespondWith` 401
564+ it "returns 200 with the right password" $ do
565+ THW.request methodGet "/basic" [("Authorization","Basic c2VydmFudDpzZXJ2ZXI=")] "" `shouldRespondWith` 200
531------------------------------------------------------------------------------
568------------------------------------------------------------------------------
532-- * Test data types {{{
569-- * Test data types {{{