Haxl/tests/BadDataSource.hs

131 lines
3.8 KiB
Haskell
Raw Normal View History

-- Copyright (c) 2014-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is distributed under the terms of a BSD license,
-- found in the LICENSE file.
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RecordWildCards #-}
-- | A data source that can be made to fail in various ways, for testing
module BadDataSource (
-- * initialise the state
State(..), initGlobalState, FetchImpl(..),
-- * requests for this data source
FailAfter(..)
) where
import Haxl.Prelude
import Prelude ()
import Haxl.Core
import Control.Exception
import Data.Typeable
import Data.Hashable
import Control.Concurrent
import Control.Monad (void)
import GHC.Conc ( PrimMVar )
import Foreign.StablePtr
import Foreign.C.Types ( CInt(..) )
foreign import ccall safe
hs_try_putmvar :: CInt -> StablePtr PrimMVar -> IO ()
data FetchImpl =
Async
| Background
| BackgroundMVar
| BackgroundSeq
| BackgroundPar
data FailAfter a where
FailAfter :: Int -> FailAfter Int
deriving Typeable
deriving instance Eq (FailAfter a)
deriving instance Show (FailAfter a)
instance ShowP FailAfter where showp = show
instance Hashable (FailAfter a) where
hashWithSalt s (FailAfter a) = hashWithSalt s (0::Int,a)
instance StateKey FailAfter where
data State FailAfter = FailAfterState
{ failAcquireDelay :: Int
, failAcquire :: IO ()
, failReleaseDelay :: Int
, failRelease :: IO ()
, failDispatchDelay :: Int
, failDispatch :: IO ()
, failWaitDelay :: Int
, failWait :: IO ()
, failImpl :: FetchImpl
}
instance DataSourceName FailAfter where
dataSourceName _ = "BadDataSource"
instance DataSource u FailAfter where
fetch state@FailAfterState{..}
| BackgroundSeq <- failImpl = backgroundFetchSeq runOne state
| BackgroundPar <- failImpl = backgroundFetchPar runOne state
| Background <- failImpl = backgroundFetchAcquireRelease
acquire release dispatchbg wait
submit state
| BackgroundMVar <- failImpl = backgroundFetchAcquireReleaseMVar
acquire release dispatchbgMVar wait
submit state
| Async <- failImpl = asyncFetchAcquireRelease
acquire release dispatch wait
submit state
where
acquire = do threadDelay failAcquireDelay; failAcquire
release _ = do threadDelay failReleaseDelay; failRelease
dispatch _ = do threadDelay failDispatchDelay; failDispatch
dispatchBase put = (do
failDispatch
_ <- mask_ $ forkIO $ finally
(threadDelay failDispatchDelay)
put
return ()) `onException` put
dispatchbg _ c m = dispatchBase (hs_try_putmvar (fromIntegral c) m)
dispatchbgMVar _ _ m = dispatchBase (void $ tryPutMVar m ())
wait _ = do threadDelay failWaitDelay; failWait
submit :: () -> FailAfter a -> IO (IO (Either SomeException a))
submit _ (FailAfter t) = do
threadDelay t
return (return (Left (toException (FetchError "failed request"))))
runOne :: FailAfter a -> IO (Either SomeException a)
runOne r = do
bracket acquire release $ \s -> do
dispatch s
getRes <- submit s r
wait s
getRes
initGlobalState :: FetchImpl -> IO (State FailAfter)
initGlobalState impl = do
return FailAfterState
{ failAcquireDelay = 0
, failAcquire = return ()
, failReleaseDelay = 0
, failRelease = return ()
, failDispatchDelay = 0
, failDispatch = return ()
, failWaitDelay = 0
, failWait = return ()
, failImpl = impl
}