1 {-# LANGUAGE NoMonomorphismRestriction #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE StrictData #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 import Control.Applicative (Applicative(..))
8 import Control.Monad (Monad(..))
10 import Data.Either (Either(..))
11 import Data.Function (($), (.))
12 import Data.Functor ((<$>))
14 import Data.Maybe (Maybe(..))
15 import Data.Proxy (Proxy(..))
16 import Data.Semigroup (Semigroup(..))
17 import Data.String (IsString(..))
18 import Prelude (error, (+), (*))
20 import Text.Read (readMaybe)
21 import Text.Show (Show(..))
22 import qualified Data.ByteString.Lazy as BSL
23 import qualified Data.Text as Text
24 import qualified Data.Text.Encoding as Text
25 import qualified Data.Text.Lazy as TL
26 import qualified Data.Text.Lazy.Encoding as TL
27 import qualified Data.Time as Time
28 import qualified Network.HTTP.Client as Client
29 import qualified Network.HTTP.Media as Media
30 import qualified Network.HTTP.Types as HTTP
31 import qualified Network.URI as URI
32 import qualified Network.Wai.Handler.Warp as Warp
33 import qualified Test.Hspec.Wai as Wai
34 import qualified Web.HttpApiData as Web
38 import Test.Tasty.Hspec
45 | API0_Time Time.ZonedTime
48 instance IsString Time.TimeZone where
49 fromString s = case s of
50 "CET" -> Time.TimeZone (1*60) False "CET"
51 "CEST" -> Time.TimeZone (2*60) False "CEST"
52 _ -> error "unknown TimeZone"
53 instance Web.FromHttpApiData Time.TimeZone where
55 "CET" -> Right $ Time.TimeZone (1*60) True "CET"
56 "CEST" -> Right $ Time.TimeZone (2*60) False "CEST"
57 _ -> Left "unknown TimeZone"
58 instance Web.ToHttpApiData Time.TimeZone where
59 toUrlPiece (Time.TimeZone _s _b n) = Text.pack n
61 manager :: IO Client.Manager
62 manager = Client.newManager Client.defaultManagerSettings
63 Just baseURI = URI.parseURI "http://localhost:8080"
64 cliEnv = clientEnv <$> manager <*> pure baseURI
67 = "time" </> capture @Time.TimeZone "timezone"
68 <.> get @TL.Text @'[PlainText]
70 <!> "date" </> get @TL.Text @'[PlainText]
72 <!> "echo" </> captureAll
73 <.> get @TL.Text @'[PlainText]
75 <!> "succ" </> capture @Int "n"
76 <.> get @Int @'[PlainText]
78 <!> "info" </> ( head @TL.Text @'[PlainText]
79 <!> get @TL.Text @'[PlainText]
82 instance MimeEncodable Int PlainText where
83 mimeEncode _mt = BSL.fromStrict . Text.encodeUtf8 . Text.pack . show
84 instance MimeDecodable Int PlainText where
86 case readMaybe $ TL.unpack $ TL.decodeUtf8 s of
88 _ -> Left "cannot parse Int"
107 route_time tz (ServerRespond respond) =
108 ServerResponse $ \_req res -> do
109 time <- Time.utcToZonedTime tz <$> Time.getCurrentTime
110 res $ respond status200 [] $
111 TL.pack $ show time <> "\n"
113 route_date (ServerRespond respond) =
114 ServerResponse $ \_req res -> do
115 date <- Time.utctDay <$> Time.getCurrentTime
116 res $ respond status200 [] $
117 TL.pack $ show date <> "\n"
119 route_echo path (ServerRespond respond) =
120 ServerResponse $ \_req res -> do
121 res $ respond status200 [] $ TL.pack $ show path <> "\n"
123 route_succ n (ServerRespond respond) =
124 ServerResponse $ \_req res -> do
125 res $ respond status200 [] $ n+1
127 route_info = route_head :!: route_get
129 route_head (ServerRespond respond) =
130 ServerResponse $ \req res -> do
131 res $ respond (HTTP.mkStatus 201 "") [] $ TL.pack $ show req <> "\n"
133 route_get (ServerRespond respond) =
134 ServerResponse $ \req res -> do
135 res $ respond status200 [] $ TL.pack $ show req <> "\n"
138 warp1 = Warp.run 8080 srv1
140 api2 = "ti"</>"me" </> get @TL.Text @'[PlainText]
141 <!> "auth" </> basicAuth @User "realm"
142 <.> get @TL.Text @'[PlainText]
143 <!> "da"</>"te" </> get @TL.Text @'[PlainText]
147 instance ServerBasicAuth User where
148 serverBasicAuth user pass =
149 return $ BasicAuth_Authorized User
156 route_time (ServerRespond respond) =
157 ServerResponse $ \_req res -> do
158 time <- Time.getCurrentTime
159 res $ respond status200 [] $
160 TL.pack $ show time <> "\n"
162 route_date (ServerRespond respond) =
163 ServerResponse $ \_req res -> do
164 date <- Time.utctDay <$> Time.getCurrentTime
165 res $ respond status200 [] $
166 TL.pack $ show date <> "\n"
168 route_auth User (ServerRespond respond) =
169 ServerResponse $ \_req res -> do
170 res $ respond status200 [] $
171 TL.pack $ show User <> "\n"
174 warp2 = Warp.run 8080 srv2
178 Wai.with (return srv2) $ do
179 it "respond with success" $ do
181 `Wai.shouldRespondWith` 200
182 it "checks Accept header" $ do
183 Wai.request HTTP.methodGet "/da/te"
184 [ (HTTP.hAccept, Media.renderHeader $ mediaType @OctetStream)
186 `Wai.shouldRespondWith` 406