module HelperSpec (helperSpec) where import Control.Exception.Base import qualified Data.ByteString as BS import Data.IORef import Data.Maybe import qualified Data.Sequence as Seq import Network.HTTP.Types.Header import Network.HTTP.Types.Status import Network.HTTP.Types.Version import OpenAI.Client.Internal.Helpers import Servant.Client import Servant.Client.Core.Request import System.Exit import Test.Hspec helperSpec :: Spec helperSpec = do describe "retries" retryTests makeFakeAction :: (Int -> Either ClientError a) -> IO (IO Int, IO (Either ClientError a)) makeFakeAction makeResult = do calls <- newIORef 0 let action = do call <- atomicModifyIORef calls $ \i -> (i + 1, i) pure (makeResult call) pure (readIORef calls, action) dummyReq :: RequestF () (BaseUrl, BS.ByteString) dummyReq = defaultRequest { requestBody = Nothing, requestPath = (fromJust $ parseBaseUrl "api.example.com", "") } retryAction :: Int -> Status -> Seq.Seq Header -> IO (ClientError, IO Int, IO (Either ClientError Bool)) retryAction n status headers = do let errResp = Response { responseStatusCode = status, responseHeaders = headers, responseHttpVersion = http11, responseBody = mempty } err = FailureResponse dummyReq errResp (getCalls, action) <- makeFakeAction $ \call -> if call < n then Left $ err else Right True pure (err, getCalls, action) retryTests :: SpecWith () retryTests = do it "does not retry on success" $ do (getCalls, action) <- makeFakeAction (const $ Right True) runRequest 10 0 action `shouldReturn` Right True getCalls `shouldReturn` 1 it "retries on connection errors" $ do (getCalls, action) <- makeFakeAction $ \call -> if call == 0 then Left (ConnectionError $ toException ExitSuccess) else Right True runRequest 10 0 action `shouldReturn` Right True getCalls `shouldReturn` 2 it "retries on 409 status code" $ do (_, getCalls, action) <- retryAction 1 status409 mempty runRequest 10 0 action `shouldReturn` Right True getCalls `shouldReturn` 2 it "retries on 500 status code" $ do (_, getCalls, action) <- retryAction 1 status500 mempty runRequest 10 0 action `shouldReturn` Right True getCalls `shouldReturn` 2 it "does not retry on status 500 if limit exceeded" $ do (err, getCalls, action) <- retryAction 11 status500 mempty runRequest 10 0 action `shouldReturn` Left err getCalls `shouldReturn` 10