packages feed

cachix-1.14.0: test/ServantSpec.hs

{-# LANGUAGE DataKinds #-}

module ServantSpec (spec) where

import Cachix.Client.Servant (withResponseTimeout)
import Network.HTTP.Client qualified as HTTP
import Network.Socket.ByteString qualified as Socket
import Protolude
import Servant.API (Get, JSON)
import Servant.Client.Streaming
import StalledServer (withServer)
import Test.Hspec

spec :: Spec
spec = describe "scoped response timeout" $ do
  it "allows a slow response only within the overridden action" $
    withDelayedClient $ \env -> do
      result <- runClientM (withResponseTimeout HTTP.responseTimeoutNone getNumber) env
      result `shouldBe` Right 17
      normalResult <- runClientM getNumber env
      normalResult `shouldSatisfy` isResponseTimeout
  it "keeps the default timeout for other actions" $
    withDelayedClient $ \env -> do
      result <- runClientM getNumber env
      result `shouldSatisfy` isResponseTimeout

getNumber :: ClientM Int
getNumber = client (Proxy :: Proxy (Get '[JSON] Int))

withDelayedClient :: (ClientEnv -> IO a) -> IO a
withDelayedClient action = withServer respond $ \port _ -> do
  manager <-
    HTTP.newManager $
      HTTP.managerSetProxy HTTP.noProxy $
        HTTP.defaultManagerSettings
          { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro 100_000
          }
  action $ mkClientEnv manager (BaseUrl Http "127.0.0.1" port "")
  where
    respond connection = do
      void $ Socket.recv connection 4096
      threadDelay 500_000
      Socket.sendAll connection "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 2\r\nConnection: close\r\n\r\n17"

isResponseTimeout :: Either ClientError a -> Bool
isResponseTimeout (Left (ConnectionError exception)) =
  case fromException exception of
    Just (HTTP.HttpExceptionRequest _ HTTP.ResponseTimeout) -> True
    _ -> False
isResponseTimeout _ = False