{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE MonoLocalBinds    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications  #-}
{-|
Copyright   : (c) 2020-2021 Tim Emiola
SPDX-License-Identifier: BSD3
Maintainer  : Tim Emiola <adetokunbo@users.noreply.github.com>

An demo @HSpec@ test that use @tmp-proc@

-}
module TmpProc.Example2.IntegrationSpec where

import           Test.Hspec
import           Test.Hspec.TmpProc             (AreProcs, HasHandle,
                                                 ServerHandle, handleOf,
                                                 handles, runServer, serverPort,
                                                 shutdown, tdescribe,
                                                 terminateAll, withConnOf, (&:))

import           Control.Exception              (onException)
import           Data.Either                    (isLeft)
import           Data.Maybe                     (isJust)
import           Data.Proxy                     (Proxy (..))
import           Network.HTTP.Client            (newManager)
import           Network.HTTP.Client.TLS        (tlsManagerSettings)
import           Servant.Client                 (BaseUrl (..), ClientEnv,
                                                 Scheme (..), mkClientEnv,
                                                 runClientM)

import           System.TmpProc.Docker.Postgres
import           System.TmpProc.Docker.Redis

import qualified TmpProc.Example2.Cache         as Cache
import qualified TmpProc.Example2.Client        as Client
import qualified TmpProc.Example2.Database      as DB
import           TmpProc.Example2.Schema        (Contact (..), ContactID)
import           TmpProc.Example2.Server        (AppEnv (..), waiApp)


{-| The test uses a Postgres database . -}
dbProc :: TmpPostgres
dbProc :: TmpPostgres
dbProc = [Text] -> TmpPostgres
TmpPostgres [Text
"contacts"] -- 'reset' will empty the contacts table


{-| The test uses Redis as a cache. -}
cacheProc :: TmpRedis
cacheProc :: TmpRedis
cacheProc = [KeyName] -> TmpRedis
TmpRedis []


{-| Specifies the procs to be launched as test fixtures.  -}
testProcs :: HList '[TmpPostgres, TmpRedis]
testProcs :: HList '[TmpPostgres, TmpRedis]
testProcs = TmpPostgres
dbProc TmpPostgres -> HList '[TmpRedis] -> HList '[TmpPostgres, TmpRedis]
forall x (xs :: [*]). x -> HList xs -> HList (x : xs)
&: TmpRedis
cacheProc TmpRedis -> HList '[] -> HList '[TmpRedis]
forall x (xs :: [*]). x -> HList xs -> HList (x : xs)
&: HList '[]
HNil


{-| Specifies the expected behaviour. -}
spec :: Spec
spec :: Spec
spec = String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
tdescribe String
"Tmp.Proc:Demo of testing of DB/Cache server" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
  IO Fixture -> SpecWith Fixture -> Spec
forall a. IO a -> SpecWith a -> Spec
beforeAll IO Fixture
mkFixture (SpecWith Fixture -> Spec) -> SpecWith Fixture -> Spec
forall a b. (a -> b) -> a -> b
$ ActionWith Fixture -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => ActionWith a -> SpecWith a -> SpecWith a
afterAll ActionWith Fixture
shutdown' (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

    String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"When the database is empty, using the client to fetch a contact" (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

      String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should throw an error" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
_, ClientEnv
clientEnv) ->
        ((Either ClientError Contact -> Bool)
-> IO (Either ClientError Contact) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either ClientError Contact -> Bool
forall a b. Either a b -> Bool
isLeft (IO (Either ClientError Contact) -> IO Bool)
-> IO (Either ClientError Contact) -> IO Bool
forall a b. (a -> b) -> a -> b
$ ClientM Contact -> ClientEnv -> IO (Either ClientError Contact)
forall a. ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM (ContactID -> ClientM Contact
Client.fetch ContactID
1) ClientEnv
clientEnv) IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
True

      String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"and the contact "(SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should not be found in the DB" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) ->
          ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
hasInDb ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
1 IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
False

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should not be found in the cache" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) -> do
          ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
forall (procs :: [*]).
HasHandle TmpRedis procs =>
ServerHandle procs -> ContactID -> IO Bool
hasInCache ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
1 IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
False


      String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"and using the client to insert a contact" (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should succeed" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
_, ClientEnv
clientEnv) ->
          ((Either ClientError ContactID -> Bool)
-> IO (Either ClientError ContactID) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either ClientError ContactID -> Bool
forall a b. Either a b -> Bool
isLeft (IO (Either ClientError ContactID) -> IO Bool)
-> IO (Either ClientError ContactID) -> IO Bool
forall a b. (a -> b) -> a -> b
$ ClientM ContactID -> ClientEnv -> IO (Either ClientError ContactID)
forall a. ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM (Contact -> ClientM ContactID
Client.create Contact
testContact) ClientEnv
clientEnv) IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
False


    String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"When the client is used to insert a contact" (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

      String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"then the contact "(SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should be found in the DB" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) ->
          ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
hasInDb ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
1 IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
True

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should not be found in the cache" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) -> do
          ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
forall (procs :: [*]).
HasHandle TmpRedis procs =>
ServerHandle procs -> ContactID -> IO Bool
hasInCache ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
1 IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
False

      String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"and using the client to fetch the contact" (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should succeed" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
_, ClientEnv
clientEnv) ->
          ((Either ClientError Contact -> Bool)
-> IO (Either ClientError Contact) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either ClientError Contact -> Bool
forall a b. Either a b -> Bool
isLeft (IO (Either ClientError Contact) -> IO Bool)
-> IO (Either ClientError Contact) -> IO Bool
forall a b. (a -> b) -> a -> b
$ ClientM Contact -> ClientEnv -> IO (Either ClientError Contact)
forall a. ClientM a -> ClientEnv -> IO (Either ClientError a)
runClientM (ContactID -> ClientM Contact
Client.fetch ContactID
1) ClientEnv
clientEnv) IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
False

    String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"After fetching the contact with the client" (SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

      String -> SpecWith Fixture -> SpecWith Fixture
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
context String
"then the contact "(SpecWith Fixture -> SpecWith Fixture)
-> SpecWith Fixture -> SpecWith Fixture
forall a b. (a -> b) -> a -> b
$ do

        String -> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"should be found in the cache" (ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture)))
-> ActionWith Fixture -> SpecWith (Arg (ActionWith Fixture))
forall a b. (a -> b) -> a -> b
$ \(ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) -> do
          ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
forall (procs :: [*]).
HasHandle TmpRedis procs =>
ServerHandle procs -> ContactID -> IO Bool
hasInCache ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
1 IO Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => IO a -> a -> Expectation
`shouldReturn` Bool
True


{-| Simplifies the test cases

Note the use of the 'HasHandle' constraint to indicate what TmpProcs the function uses.

-}
hasInCache :: HasHandle TmpRedis procs => ServerHandle procs -> ContactID -> IO Bool
hasInCache :: ServerHandle procs -> ContactID -> IO Bool
hasInCache ServerHandle procs
sh ContactID
cid = Proxy TmpRedis
-> HandlesOf procs -> (Conn TmpRedis -> IO Bool) -> IO Bool
forall k (idx :: k) (procs :: [*]) namedConn b.
(HandleOf idx procs namedConn, Connectable namedConn) =>
Proxy idx -> HandlesOf procs -> (Conn namedConn -> IO b) -> IO b
withConnOf @TmpRedis Proxy TmpRedis
forall k (t :: k). Proxy t
Proxy (ServerHandle procs -> HandlesOf procs
forall (procs :: [*]).
AreProcs procs =>
ServerHandle procs -> HandlesOf procs
handles ServerHandle procs
sh) ((Conn TmpRedis -> IO Bool) -> IO Bool)
-> (Conn TmpRedis -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Conn TmpRedis
cache ->
  (Maybe Contact -> Bool) -> IO (Maybe Contact) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe Contact -> Bool
forall a. Maybe a -> Bool
isJust (IO (Maybe Contact) -> IO Bool) -> IO (Maybe Contact) -> IO Bool
forall a b. (a -> b) -> a -> b
$ Connection -> ContactID -> IO (Maybe Contact)
Cache.loadContact Connection
Conn TmpRedis
cache ContactID
cid


{-| Simplifies the test cases

Here, ServerHandle specifies the full list of types required by the calling test code.

-}
hasInDb :: ServerHandle ('[TmpPostgres, TmpRedis]) -> ContactID -> IO Bool
hasInDb :: ServerHandle '[TmpPostgres, TmpRedis] -> ContactID -> IO Bool
hasInDb ServerHandle '[TmpPostgres, TmpRedis]
sh ContactID
cid = do
  let dbUriOf :: ServerHandle '[TmpPostgres, TmpRedis] -> KeyName
dbUriOf = ProcHandle TmpPostgres -> KeyName
forall a. ProcHandle a -> KeyName
hUri (ProcHandle TmpPostgres -> KeyName)
-> (ServerHandle '[TmpPostgres, TmpRedis]
    -> ProcHandle TmpPostgres)
-> ServerHandle '[TmpPostgres, TmpRedis]
-> KeyName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy "a-postgres-db"
-> HandlesOf '[TmpPostgres, TmpRedis] -> ProcHandle TmpPostgres
forall k (a :: k) (procs :: [*]) b.
HandleOf a procs b =>
Proxy a -> HandlesOf procs -> ProcHandle b
handleOf @"a-postgres-db" Proxy "a-postgres-db"
forall k (t :: k). Proxy t
Proxy (HandlesOf '[TmpPostgres, TmpRedis] -> ProcHandle TmpPostgres)
-> (ServerHandle '[TmpPostgres, TmpRedis]
    -> HandlesOf '[TmpPostgres, TmpRedis])
-> ServerHandle '[TmpPostgres, TmpRedis]
-> ProcHandle TmpPostgres
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ServerHandle '[TmpPostgres, TmpRedis]
-> HandlesOf '[TmpPostgres, TmpRedis]
forall (procs :: [*]).
AreProcs procs =>
ServerHandle procs -> HandlesOf procs
handles
  (Maybe Contact -> Bool) -> IO (Maybe Contact) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe Contact -> Bool
forall a. Maybe a -> Bool
isJust (IO (Maybe Contact) -> IO Bool) -> IO (Maybe Contact) -> IO Bool
forall a b. (a -> b) -> a -> b
$ (KeyName -> ContactID -> IO (Maybe Contact))
-> ContactID -> KeyName -> IO (Maybe Contact)
forall a b c. (a -> b -> c) -> b -> a -> c
flip KeyName -> ContactID -> IO (Maybe Contact)
DB.fetch ContactID
cid (KeyName -> IO (Maybe Contact)) -> KeyName -> IO (Maybe Contact)
forall a b. (a -> b) -> a -> b
$ ServerHandle '[TmpPostgres, TmpRedis] -> KeyName
dbUriOf ServerHandle '[TmpPostgres, TmpRedis]
sh


{-| The full test fixture.

It allows tests to

- use the servant client to invoke the backend
- check the state of service backends via the @ProcHandles@ in the 'ServerHandle'.

-}
type Fixture = (ServerHandle ('[TmpPostgres, TmpRedis]), ClientEnv)


mkFixture :: IO Fixture
mkFixture :: IO Fixture
mkFixture = do
  let mkApp :: HList (Proc2Handle procs) -> IO Application
mkApp HList (Proc2Handle procs)
someHandles = do

        -- handleOf can obtain a handle using either the Proc type ...
        let redisH :: ProcHandle TmpRedis
redisH = Proxy TmpRedis -> HList (Proc2Handle procs) -> ProcHandle TmpRedis
forall k (a :: k) (procs :: [*]) b.
HandleOf a procs b =>
Proxy a -> HandlesOf procs -> ProcHandle b
handleOf @TmpRedis Proxy TmpRedis
forall k (t :: k). Proxy t
Proxy HList (Proc2Handle procs)
someHandles

            -- or the Name of it's Proc type
            dbLoc :: KeyName
dbLoc  = ProcHandle TmpPostgres -> KeyName
forall a. ProcHandle a -> KeyName
hUri (ProcHandle TmpPostgres -> KeyName)
-> ProcHandle TmpPostgres -> KeyName
forall a b. (a -> b) -> a -> b
$ Proxy "a-postgres-db"
-> HList (Proc2Handle procs) -> ProcHandle TmpPostgres
forall k (a :: k) (procs :: [*]) b.
HandleOf a procs b =>
Proxy a -> HandlesOf procs -> ProcHandle b
handleOf @"a-postgres-db" Proxy "a-postgres-db"
forall k (t :: k). Proxy t
Proxy HList (Proc2Handle procs)
someHandles

        -- Create the database schema
        KeyName -> Expectation
DB.migrateDB KeyName
dbLoc Expectation -> Expectation -> Expectation
forall a b. IO a -> IO b -> IO a
`onException` HList (Proc2Handle procs) -> Expectation
forall (procs :: [*]).
AreProcs procs =>
HandlesOf procs -> Expectation
terminateAll HList (Proc2Handle procs)
someHandles

        -- Determine the redis location
        Connection
cache <- ProcHandle TmpRedis -> IO (Conn TmpRedis)
forall a. Connectable a => ProcHandle a -> IO (Conn a)
openConn ProcHandle TmpRedis
redisH  IO Connection -> Expectation -> IO Connection
forall a b. IO a -> IO b -> IO a
`onException` HList (Proc2Handle procs) -> Expectation
forall (procs :: [*]).
AreProcs procs =>
HandlesOf procs -> Expectation
terminateAll HList (Proc2Handle procs)
someHandles

        Application -> IO Application
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Application -> IO Application) -> Application -> IO Application
forall a b. (a -> b) -> a -> b
$ AppEnv -> Application
waiApp (AppEnv -> Application) -> AppEnv -> Application
forall a b. (a -> b) -> a -> b
$ KeyName -> Connection -> AppEnv
AppEnv KeyName
dbLoc Connection
cache

  ServerHandle '[TmpPostgres, TmpRedis]
sh <- HList '[TmpPostgres, TmpRedis]
-> (HandlesOf '[TmpPostgres, TmpRedis] -> IO Application)
-> IO (ServerHandle '[TmpPostgres, TmpRedis])
forall (procs :: [*]).
AreProcs procs =>
HList procs
-> (HandlesOf procs -> IO Application) -> IO (ServerHandle procs)
runServer HList '[TmpPostgres, TmpRedis]
testProcs HandlesOf '[TmpPostgres, TmpRedis] -> IO Application
forall (procs :: [*]).
(AreProcs procs,
 MemberKV
   "a-postgres-db"
   (ProcHandle TmpPostgres)
   (Handle2KV (Proc2Handle procs)),
 IsInProof (ProcHandle TmpRedis) (Proc2Handle procs)) =>
HList (Proc2Handle procs) -> IO Application
mkApp
  ClientEnv
clientEnv <- ServerHandle '[TmpPostgres, TmpRedis] -> IO ClientEnv
forall (procs :: [*]).
AreProcs procs =>
ServerHandle procs -> IO ClientEnv
clientEnvOf ServerHandle '[TmpPostgres, TmpRedis]
sh
  Fixture -> IO Fixture
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
clientEnv)


shutdown' :: Fixture -> IO ()
shutdown' :: ActionWith Fixture
shutdown' (ServerHandle '[TmpPostgres, TmpRedis]
sh, ClientEnv
_) = ServerHandle '[TmpPostgres, TmpRedis] -> Expectation
forall (procs :: [*]).
AreProcs procs =>
ServerHandle procs -> Expectation
shutdown ServerHandle '[TmpPostgres, TmpRedis]
sh


clientEnvOf :: AreProcs procs => ServerHandle procs -> IO ClientEnv
clientEnvOf :: ServerHandle procs -> IO ClientEnv
clientEnvOf ServerHandle procs
s = do
  Manager
mgr <- ManagerSettings -> IO Manager
newManager ManagerSettings
tlsManagerSettings
  ClientEnv -> IO ClientEnv
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ClientEnv -> IO ClientEnv) -> ClientEnv -> IO ClientEnv
forall a b. (a -> b) -> a -> b
$ Manager -> BaseUrl -> ClientEnv
mkClientEnv Manager
mgr (BaseUrl -> ClientEnv) -> BaseUrl -> ClientEnv
forall a b. (a -> b) -> a -> b
$ Scheme -> String -> Int -> String -> BaseUrl
BaseUrl Scheme
Http String
"localhost" (ServerHandle procs -> Int
forall (procs :: [*]). ServerHandle procs -> Int
serverPort ServerHandle procs
s) String
""


testContact :: Contact
testContact :: Contact
testContact = Contact :: Text -> Text -> Int -> Text -> Contact
Contact
  { contactName :: Text
contactName = Text
"Bond"
  , contactEmail :: Text
contactEmail = Text
"james@hmss.gov.uk"
  , contactAge :: Int
contactAge = Int
45
  , contactTitle :: Text
contactTitle = Text
"Mr"
  }