packages feed

rdkafka-hs-1.1.0.0: test-integration/Kafka/ConsumerStateSupport.hs

module Kafka.ConsumerStateSupport (withStateFault, endStateFault, stateStat, triggerRebalance, triggerCooperative, stateLeakControl, commitObservation, withQueueTracking, queueEventStat, awaitQueuedRecord) where

import Control.Concurrent (threadDelay)
import Control.Exception (bracket_)
import Data.Text qualified as Text
import Foreign.C.String (CString, withCString)
import Foreign.C.Types (CInt (..))
import Kafka.Types (TopicName (..))
import System.Timeout (timeout)
import Test.Tasty.HUnit (assertFailure)

foreign import ccall unsafe "rdkafka_hs_test_state_begin" begin :: CInt -> IO ()

foreign import ccall unsafe "rdkafka_hs_test_state_end" endStateFault :: IO ()

foreign import ccall unsafe "rdkafka_hs_test_state_stat" stat :: CInt -> IO CInt

foreign import ccall safe "rdkafka_hs_test_state_trigger" trigger :: CString -> IO ()

foreign import ccall safe "rdkafka_hs_test_state_trigger_cooperative" triggerCooperativeNative :: CString -> CInt -> IO ()

triggerCooperative :: TopicName -> Bool -> IO ()
triggerCooperative (TopicName topic) revoke = withCString (Text.unpack topic) (\name -> triggerCooperativeNative name (if revoke then 1 else 0))

foreign import ccall unsafe "rdkafka_hs_test_state_leak_control" stateLeakControl :: IO ()

withStateFault :: Int -> IO a -> IO a
withStateFault mode = bracket_ (begin (fromIntegral mode)) endStateFault

stateStat :: Int -> IO Int
stateStat index = fromIntegral <$> stat (fromIntegral index)

triggerRebalance :: TopicName -> IO ()
triggerRebalance (TopicName topic) = withCString (Text.unpack topic) trigger

foreign import ccall unsafe "rdkafka_hs_test_state_commit_count" commitCount :: IO CInt

foreign import ccall unsafe "rdkafka_hs_test_state_commit_async" commitAsync :: IO CInt

commitObservation :: IO (Int, Int)
commitObservation = (,) <$> (fromIntegral <$> commitCount) <*> (fromIntegral <$> commitAsync)

foreign import ccall unsafe "rdkafka_hs_test_queue_begin" beginQueue :: IO ()

foreign import ccall unsafe "rdkafka_hs_test_queue_end" endQueue :: IO ()

foreign import ccall unsafe "rdkafka_hs_test_queue_stat" statQueue :: CInt -> IO CInt

withQueueTracking :: IO a -> IO a
withQueueTracking = bracket_ beginQueue endQueue

queueEventStat :: Int -> IO Int
queueEventStat index = fromIntegral <$> statQueue (fromIntegral index)

awaitQueuedRecord :: IO () -> IO ()
awaitQueuedRecord refresh = timeout 10000000 loop >>= maybe (assertFailure "record was not queued before enabling notification") pure
  where
    loop = do
      refresh
      count <- queueEventStat 1
      if count < 0
        then assertFailure "notification destination queue was not observed"
        else if count > 0 then pure () else threadDelay 1000 >> loop